<commit_before>// Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@vimperator.org>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the License.txt file included with this file.

/** @scope modules */

// TODO: proper backwards search - implement our own component?
//     : implement our own highlighter?
//     : <ESC> should cancel search highlighting in 'incsearch' mode and jump
//       back to the presearch page location - can probably use the same
//       solution as marks
//     : 'linksearch' searches should highlight link matches only
//     : changing any search settings should also update the search state including highlighting
//     : incremental searches shouldn't permanently update search modifiers

// NOTE: (by Quicksaver) please don't do any of the above TODOs. Right now the findbar is
// not only per-tab, but it is also completely asynchronous to allow for proper behavior in e10s.
// Because of that, it's better to have Vimperator be more of a mediator between the user
// and the findbar (using its methods, keeping in sync with it, etc), than implementing any
// components itself.

/**
 * @instance finder
 */
var Finder = Module("finder", {
    requires: ["config"],

    init: function () {
        this._backwards = false;           // currently searching backwards
        this._searchPattern = "";          // current search string (includes modifiers)
        this._lastSearchPattern = "";      // the last searched pattern (includes modifiers)
    },

    get findbar () {
        return (config.name == "Muttator") ? document.getElementById('FindToolbar') : window.gFindBar;
    },

    get findbarInitialized () {
        return (config.name == "Muttator") || window.gFindBarInitialized;
    },

    // set searchString, searchPattern, caseSensitive, linksOnly
    _processUserPattern: function (pattern) {
        //// strip off pattern terminator and offset
        //if (backwards)
        //    pattern = pattern.replace(/\?.*/, "");
        //else
        //    pattern = pattern.replace(/\/.*/, "");

        this._searchPattern = pattern;
        let findbar = this.findbar;

        // links only search - \l wins if both modifiers specified
        let fm = findbar._findMode;
        if (/\\l/.test(pattern))
            fm = findbar.FIND_LINKS;
        else if (/\\L/.test(pattern))
            fm = findbar.FIND_NORMAL;
        else if (options["linksearch"])
            fm = findbar.FIND_LINKS;
        else
            fm = findbar.FIND_NORMAL;
        this.updateFindMode(fm);

        // strip links-only modifiers
        pattern = pattern.replace(/(\\)?\\[lL]/g, function ($0, $1) { return $1 ? $0 : ""; });

        // case sensitivity - \c wins if both modifiers specified
        let cs = findbar._typeAheadCaseSensitive;
        if (/\\c/.test(pattern))
            cs = false;
        else if (/\\C/.test(pattern))
            cs = true;
        else if (options["ignorecase"] && options["smartcase"] && /[A-Z]/.test(pattern))
            cs = true;
        else if (options["ignorecase"])
            cs = false;
        else
            cs = true;
        this.updateCaseSensitive(cs);

        // strip case-sensitive modifiers
        pattern = pattern.replace(/(\\)?\\[cC]/g, function ($0, $1) { return $1 ? $0 : ""; });

        // remove any modifier escape \
        pattern = pattern.replace(/\\(\\[cClL])/g, "$1");

        findbar._findField.value = pattern;
    },

    /**
     * Called when the search dialog is requested.
     *
     * @param {number} mode The search mode, either modes.SEARCH_FORWARD or
     *     modes.SEARCH_BACKWARD.
     * @default modes.SEARCH_FORWARD
     */
    openPrompt: function (mode) {
        this._backwards = mode == modes.SEARCH_BACKWARD;
        //commandline.open(this._backwards ? "Find backwards" : "Find", "", mode);
        commandline.input(this._backwards ? "Find backwards" : "Find", this.closure.onSubmit, {
            onChange: function() {
                if (options["incsearch"] && !commandline._isIMEComposing) {
                    finder.find(commandline.command);
                }
            }
        });
        //modes.extended = mode;

        // TODO: focus the top of the currently visible screen
    },

    /**
     * Searches the current buffer for str.
     *
     * @param {string} str The string to find.
     */
    find: function (str) {
        this._processUserPattern(str);

        let findbar = this.findbar;
        if (!findbar.vimperated) {
            findbar.vimperated = true;

            // Make sure we're listening for the result, so that we show it on the prompt later.
            findbar.browser.finder.addResultListener(this);

            // PDF.JS files are different, they use their own messages to communicate the results.
            // So we piggyback the end changes to the findbar when there are any.
            findbar._vimpbackup_updateControlState = findbar.updateControlState;
            findbar.updateControlState = function(aResult, aFindPrevious) {
                this._vimpbackup_updateControlState(aResult, aFindPrevious);
                finder.onFindResult({
                    searchString: this._findField.value,
                    result: aResult,
                    findBackwards: aFindPrevious
                });
            };

            // Normally the findbar appears to notify on failed results.
            // However, this shouldn't happen when we're finding through the command line,
            // even though that way we lose any kind of no matches notification until we
            // stop typing altogether; something to work on at a later time:
            // - show the quick findbar which will hide after a few seconds?
            // - or notify the user somehow in the command line itself?
            findbar._vimpbackup_open = findbar.open;
            findbar.open = function (aMode) {
                if (commandline._keepOpenForInput) { return false; }
                return this._vimpbackup_open(aMode);
            };
        }

        findbar._find();
    },

    /**
     * Searches the current buffer again for the most recently used search
     * string.
     *
     * @param {boolean} reverse Whether to search forwards or backwards.
     * @default false
     * @see Bug537013 https://bugzilla.mozilla.org/show_bug.cgi?id=537013
     */
    findAgain: function (reverse) {
        // Nothing to find?
        if (!this.findbarInitialized || !this.findbar._findField.value)
            return;

        this.findbar.onFindAgainCommand(reverse);
    },

    /**
     * Updates the status line with the result from the find operation;
     * this is done aSync from the main (input) process.
     */
    onFindResult: function(aData) {
        if (aData.result == Ci.nsITypeAheadFind.FIND_NOTFOUND) {
            liberator.echoerr("Pattern not found: " + aData.searchString, commandline.FORCE_SINGLELINE);
        }
        else if (aData.result == Ci.nsITypeAheadFind.FIND_WRAPPED) {
            let msg = aData.findBackwards ? "Search hit TOP, continuing at BOTTOM" : "Search hit BOTTOM, continuing at TOP";
            commandline.echo(msg, commandline.HL_WARNINGMSG, commandline.APPEND_TO_MESSAGES | commandline.FORCE_SINGLELINE);
        }
        else {
            liberator.echomsg("Found pattern: " + aData.searchString);
        }
    },

    /**
     * Called when the <Enter> key is pressed to trigger a search.
     *
     * @param {string} str The search string.
     * @param {boolean} forcedBackward Whether to search forwards or
     *     backwards. This overrides the direction set in
     *     (@link #openPrompt).
     * @default false
     */
    onSubmit: function (str, forcedBackward) {
        let findbar = this.findbar;

        if (typeof forcedBackward === "boolean")
            this._backwards = forcedBackward;

        let pattern;
        if (str)
            pattern = str;
        else {
            liberator.assert(this._lastSearchPattern, "No previous search pattern");
            pattern = this._lastSearchPattern;
        }

        // liberator.log('inc: ' + options["incsearch"] + ' sea:' + this._searchPattern + ' pat:' + pattern);
        if (!options["incsearch"] || this._searchPattern != pattern) {
            this.find(pattern);
        }

        this._lastSearchPattern = pattern;

        // TODO: move to find() when reverse incremental searching is kludged in
        // need to find again for reverse searching
        if (this._backwards)
            this.findAgain(true);

        if (options["hlsearch"])
            this.highlight(findbar._findField.value);
    },

    /**
     * Highlights all occurances of str in the buffer.
     *
     * @param {string} str The string to highlight.
     */
    highlight: function (str) {
        let findbar = this.findbar;

        let btn = findbar.getElement("highlight");
        btn.checked = true;

        findbar._setHighlightTimeout();
    },

    /**
     * Clears all search highlighting.
     */
    clear: function () {
        if (!this.findbarInitialized)
            return;

        let findbar = this.findbar;

        let btn = findbar.getElement("highlight");
        btn.checked = false;

        findbar.toggleHighlight(false);
    },

    /**
     * Updates the case sensitivity parameter.
     */
    updateCaseSensitive: function (cs) {
        let findbar = this.findbar;
        if (cs != findbar._typeAheadCaseSensitive) {
            findbar._setCaseSensitivity(cs);
        }
    },

    /**
     * Updates the find mode to show only matches in links or all matches.
     */
    updateFindMode: function (fm) {
        let findbar = this.findbar;

        // We need to pretend like we're opening the findbar with a different mode,
        // but not actually do it.
        if (fm != findbar._findMode) {
            findbar._findMode = fm;
            findbar._findFailedString = null;
            if(!findbar.hidden) {
                findbar._updateFindUI();
            }
        }
    }
}, {
}, {
    commands: function () {
        // TODO: Remove in favor of :set nohlsearch?
        commands.add(["noh[lsearch]"],
            "Remove the search highlighting",
            function () { finder.clear(); },
            { argCount: "0" });
    },
    events: function() {
        if (config.name == 'Vimperator') {
            // Same thing as the note above for not showing the findbar on failed results
            // through the command line, but for compatibility with FindBar Tweak.
            events.addSessionListener(window, "WillOpenFindBar", function (event) {
                if (commandline._keepOpenForInput) {
                    event.preventDefault();
                    event.stopPropagation();
                }
            }, true);
        }
    },
    mappings: function () {
        var myModes = config.browserModes;
        myModes = myModes.concat([modes.CARET]);

        mappings.add(myModes,
            ["/"], "Search forward for a pattern",
            function () { finder.openPrompt(modes.SEARCH_FORWARD); });

        mappings.add(myModes,
            ["?"], "Search backwards for a pattern",
            function () { finder.openPrompt(modes.SEARCH_BACKWARD); });

        mappings.add(myModes,
            ["n"], "Find next",
            function () { finder.findAgain(false); });

        mappings.add(myModes,
            ["N"], "Find previous",
            function () { finder.findAgain(true); });

        mappings.add(myModes.concat([modes.CARET, modes.TEXTAREA]), ["*"],
            "Find word under cursor",
            function () {
                finder.onSubmit(buffer.getCurrentWord(), false);
            });

        mappings.add(myModes.concat([modes.CARET, modes.TEXTAREA]), ["#"],
            "Find word under cursor backwards",
            function () {
                finder.onSubmit(buffer.getCurrentWord(), true);
            });
    },
    options: function () {
        options.add(["hlsearch", "hls"],
            "Highlight previous search pattern matches",
            "boolean", true, {
                setter: function (value) {
                    try {
                        if (value)
                            finder.highlight();
                        else
                            finder.clear();
                    }
                    catch (e) {}

                    return value;
                }
            });

        options.add(["ignorecase", "ic"],
            "Ignore case in search patterns",
            "boolean", true, {
                setter: function (value) {
                    try {
                        finder.updateCaseSensitive(!value);
                    }
                    catch (e) {}

                    return value;
                }
            });

        options.add(["incsearch", "is"],
            "Show where the search pattern matches as it is typed",
            "boolean", true);

        options.add(["linksearch", "lks"],
            "Limit the search to hyperlink text",
            "boolean", false, {
                setter: function (value) {
                    try {
                        let findbar = finder.findbar;
                        let fm = (value) ? findbar.FIND_LINKS : findbar.FIND_NORMAL;
                        finder.updateFindMode(fm);
                    }
                    catch (e) {}

                    return value;
                }
            });

        options.add(["smartcase", "scs"],
            "Override the 'ignorecase' option if the pattern contains uppercase characters",
            "boolean", true);
    }
});

