API-Version: 1.9
// See COPYING for copyright and license details
(function() {
    var _modules = {};
    var _requires = {};
    var _callbacks = [];
    var _initialized = false;
    var _pending = [];
    var _contexts = {};
    var _applyRequired = function(names, callback) 
    {
        if (names === null) {
            callback.call(this, _modules);
        }
        else 
        {
            var j, m;
            var modules = [];
            var name, detail;
            for (j=0, m=names.length; j<m; j++) 
            {
                name = names[j];
                if (/^\w*!/.test(name)) 
                {
                    detail = name.split("!");
                    name = detail[0];
                    if (!_modules[name]) {
                        include(detail.slice(1).join("!"));
                    }
                }
                if (_modules[name])
                {
                    modules.push(_modules[name]);
                }
                else 
                {
                    _pending.push({names : names, callback : callback});
                    return;
                }
            } 
            /**
             * Callback that will be called when all provided modules have been
             * loaded
             *
             * @callback requireCallback
             *
             * @param {...varargs|Object} arguments 
             *      Variable number of modules, for each module one argument, if
             *      <i>null</i> was passed to require the callback will only
             *      have one parameter that contains all modules.
             *
             * @example 
             * require(["foo", "bar"], function(foo, bar) {
             *      ...
             * });
             * require(null, function(modules) {
             *      var foo = modules.foo;
             *      var bar = modules.bar;
             * });
             *
             *
             * */
            if (callback) {
                callback.apply(callback, modules);
            }
        }
    };
    function _removeTimerHandle()  {
        timer._stop(this.id);
    }
    /**
     * Calls a function reqeatedly or after a timeout, similar to window.setInterval
     * or window.setTimeout that are available in the webcontext.
     * @name start 
     * @memberOf timer
     * @function
     * @example 
     * // equivalent to window.setInterval
     * timer.start(1000, function() {
     *      ...
     * });
     * // equivalent to window.setTimeout
     * timer.start(1000, function() {
     *      ...
     *      return false;
     * });
     * 
     * @param {Number} interval The interval in milliseconds, the minimum interval
     *                          is 10 milliseconds
     * @param {timer~startCallback} callback 
     *      The callback that will be called, if the callback returns <i>false</i>
     *      the timer will be stopped
     *
     * @returns {Object}
     *      A handle, call handle.remove or timer.stop(handle) to stop the
     *      timer.
     * */

    Object.defineProperties(timer, { 
        "start" : {
            value : function() {
                var id = this._start.apply(null, arguments);
                return { id : id, remove : _removeTimerHandle };
            }
        },
        // FIXME: wrapper for old api, remove the at some point
        "stop" : {
            value : function(handle) {
                return this._stop(handle.id);
            }
        }

    });
    Object.defineProperties(this, { 
        /** 
         * Bind a function to a shortcut or commandline command, use {@link unbind} to remove
         * the command
         * @name bind 
         * @function
         *
         * @param {String} shortcut 
         *      A shortcut, the syntax is the same as in dwb:keys, pass <i>null</i> if
         *      only a commandline command should be bound 
         * @param {bindCallback} callback 
         *      A callback function that will be called if the shortcut is pressed or
         *      the command was executed from commandline
         * @param {String|OverrideKey} [command|override] 
         *      A command the can be used on dwb's commandline or an 
         *      {@link Enums and Flags.OverrideKey|OverrideKey} flag 
         *
         * @returns {Object}
         *      An handle that contains an id, handle.remove() or
         *      unbind(handle.id) will unbind this shortcut
         * @example 
         * bind("Control U", function () { 
         *      execute("tabopen " + tabs.current.uri);
         * }, "tabopen_current");
         *
         * */
        "bind" : {
            value : function() {
                var id = _bind.apply(null, arguments);
                if (id != -1) {
                    return { 
                        id : id, 
                        remove : function() {
                            unbind(id);
                        }
                    };
                }
                return { remove : function() {} };
            }
        },
        /** 
         * Adds a custom hintmode, similar to {@link bind} but executes the
         * function before the hint will be followed, use {@link unbind} to
         * remove the hintmode
         *
         * @name hint
         * @function
         * @since 1.4
         *
         * @param {String} shortcut 
         *      A shortcut to start the hint mode
         * @param {Function} callback 
         *      The callback function, that will be called before the hint is
         *      followed, see {@link signals~onFollowHint}. To handle the hint
         *      and prevent dwb from following the hint the callback must
         *      return true. The callback won't be called if escape was pressed.
         * @param {String} command 
         *      The command to start the hint mode
         * @param {String} [selector] 
         *      A css selector passed to querySelectorAll
         * */
        "hint" : { 
            value : function(shortcut, callback, command, selector) {
                bind(shortcut, function() {
                    Signal.once("followHint", function(wv, resource) {
                        if (resource == "@abort")
                            return false;
                        return callback(wv, resource);
                    });
                    if (selector)
                    {
                        execute("hints_selector " + selector);
                    }
                    else 
                    {
                        execute("hints");
                    }
                });
            }
        },
        "Glob" : 
        { 
            value : (function() {
                var esc = new RegExp("[-\/\\^$+.()|[\]{}]", "g");
                var matcher = new RegExp("(\\\\)?([*?])", "g");
                var cnstr = function (m, f, s) { 
                    return f ? m : s == "?" ? "." : ".*";
                };
                /** 
                 * Constructs a new Glob
                 *
                 * @name Glob
                 * @class   Globs are similar to regular expressions but much
                 *          simpler, can be used for pattern matching. They
                 *          only match against wildcard <b>*</b> and joker
                 *          <b>?</b> where the wildcard character matches
                 *          any number of unknown characters and the joker
                 *          matches exactly one unkown character. Note that
                 *          internally regular expressions are used, so Glob
                 *          matching is not faster than RegExp matching.
                 * @constructs Glob
                 *
                 * @param {String} pattern The pattern to match against
                 *
                 * @example 
                 * var g = new Glob("foo*ba?baz");
                 * */
                return function(p) { 
                    var inner = p.replace(esc, '\\$&').replace(matcher, cnstr);
                    var regex = new RegExp("^" + inner + "$");
                    var searchPattern = new RegExp(inner);
                    return Object.create(Object.prototype, {
                            /** 
                             * Match against a text
                             * @name match
                             * @memberOf Glob.prototype
                             * @function 
                             * @example 
                             * var glob = new Glob("foo*ba?");
                             * glob.match("foobarbaz");       // true
                             * glob.match("foobaz");          // true
                             * glob.match("foobarbazx");      // false
                             * glob.match("fooba");           // false
                             *
                             * @param {String} text The text to match
                             *                      against 
                             * @returns {Boolean}
                             *      <i>true</i> if the pattern was found
                             * */
                            match : { value : function(string) { return regex.test(string); } }, 
                            /**
                             * Searches for the first occurence of the pattern
                             * in a string and returns the position.
                             *
                             * @name search
                             * @memberOf Glob.prototype
                             * @function
                             *
                             * @param {String} string 
                             *      The string to search for the pattern 
                             *
                             * @returns {Number} 
                             *      The first occurence or -1 if the pattern was
                             *      not found
                             *
                             * @example 
                             * var glob = new Glob("l?si*");
                             * glob.search("Melosine"); // 2
                             * */
                            search : { value : function(string) { return string.search(searchPattern); } },
                            /**
                             * Searches for the first occurence of the pattern
                             * in a string and returns the match.
                             *
                             * @name exec 
                             * @memberOf Glob.prototype
                             * @function 
                             *
                             * @param {String} string 
                             *      The string to search for the pattern 
                             *
                             * @returns {String} 
                             *      The match or <i>null</i> if the pattern
                             *      wasn't found
                             * @example 
                             * var glob = new Glob("l*si?");
                             * glob.exec("Melosine"); // "losin"
                             * */
                            exec : 
                            { 
                                value : function(string) 
                                { 
                                    var match = searchPattern.exec(string);
                                    return match ? match[0] : null;
                                } 
                            }, 
                            /** 
                             * Converts a glob to string
                             * @name toString
                             * @memberOf Glob.prototype
                             * @function 
                             *
                             * @returns {String}
                             *      The original pattern passed to the constructor
                             * */
                            toString : { value : function() { return p; } }
                    });
                };
            })()
        },
        /** 
         * Define a module that can be retrieved with require in other scripts
         * @name provide 
         * @function
         *
         * @param {String} name The name of the module
         * @param {Object} module The module
         * @param {Boolean} [overwrite]
         *      Whether to overwrite existing module with
         *      the same name, default false
         * @example 
         * provide("foo", {
         *    baz : 37, 
         *    bar : function() { ... }
         * });
         *
         * */
        "provide" : 
        { 
            value : function(name, module, overwrite) 
            {
                if (overwrite)
                {
                    if (!module && _modules[name])
                    {
                        for (var key in _modules[name]) 
                            delete _modules[name][key];

                        delete _modules[name];
                    }
                }
                if (!overwrite && _modules[name]) 
                {
                    io.debug({ 
                            offset : 1, arguments : arguments,
                            error : new Error("provide: Module " + 
                                              name + " is already defined!")
                    });
                }
                else 
                    _modules[name] = module;

                var pl = _pending.length;
                if (pl > 0)
                {
                    var pending = [];
                    var finished = [];
                    for (var i=0; i<pl; i++) 
                    {
                        if (_pending[i].names.every(function(name) { return _modules[name]; }))
                        {
                            finished.push(_pending[i]);
                        }
                        else 
                            pending.push(_pending[i]);
                    }
                    for (i=0; i<finished.length; i++)
                        _applyRequired(finished[i].names, finished[i].callback);
                    _pending = pending;
                }
            }
        },
        /** 
         * Load modules defined in other scripts. 
         * @name require 
         * @function
         *
         * @param {Array|String} names 
         *      Array of module names, a module name or null. If an array or
         *      null is passed require is called asynchronously, passing null
         *      will require all modules. If a string is passed to require
         *      it will be synchronous. The module must have been already defined if the
         *      synchronous version is used. If all modules are defined during
         *      startup all modules will be defined after the <i>ready</i> event
         *      has been emitted.
         *      
         * @param {requireCallback} [callback]
         *      A callback function, the modules are passed as parameters to
         *      the callback, only used if require is used asynchronously
         *
         * @returns {Object|undefined}
         *      The synchronous version returns the module, the asynchronous
         *      version returns nothing.
         * @example 
         * // asynchronous
         * require(["foo", "bar"], function(foo, bar) {
         *    io.print(foo.baz);
         * });
         *
         * // synchronous
         * var foo = require("foo");
         * io.print(foo.baz);
         *
         * // ensuring that all modules have been defined for synchronous loading
         * Signal.connect("ready", function() {
         *     var foo = require("foo");
         * });
         * */
        "require" : 
        {
            value : function(names, callback) 
            {
                if (names !== null && ! (names instanceof Array) && !(typeof names == "string")) 
                {
                    io.debug({ 
                            error : new Error("require : invalid argument (" + 
                                                JSON.stringify(names) + ")"), 
                            offset : 1, 
                            arguments : arguments 
                    });
                    return; 
                }
                if (typeof names == "string") {
                    if (_modules[names])
                    {
                        return _modules[names];
                    }
                    else 
                    {
                        io.debug({ 
                            error : new Error("require : module " + names + " hasn't been loaded yet!"),
                            offset : 1, 
                            arguments : arguments 
                        });
                    }

                }
                else {
                if (!_initialized) 
                    _callbacks.push({callback : callback, names : names});
                else 
                    _applyRequired(names, callback);
                }
            }
        },
        "_deprecated" : 
        {
            value : function(on, nn, args, attachScope) 
            {
                var i, l, ns, ctx, actx;
                io.print("\033[31;1mDWB DEPRECATION:\033[0m " + on + "() is deprecated, use " + nn + "() instead!");
                ns = nn.split(".");
                ctx = actx = attachScope || this;
                for (i=0, l=ns.length; i<l-1; i++)
                    ctx = ctx[ns[i]];
                return ctx[ns[l-1]].apply(actx, args);
            }
        },
        "_initNewContext" : 
        {
            value : (function() {
                return function(self, arguments, path) {
                    var generateId = (function() {
                        var id = 0;
                        var timeStamp = new Date().getTime();
                        return function() {
                            id++;
                            return util.checksum(timeStamp + (id) + path, ChecksumType.sha1);
                        };
                    })();
                    var id = "_" + generateId();
                    _contexts[id] = self;
                    /**
                     * In every script the variable <i>script</i>
                     * refers to the encapsulating function.
                     *
                     * @namespace 
                     * @name script 
                     *
                     * */
                    Object.defineProperties(self, { 
                            /** 
                             * The path of the script
                             *
                             * @name path 
                             * @memberOf script
                             * @constant
                             * */
                            "path" : { value : path },
                            /** 
                             * Print debug messages. Basically the same as
                             * {@link io.debug} but prints some additional
                             * information. 
                             *
                             * @name debug
                             * @memberOf script
                             * @function 
                             * @param {Object|Function} params|Function 
                             *      Parameters passed to {@link io.debug} or a function to debug, see also {@link Function}
                             *
                             * @example 
                             * script.debug({ message : "foobar" });
                             *
                             * var myFunction = function() {
                             *      ...
                             * };
                             *
                             * bind("xx", script.debug(myFunction));
                             *
                             * // Equivalent to 
                             * bind("xx", myFunction.debug(script));
                             *
                             * */
                            "debug" : { value : io.debug.bind(self) }, 
                            /** 
                             * For internal usage only
                             *
                             * @name _arguments
                             * @memberOf script
                             * @property {Object}
                             * @private
                             *
                             * */
                            "_arguments" : { value : arguments },
                            /** 
                             * For internal usage only
                             *
                             * @name _handles
                             * @memberOf script
                             * @property {Object}
                             * @private
                             *
                             * */
                            "_handles" : { value : [], writable : true },
                            /** 
                             * Own handles returned from timer.start,
                             * Signal.connect and bind or other objects that
                             * implement a remove function.
                             *
                             * @name own
                             * @memberOf script
                             * @function
                             * @param {Objects...} objects 
                             *      Some objects that implement a remove
                             *      function
                             *
                             * @returns {Array} 
                             *      The arguments accumulated to an array
                             * @example 
                             * script.own(
                             *      timer.start(1000, timerCallback), 
                             *      bind.start("shortcut", bindCallback), 
                             *      Signal.connect("navigation", navigationCallback)
                             * );
                             * */
                            "own" : {
                                value : function() {
                                   this._handles = this._handles.concat(Array.prototype.slice.call(arguments));
                                   return this._handles;
                                }
                            },
                            /** 
                             * Removes all handles owned by this script
                             *
                             * @name removeHandles
                             * @memberOf script
                             * @function 
                             *
                             * @example 
                             * script.own(
                             *      bind.start("shortcut", bindCallback), 
                             *      Signal.connect("navigation", navigationCallback)
                             * );
                             * bind(null, function() {
                             *      script.removeHandles();
                             * }, "stopscript");
                             * */
                            "removeHandles" : {
                                value : function() {
                                    this._handles.forEach(function(handle) { 
                                        handle.remove();
                                    });
                                }
                            },
                            /** 
                             * Generates a unique id. Successive calls will
                             * generate new ids.
                             *
                             * @name generateId 
                             * @memberOf script
                             * @function 
                             *
                             * @returns {String}
                             *      A unique id
                             * */
                            "generateId" : { value : generateId },
                            /**
                             * 
                             * Convenience function to set a private property on an object that doesn’t conflict
                             * with properties set in other scripts. It uses a random unique id to set the property, so
                             * the property can most likely only be retrieved with {@link script.getPrivate|getPrivate}. This is
                             * mostly useful for objects derived from GObject since GObjects are shared between all
                             * scripts.
                             *
                             * @name setPrivate
                             * @memberOf script
                             * @function 
                             *
                             * @param {Object} object 
                             *  The object whichs property will be set
                             * @param {String} key    The property name
                             * @param {Object} value  The value to set
                             * @example 
                             * signals.connect("loadFinished", function(wv) {
                             *      // would conflict if another script also sets foo on the same webview
                             *      wv.foo = "bar" 
                             *      // secure, won't conflict with other scripts
                             *      script.setPrivate(wv, "foo", "bar");
                             * });
                             * */
                            "setPrivate" : 
                            { 
                                value : function(id, object, key, value) 
                                {
                                    var realKey = key + id;
                                    if (object[realKey]) 
                                        object[realKey] = value;
                                    else 
                                    {
                                        Object.defineProperty(object, realKey, {
                                                value : value, writable : true
                                        });
                                    }
                                }.bind(self, id)
                            }, 
                            /**
                             * Gets a private property of an object previously set with {@link script.setPrivate|setPrivate}
                             *
                             * @name getPrivate
                             * @memberOf script
                             * @function 
                             *
                             * @param {Object} object The object on which the value was set
                             * @param {String} key    The property name
                             *
                             * @returns {Object}
                             *      The private value
                             * */
                            "getPrivate" : 
                            { 
                                value : function(id, object, key) 
                                { 
                                    return object[key + id];
                                }.bind(self, id)
                            },
                            /** 
                             * Deletes a private property from an object
                             * previously set with {@link script.setPrivate|setPrivate}
                             * and returns the previously set property if any
                             *
                             * @name deletePrivate
                             * @memberOf script
                             * @function
                             *
                             * @param {Object} object 
                             *      The object on which the value was set
                             * @param {String} key
                             *      The property name
                             *
                             * @returns {Object}
                             *      The private value
                             * */
                             "deletePrivate" : {
                                 value : function(id, object, key) {
                                     var realKey = key + id;
                                     var value = object[realKey];
                                     delete object[realKey];
                                     return value;
                                 }.bind(self, id)
                             },
                            /**
                             * Includes a script, same as {@link include} but
                             * the path must be relative to the including
                             * script's path. 
                             *
                             * @name include
                             * @memberOf script
                             * @function
                             *
                             * @param {String} relPath 
                             *      The relative path of the script
                             * @param {Boolean} global 
                             *      Whether to inject the script into the global
                             *      scope
                             *
                             * @returns {Object}
                             *      The object returned from the included script
                             * */
                            "include" : 
                            {
                                value : function(relPath, global)
                                {
                                    var dirName = path.substring(0, path.lastIndexOf("/") + 1);
                                    return include(dirName + relPath, global);
                                }
                            }
                    });
                    Object.preventExtensions(self);

                };
            })() 
        },
        /* 
        * Called after all scripts have been loaded and executed
        * Immediately deleted from the global object, so it is not callable
        * from other scripts 
        * */
        "_initAfter" : 
        { 
            value : function() 
            {
                var i, l;
                _initialized = true;
                for (i=0, l=_callbacks.length; i<l; i++) 
                {
                    _applyRequired(_callbacks[i].names, _callbacks[i].callback);
                }
            },
            configurable : true
        },
        "_initBefore" : 
        {
            value : function(contexts) 
            {
                Object.freeze(this);
            },
            configurable : true
        }
    });
    
    Object.defineProperties(GObject.prototype, {
            /** 
             * Connects to a property change notification
             *
             * @memberOf GObject.prototype
             * @name notify 
             * @function
             *
             * @param {String} name 
             *      The property name, can also be in camelcase.
             * @param {GObject~notifyCallback} callback 
             *      Callback that will be called when the property changes
             * @param {Boolean} [after] 
             *      Whether to connect after the default handler.
             *
             * @returns {Number}
             *      The signal id of this signal
             * */
            "notify" : 
            { 
                value : function(name, callback, after) 
                { 
                    return this.connect.call(this, "notify::" + util.uncamelize(name), callback, after || false);
                }
            },
            /** 
             * Connect to a gobject-signal but block the emission of the own
             * callback during execution of the callback. Useful if the object
             * is connected to a notify event and the the property is changed in
             * the callback function.
             * @memberOf GObject.prototype
             * @name connectBlocked
             * @function
             *
             * @param {String} name The signal name.
             * @param {Function} callback Callback that will be called when the signal is emitted.
             * @param {Boolean} [after] Whether to connect after the default signal handler.
             *
             * @returns  {Number}
             *      The signal id of this signal
             * */
            "connectBlocked" : 
            { 
                value : function(name, callback, after) 
                { 
                    var sig = this.connect(name, (function() { 
                        this.blockSignal(sig);
                        var result = callback.apply(this, arguments);
                        this.unblockSignal(sig);
                        return result;
                    }).bind(this));
                    return sig;
                }
            },
            /** 
             * Connects to a property change notification but with signal
             * blocking. Must be used if the property is modified in the
             * callback function.
             *
             * @memberOf GObject.prototype
             * @name notifyBlocked
             * @function
             * @deprecated
             *
             * @param {String} name     
             *      The property name, can also be in camelcase.
             * @param {GObject~notifyCallback} callback 
             *      Callback that will be called when the property changes
             * @param {Boolean} [after]   
             *      Whether to connect after the default handler.
             *
             * @returns {Number}
             *      The signal id of this signal
             *
             * @example 
             * gui.statusLabel.notifyBlocked("label", function() {
             *      this.label += "foo"; 
             * });
             *
             * */
            "notifyBlocked" : 
            {
                value : function() 
                {
                    return _deprecated("notifyBlocked", "notify", arguments, this);
                }
            }
    });
    Object.defineProperties(Deferred.prototype, {
            /**
             * Registers a function for the done-chain
             *
             * @name done
             * @memberOf Deferred.prototype
             * @function 
             *
             * @param {Deferred~resolveCallback} callback 
             *      A callback function that will be called when the Deferred is
             *      resolved. If the function returns a deferred the original
             *      deferred will be replaced with the new deferred.
             *
             * @returns {Deferred}
             *      A new Deferred that can be used to chain callbacks
             * */
            "done" : {
                value : function(method) 
                {
                    return this.then(method);
                }
            },
            /**
             * Registers a function for the fail-chain
             *
             * @name fail
             * @memberOf Deferred.prototype
             * @function 
             *
             * @param {Deferred~rejectCallback} callback 
             *      A callback function that will be called when the Deferred is
             *      rejected. If the function returns a deferred the original
             *      deferred will be replaced with the new deferred.
             *
             * @returns {Deferred}
             *      A new Deferred that can be used to chain callbacks
             * */
            "fail" : {
                value : function(method) 
                {
                    return this.then(null, method);
                }
            },
            /**
             * Registers a function for the done- and fail-chain
             *
             * @name always
             * @memberOf Deferred.prototype
             * @function 
             *
             * @param {Deferred~resolveCallback|Deferred~rejectCallback} callback 
             *      A callback function that will be called when the Deferred is
             *      resolved or rejected. If the function returns a deferred the
             *      original deferred will be replaced with the new deferred.
             *
             * @returns {Deferred}
             *      A new Deferred that can be used to chain callbacks
             * */
            "always" : {
                value : function(method)
                {
                    return this.then(method, method);
                }
            }
    });
    /**
     * Static method that can be used for synchronous and asynchronous
     * operations. 
     * If the first parameter is a Deferred ondone is called when the Deferred is
     * resolved and onfail is called if the Deferred is rejected, otherwise
     * ondone is called and value is the first parameter of the callback.
     *
     * @name when 
     * @memberOf Deferred
     * @function 
     *
     * @param {Value|Deferred} value 
     *      A Deferred or an arbitrary value
     * @param {Deferred~resolveCallback} ondone 
     *      Callback function for the done chain
     * @param {Deferred~rejectCallback} onFail
     *      Callback function for the fail chain
     *
     * @returns {Any value}
     *      The value
     *
     * @example 
     * function sync() {
     *     return  "sync";
     * }
     * function async() {
     *     var stdout;
     *     var d = new Deferred();
     *     timer.start(1000, function() {
     *         d.resolve("async");
     *         return false;
     *     });
     *     return d;
     * }
     * Deferred.when(sync(), function(response) {
     *     // sync
     *     io.print(response);
     * });
     * Deferred.when(async(), function(response) {
     *     // async
     *     io.print(response);
     * });
     * */
    Object.defineProperty(Deferred, "when", {
            value : function(value, callback, errback)
            {
                if (value instanceof Deferred)
                    return value.then(callback, errback);
                else 
                    return callback(value);
            }
    });
    /**
     * Standard javascript Function object with additional methods
     * @name Function
     * @class
     * */
    /**
     * Convenience method to print debug messages, wraps the function into a
     * try/catch statement
     *
     * @name debug
     * @memberOf Function.prototype
     * @function
     *
     * @param {Object} [info] 
     *      Arguments passed to io.debug, the recommended argument is {@link script}
     *
     * @example 
     * //!javascript
     *
     * function onNavigation() {
     *      var x = y;
     * };
     * Signal.connect("navigation", onNavigation.debug(script));
     *
     * // Debug message:
     * ==> DEBUG [FILE]       : /path/to/script.js
     * ==> DEBUG [ERROR]      : Error in line 4: Can't find variable: y
     * ==> DEBUG [STACK]      : [onNavigation] [[native code]] [value] [[native code]]
     * ==> DEBUG [SOURCE]
     *     ...
     *     4 > function onNavigation( {
     * --> 5 >     var x = y;
     *     6 > }
     *     ...
     * */
    if (!Function.prototype.debug) 
    {
        Object.defineProperty(Function.prototype, "debug", {
                value : function(scope)
                {
                    return function() {
                        try 
                        {
                            return this.apply(this, arguments);
                        }
                        catch (e) 
                        { 
                            if (scope)
                                scope.debug(e);
                            else 
                                io.debug(e);
                        }
                        return undefined;
                    }.bind(this);
                }
        });
    }

    /**
     * Standard RegExp object with additional methods
     * @name RegExp
     * @class 
     * */
    /**
     * Escapes special characters that are used in regular expressions
     * @name escape
     * @memberOf RegExp
     * @function 
     *
     * @param {String} string String to escape
     *
     * @returns {String}
     *      The escaped string
     * @example 
     * // /.*foo\.bar\[\].*$/
     * var r = new RegExp(".*" + RegExp.escape("foo.bar[]") + ".*$"); 
     * */
    if (! RegExp.escape)
    {
        Object.defineProperty(RegExp, "escape", 
        {
            value : function(string)
            {
                return string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
            }
        });
    }
    Object.defineProperties(tabs, {
        /** 
         * tabs.nth has been deprecated, tabs are now an array-like object, use tabs[n]
         * instead.
         * @name nth
         * @memberOf tabs
         * @function
         * @deprecated
         *
         * @param {Number} number Number of the tab
         *
         * @returns {WebKitWebView} 
         *      The corresponding {@link WebKitWebView}
         * */
         nth : {
             value : function(n) {
                 io.print("\033[31;1mDWB DEPRECATION:\033[0m tabs.nth(n) is deprecated, use tabs[n] instead!");
                     return this[n];
             }
         },
    });
    [ "forEach", "indexOf", "lastIndexOf", "filter", "map", "reduce", "reduceRight", "every", "some" ].forEach(function(method) {
        Object.defineProperty(tabs, method, { value : function() { 
            return Array.prototype[method].apply(tabs, arguments); 
        }});
    });
    Object.freeze(tabs);
})();

Object.preventExtensions(this);