// vim: set fdm=marker sw=4 ts=4 et:
<commit_msg>remove unnecessary FindBar Tweak compatibility bit<commit_after>// Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@vimperator.org>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the License.txt file included with this file.

/** @scope modules */

// TODO: proper backwards search - implement our own component?
//     : implement our own highlighter?
//     : <ESC> should cancel search highlighting in 'incsearch' mode and jump
//       back to the presearch page location - can probably use the same
//       solution as marks
//     : 'linksearch' searches should highlight link matches only
//     : changing any search settings should also update the search state including highlighting
//     : incremental searches shouldn't permanently update search modifiers

// NOTE: (by Quicksaver) please don't do any of the above TODOs. Right now the findbar is
// not only per-tab, but it is also completely asynchronous to allow for proper behavior in e10s.
// Because of that, it's better to have Vimperator be more of a mediator between the user
// and the findbar (using its methods, keeping in sync with it, etc), than implementing any
// components itself.

/**
 * @instance finder
 */
var Finder = Module("finder", {
    requires: ["config"],

    init: function () {
        this._backwards = false;           // currently searching backwards
        this._searchPattern = "";          // current search string (includes modifiers)
        this._lastSearchPattern = "";      // the last searched pattern (includes modifiers)
    },

    get findbar () {
        return (config.name == "Muttator") ? document.getElementById('FindToolbar') : window.gFindBar;
    },

    get findbarInitialized () {
        return (config.name == "Muttator") || window.gFindBarInitialized;
    },

    // set searchString, searchPattern, caseSensitive, linksOnly
    _processUserPattern: function (pattern) {
        //// strip off pattern terminator and offset
        //if (backwards)
        //    pattern = pattern.replace(/\?.*/, "");
        //else
        //    pattern = pattern.replace(/\/.*/, "");

        this._searchPattern = pattern;
        let findbar = this.findbar;

        // links only search - \l wins if both modifiers specified
        let fm = findbar._findMode;
        if (/\\l/.test(pattern))
            fm = findbar.FIND_LINKS;
        else if (/\\L/.test(pattern))
            fm = findbar.FIND_NORMAL;
        else if (options["linksearch"])
            fm = findbar.FIND_LINKS;
        else
            fm = findbar.FIND_NORMAL;
        this.updateFindMode(fm);

        // strip links-only modifiers
        pattern = pattern.replace(/(\\)?\\[lL]/g, function ($0, $1) { return $1 ? $0 : ""; });

        // case sensitivity - \c wins if both modifiers specified
        let cs = findbar._typeAheadCaseSensitive;
        if (/\\c/.test(pattern))
            cs = false;
        else if (/\\C/.test(pattern))
            cs = true;
        else if (options["ignorecase"] && options["smartcase"] && /[A-Z]/.test(pattern))
            cs = true;
        else if (options["ignorecase"])
            cs = false;
        else
            cs = true;
        this.updateCaseSensitive(cs);

        // strip case-sensitive modifiers
        pattern = pattern.replace(/(\\)?\\[cC]/g, function ($0, $1) { return $1 ? $0 : ""; });

        // remove any modifier escape \
        pattern = pattern.replace(/\\(\\[cClL])/g, "$1");

        findbar._findField.value = pattern;
    },

    /**
     * Called when the search dialog is requested.
     *
     * @param {number} mode The search mode, either modes.SEARCH_FORWARD or
     *     modes.SEARCH_BACKWARD.
     * @default modes.SEARCH_FORWARD
     */
    openPrompt: function (mode) {
        this._backwards = mode == modes.SEARCH_BACKWARD;
        //commandline.open(this._backwards ? "Find backwards" : "Find", "", mode);
        commandline.input(this._backwards ? "Find backwards" : "Find", this.closure.onSubmit, {
            onChange: function() {
                if (options["incsearch"] && !commandline._isIMEComposing) {
                    finder.find(commandline.command);
                }
            }
        });
        //modes.extended = mode;

        // TODO: focus the top of the currently visible screen
    },

    /**
     * Searches the current buffer for str.
     *
     * @param {string} str The string to find.
     */
    find: function (str) {
        this._processUserPattern(str);

        let findbar = this.findbar;
        if (!findbar.vimperated) {
            findbar.vimperated = true;

            // Make sure we're listening for the result, so that we show it on the prompt later.
            findbar.browser.finder.addResultListener(this);

            // PDF.JS files are different, they use their own messages to communicate the results.
            // So we piggyback the end changes to the findbar when there are any.
            findbar._vimpbackup_updateControlState = findbar.updateControlState;
            findbar.updateControlState = function(aResult, aFindPrevious) {
                this._vimpbackup_updateControlState(aResult, aFindPrevious);
                finder.onFindResult({
                    searchString: this._findField.value,
                    result: aResult,
                    findBackwards: aFindPrevious
                });
            };

            // Normally the findbar appears to notify on failed results.
            // However, this shouldn't happen when we're finding through the command line,
            // even though that way we lose any kind of no matches notification until we
            // stop typing altogether; something to work on at a later time:
            // - show the quick findbar which will hide after a few seconds?
            // - or notify the user somehow in the command line itself?
            findbar._vimpbackup_open = findbar.open;
            findbar.open = function (aMode) {
                if (commandline._keepOpenForInput) { return false; }
                return this._vimpbackup_open(aMode);
            };
        }

        findbar._find();
    },

    /**
     * Searches the current buffer again for the most recently used search
     * string.
     *
     * @param {boolean} reverse Whether to search forwards or backwards.
     * @default false
     * @see Bug537013 https://bugzilla.mozilla.org/show_bug.cgi?id=537013
     */
    findAgain: function (reverse) {
        // Nothing to find?
        if (!this.findbarInitialized || !this.findbar._findField.value)
            return;

        this.findbar.onFindAgainCommand(reverse);
    },

    /**
     * Updates the status line with the result from the find operation;
     * this is done aSync from the main (input) process.
     */
    onFindResult: function(aData) {
        if (aData.result == Ci.nsITypeAheadFind.FIND_NOTFOUND) {
            liberator.echoerr("Pattern not found: " + aData.searchString, commandline.FORCE_SINGLELINE);
        }
        else if (aData.result == Ci.nsITypeAheadFind.FIND_WRAPPED) {
            let msg = aData.findBackwards ? "Search hit TOP, continuing at BOTTOM" : "Search hit BOTTOM, continuing at TOP";
            commandline.echo(msg, commandline.HL_WARNINGMSG, commandline.APPEND_TO_MESSAGES | commandline.FORCE_SINGLELINE);
        }
        else {
            liberator.echomsg("Found pattern: " + aData.searchString);
        }
    },

    /**
     * Called when the <Enter> key is pressed to trigger a search.
     *
     * @param {string} str The search string.
     * @param {boolean} forcedBackward Whether to search forwards or
     *     backwards. This overrides the direction set in
     *     (@link #openPrompt).
     * @default false
     */
    onSubmit: function (str, forcedBackward) {
        let findbar = this.findbar;

        if (typeof forcedBackward === "boolean")
            this._backwards = forcedBackward;

        let pattern;
        if (str)
            pattern = str;
        else {
            liberator.assert(this._lastSearchPattern, "No previous search pattern");
            pattern = this._lastSearchPattern;
        }

        // liberator.log('inc: ' + options["incsearch"] + ' sea:' + this._searchPattern + ' pat:' + pattern);
        if (!options["incsearch"] || this._searchPattern != pattern) {
            this.find(pattern);
        }

        this._lastSearchPattern = pattern;

        // TODO: move to find() when reverse incremental searching is kludged in
        // need to find again for reverse searching
        if (this._backwards)
            this.findAgain(true);

        if (options["hlsearch"])
            this.highlight(findbar._findField.value);
    },

    /**
     * Highlights all occurances of str in the buffer.
     *
     * @param {string} str The string to highlight.
     */
    highlight: function (str) {
        let findbar = this.findbar;

        let btn = findbar.getElement("highlight");
        btn.checked = true;

        findbar._setHighlightTimeout();
    },

    /**
     * Clears all search highlighting.
     */
    clear: function () {
        if (!this.findbarInitialized)
            return;

        let findbar = this.findbar;

        let btn = findbar.getElement("highlight");
        btn.checked = false;

        findbar.toggleHighlight(false);
    },

    /**
     * Updates the case sensitivity parameter.
     */
    updateCaseSensitive: function (cs) {
        let findbar = this.findbar;
        if (cs != findbar._typeAheadCaseSensitive) {
            findbar._setCaseSensitivity(cs);
        }
    },

    /**
     * Updates the find mode to show only matches in links or all matches.
     */
    updateFindMode: function (fm) {
        let findbar = this.findbar;

        // We need to pretend like we're opening the findbar with a different mode,
        // but not actually do it.
        if (fm != findbar._findMode) {
            findbar._findMode = fm;
            findbar._findFailedString = null;
            if(!findbar.hidden) {
                findbar._updateFindUI();
            }
        }
    }
}, {
}, {
    commands: function () {
        // TODO: Remove in favor of :set nohlsearch?
        commands.add(["noh[lsearch]"],
            "Remove the search highlighting",
            function () { finder.clear(); },
            { argCount: "0" });
    },
    mappings: function () {
        var myModes = config.browserModes;
        myModes = myModes.concat([modes.CARET]);

        mappings.add(myModes,
            ["/"], "Search forward for a pattern",
            function () { finder.openPrompt(modes.SEARCH_FORWARD); });

        mappings.add(myModes,
            ["?"], "Search backwards for a pattern",
            function () { finder.openPrompt(modes.SEARCH_BACKWARD); });

        mappings.add(myModes,
            ["n"], "Find next",
            function () { finder.findAgain(false); });

        mappings.add(myModes,
            ["N"], "Find previous",
            function () { finder.findAgain(true); });

        mappings.add(myModes.concat([modes.CARET, modes.TEXTAREA]), ["*"],
            "Find word under cursor",
            function () {
                finder.onSubmit(buffer.getCurrentWord(), false);
            });

        mappings.add(myModes.concat([modes.CARET, modes.TEXTAREA]), ["#"],
            "Find word under cursor backwards",
            function () {
                finder.onSubmit(buffer.getCurrentWord(), true);
            });
    },
    options: function () {
        options.add(["hlsearch", "hls"],
            "Highlight previous search pattern matches",
            "boolean", true, {
                setter: function (value) {
                    try {
                        if (value)
                            finder.highlight();
                        else
                            finder.clear();
                    }
                    catch (e) {}

                    return value;
                }
            });

        options.add(["ignorecase", "ic"],
            "Ignore case in search patterns",
            "boolean", true, {
                setter: function (value) {
                    try {
                        finder.updateCaseSensitive(!value);
                    }
                    catch (e) {}

                    return value;
                }
            });

        options.add(["incsearch", "is"],
            "Show where the search pattern matches as it is typed",
            "boolean", true);

        options.add(["linksearch", "lks"],
            "Limit the search to hyperlink text",
            "boolean", false, {
                setter: function (value) {
                    try {
                        let findbar = finder.findbar;
                        let fm = (value) ? findbar.FIND_LINKS : findbar.FIND_NORMAL;
                        finder.updateFindMode(fm);
                    }
                    catch (e) {}

                    return value;
                }
            });

        options.add(["smartcase", "scs"],
            "Override the 'ignorecase' option if the pattern contains uppercase characters",
            "boolean", true);
    }
});

// vim: set fdm=marker sw=4 ts=4 et:
<|endoftext|>


<commit_before>function LoadWebGLExtensions(webglExtensions)
{
    for (let extension of webglExtensions)
    {
        if(gl.getExtension(extension) === null)
        {
            console.warn("Extension " + extension + " not supported!");
        }
    }

    let EXT_texture_filter_anisotropic = gl.getExtension("EXT_texture_filter_anisotropic");

    if (EXT_texture_filter_anisotropic)
    {
        gl.anisotropy = EXT_texture_filter_anisotropic.TEXTURE_MAX_ANISOTROPY_EXT;
        gl.maxAnisotropy = gl.getParameter(EXT_texture_filter_anisotropic.MAX_TEXTURE_MAX_ANISOTROPY_EXT);
        gl.supports_EXT_texture_filter_anisotropic = true;
    }
    else
    {
        gl.supports_EXT_texture_filter_anisotropic = false;
    }
}

//https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Constants
function SetSampler(gltfSamplerObj, type) // TEXTURE_2D
{
    gl.texParameteri(type, gl.TEXTURE_WRAP_S, gltfSamplerObj.wrapS);
    gl.texParameteri(type, gl.TEXTURE_WRAP_T, gltfSamplerObj.wrapT);
    gl.texParameteri(type, gl.TEXTURE_MIN_FILTER, gltfSamplerObj.minFilter);
    gl.texParameteri(type, gl.TEXTURE_MAG_FILTER, gltfSamplerObj.magFilter);

    if (gl.supports_EXT_texture_filter_anisotropic)
    {
        gl.texParameterf(type, gl.anisotropy, gl.maxAnisotropy); // => 16xAF
    }
}

function SetTexture(loc, gltf, textureInfo, texSlot)
{
    if(loc == -1)
    {
        return false;
    }

    let gltfTex = gltf.textures[textureInfo.index];

    if(gltfTex === undefined)
    {
        console.warn("Texture is undefined: " + textureInfo.index);
        return false;
    }

    if(gltfTex.glTexture === undefined)
    {
        gltfTex.glTexture = gl.createTexture();
    }

    gl.activeTexture(gl.TEXTURE0 + texSlot);
    gl.bindTexture(gltfTex.type, gltfTex.glTexture);

    gl.uniform1i(loc, texSlot);

    if(!gltfTex.initialized)
    {
        const gltfSampler = gltf.samplers[gltfTex.sampler];

        if(gltfSampler === undefined)
        {
            console.warn("Sampler is undefined for texture: " + textureInfo.index);
            return false;
        }

        SetSampler(gltfSampler, gltfTex.type);

        gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);

        let images = [];

        if(gltfTex.source.length !== undefined)
        {
            // assume we have an array of textures (this is an unofficial extension to what glTF json can represent)
            images = gltfTex.source;
        }
        else
        {
            images = [gltfTex.source];
        }

        let generateMips = true;

        for(const src of images)
        {
            const image =  gltf.images[src];

            if (image === undefined)
            {
                console.warn("Image is undefined for texture: " + gltfTex.source);
                return false;
            }

            if (image.image.dataRGBE !== undefined)
            {
                gl.texImage2D(image.type, image.miplevel, gl.RGB, image.image.width, image.image.height, 0, gl.RGB, gl.FLOAT, image.image.dataFloat);
                generateMips = false;

                // Release the complete HDR image after usage.
                image.image = undefined;
            }
            else
            {
                gl.texImage2D(image.type, image.miplevel, textureInfo.colorSpace, textureInfo.colorSpace, gl.UNSIGNED_BYTE, image.image);
            }
        }

        if (textureInfo.generateMips && generateMips)
        {
            // Until this point, images can be assumed to be power of two.
            switch (gltfSampler.minFilter) {
                case gl.NEAREST_MIPMAP_NEAREST:
                case gl.NEAREST_MIPMAP_LINEAR:
                case gl.LINEAR_MIPMAP_NEAREST:
                case gl.LINEAR_MIPMAP_LINEAR:
                    gl.generateMipmap(gltfTex.type);
                    break;
                default:
                    break;
            }
        }

        gltfTex.initialized = true;
    }

    return gltfTex.initialized;
}

function SetIndices(gltf, accessorIndex)
{
    let gltfAccessor = gltf.accessors[accessorIndex];

    if (gltfAccessor.glBuffer === undefined)
    {
        gltfAccessor.glBuffer = gl.createBuffer();

        let data = gltfAccessor.getTypedView(gltf);

        if (data === undefined)
        {
            return false;
        }

        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, gltfAccessor.glBuffer);
        gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, data, gl.STATIC_DRAW);
    }
    else
    {
        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, gltfAccessor.glBuffer);
    }

    return true;
}

function EnableAttribute(gltf, attributeLocation, gltfAccessor)
{
    if(attributeLocation == -1)
    {
        return false;
    }

    let gltfBufferView = gltf.bufferViews[gltfAccessor.bufferView];

    if (gltfAccessor.glBuffer === undefined)
    {
        gltfAccessor.glBuffer = gl.createBuffer();

        let data = gltfAccessor.getTypedView(gltf);

        if (data === undefined)
        {
            return false;
        }

        gl.bindBuffer(gl.ARRAY_BUFFER, gltfAccessor.glBuffer);
        gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
    }
    else
    {
        gl.bindBuffer(gl.ARRAY_BUFFER, gltfAccessor.glBuffer);
    }

    gl.vertexAttribPointer(attributeLocation, gltfAccessor.getComponentCount(), gltfAccessor.componentType,
                           gltfAccessor.normalized, gltfBufferView.byteStride, gltfAccessor.byteOffset);
    gl.enableVertexAttribArray(attributeLocation);

    return true;
}

function CompileShader(isVert, shaderSource)
{
    let shader = gl.createShader(isVert ? gl.VERTEX_SHADER : gl.FRAGMENT_SHADER);
    gl.shaderSource(shader, shaderSource);
    gl.compileShader(shader);
    let compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);

    if (!compiled) {

        console.warn(gl.getShaderInfoLog(shader));
        return null;
    }

    return shader;
}

function LinkProgram(vertex, fragment)
{
    let program = gl.createProgram();
    gl.attachShader(program, vertex);
    gl.attachShader(program, fragment);
    gl.linkProgram(program);

    return program;
}
<commit_msg>Freeing all images after usage.<commit_after>function LoadWebGLExtensions(webglExtensions)
{
    for (let extension of webglExtensions)
    {
        if(gl.getExtension(extension) === null)
        {
            console.warn("Extension " + extension + " not supported!");
        }
    }

    let EXT_texture_filter_anisotropic = gl.getExtension("EXT_texture_filter_anisotropic");

    if (EXT_texture_filter_anisotropic)
    {
        gl.anisotropy = EXT_texture_filter_anisotropic.TEXTURE_MAX_ANISOTROPY_EXT;
        gl.maxAnisotropy = gl.getParameter(EXT_texture_filter_anisotropic.MAX_TEXTURE_MAX_ANISOTROPY_EXT);
        gl.supports_EXT_texture_filter_anisotropic = true;
    }
    else
    {
        gl.supports_EXT_texture_filter_anisotropic = false;
    }
}

//https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Constants
function SetSampler(gltfSamplerObj, type) // TEXTURE_2D
{
    gl.texParameteri(type, gl.TEXTURE_WRAP_S, gltfSamplerObj.wrapS);
    gl.texParameteri(type, gl.TEXTURE_WRAP_T, gltfSamplerObj.wrapT);
    gl.texParameteri(type, gl.TEXTURE_MIN_FILTER, gltfSamplerObj.minFilter);
    gl.texParameteri(type, gl.TEXTURE_MAG_FILTER, gltfSamplerObj.magFilter);

    if (gl.supports_EXT_texture_filter_anisotropic)
    {
        gl.texParameterf(type, gl.anisotropy, gl.maxAnisotropy); // => 16xAF
    }
}

function SetTexture(loc, gltf, textureInfo, texSlot)
{
    if(loc == -1)
    {
        return false;
    }

    let gltfTex = gltf.textures[textureInfo.index];

    if(gltfTex === undefined)
    {
        console.warn("Texture is undefined: " + textureInfo.index);
        return false;
    }

    if(gltfTex.glTexture === undefined)
    {
        gltfTex.glTexture = gl.createTexture();
    }

    gl.activeTexture(gl.TEXTURE0 + texSlot);
    gl.bindTexture(gltfTex.type, gltfTex.glTexture);

    gl.uniform1i(loc, texSlot);

    if(!gltfTex.initialized)
    {
        const gltfSampler = gltf.samplers[gltfTex.sampler];

        if(gltfSampler === undefined)
        {
            console.warn("Sampler is undefined for texture: " + textureInfo.index);
            return false;
        }

        SetSampler(gltfSampler, gltfTex.type);

        gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);

        let images = [];

        if(gltfTex.source.length !== undefined)
        {
            // assume we have an array of textures (this is an unofficial extension to what glTF json can represent)
            images = gltfTex.source;
        }
        else
        {
            images = [gltfTex.source];
        }

        let generateMips = true;

        for(const src of images)
        {
            const image =  gltf.images[src];

            if (image === undefined)
            {
                console.warn("Image is undefined for texture: " + gltfTex.source);
                return false;
            }

            if (image.image.dataRGBE !== undefined)
            {
                gl.texImage2D(image.type, image.miplevel, gl.RGB, image.image.width, image.image.height, 0, gl.RGB, gl.FLOAT, image.image.dataFloat);
                generateMips = false;
            }
            else
            {
                gl.texImage2D(image.type, image.miplevel, textureInfo.colorSpace, textureInfo.colorSpace, gl.UNSIGNED_BYTE, image.image);
            }
        }

        if (textureInfo.generateMips && generateMips)
        {
            // Until this point, images can be assumed to be power of two.
            switch (gltfSampler.minFilter) {
                case gl.NEAREST_MIPMAP_NEAREST:
                case gl.NEAREST_MIPMAP_LINEAR:
                case gl.LINEAR_MIPMAP_NEAREST:
                case gl.LINEAR_MIPMAP_LINEAR:
                    gl.generateMipmap(gltfTex.type);
                    break;
                default:
                    break;
            }
        }

        // Release the complete image buffer after usage.
        gl.finish();
        for(const src of images)
        {
        	gltf.images[src].image = undefined;
        }

        gltfTex.initialized = true;
    }

    return gltfTex.initialized;
}

function SetIndices(gltf, accessorIndex)
{
    let gltfAccessor = gltf.accessors[accessorIndex];

    if (gltfAccessor.glBuffer === undefined)
    {
        gltfAccessor.glBuffer = gl.createBuffer();

        let data = gltfAccessor.getTypedView(gltf);

        if (data === undefined)
        {
            return false;
        }

        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, gltfAccessor.glBuffer);
        gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, data, gl.STATIC_DRAW);
    }
    else
    {
        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, gltfAccessor.glBuffer);
    }

    return true;
}

function EnableAttribute(gltf, attributeLocation, gltfAccessor)
{
    if(attributeLocation == -1)
    {
        return false;
    }

    let gltfBufferView = gltf.bufferViews[gltfAccessor.bufferView];

    if (gltfAccessor.glBuffer === undefined)
    {
        gltfAccessor.glBuffer = gl.createBuffer();

        let data = gltfAccessor.getTypedView(gltf);

        if (data === undefined)
        {
            return false;
        }

        gl.bindBuffer(gl.ARRAY_BUFFER, gltfAccessor.glBuffer);
        gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
    }
    else
    {
        gl.bindBuffer(gl.ARRAY_BUFFER, gltfAccessor.glBuffer);
    }

    gl.vertexAttribPointer(attributeLocation, gltfAccessor.getComponentCount(), gltfAccessor.componentType,
                           gltfAccessor.normalized, gltfBufferView.byteStride, gltfAccessor.byteOffset);
    gl.enableVertexAttribArray(attributeLocation);

    return true;
}

function CompileShader(isVert, shaderSource)
{
    let shader = gl.createShader(isVert ? gl.VERTEX_SHADER : gl.FRAGMENT_SHADER);
    gl.shaderSource(shader, shaderSource);
    gl.compileShader(shader);
    let compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);

    if (!compiled) {

        console.warn(gl.getShaderInfoLog(shader));
        return null;
    }

    return shader;
}

function LinkProgram(vertex, fragment)
{
    let program = gl.createProgram();
    gl.attachShader(program, vertex);
    gl.attachShader(program, fragment);
    gl.linkProgram(program);

    return program;
}
<|endoftext|>


<commit_before>/* Vim-sytle UI
   The state machine design in this class is taken directly from here (Thanks IBM!):
   http://www.ibm.com/developerworks/library/wa-finitemach1/

   Offical WIMUI state transition table is here (x indicates disallowed state):
   https://docs.google.com/spreadsheets/d/1gVKCasnhn3aBtXefvZiW6Ht5fp7YofSgvZtBTXDhdzE/edit?usp=sharing
*/
const WIMUI={
    multiplier:1,
    multiplier_str:['',''],
    get_multiplier(multstr){/* [String] -> Int */ return multstr.reduce((a,b)=>a*(b||1),1)},
    reset_multiplier(){this.multiplier=1; this.multiplier_str=['',''];},
    initial_state:'normal',
    current_state:'normal',

    get atom(){/* {Char:[Type]} */
        delete this.atom;
        let atm={/* {Type:[Char]} */
            mult_0:'123456789',
            mult_N:'0123456789',
            verb:'cdy',
            modifier:'ai',
            text_object:'0^$%{}()[]<>`"\'bBeEpwWG',
            motion:'hjkl',
            edit:'oOpPrxX',
            insert:'aAiI',
            visual:'v',
            visual_line:'V',
            find_char:'fFtT',
            undo:'u',
            repeat:'.',
            ascii:' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~',
        };
        let it={}; for(let s in atm){[...atm[s]].forEach(x=>it[x]?it[x].push(s):it[x]=[s]);}
        it.Escape=['escape'];
        return this.atom=it;
    },

    chord:{
        'C-[':{act:'escape',code:'BracketLeft',mods:[2]},
        'C-g':{act:'escape',code:'KeyG',mods:[2]},
        'C-d':{act:'motion',code:'KeyD',mods:[2]},
        'C-u':{act:'motion',code:'KeyU',mods:[2]},
        'C-v':{act:'visual_block',code:'KeyV',mods:[2]},
    },

    get seq(){/* {Seq:{Action,MinMilliseconds?}} */
        delete this.seq;
        let tsq={
            'fd':{act:'escape',dt:500},
            'cs':{act:'surround'},
            'ds':{act:'surround'},
            'ys':{act:'surround'},
            /* 'jk':{act:'escape'}, */
        };
        for(let i in tsq){tsq[i].rn=[...i].reverse().join('');}
        return this.seq=tsq;
    },

    /* methods */
    /* NOTE input can contain: key chords, single keys, and mouse events. */
    handle_evt(input){
        let fd=input.KS[0], action='nop', fn, ok_chord={}, ok_seq;

        /* Test input for chord. */
        for(let icc in this.chord){
            let i=this.chord[icc], eci=Array.from(input.KC).indexOf(i.code);
            if(eci>-1 && (0>i.mods || i.mods.some(x=>x==input.KS[3][0]))){
                ok_chord=i;
                ok_chord.name=icc;
                break;
            }
        }

        /* Test input for sequence. */
        let inseq=input.KS[0].join('');
        for(let si in this.seq){
            let i=this.seq[si];
            if(inseq.startsWith(i.rn)){
                if(!i.dt){ok_seq=i;}
                else if(i.dt > input.KS[2].slice(0,si.length).reduce((a,b)=>a-b)){ok_seq=i;}
                break;
            }
        }

        if(Object.keys(ok_chord).length){/* chord? */
            if(fn=this.st[this.current_state][ok_chord.act]){action=ok_chord.act;}
            else{console.log(`chord (${ok_chord.name}) unexpected in state (${this.current_state})`);}
        }
        else if(ok_seq){/* sequence? */
            if(fn=this.st[this.current_state][ok_seq.act]){action=ok_seq.act;}
            else{console.log(`seq (${[...ok_seq.rn].reverse().join('')}) has no associated action`);}
        }
        else{/* single key? */
            let et=this.atom[input.KS[0][0]]||[];
            for(let i=0;i<et.length;++i){
                if(et.length && (fn=this.st[this.current_state][et[i]])){action=et[i]; break;}
            }
        }

        /* Action or nop? */
        if(action==='nop'){return;}
        if(!action){fn=this.unexpected_event;}

        /* Compute next state. */
        let obj={}, next_state=fn.call(this,obj);/* try */
        if(!next_state){next_state=this.current_state;}/* fallback 1 */
        if(!this.st[next_state]){next_state=this.unexpected_state(action,next_state);}/* fallback 2 */

        console.log(`state: ${next_state}`);
        //console.log(obj);

        this.current_state=next_state;
        /* TODO accumulate actual keys and, upon successful state change,
           export the key sequence to external handling function. */
    },

    unexpected_event(e){
        console.log(`unexpected event: ${e}`);
        this.reset_multiplier();
        return this.initial_state;
    },

    unexpected_state(e,s){
        console.log(`unexpected state: ${e}`);
        return this.unexpected_event(e);
    },

    get st(){/* {State:{Event->State}} */
        delete this.st;
        let st={

            normal:{
                mult_0(e){/*this.multiplier_str[0]+=e.val;*/ return 'mult_N';},
                verb(e){return 'verb';},
                text_object(e){/* move_cursor_to_object_if_possible */ return 'normal';},
                motion(e){/* move_cursor_by_motion_if_possible */ console.log(e);return 'normal';},
                visual(e){return 'visual';},
                visual_line(e){return 'visual_line';},
                visual_block(e){return 'visual_block';},
                find_char(e){return 'find_char';},
                insert(e){return 'insert';},
                escape(e){return 'normal';},
                edit(e){/* switch(e){...} */ return 'normal';},
                undo(e){return 'normal';},
                repeat(e){/* repeat_last_thing */ return 'normal';},
            },

            mult_N:{
                mult_N(e){/*this.multiplier_str[0]+=e.val; */ return 'mult_N';},
                verb(e){/*this.multiplier_str[0]*=parseInt(this.multiplier_str[0],10); */ return 'verb';},
                text_object(e){/* go(e) */ return 'normal';},
                motion(e){/* go(e) */ return 'normal';},
                visual(e){return 'visual';},
                visual_line(e){return 'visual_line';},
                visual_block(e){return 'visual_block';},
                find_char(e){/*this.multiplier_str[1]+=e.val; */ return 'find_char';},
                insert(e){return 'insert_N';},
                escape(e){return 'normal';},
                edit(e){return 'normal';},
                undo(e){return 'normal';},
                repeat(e){return 'normal';},
            },

            verb:{
                mult_0(e){/* save n1 */ return 'post_verb';},
                mult_N(e){/* save n1 */ return 'post_verb';},
                verb(e){/* if (verb == earlier verb) do(linewise); */ return 'normal';},
                modifier(e){return 'modifier';},
                text_object(e){/* go(object) */ return 'normal';},
                motion(e){/* go(motion) */ return 'normal';},
                find_char(e){return 'find_char_verb';},
                escape(e){return 'normal';},
            },

            post_verb:{
                verb(e){/* if (post_verb == verb) do(linewise); */ return 'normal';},
                modifier(e){return 'modifier';},
                text_object(e){/* do(object) */ return 'normal';},
                motion(e){/* do(motion) */ return 'normal';},
                find_char(e){return 'find_char_verb';},
                escape(e){return 'normal';},
            },

            modifier:{
                text_object(e){/* do(object) */ return 'normal';},
                motion(e){/* do(motion) */ return 'normal';},
            },

            visual:{
                mult_0(e){/* save n0 */ return 'visual';},
                mult_N(e){/* save n0 */ return 'visual';},
                verb(e){/* do(range) */ return 'normal';},
                text_object(e){/* go(object) */ return 'visual';},
                motion(e){/* go(motion) */ return 'visual';},
                visual(e){return 'normal';},
                visual_line(e){return 'visual_line';},
                visual_block(e){return 'visual_block';},
                find_char(e){return 'find_char_visual';},
                insert(e){return 'insert';},
                escape(e){return 'normal';},
                edit(e){/* edit() */ return 'normal';},
            },

            visual_line:{
                mult_0(e){/* save n0 */ return 'visual_line';},
                mult_N(e){/* save n0 */ return 'visual_line';},
                verb(e){/* do(linewise) */ return 'normal';},
                text_object(e){/* go(object) */ return 'visual_line';},
                motion(e){/* go(motion) */ return 'visual_line';},
                visual(e){return 'visual';},
                visual_line(e){return 'normal';},
                visual_block(e){return 'visual_block';},
                find_char(e){return 'find_char_visual_line';},
                insert(e){/* if(AIS) */ return 'insert_block';},
                escape(e){return 'normal';},
                edit(e){/* edit() */ return 'normal';},
            },

            visual_block:{
                mult_0(e){/* save n0 */ return 'visual_line';},
                mult_N(e){/* save n0 */ return 'visual_line';},
                verb(e){/* do(linewise) */ return 'normal';},
                text_object(e){/* go(object) */ return 'visual_block';},
                motion(e){/* go(motion) */ return 'visual_block';},
                visual(e){return 'visual';},
                visual_line(e){return 'visual_line';},
                visual_block(e){return 'normal';},
                find_char(e){return 'find_char_visual_block';},
                insert(e){/* if(AIS) */ return 'insert_block';},
                escape(e){return 'normal';},
                edit(e){/* edit() */ return 'normal';},
            },

            /* TODO implement ascii(e) */
            find_char:{
                escape(e){return 'normal'},
                ascii(e){/* go(range) */ return 'normal';},
            },

            find_char_visual:{
                escape(e){return 'normal'},
                ascii(e){/* go(range) */ return 'visual';},
            },

            find_char_visual_line:{
                escape(e){return 'normal'},
                ascii(e){/* go(range) */ return 'visual_line';},
            },

            find_char_visual_block:{
                escape(e){return 'normal'},
                ascii(e){/* go(range) */ return 'visual_block';},
            },

            find_char_verb:{
                escape(e){return 'normal'},
                ascii(e){/* if e is found do(range) */ return 'normal'},
            },

            insert:{
                escape(e){return 'normal';},
                ascii(e){/* put(e) */ return 'insert';},
            },

            insert_N:{
                escape(e){/* put(e) in other lines */ return 'normal';},
                ascii(e){/* put(e) */ return 'insert_N';},
            },

            insert_block:{
                escape(e){/* put(e) in other lines */ return 'normal';},
                ascii(e){/* put(e) */ return 'insert_block';},
            },

            insert_block_N:{
                escape(e){/* put(e) in other lines */ return 'normal';},
                ascii(e){/* put(e) */ return 'insert_block_N';},
            },

        };
        st.mult_0=st.mult_N; /* mult_0 is a copy of mult_N */
        return this.st=st;
    },
};
<commit_msg>something<commit_after>/* Vim-sytle UI
   The state machine design in this class is taken directly from here (Thanks IBM!):
   http://www.ibm.com/developerworks/library/wa-finitemach1/

   Offical WIMUI state transition table is here (x indicates disallowed state):
   https://docs.google.com/spreadsheets/d/1gVKCasnhn3aBtXefvZiW6Ht5fp7YofSgvZtBTXDhdzE/edit?usp=sharing
*/
const WIMUI={
    multiplier:1,
    multiplier_str:['',''],
    get_multiplier(multstr){/* [String] -> Int */ return multstr.reduce((a,b)=>a*(b||1),1)},
    reset_multiplier(){this.multiplier=1; this.multiplier_str=['',''];},
    initial_state:'normal',
    current_state:'normal',

    get atom(){/* {Char:[Type]} */
        delete this.atom;
        let atm={/* {Type:[Char]} */
            mult_0:'123456789',
            mult_N:'0123456789',
            verb:'cdy',
            modifier:'ai',
            text_object:'0^$%{}()[]<>`"\'bBeEpwWG',
            motion:'hjkl',
            edit:'oOpPrxX',
            insert:'aAiI',
            visual:'v',
            visual_line:'V',
            find_char:'fFtT',
            undo:'u',
            repeat:'.',
            ascii:' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~',
        };
        let it={}; for(let s in atm){[...atm[s]].forEach(x=>it[x]?it[x].push(s):it[x]=[s]);}
        it.Escape=['escape'];
        return this.atom=it;
    },

    chord:{
        'C-[':{act:'escape',code:'BracketLeft',mods:[2]},
        'C-g':{act:'escape',code:'KeyG',mods:[2]},
        'C-d':{act:'motion',code:'KeyD',mods:[2]},
        'C-u':{act:'motion',code:'KeyU',mods:[2]},
        'C-v':{act:'visual_block',code:'KeyV',mods:[2]},
    },

    get seq(){/* {Seq:{Action,MinMilliseconds?}} */
        delete this.seq;
        let tsq={
            'fd':{act:'escape',dt:500},
            'cs':{act:'surround'},
            'ds':{act:'surround'},
            'ys':{act:'surround'},
            /* 'jk':{act:'escape'}, */
        };
        for(let i in tsq){tsq[i].rn=[...i].reverse().join('');}
        return this.seq=tsq;
    },

    /* methods */
    /* NOTE input can contain: key chords, single keys, and mouse events. */
    handle_evt(input){
        let fd=input.KS[0], action='nop', fn, ok_chord={}, ok_seq;

        /* Test input for chord. */
        for(let icc in this.chord){
            let i=this.chord[icc], eci=Array.from(input.KC).indexOf(i.code);
            if(eci>-1 && (0>i.mods || i.mods.some(x=>x==input.KS[3][0]))){
                ok_chord=i;
                ok_chord.name=icc;
                break;
            }
        }

        /* Test input for sequence. */
        let inseq=input.KS[0].join('');
        for(let si in this.seq){
            let i=this.seq[si];
            if(inseq.startsWith(i.rn)){
                if(!i.dt){ok_seq=i;}
                else if(i.dt > input.KS[2].slice(0,si.length).reduce((a,b)=>a-b)){ok_seq=i;}
                break;
            }
        }

        if(Object.keys(ok_chord).length){/* chord? */
            if(fn=this.st[this.current_state][ok_chord.act]){action=ok_chord.act;}
            else{console.log(`chord (${ok_chord.name}) unexpected in state (${this.current_state})`);}
        }
        else if(ok_seq){/* sequence? */
            if(fn=this.st[this.current_state][ok_seq.act]){action=ok_seq.act;}
            else{console.log(`seq (${[...ok_seq.rn].reverse().join('')}) has no associated action`);}
        }
        else{/* single key? */
            let et=this.atom[input.KS[0][0]]||[];
            for(let i=0;i<et.length;++i){
                if(et.length && (fn=this.st[this.current_state][et[i]])){action=et[i]; break;}
            }
        }

        /* Action or nop? */
        if(action==='nop'){return;}
        if(!action){fn=this.unexpected_event;}

        /* Compute next state. */
        let obj={}, next_state=fn.call(this,obj);/* try */
        if(!next_state){next_state=this.current_state;}/* fallback 1 */
        if(!this.st[next_state]){next_state=this.unexpected_state(action,next_state);}/* fallback 2 */

        console.log(`state: ${next_state}`);
        //console.log(obj);

        this.current_state=next_state;
        /* TODO accumulate actual keys and, upon successful state change,
           export the key sequence to external handling function. */
    },

    unexpected_event(e){
        console.log(`unexpected event: ${e}`);
        this.reset_multiplier();
        return this.initial_state;
    },

    unexpected_state(e,s){
        console.log(`unexpected state: ${e}`);
        return this.unexpected_event(e);
    },

    get st(){/* {State:{Event->State}} */
        delete this.st;
        let st={

            normal:{
                mult_0(e){/*this.multiplier_str[0]+=e.val;*/ return 'mult_N';},
                verb(e){return 'verb';},
                text_object(e){/* move_cursor_to_object_if_possible */return 'normal';},
                motion(e){/* move_cursor_by_motion_if_possible */return 'normal';},
                visual(e){return 'visual';},
                visual_line(e){return 'visual_line';},
                visual_block(e){return 'visual_block';},
                find_char(e){return 'find_char';},
                insert(e){return 'insert';},
                escape(e){return 'normal';},
                edit(e){/* switch(e){...} */ return 'normal';},
                undo(e){return 'normal';},
                repeat(e){/* repeat_last_thing */ return 'normal';},
            },

            mult_N:{
                mult_N(e){/*this.multiplier_str[0]+=e.val; */ return 'mult_N';},
                verb(e){/*this.multiplier_str[0]*=parseInt(this.multiplier_str[0],10); */ return 'verb';},
                text_object(e){/* go(e) */ return 'normal';},
                motion(e){/* go(e) */ return 'normal';},
                visual(e){return 'visual';},
                visual_line(e){return 'visual_line';},
                visual_block(e){return 'visual_block';},
                find_char(e){/*this.multiplier_str[1]+=e.val; */ return 'find_char';},
                insert(e){return 'insert_N';},
                escape(e){return 'normal';},
                edit(e){return 'normal';},
                undo(e){return 'normal';},
                repeat(e){return 'normal';},
            },

            verb:{
                mult_0(e){/* save n1 */ return 'post_verb';},
                mult_N(e){/* save n1 */ return 'post_verb';},
                verb(e){/* if (verb == earlier verb) do(linewise); */ return 'normal';},
                modifier(e){return 'modifier';},
                text_object(e){/* go(object) */ return 'normal';},
                motion(e){/* go(motion) */ return 'normal';},
                find_char(e){return 'find_char_verb';},
                escape(e){return 'normal';},
            },

            post_verb:{
                verb(e){/* if (post_verb == verb) do(linewise); */ return 'normal';},
                modifier(e){return 'modifier';},
                text_object(e){/* do(object) */ return 'normal';},
                motion(e){/* do(motion) */ return 'normal';},
                find_char(e){return 'find_char_verb';},
                escape(e){return 'normal';},
            },

            modifier:{
                text_object(e){/* do(object) */ return 'normal';},
                motion(e){/* do(motion) */ return 'normal';},
            },

            visual:{
                mult_0(e){/* save n0 */ return 'visual';},
                mult_N(e){/* save n0 */ return 'visual';},
                verb(e){/* do(range) */ return 'normal';},
                text_object(e){/* go(object) */ return 'visual';},
                motion(e){/* go(motion) */ return 'visual';},
                visual(e){return 'normal';},
                visual_line(e){return 'visual_line';},
                visual_block(e){return 'visual_block';},
                find_char(e){return 'find_char_visual';},
                insert(e){return 'insert';},
                escape(e){return 'normal';},
                edit(e){/* edit() */ return 'normal';},
            },

            visual_line:{
                mult_0(e){/* save n0 */ return 'visual_line';},
                mult_N(e){/* save n0 */ return 'visual_line';},
                verb(e){/* do(linewise) */ return 'normal';},
                text_object(e){/* go(object) */ return 'visual_line';},
                motion(e){/* go(motion) */ return 'visual_line';},
                visual(e){return 'visual';},
                visual_line(e){return 'normal';},
                visual_block(e){return 'visual_block';},
                find_char(e){return 'find_char_visual_line';},
                insert(e){/* if(AIS) */ return 'insert_block';},
                escape(e){return 'normal';},
                edit(e){/* edit() */ return 'normal';},
            },

            visual_block:{
                mult_0(e){/* save n0 */ return 'visual_line';},
                mult_N(e){/* save n0 */ return 'visual_line';},
                verb(e){/* do(linewise) */ return 'normal';},
                text_object(e){/* go(object) */ return 'visual_block';},
                motion(e){/* go(motion) */ return 'visual_block';},
                visual(e){return 'visual';},
                visual_line(e){return 'visual_line';},
                visual_block(e){return 'normal';},
                find_char(e){return 'find_char_visual_block';},
                insert(e){/* if(AIS) */ return 'insert_block';},
                escape(e){return 'normal';},
                edit(e){/* edit() */ return 'normal';},
            },

            /* TODO implement ascii(e) */
            find_char:{
                escape(e){return 'normal'},
                ascii(e){/* go(range) */ return 'normal';},
            },

            find_char_visual:{
                escape(e){return 'normal'},
                ascii(e){/* go(range) */ return 'visual';},
            },

            find_char_visual_line:{
                escape(e){return 'normal'},
                ascii(e){/* go(range) */ return 'visual_line';},
            },

            find_char_visual_block:{
                escape(e){return 'normal'},
                ascii(e){/* go(range) */ return 'visual_block';},
            },

            find_char_verb:{
                escape(e){return 'normal'},
                ascii(e){/* if e is found do(range) */ return 'normal'},
            },

            insert:{
                escape(e){return 'normal';},
                ascii(e){/* put(e) */ return 'insert';},
            },

            insert_N:{
                escape(e){/* put(e) in other lines */ return 'normal';},
                ascii(e){/* put(e) */ return 'insert_N';},
            },

            insert_block:{
                escape(e){/* put(e) in other lines */ return 'normal';},
                ascii(e){/* put(e) */ return 'insert_block';},
            },

            insert_block_N:{
                escape(e){/* put(e) in other lines */ return 'normal';},
                ascii(e){/* put(e) */ return 'insert_block_N';},
            },

        };
        st.mult_0=st.mult_N; /* mult_0 is a copy of mult_N */
        return this.st=st;
    },
};
<|endoftext|>


<commit_before>var Zepto = (function() {
  var slice=[].slice, d=document,
    ADJ_OPS={append: 'beforeEnd', prepend: 'afterBegin', before: 'beforeBegin', after: 'afterEnd'},
    e, k, css, dom, un;

  // fix for iOS 3.2
  if(String.prototype.trim === un)
    String.prototype.trim = function(){ return this.replace(/^\s+/, '').replace(/\s+$/, '') };

  function $$(el, selector){ return slice.call(el.querySelectorAll(selector)) }
  function classRE(name){ return new RegExp("(^|\\s)"+name+"(\\s|$)") }
  function compact(array){ return array.filter(function(el){ return el !== un && el !== null }) }

  function Z(dom, _){ this.dom = dom; this.selector = _ }
  Z.prototype = $.fn;

  function $(_, context){
    if(context !== un) return $(context).find(_);
    dom = compact(_ instanceof Z ? _.dom : (_ instanceof Array ? _ : (_ instanceof Element ? [_] : $$(d, _))));
    return new Z(dom, _);
  }

  $.extend = function(target, src){ for(k in src) target[k] = src[k] }
  camelize = function(str){ return str.replace(/-+(.)?/g, function(match, chr){ return chr ? chr.toUpperCase() : '' }) }

  $.fn = {
    compact: function(){ this.dom=compact(this.dom); return this },
    get: function(idx){ return idx === un ? this.dom : this.dom[idx] },
    remove: function(){
      return this.each(function(el){ el.parentNode.removeChild(el) });
    },
    each: function(callback){ this.dom.forEach(callback); return this },
    filter: function(selector){
      return $(this.dom.filter(function(el){ return $$(el.parentNode, selector).indexOf(el)>=0; }));
    },
    is: function(selector){
      return this.dom.length>0 && $(this.dom[0]).filter(selector).dom.length>0;
    },
    first: function(callback){ this.dom=compact([this.dom[0]]); return this },
    find: function(selector){
      return $(this.dom.map(function(el){ return $$(el, selector) }).reduce(function(a,b){ return a.concat(b) }, []));
    },
    closest: function(selector){
      var el = this.dom[0].parentNode, nodes = $$(d, selector);
      while(el && nodes.indexOf(el)<0) el = el.parentNode;
      return $(el && !(el===d) ? el : []);
    },
    pluck: function(property){ return this.dom.map(function(el){ return el[property] }) },
    show: function(){ return this.css('display', 'block') },
    hide: function(){ return this.css('display', 'none') },
    prev: function(){ return $(this.pluck('previousElementSibling')) },
    next: function(){ return $(this.pluck('nextElementSibling')) },
    html: function(html){
      return html === un ?
        (this.dom.length>0 ? this.dom[0].innerHTML : null) :
        this.each(function(el){ el.innerHTML = html });
    },
    attr: function(name,value){
      return (typeof name == 'string' && value === un) ?
        (this.dom.length>0 ? this.dom[0].getAttribute(name) || undefined : null) :
        this.each(function(el){
          if (typeof name == 'object') for(k in name) el.setAttribute(k, name[k])
          else el.setAttribute(name,value);
        });
    },
    offset: function(){
      var obj = this.dom[0].getBoundingClientRect();
      return { left: obj.left+d.body.scrollLeft, top: obj.top+d.body.scrollTop, width: obj.width, height: obj.height };
    },
    css: function(prop, value){
      if(value === un && typeof prop == 'string') return this.dom[0].style[camelize(prop)];
      css=""; for(k in prop) css += k+':'+prop[k]+';';
      if(typeof prop == 'string') css = prop+":"+value;
      return this.each(function(el) { el.style.cssText += ';' + css });
    },
    index: function(el){
      return this.dom.indexOf($(el).get(0));
    },
    bind: function(event, callback){
      return this.each(function(el){
        event.split(/\s/).forEach(function(event){ el.addEventListener(event, callback, false); });
      });
    },
    delegate: function(selector, event, callback){
      return this.each(function(el){
        el.addEventListener(event, function(event){
          var target = event.target, nodes = $$(el, selector);
          while(target && nodes.indexOf(target)<0) target = target.parentNode;
          if(target && !(target===el) && !(target===d)) callback(target, event);
        }, false);
      });
    },
    live: function(event, callback){
      $(d.body).delegate(this.selector, event, callback); return this;
    },
    hasClass: function(name){
      return classRE(name).test(this.dom[0].className);
    },
    addClass: function(name){
      return this.each(function(el){ !$(el).hasClass(name) && (el.className += (el.className ? ' ' : '') + name) });
    },
    removeClass: function(name){
      return this.each(function(el){ el.className = el.className.replace(classRE(name), ' ').trim() });
    },
    trigger: function(event){
      return this.each(function(el){ var e; el.dispatchEvent(e = d.createEvent('Events'), e.initEvent(event, true, false)) });
    }
  };

  ['width','height'].forEach(function(m){ $.fn[m] = function(){ return this.offset()[m] }});

  for(k in ADJ_OPS)
    $.fn[k] = (function(op){
      return function(html){ return this.each(function(el){
        el['insertAdjacent' + (html instanceof Element ? 'Element' : 'HTML')](op,html)
      })};
    })(ADJ_OPS[k]);

  Z.prototype = $.fn;

  return $;
})();

'$' in window||(window.$=Zepto);
<commit_msg>remove the dom local variable and use short if for $ function<commit_after>var Zepto = (function() {
  var slice=[].slice, d=document,
    ADJ_OPS={append: 'beforeEnd', prepend: 'afterBegin', before: 'beforeBegin', after: 'afterEnd'},
    e, k, css, un;

  // fix for iOS 3.2
  if(String.prototype.trim === un)
    String.prototype.trim = function(){ return this.replace(/^\s+/, '').replace(/\s+$/, '') };

  function $$(el, selector){ return slice.call(el.querySelectorAll(selector)) }
  function classRE(name){ return new RegExp("(^|\\s)"+name+"(\\s|$)") }
  function compact(array){ return array.filter(function(el){ return el !== un && el !== null }) }

  function Z(dom, _){ this.dom = dom; this.selector = _ }
  Z.prototype = $.fn;

  function $(_, context){
    return (context !== un) ? $(context).find(_) : new Z(compact(_ instanceof Z ? _.dom: (_ instanceof Array ? _ : (_ instanceof Element ? [_] : $$(d, _)))), _);
  }

  $.extend = function(target, src){ for(k in src) target[k] = src[k] }
  camelize = function(str){ return str.replace(/-+(.)?/g, function(match, chr){ return chr ? chr.toUpperCase() : '' }) }

  $.fn = {
    compact: function(){ this.dom=compact(this.dom); return this },
    get: function(idx){ return idx === un ? this.dom : this.dom[idx] },
    remove: function(){
      return this.each(function(el){ el.parentNode.removeChild(el) });
    },
    each: function(callback){ this.dom.forEach(callback); return this },
    filter: function(selector){
      return $(this.dom.filter(function(el){ return $$(el.parentNode, selector).indexOf(el)>=0; }));
    },
    is: function(selector){
      return this.dom.length>0 && $(this.dom[0]).filter(selector).dom.length>0;
    },
    first: function(callback){ this.dom=compact([this.dom[0]]); return this },
    find: function(selector){
      return $(this.dom.map(function(el){ return $$(el, selector) }).reduce(function(a,b){ return a.concat(b) }, []));
    },
    closest: function(selector){
      var el = this.dom[0].parentNode, nodes = $$(d, selector);
      while(el && nodes.indexOf(el)<0) el = el.parentNode;
      return $(el && !(el===d) ? el : []);
    },
    pluck: function(property){ return this.dom.map(function(el){ return el[property] }) },
    show: function(){ return this.css('display', 'block') },
    hide: function(){ return this.css('display', 'none') },
    prev: function(){ return $(this.pluck('previousElementSibling')) },
    next: function(){ return $(this.pluck('nextElementSibling')) },
    html: function(html){
      return html === un ?
        (this.dom.length>0 ? this.dom[0].innerHTML : null) :
        this.each(function(el){ el.innerHTML = html });
    },
    attr: function(name,value){
      return (typeof name == 'string' && value === un) ?
        (this.dom.length>0 ? this.dom[0].getAttribute(name) || undefined : null) :
        this.each(function(el){
          if (typeof name == 'object') for(k in name) el.setAttribute(k, name[k])
          else el.setAttribute(name,value);
        });
    },
    offset: function(){
      var obj = this.dom[0].getBoundingClientRect();
      return { left: obj.left+d.body.scrollLeft, top: obj.top+d.body.scrollTop, width: obj.width, height: obj.height };
    },
    css: function(prop, value){
      if(value === un && typeof prop == 'string') return this.dom[0].style[camelize(prop)];
      css=""; for(k in prop) css += k+':'+prop[k]+';';
      if(typeof prop == 'string') css = prop+":"+value;
      return this.each(function(el) { el.style.cssText += ';' + css });
    },
    index: function(el){
      return this.dom.indexOf($(el).get(0));
    },
    bind: function(event, callback){
      return this.each(function(el){
        event.split(/\s/).forEach(function(event){ el.addEventListener(event, callback, false); });
      });
    },
    delegate: function(selector, event, callback){
      return this.each(function(el){
        el.addEventListener(event, function(event){
          var target = event.target, nodes = $$(el, selector);
          while(target && nodes.indexOf(target)<0) target = target.parentNode;
          if(target && !(target===el) && !(target===d)) callback(target, event);
        }, false);
      });
    },
    live: function(event, callback){
      $(d.body).delegate(this.selector, event, callback); return this;
    },
    hasClass: function(name){
      return classRE(name).test(this.dom[0].className);
    },
    addClass: function(name){
      return this.each(function(el){ !$(el).hasClass(name) && (el.className += (el.className ? ' ' : '') + name) });
    },
    removeClass: function(name){
      return this.each(function(el){ el.className = el.className.replace(classRE(name), ' ').trim() });
    },
    trigger: function(event){
      return this.each(function(el){ var e; el.dispatchEvent(e = d.createEvent('Events'), e.initEvent(event, true, false)) });
    }
  };

  ['width','height'].forEach(function(m){ $.fn[m] = function(){ return this.offset()[m] }});

  for(k in ADJ_OPS)
    $.fn[k] = (function(op){
      return function(html){ return this.each(function(el){
        el['insertAdjacent' + (html instanceof Element ? 'Element' : 'HTML')](op,html)
      })};
    })(ADJ_OPS[k]);

  Z.prototype = $.fn;

  return $;
})();

'$' in window||(window.$=Zepto);
<|endoftext|>


<commit_before>'use strict';
//pics/ps1/residentevil_eu.jpg

var changes = {
  'residentevil': 'Resident Evil ',
  '.jpg': ''
}
module.exports = function(src) {
  src = src.split('/').pop();

  for (var i in changes) {
    src = src.replace(i, changes[i]);
  }

  return src;
};
<commit_msg>:chestnut: lint fixes<commit_after>'use strict';
//pics/ps1/residentevil_eu.jpg

var changes = {
  'residentevil': 'Resident Evil ',
  '.jpg': ''
};

module.exports = function(src) {
  src = src.split('/').pop();

  for (var i in changes) {
    src = src.replace(i, changes[i]);
  }

  return src;
};
<|endoftext|>


<commit_before>import React from 'react';
import Link from 'gatsby-link';

import { BlogPostContent, BlogPostContainer } from '../utils/styles';

const About = () =>
  <BlogPostContainer>
    <BlogPostContent>

A little bit about me...

    </BlogPostContent>
  </BlogPostContainer>

export default About;<commit_msg>working on about page<commit_after>import React from 'react';
import Link from 'gatsby-link';

import { BlogPostContent, BlogPostContainer } from '../utils/styles';

const About = () =>
  <BlogPostContainer>
    <BlogPostContent>

I'm Adam. Nice to meet you!

I'm a web developer based in West Hartford Connecticut. Believe it or not, web development is my second career. Before that, I was a professional musician (performer/educator) for over 10 years. Now, I work full-time for UConn's office of University Communications and I'm loving every minute of it! Every day I get to work on with an amazing (and small) team (2 other devs, 2 designers,and a project manager). Together we work on sites that get seen and used by thousands of people every day.

My goal for this site is pretty simple. Because I'm self taught now that I've been working in this field for a year, I wanted to:

share what I've learned so far

keep a record of things I've found interesting and/or challenging

take part in the conversation other developers are having.

Because we're such a small team, I've had the good fortune to work on a lot of different kinds of projects. So, what you'll find on this site is going to be a combination of lots of different things!

tips and tricks

tutorials

problems I've solved for the different technologies I work with like:

web accessibility (aka a11y)

command line tools and techniques

Docker

HTML/CSS/SCSS

Javascript (e.g. es6, gulp, webpack, react, "vanilla", jquery, etc...

WordPress and PHP in general

programming concepts I've learned

and a lot more!

Here are some more lists

Things I want to learn/learn more about:

a11y

kubernetes

vue

the web audio API

I'd love to chat, share, and learn more about web development, programming, and music. Feel free to reach out by

email

twitter

github

Resume

A few more things

    </BlogPostContent>
  </BlogPostContainer>

export default About;<|endoftext|>


<commit_before>import React from 'react'
import Image from 'next/image'
import { Page } from '../components'
import profilePic from '../../static/img/photo.jpg'

const Title = () => {
  return (

      <Image
        src={profilePic}
        alt="Picture of the author"
        width="80"
        height="80"
        placeholder="blur" // Optional blur-up while loading
        className="rounded-full"
      />

        Crafting{' '}

          experiences
        {' '}
        with code.

  )
}

const Home = () => {
  return (
    <Title />
  )
}

Home.getLayout = page => (
  <Page title="Home">
    {page}
  </Page>
)

export default Home
<commit_msg>Remove blur<commit_after>import React from 'react'
import Image from 'next/image'
import { Page } from '../components'
import profilePic from '../../static/img/photo.jpg'

const Title = () => {
  return (

      <Image
        src={profilePic}
        alt="Picture of the author"
        width="80"
        height="80"
        className="rounded-full"
      />

        Crafting{' '}

          experiences
        {' '}
        with code.

  )
}

const Home = () => {
  return <Title />
}

Home.getLayout = (page) => <Page title="Home">{page}</Page>

export default Home
<|endoftext|>


<commit_before>import $ from "jquery";

/**
 * Entity information screen.
 */
class EntityInfoModal {
    /**
     *
     * @param entity Entity
     */
    constructor(entity) {
        this.entity = entity;
    }

    show() {
        // Fill in data.
        var modal = $("#modal-entityInfo").show();
        modal.find(".entityMeta-name").html(this.entity.entityType.name);
        modal.find(".entityMeta-subtitle").html(this.entity.entityType.subtitle);
        modal.find(".stat-armour").html(this.entity.entityType.armor);
        modal.find(".stat-hp").html(this.entity.entityType.health);
        modal.find(".entityIcon")[0].src = this.entity.entityType.texture.baseTexture.imageUrl;

    }
}

export default EntityInfoModal;

<commit_msg>Entity speed and surge value is now displayed in entity info.<commit_after>import $ from "jquery";

/**
 * Entity information screen.
 */
class EntityInfoModal {
    /**
     *
     * @param entity Entity
     */
    constructor(entity) {
        this.entity = entity;
    }

    show() {
        // Fill in data.
        var modal = $("#modal-entityInfo").show();
        modal.find(".entityMeta-name").html(this.entity.entityType.name);
        modal.find(".entityMeta-subtitle").html(this.entity.entityType.subtitle);
        modal.find(".stat-armour").html(this.entity.entityType.armor);
        modal.find(".stat-hp").html(this.entity.entityType.health);
        modal.find(".stat-speed").html(this.entity.entityType.speed);
        modal.find(".stat-surge").html(this.entity.entityType.surgeValue + " HP");
        modal.find(".entityIcon")[0].src = this.entity.entityType.texture.baseTexture.imageUrl;

    }
}

export default EntityInfoModal;

<|endoftext|>