/**@license
 *       __ _____                     ________                              __
 *      / // _  /__ __ _____ ___ __ _/__  ___/__ ___ ______ __ __  __ ___  / /
 *  __ / // // // // // _  // _// // / / // _  // _//     // //  \/ // _ \/ /
 * /  / // // // // // ___// / / // / / // ___// / / / / // // /\  // // / /__
 * \___//____ \\___//____//_/ _\_  / /_//____//_/ /_/ /_//_//_/ /_/ \__\_\___/
 *           \/              /____/
 * http://terminal.jcubic.pl
 *
 * This is example of how to create custom formatter for jQuery Terminal
 *
 * Copyright (c) 2014-2023 Jakub Jankiewicz <https://jcubic.pl/me>
 * Released under the MIT license
 *
 * Includes: node-ansiparser, MIT license, Copyright (c) 2014 Joerg Breitbart
 *
 * Last Update in jQuery Terminal 2.23.0
 *
 */
/* global define */
(function(factory) {
    var root;
    if (typeof window !== 'undefined') {
        root = window;
    } else if (typeof self !== 'undefined') {
        root = self;
    } else if (typeof global !== 'undefined') {
        root = global;
    } else {
        throw new Error('Unknow context');
    }
    if (typeof define === 'function' && define.amd) {
        // AMD. Register as an anonymous module.
        // istanbul ignore next
        define(['jquery', 'jquery.terminal'], factory);
    } else if (typeof module === 'object' && module.exports) {
        // Node/CommonJS
        module.exports = function(root, jQuery) {
            if (jQuery === undefined) {
                // require('jQuery') returns a factory that requires window to
                // build a jQuery instance, we normalize how we use modules
                // that require this pattern but the window provided is a noop
                // if it's defined (how jquery works)
                if (typeof window !== 'undefined') {
                    jQuery = require('jquery');
                } else {
                    jQuery = require('jquery')(root);
                }
            }
            if (!jQuery.fn.terminal) {
                if (typeof window !== 'undefined') {
                    require('jquery.terminal');
                } else {
                    require('jquery.terminal')(jQuery);
                }
            }
            factory(jQuery);
            return jQuery;
        };
    } else {
        // Browser
        // istanbul ignore next
        factory(root.jQuery);
    }
})(function($) {
    var DEBUG = true;
    /* eslint-disable */
    /* istanbul ignore next */
    function warn(str) {
        if ('warn' in console) {
            console.warn(str);
        }
    }
    // node-ansiparser
    // The MIT License (MIT)
    // Copyright (c) 2014 Joerg Breitbart
    /* istanbul ignore next */
    var AnsiParser = (function () {
        'use strict';

        /**
         * range function for numbers [a, .., b-1]
         *
         * @param {number} a
         * @param {number} b
         * @return {Array}
         */
        function r(a, b) {
            var c = b - a;
            var arr = new Array(c);
            while (c--)
                arr[c] = --b;
            return arr;
        }

        /**
         * Add a transition to the transition table.
         *
         * @param table - table to add transition
         * @param {number} inp - input character code
         * @param {number} state - current state
         * @param {number=} action - action to be taken
         * @param {number=} next - next state
         */
        function add(table, inp, state, action, next) {
            table[state<<8|inp] = ((action | 0) << 4) | ((next === undefined) ? state : next);
        }

        /**
         * Add multiple transitions to the transition table.
         *
         * @param table - table to add transition
         * @param {Array} inps - array of input character codes
         * @param {number} state - current state
         * @param {number=} action - action to be taken
         * @param {number=} next - next state
         */
        function add_list(table, inps, state, action, next) {
            for (var i=0; i<inps.length; i++)
                add(table, inps[i], state, action, next);
        }

        /** global definition of printables and executables */
        var PRINTABLES = r(0x20, 0x7f);
        var EXECUTABLES = r(0x00, 0x18);
        EXECUTABLES.push(0x19);
        EXECUTABLES.push(0x1E);
        EXECUTABLES.concat(r(0x1c, 0x20));

        /* meaning of state and action indices
           var STATES = [
           'GROUND',
           'ESCAPE',
           'ESCAPE_INTERMEDIATE',
           'CSI_ENTRY',
           'CSI_PARAM',
           'CSI_INTERMEDIATE',
           'CSI_IGNORE',
           'SOS_PM_APC_STRING',
           'OSC_STRING',
           'DCS_ENTRY',
           'DCS_PARAM',
           'DCS_IGNORE',
           'DCS_INTERMEDIATE',
           'DCS_PASSTHROUGH'
           ];
           var ACTIONS = [
           'ignore',
           'error',
           'print',
           'execute',
           'osc_start',
           'osc_put',
           'osc_end',
           'csi_dispatch',
           'param',
           'collect',
           'esc_dispatch',
           'clear',
           'dcs_hook',
           'dcs_put',
           'dcs_unhook'
           ];
        */

        /**
         * create the standard transition table - used by all parser instances
         *
         *     table[state << 8 | character code] = action << 4 | next state
         *
         *     - states are indices of STATES (0 to 13)
         *     - control character codes defined from 0 to 159 (C0 and C1)
         *     - actions are indices of ACTIONS (0 to 14)
         *     - any higher character than 159 is handled by the 'error' action
         */
        var TRANSITION_TABLE = (function() {
            var t = new Uint8Array(4095);

            // table with default transition [any] --> [error, GROUND]
            for (var state=0; state<14; ++state) {
                for (var code=0; code<160; ++code) {
                    t[state<<8|code] = 16;
                }
            }

            // apply transitions
            // printables
            add_list(t, PRINTABLES, 0, 2);
            // global anywhere rules
            for (state=0; state<14; ++state) {
                add_list(t, [0x18, 0x1a, 0x99, 0x9a], state, 3, 0);
                add_list(t, r(0x80, 0x90), state, 3, 0);
                add_list(t, r(0x90, 0x98), state, 3, 0);
                add(t, 0x9c, state, 0, 0);   // ST as terminator
                add(t, 0x1b, state, 11, 1);  // ESC
                add(t, 0x9d, state, 4, 8);   // OSC
                add_list(t, [0x98, 0x9e, 0x9f], state, 0, 7);
                add(t, 0x9b, state, 11, 3);  // CSI
                add(t, 0x90, state, 11, 9);  // DCS
            }
            // rules for executables and 7f
            add_list(t, EXECUTABLES, 0, 3);
            add_list(t, EXECUTABLES, 1, 3);
            add(t, 0x7f, 1);
            add_list(t, EXECUTABLES, 8);
            add_list(t, EXECUTABLES, 3, 3);
            add(t, 0x7f, 3);
            add_list(t, EXECUTABLES, 4, 3);
            add(t, 0x7f, 4);
            add_list(t, EXECUTABLES, 6, 3);
            add_list(t, EXECUTABLES, 5, 3);
            add(t, 0x7f, 5);
            add_list(t, EXECUTABLES, 2, 3);
            add(t, 0x7f, 2);
            // osc
            add(t, 0x5d, 1, 4, 8);
            add_list(t, PRINTABLES, 8, 5);
            add(t, 0x7f, 8, 5);
            add_list(t, [0x9c, 0x1b, 0x18, 0x1a, 0x07], 8, 6, 0);
            add_list(t, r(0x1c, 0x20), 8, 0);
            // sos/pm/apc does nothing
            add_list(t, [0x58, 0x5e, 0x5f], 1, 0, 7);
            add_list(t, PRINTABLES, 7);
            add_list(t, EXECUTABLES, 7);
            add(t, 0x9c, 7, 0, 0);
            // csi entries
            add(t, 0x5b, 1, 11, 3);
            add_list(t, r(0x40, 0x7f), 3, 7, 0);
            add_list(t, r(0x30, 0x3a), 3, 8, 4);
            add(t, 0x3b, 3, 8, 4);
            add_list(t, [0x3c, 0x3d, 0x3e, 0x3f], 3, 9, 4);
            add_list(t, r(0x30, 0x3a), 4, 8);
            add(t, 0x3b, 4, 8);
            add_list(t, r(0x40, 0x7f), 4, 7, 0);
            add_list(t, [0x3a, 0x3c, 0x3d, 0x3e, 0x3f], 4, 0, 6);
            add_list(t, r(0x20, 0x40), 6);
            add(t, 0x7f, 6);
            add_list(t, r(0x40, 0x7f), 6, 0, 0);
            add(t, 0x3a, 3, 0, 6);
            add_list(t, r(0x20, 0x30), 3, 9, 5);
            add_list(t, r(0x20, 0x30), 5, 9);
            add_list(t, r(0x30, 0x40), 5, 0, 6);
            add_list(t, r(0x40, 0x7f), 5, 7, 0);
            add_list(t, r(0x20, 0x30), 4, 9, 5);
            // esc_intermediate
            add_list(t, r(0x20, 0x30), 1, 9, 2);
            add_list(t, r(0x20, 0x30), 2, 9);
            add_list(t, r(0x30, 0x7f), 2, 10, 0);
            add_list(t, r(0x30, 0x50), 1, 10, 0);
            add_list(t, [0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x59, 0x5a, 0x5c], 1, 10, 0);
            add_list(t, r(0x60, 0x7f), 1, 10, 0);
            // dcs entry
            add(t, 0x50, 1, 11, 9);
            add_list(t, EXECUTABLES, 9);
            add(t, 0x7f, 9);
            add_list(t, r(0x1c, 0x20), 9);
            add_list(t, r(0x20, 0x30), 9, 9, 12);
            add(t, 0x3a, 9, 0, 11);
            add_list(t, r(0x30, 0x3a), 9, 8, 10);
            add(t, 0x3b, 9, 8, 10);
            add_list(t, [0x3c, 0x3d, 0x3e, 0x3f], 9, 9, 10);
            add_list(t, EXECUTABLES, 11);
            add_list(t, r(0x20, 0x80), 11);
            add_list(t, r(0x1c, 0x20), 11);
            add_list(t, EXECUTABLES, 10);
            add(t, 0x7f, 10);
            add_list(t, r(0x1c, 0x20), 10);
            add_list(t, r(0x30, 0x3a), 10, 8);
            add(t, 0x3b, 10, 8);
            add_list(t, [0x3a, 0x3c, 0x3d, 0x3e, 0x3f], 10, 0, 11);
            add_list(t, r(0x20, 0x30), 10, 9, 12);
            add_list(t, EXECUTABLES, 12);
            add(t, 0x7f, 12);
            add_list(t, r(0x1c, 0x20), 12);
            add_list(t, r(0x20, 0x30), 12, 9);
            add_list(t, r(0x30, 0x40), 12, 0, 11);
            add_list(t, r(0x40, 0x7f), 12, 12, 13);
            add_list(t, r(0x40, 0x7f), 10, 12, 13);
            add_list(t, r(0x40, 0x7f), 9, 12, 13);
            add_list(t, EXECUTABLES, 13, 13);
            add_list(t, PRINTABLES, 13, 13);
            add(t, 0x7f, 13);
            add_list(t, [0x1b, 0x9c], 13, 14, 0);

            return t;
        })();


        /**
         *  AnsiParser - Parser for ANSI terminal escape sequences.
         *
         * @param {Object=} terminal emulation object
         * @constructor
         */
        function AnsiParser(terminal) {
            this.initial_state = 0;  // 'GROUND' is default
            this.current_state = this.initial_state|0;

            // clone global transition table
            this.transitions = new Uint8Array(4095);
            this.transitions.set(TRANSITION_TABLE);

            // global non pushable buffers for multiple parse invocations
            this.osc = '';
            this.params = [0];
            this.collected = '';

            // back reference to terminal
            this.term = terminal || {};
            var instructions = ['inst_p', 'inst_o', 'inst_x', 'inst_c',
                                'inst_e', 'inst_H', 'inst_P', 'inst_U', 'inst_E'];
            for (var i=0; i<instructions.length; ++i)
                if (!(instructions[i] in this.term))
                    this.term[instructions[i]] = function() {};
        }

        /**
         * Reset the parser.
         */
        AnsiParser.prototype.reset = function() {
            this.current_state = this.initial_state|0;
            this.osc = '';
            this.params = [0];
            this.collected = '';
        };

        /**
         * Parse string s.
         * @param {string} s
         */
        AnsiParser.prototype.parse = function(s) {
            var code = 0,
                transition = 0,
                error = false,
                current_state = this.current_state|0;

            // local buffers
            var printed = -1;
            var dcs = -1;
            var osc = this.osc;
            var collected = this.collected;
            var params = this.params;

            // process input string
            for (var i=0, l=s.length|0; i<l; ++i) {
                code = s.charCodeAt(i)|0;
                // shortcut for most chars (print action)
                if (current_state===0 && code>0x1f && code<0x80) {
                    printed = (printed + 1) ? printed|0: i|0;
                    continue;
                }
                transition = ((code < 0xa0) ? (this.transitions[(current_state<<8|code)|0])|0 : 16)|0;
                switch ((transition >> 4)|0) {
                    case 2: // print
                        printed = (printed + 1) ? printed|0: i|0;
                        break;
                    case 3: // execute
                        if (printed + 1) {
                            this.term.inst_p(s.substring(printed, i));
                            printed = -1;
                        }
                        this.term.inst_x(String.fromCharCode(code));
                        break;
                    case 0: // ignore
                        // handle leftover print and dcs chars
                        if (printed + 1) {
                            this.term.inst_p(s.substring(printed, i));
                            printed = -1;
                        } else if (dcs + 1) {
                            this.term.inst_P(s.substring(dcs, i));
                            dcs = -1;
                        }
                        break;
                    case 1: // error
                        // handle unicode chars in write buffers w'o state change
                        if (code > 0x9f) {
                            switch (current_state) {
                                case 0: // GROUND -> add char to print string
                                    printed = (!(printed+1)) ? i|0 : printed|0;
                                    break;
                                case 8: // OSC_STRING -> add char to osc string
                                    osc += String.fromCharCode(code);
                                    transition = (transition | 8)|0;
                                    break;
                                case 6: // CSI_IGNORE -> ignore char
                                    transition = (transition | 6)|0;
                                    break;
                                case 11: // DCS_IGNORE -> ignore char
                                    transition = (transition | 11)|0;
                                    break;
                                case 13: // DCS_PASSTHROUGH -> add char to dcs
                                    if (!(dcs + 1))
                                        dcs = i|0;
                                    transition = (transition | 13)|0;
                                    break;
                                default: // real error
                                    error = true;
                            }
                        } else { // real error
                            error = true;
                        }
                        if (error) {
                            if (this.term.inst_E(
                                {
                                    pos: i,                 // position in parse string
                                    character: String.fromCharCode(code), // wrong character
                                    state: current_state,   // in state
                                    print: printed,         // print buffer
                                    dcs: dcs,               // dcs buffer
                                    osc: osc,               // osc buffer
                                    collect: collected,     // collect buffer
                                    params: params          // params buffer
                                })) {
                                return;
                            }
                            error = false;
                        }
                        break;
                    case 7: // csi_dispatch
                        this.term.inst_c(collected, params, String.fromCharCode(code));
                        break;
                    case 8: // param
                        if (code === 0x3b)
                            params.push(0);
                        else
                            params[params.length-1] = (params[params.length-1] * 10 + code - 48)|0;
                        break;
                    case 9: // collect
                        collected += String.fromCharCode(code);
                        break;
                    case 10: // esc_dispatch
                        this.term.inst_e(collected, String.fromCharCode(code));
                        break;
                    case 11: // clear
                        if (printed + 1) {
                            this.term.inst_p(s.substring(printed, i));
                            printed = -1;
                        }
                        osc = '';
                        params = [0];
                        collected = '';
                        dcs = -1;
                        break;
                    case 12: // dcs_hook
                        this.term.inst_H(collected, params, String.fromCharCode(code));
                        break;
                    case 13: // dcs_put
                        if (!(dcs + 1))
                            dcs = i|0;
                        break;
                    case 14: // dcs_unhook
                        if (dcs + 1) {
                            this.term.inst_P(s.substring(dcs, i));
                        }
                        this.term.inst_U();
                        if (code === 0x1b)
                            transition = (transition | 1)|0;
                        osc = '';
                        params = [0];
                        collected = '';
                        dcs = -1;
                        break;
                    case 4: // osc_start
                        if (~printed) {
                            this.term.inst_p(s.substring(printed, i));
                            printed = -1;
                        }
                        osc = '';
                        break;
                    case 5: // osc_put
                        osc += s.charAt(i);
                        break;
                    case 6: // osc_end
                        if (osc && code !== 0x18 && code !== 0x1a)
                            this.term.inst_o(osc);
                        if (code === 0x1b)
                            transition = (transition | 1)|0;
                        osc = '';
                        params = [0];
                        collected = '';
                        dcs = -1;
                        break;
                }
                current_state = (transition & 15)|0;
            }

            // push leftover pushable buffers to terminal
            if (!current_state && (printed + 1)) {
                this.term.inst_p(s.substring(printed));
            } else if (current_state===13 && (dcs + 1)) {
                this.term.inst_P(s.substring(dcs));
            }

            // save non pushable buffers
            this.osc = osc;
            this.collected = collected;
            this.params = params;

            // save state
            this.current_state = current_state|0;
        };
        return AnsiParser;
    })();
    /* eslint-enable */
    // ---------------------------------------------------------------------
    $.terminal.AnsiParser = AnsiParser;
    // ---------------------------------------------------------------------
    // we match characters and html entities because command line escape brackets
    // echo don't, when writing formatter always process html entitites so it work
    // for cmd plugin as well for echo
    var chr = '[^\\x08]|[\\r\\n]{2}|&[^;]+;';
    var backspace_re = new RegExp('^(' + chr + ')?\\x08');
    var overtyping_re = new RegExp('^(?:(' + chr + ')?\\x08(_|\\1)|' +
                                   '(_)\\x08(' + chr + '))');
    var new_line_re = /^(\r\n|\n\r|\r|\n)/;
    var clear_line_re = /[^\r\n]+\r\x1B\[K/g;
    // ---------------------------------------------------------------------
    function length(string) {
        return $.terminal.length(string);
    }
    // ---------------------------------------------------------------------
    function get_settings(options) {
        var unixFormatting = {
            escapeBrackets: false,
            ansiParser: {},
            position: 0,
            ansiArt: false
        };
        if (options) {
            if (options.unixFormatting) {
                $.extend(unixFormatting, options.unixFormatting);
            }
            if ('position' in options) {
                unixFormatting.position = options.position;
            }
            if ('unixFormattingEscapeBrackets' in options) {
                unixFormatting.escapeBrackets = options.unixFormattingEscapeBrackets;
            }
            if ('ansiParser' in options) {
                unixFormatting.ansiParser = options.ansiParser;
            }
        }
        return unixFormatting;
    }
    // ---------------------------------------------------------------------
    // :: Replace overtyping (from man) formatting with terminal formatting
    // ---------------------------------------------------------------------
    $.terminal.overtyping = function overtyping(string, options) {
        string = $.terminal.unescape_brackets(string);
        var settings = get_settings(options);
        var removed_chars = [];
        var new_position;
        var char_count = 0;
        var backspaces = [];
        function replace(string, position) {
            var result = '';
            var push = 0;
            var start;
            char_count = 0;
            function correct_position(start, match, rep_string) {
                // logic taken from $.terminal.tracking_replace
                if (start < position) {
                    var last_index = start + length(match);
                    if (last_index < position) {
                        // It's after the replacement, move it
                        new_position = Math.max(
                            0,
                            new_position +
                            length(rep_string) -
                            length(match)
                        );
                    } else {
                        // It's *in* the replacement, put it just after
                        new_position += length(rep_string) - (position - start);
                    }
                }
            }
            for (var i = 0; i < string.length; ++i) {
                var partial = string.substring(i);
                var match = partial.match(backspace_re);
                var removed_char = removed_chars[0];
                if (match) {
                    // we remove backspace and character or html entity before it
                    // but we keep it in removed array so we can put it back
                    // when we have caritage return or line feed
                    if (match[1]) {
                        start = i - match[1].length + push;
                        removed_chars.push({
                            index: start,
                            string: match[1],
                            overtyping: partial.match(overtyping_re)
                        });
                        correct_position(start, match[0], '', 1);
                    }
                    if (char_count < 0) {
                        char_count = 0;
                    }
                    backspaces = backspaces.map(function(b) {
                        return b - 1;
                    });
                    backspaces.push(start);
                    return result + partial.replace(backspace_re, '');
                } else if (partial.match(new_line_re)) {
                    // if newline we need to add at the end all characters
                    // removed by backspace but only if there are no more
                    // other characters than backspaces added between
                    // backspaces and newline
                    if (removed_chars.length) {
                        var chars = removed_chars;
                        removed_chars = [];
                        chars.reverse().forEach(function(char) {
                            if (i > char.index) {
                                if (--char_count <= 0) {
                                    correct_position(char.index, '', char.string, 2);
                                    result += char.string;
                                }
                            } else {
                                removed_chars.unshift(char);
                            }
                        });
                    }
                    var m = partial.match(new_line_re);
                    result += m[1];
                    i += m[1].length - 1;
                } else {
                    if (backspaces.length) {
                        var backspace = backspaces[0];
                        if (i === backspace) {
                            backspaces.shift();
                        }
                        if (i >= backspace) {
                            char_count++;
                        }
                    }
                    if (removed_chars.length) {
                        // if we are in index of removed character we check if the
                        // character is the same it will be bold or if removed char
                        // or char at index is underscore then it will
                        // be terminal formatting with underscore
                        if (i > removed_char.index && removed_char.overtyping) {
                            removed_chars.shift();
                            correct_position(removed_char.index, '', removed_char.string);
                            // if we add special character we need to correct
                            // next push to removed_char array
                            push++;
                            // we use special characters instead of terminal
                            // formatting so it's easier to proccess when removing
                            // backspaces
                            if (removed_char.string === string[i]) {
                                result += string[i] + '\uFFF1';
                                continue;
                            } else if (removed_char.string === '_' ||
                                       string[i] === '_') {
                                var chr;
                                if (removed_char.string === '_') {
                                    chr = string[i];
                                } else {
                                    chr = removed_char.string;
                                }
                                result += chr + '\uFFF2';
                                continue;
                            }
                        }
                    }
                    result += string[i];
                }
            }
            return result;
        }
        var break_next = false;
        // loop until not more backspaces
        new_position = settings.position;
        // we need to clear line \x1b[K in overtyping because it need to be before
        // overtyping and from_ansi need to be called after so it escape stuff
        // between Escape Code and cmd will have escaped formatting typed by user
        var rep = $.terminal.tracking_replace(string, clear_line_re, '', new_position);
        string = rep[0];
        new_position = rep[1];
        while (string.match(/\x08/) || removed_chars.length) {
            string = replace(string, new_position);
            if (break_next) {
                break;
            }
            if (!string.match(/\x08/)) {
                // we break the loop so if removed_chars still chave items
                // we don't have infite loop
                break_next = true;
            }
        }
        function format(string, chr, style) {
            var re = new RegExp('((:?.' + chr + ')+)', 'g');
            return string.replace(re, function(_, string) {
                var re = new RegExp(chr, 'g');
                return '[[' + style + ']' + string.replace(re, '') + ']';
            });
        }
        // replace special characters with terminal formatting
        string = format(string, '\uFFF1', 'b;#fff;');
        string = format(string, '\uFFF2', 'u;;');
        if (settings.escapeBrackets) {
            string = $.terminal.escape_brackets(string);
        }
        if (options && typeof options.position === 'number') {
            return [string, new_position];
        }
        return string;
    };
    var CHARSETS = {};
    // taken from xterm.js MIT License
    // see https://github.com/xtermjs/xterm.js for more details
    CHARSETS['0'] = {
        '`': '\u25c6', // '◆'
        'a': '\u2592', // '▒'
        'b': '\u2409', // (HT)
        'c': '\u240c', // (FF)
        'd': '\u240d', // (CR)
        'e': '\u240a', // (LF)
        'f': '\u00b0', // '°'
        'g': '\u00b1', // '±'
        'h': '\u2424', // (NL)
        'i': '\u240b', // (VT)
        'j': '\u2518', // '┘'
        'k': '\u2510', // '┐'
        'l': '\u250c', // '┌'
        'm': '\u2514', // '└'
        'n': '\u253c', // '┼'
        'o': '\u23ba', // '⎺'
        'p': '\u23bb', // '⎻'
        'q': '\u2500', // '─'
        'r': '\u23bc', // '⎼'
        's': '\u23bd', // '⎽'
        't': '\u251c', // '├'
        'u': '\u2524', // '┤'
        'v': '\u2534', // '┴'
        'w': '\u252c', // '┬'
        'x': '\u2502', // '│'
        'y': '\u2264', // '≤'
        'z': '\u2265', // '≥'
        '{': '\u03c0', // 'π'
        '|': '\u2260', // '≠'
        '}': '\u00a3', // '£'
        '~': '\u00b7' // '·'
    };

    /**
     * British character set
     * ESC (A
     * Reference: http://vt100.net/docs/vt220-rm/table2-5.html
     */
    CHARSETS['A'] = {
        '#': '£'
    };

    /**
     * United States character set
     * ESC (B
     */
    CHARSETS['B'] = null;

    /**
     * Dutch character set
     * ESC (4
     * Reference: http://vt100.net/docs/vt220-rm/table2-6.html
     */
    CHARSETS['4'] = {
        '#': '£',
        '@': '¾',
        '[': 'ij',
        '\\': '½',
        ']': '|',
        '{': '¨',
        '|': 'f',
        '}': '¼',
        '~': '´'
    };

    /**
     * Finnish character set
     * ESC (C or ESC (5
     * Reference: http://vt100.net/docs/vt220-rm/table2-7.html
     */
    CHARSETS['C'] = CHARSETS['5'] = {
        '[': 'Ä',
        '\\': 'Ö',
        ']': 'Å',
        '^': 'Ü',
        '`': 'é',
        '{': 'ä',
        '|': 'ö',
        '}': 'å',
        '~': 'ü'
    };

    /**
     * French character set
     * ESC (R
     * Reference: http://vt100.net/docs/vt220-rm/table2-8.html
     */
    CHARSETS['R'] = {
        '#': '£',
        '@': 'à',
        '[': '°',
        '\\': 'ç',
        ']': '§',
        '{': 'é',
        '|': 'ù',
        '}': 'è',
        '~': '¨'
    };

    /**
     * French Canadian character set
     * ESC (Q
     * Reference: http://vt100.net/docs/vt220-rm/table2-9.html
     */
    CHARSETS['Q'] = {
        '@': 'à',
        '[': 'â',
        '\\': 'ç',
        ']': 'ê',
        '^': 'î',
        '`': 'ô',
        '{': 'é',
        '|': 'ù',
        '}': 'è',
        '~': 'û'
    };

    /**
     * German character set
     * ESC (K
     * Reference: http://vt100.net/docs/vt220-rm/table2-10.html
     */
    CHARSETS['K'] = {
        '@': '§',
        '[': 'Ä',
        '\\': 'Ö',
        ']': 'Ü',
        '{': 'ä',
        '|': 'ö',
        '}': 'ü',
        '~': 'ß'
    };

    /**
     * Italian character set
     * ESC (Y
     * Reference: http://vt100.net/docs/vt220-rm/table2-11.html
     */
    CHARSETS['Y'] = {
        '#': '£',
        '@': '§',
        '[': '°',
        '\\': 'ç',
        ']': 'é',
        '`': 'ù',
        '{': 'à',
        '|': 'ò',
        '}': 'è',
        '~': 'ì'
    };

    /**
     * Norwegian/Danish character set
     * ESC (E or ESC (6
     * Reference: http://vt100.net/docs/vt220-rm/table2-12.html
     */
    CHARSETS['E'] =
        CHARSETS['6'] = {
            '@': 'Ä',
            '[': 'Æ',
            '\\': 'Ø',
            ']': 'Å',
            '^': 'Ü',
            '`': 'ä',
            '{': 'æ',
            '|': 'ø',
            '}': 'å',
            '~': 'ü'
        };

    /**
     * Spanish character set
     * ESC (Z
     * Reference: http://vt100.net/docs/vt220-rm/table2-13.html
     */
    CHARSETS['Z'] = {
        '#': '£',
        '@': '§',
        '[': '¡',
        '\\': 'Ñ',
        ']': '¿',
        '{': '°',
        '|': 'ñ',
        '}': 'ç'
    };

    /**
     * Swedish character set
     * ESC (H or ESC (7
     * Reference: http://vt100.net/docs/vt220-rm/table2-14.html
     */
    CHARSETS['H'] =
        CHARSETS['7'] = {
            '@': 'É',
            '[': 'Ä',
            '\\': 'Ö',
            ']': 'Å',
            '^': 'Ü',
            '`': 'é',
            '{': 'ä',
            '|': 'ö',
            '}': 'å',
            '~': 'ü'
        };

    /**
     * Swiss character set
     * ESC (=
     * Reference: http://vt100.net/docs/vt220-rm/table2-15.html
     */
    CHARSETS['='] = {
        '#': 'ù',
        '@': 'à',
        '[': 'é',
        '\\': 'ç',
        ']': 'ê',
        '^': 'î',
        '_': 'è',
        '`': 'ô',
        '{': 'ä',
        '|': 'ö',
        '}': 'ü',
        '~': 'û'
    };
    // ---------------------------------------------------------------------
    // :: Html colors taken from ANSI formatting in Linux Terminal
    // ---------------------------------------------------------------------
    $.terminal.ansi_colors = {
        normal: {
            black: '#000',
            red: '#A00',
            green: '#008400',
            yellow: '#A50',
            blue: '#00A',
            magenta: '#A0A',
            cyan: '#0AA',
            white: '#AAA'
        },
        faited: {
            black: '#000',
            red: '#640000',
            green: '#006100',
            yellow: '#737300',
            blue: '#000087',
            magenta: '#650065',
            cyan: '#008787',
            white: '#818181'
        },
        bold: {
            black: '#555',
            red: '#F55',
            green: '#44D544',
            yellow: '#FF5',
            blue: '#55F',
            magenta: '#F5F',
            cyan: '#5FF',
            white: '#FFF'
        },
        // XTerm 8-bit pallete
        palette: [
            '#000000', '#AA0000', '#00AA00', '#AA5500', '#0000AA', '#AA00AA',
            '#00AAAA', '#AAAAAA', '#555555', '#FF5555', '#55FF55', '#FFFF55',
            '#5555FF', '#FF55FF', '#55FFFF', '#FFFFFF', '#000000', '#00005F',
            '#000087', '#0000AF', '#0000D7', '#0000FF', '#005F00', '#005F5F',
            '#005F87', '#005FAF', '#005FD7', '#005FFF', '#008700', '#00875F',
            '#008787', '#0087AF', '#0087D7', '#0087FF', '#00AF00', '#00AF5F',
            '#00AF87', '#00AFAF', '#00AFD7', '#00AFFF', '#00D700', '#00D75F',
            '#00D787', '#00D7AF', '#00D7D7', '#00D7FF', '#00FF00', '#00FF5F',
            '#00FF87', '#00FFAF', '#00FFD7', '#00FFFF', '#5F0000', '#5F005F',
            '#5F0087', '#5F00AF', '#5F00D7', '#5F00FF', '#5F5F00', '#5F5F5F',
            '#5F5F87', '#5F5FAF', '#5F5FD7', '#5F5FFF', '#5F8700', '#5F875F',
            '#5F8787', '#5F87AF', '#5F87D7', '#5F87FF', '#5FAF00', '#5FAF5F',
            '#5FAF87', '#5FAFAF', '#5FAFD7', '#5FAFFF', '#5FD700', '#5FD75F',
            '#5FD787', '#5FD7AF', '#5FD7D7', '#5FD7FF', '#5FFF00', '#5FFF5F',
            '#5FFF87', '#5FFFAF', '#5FFFD7', '#5FFFFF', '#870000', '#87005F',
            '#870087', '#8700AF', '#8700D7', '#8700FF', '#875F00', '#875F5F',
            '#875F87', '#875FAF', '#875FD7', '#875FFF', '#878700', '#87875F',
            '#878787', '#8787AF', '#8787D7', '#8787FF', '#87AF00', '#87AF5F',
            '#87AF87', '#87AFAF', '#87AFD7', '#87AFFF', '#87D700', '#87D75F',
            '#87D787', '#87D7AF', '#87D7D7', '#87D7FF', '#87FF00', '#87FF5F',
            '#87FF87', '#87FFAF', '#87FFD7', '#87FFFF', '#AF0000', '#AF005F',
            '#AF0087', '#AF00AF', '#AF00D7', '#AF00FF', '#AF5F00', '#AF5F5F',
            '#AF5F87', '#AF5FAF', '#AF5FD7', '#AF5FFF', '#AF8700', '#AF875F',
            '#AF8787', '#AF87AF', '#AF87D7', '#AF87FF', '#AFAF00', '#AFAF5F',
            '#AFAF87', '#AFAFAF', '#AFAFD7', '#AFAFFF', '#AFD700', '#AFD75F',
            '#AFD787', '#AFD7AF', '#AFD7D7', '#AFD7FF', '#AFFF00', '#AFFF5F',
            '#AFFF87', '#AFFFAF', '#AFFFD7', '#AFFFFF', '#D70000', '#D7005F',
            '#D70087', '#D700AF', '#D700D7', '#D700FF', '#D75F00', '#D75F5F',
            '#D75F87', '#D75FAF', '#D75FD7', '#D75FFF', '#D78700', '#D7875F',
            '#D78787', '#D787AF', '#D787D7', '#D787FF', '#D7AF00', '#D7AF5F',
            '#D7AF87', '#D7AFAF', '#D7AFD7', '#D7AFFF', '#D7D700', '#D7D75F',
            '#D7D787', '#D7D7AF', '#D7D7D7', '#D7D7FF', '#D7FF00', '#D7FF5F',
            '#D7FF87', '#D7FFAF', '#D7FFD7', '#D7FFFF', '#FF0000', '#FF005F',
            '#FF0087', '#FF00AF', '#FF00D7', '#FF00FF', '#FF5F00', '#FF5F5F',
            '#FF5F87', '#FF5FAF', '#FF5FD7', '#FF5FFF', '#FF8700', '#FF875F',
            '#FF8787', '#FF87AF', '#FF87D7', '#FF87FF', '#FFAF00', '#FFAF5F',
            '#FFAF87', '#FFAFAF', '#FFAFD7', '#FFAFFF', '#FFD700', '#FFD75F',
            '#FFD787', '#FFD7AF', '#FFD7D7', '#FFD7FF', '#FFFF00', '#FFFF5F',
            '#FFFF87', '#FFFFAF', '#FFFFD7', '#FFFFFF', '#080808', '#121212',
            '#1C1C1C', '#262626', '#303030', '#3A3A3A', '#444444', '#4E4E4E',
            '#585858', '#626262', '#6C6C6C', '#767676', '#808080', '#8A8A8A',
            '#949494', '#9E9E9E', '#A8A8A8', '#B2B2B2', '#BCBCBC', '#C6C6C6',
            '#D0D0D0', '#DADADA', '#E4E4E4', '#EEEEEE'
        ]
    };
    // ---------------------------------------------------------------------
    // :: Replace ANSI formatting with terminal formatting
    // ---------------------------------------------------------------------
    $.terminal.from_ansi = (function() {
        var color_list = {
            30: 'black',
            31: 'red',
            32: 'green',
            33: 'yellow',
            34: 'blue',
            35: 'magenta',
            36: 'cyan',
            37: 'white',

            39: 'inherit' // default color
        };
        var background_list = {
            40: 'black',
            41: 'red',
            42: 'green',
            43: 'yellow',
            44: 'blue',
            45: 'magenta',
            46: 'cyan',
            47: 'white',

            49: 'transparent' // default background
        };
        function format_ansi(controls, state, ansi_art) {
            var num;
            var styles = [];
            var output_color;
            var output_background;
            var _process_true_color = -1;
            var _ex_color = false;
            var _ex_background = false;
            var _process_8bit = false;
            var palette = $.terminal.ansi_colors.palette;
            function set_styles(num) {
                switch (num) {
                    case 0:
                        Object.keys(state).forEach(function(key) {
                            delete state[key];
                        });
                        state.blink = false;
                        state.bold = false;
                        state.faited = false;
                        break;
                    case 1:
                        styles.push('b');
                        state.bold = true;
                        state.faited = false;
                        break;
                    case 4:
                        styles.push('u');
                        break;
                    case 3:
                        styles.push('i');
                        break;
                    case 5:
                        if (_ex_color || _ex_background) {
                            _process_8bit = true;
                        } else {
                            state.blink = true;
                        }
                        break;
                    case 38:
                        _ex_color = true;
                        break;
                    case 48:
                        _ex_background = true;
                        break;
                    case 2:
                        if (_ex_color || _ex_background) {
                            _process_true_color = 0;
                        } else {
                            state.faited = true;
                            state.bold = false;
                        }
                        break;
                    case 7:
                        state.reverse = true;
                        break;
                    default:
                        if (color_list[num]) {
                            output_color = color_list[num];
                        }
                        if (background_list[num]) {
                            output_background = background_list[num];
                        }
                }
            }
            // -----------------------------------------------------------------
            function process_true_color() {
                if (_ex_color) {
                    if (!output_color) {
                        output_color = '#';
                    }
                    if (output_color.length < 7) {
                        output_color += ('0' + num.toString(16)).slice(-2);
                    }
                }
                if (_ex_background) {
                    if (!output_background) {
                        output_background = '#';
                    }
                    if (output_background.length < 7) {
                        output_background += ('0' + num.toString(16)).slice(-2);
                    }
                }
                if (_process_true_color === 2) {
                    _process_true_color = -1;
                } else {
                    _process_true_color++;
                }
            }
            // -----------------------------------------------------------------
            function should__process_8bit() {
                return _process_8bit && ((_ex_background && !output_background) ||
                                        (_ex_color && !output_color));
            }
            // -----------------------------------------------------------------
            function process_8bit() {
                if (_ex_color && palette[num] && !output_color) {
                    output_color = palette[num];
                }
                if (_ex_background && palette[num] && !output_background) {
                    output_background = palette[num];
                }
                _process_8bit = false;
            }
            // -----------------------------------------------------------------
            for (var i in controls) {
                if (controls.hasOwnProperty(i)) {
                    num = parseInt(controls[i], 10);
                    if (_process_true_color > -1) {
                        process_true_color();
                    } else if (should__process_8bit()) {
                        process_8bit();
                    } else {
                        set_styles(num);
                    }
                }
            }
            if (state.reverse) {
                if (output_color || output_background) {
                    var tmp = output_background;
                    output_background = output_color;
                    output_color = tmp;
                } else {
                    output_color = 'black';
                    output_background = 'white';
                }
            }
            output_color = output_color || state.color;
            output_background = output_background || state.background;
            var colors, color, background;
            if (state.bold) {
                colors = $.terminal.ansi_colors.bold;
            } else if (state.faited) {
                colors = $.terminal.ansi_colors.faited;
            } else {
                colors = $.terminal.ansi_colors.normal;
            }
            if (typeof output_color !== 'undefined') {
                if (output_color.match(/^#/)) {
                    color = output_color;
                } else if (output_color === 'inherit') {
                    color = output_color;
                } else {
                    color = colors[output_color];
                }
                state.color = output_color;
            } else {
                color = colors['white'];
            }
            if (typeof output_background !== 'undefined') {
                if (output_background.match(/^#/)) { // already 8bit color #460
                    background = output_background;
                } else if (output_background === 'transparent') {
                    background = output_background;
                } else if (state.blink && ansi_art) {
                    background = $.terminal.ansi_colors.bold[output_background];
                } else {
                    // background is not changed by bold flag
                    background = $.terminal.ansi_colors.normal[output_background];
                }
                state.background = output_background;
            } else if (state.blink && ansi_art) {
                background = $.terminal.ansi_colors.bold['black'];
            }
            var ret = [styles.join(''), color, background];
            if (state.blink && !ansi_art) {
                ret.push('terminal-blink');
            }
            return ret;
        }
        // -------------------------------------------------------------------------------
        return function from_ansi(input, options) {
            options = options || {};
            var settings = get_settings(options);
            var ansi_art = settings.ansiArt;
            // if there are SAUCE record if something after end of file
            input = input.replace(/\x1A.*/, '');
            input = input.replace(/\r?\n?\x1b\[A\x1b\[[0-9]+C/g, '');
            input = $.terminal.unescape_brackets(input);
            var code, inside, format, charset, saved_cursor;
            var print = function print(s) {
                var s_len = s.length;
                if (settings.escapeBrackets) {
                    s = $.terminal.escape_formatting(s);
                }
                if (charset) {
                    s = s.split('').map(function(chr) {
                        return charset[chr] || chr;
                    }).join('');
                }
                if (format) {
                    // this will always need to be escaped
                    if (s.match(/\\$|[[\]]/) &&
                        !settings.escapeBrackets &&
                        !$.terminal.have_formatting(s)) {
                        s = $.terminal.escape_formatting(s);
                    }
                    s = format + s + ']';
                }
                var line = this.result[this.cursor.y];
                var len, after, before, line_len;
                if (!line) {
                    if (this.cursor.x > 0) {
                        var space = new Array(this.cursor.x + 1).join(' ');
                        this.result[this.cursor.y] = space + s;
                    } else {
                        this.result[this.cursor.y] = s;
                    }
                } else {
                    var stripped = $.terminal.strip(line);
                    line_len = $.terminal.unescape_brackets(stripped).length;
                    if (this.cursor.x === 0) {
                        after = $.terminal.substring(line, s_len);
                        this.result[this.cursor.y] = s + after;
                    } else if (line_len < this.cursor.x) {
                        len = this.cursor.x - (line_len - 1);
                        this.result[this.cursor.y] += new Array(len).join(' ') + s;
                    } else if (line_len === this.cursor.x) {
                        this.result[this.cursor.y] += s;
                    } else {
                        before = $.terminal.substring(line, 0, this.cursor.x);
                        after = $.terminal.substring(line, this.cursor.x + s_len);
                        this.result[this.cursor.y] = before + s + after;
                    }
                }
                this.cursor.x += s_len;
            };
            var term = $.terminal.active();
            var ROWS = term && term.rows() || 1000;
            var COLS = term && term.cols() || 80;
            // correction to CP 437
            // ref: https://unix.stackexchange.com/a/611513/1806
            //      https://unix.stackexchange.com/a/611344/1806
            var cp_437_control = {
                0x00: ' ',
                0x01: '☺',
                0x02: '☻',
                0x03: '♥',
                0x07: '•',
                0x08: '█',
                0x0F: '*',
                0x10: '█',
                0x11: '◄',
                0x12: '↕',
                0x14: '¶',
                0x15: '§',
                0x16: '▬',
                0x17: '↨',
                0x18: '↑',
                0x19: '↓',
                0x1E: '▲'
            };
            var characters = 'qwertyuiopasdfghjklzxcvbnm';
            var prev_code;
            var parser_events = {
                cursor: {x: 0, y: 0},
                result: [],
                state: {},
                inst_p: print,
                inst_x: function(flag) {
                    var code = flag.charCodeAt(0);
                    if (code === 13) {
                        this.cursor.x = 0;
                    } else if (code === 10) {
                        this.cursor.y++;
                        if (prev_code !== 13) {
                            this.cursor.x = 0;
                        }
                    } else if (code === 9) {
                        print.call(this, '\t');
                    } else if (ansi_art && code in cp_437_control) {
                        // eslint-disable-next-line no-console
                        console.log({code: '0x' + code.toString(16)});
                        print.call(this, cp_437_control[code]);
                    } else if (DEBUG) {
                        var mod = code % characters.length;
                        var char = characters[mod];
                        // eslint-disable-next-line no-console
                        console.log({code: code, char: char});
                        print.call(this, char);
                    }
                    if (!this.result[this.cursor.y]) {
                        this.result[this.cursor.y] = '';
                    }
                    prev_code = code;
                },
                inst_e: function(collected, flag) {
                    if (collected === '(') {
                        if (flag in CHARSETS) {
                            charset = CHARSETS[flag];
                        }
                    }
                },
                inst_E: function(data) {
                    /* eslint-disable no-console */
                    console.log(data);
                    /* eslint-enable no-console */
                },
                inst_c: function(collected, params, flag) {
                    var value = params[0] === 0 ? 1 : params[0];
                    switch (flag) {
                        case 's':
                            saved_cursor = Object.assign({}, this.cursor);
                            break;
                        case 'u':
                            this.cursor = saved_cursor;
                            break;
                        case 'A': // UP
                            this.cursor.y -= value;
                            break;
                        case 'B': // Down
                            this.cursor.y += value;
                            break;
                        case 'C': // Forward
                            this.cursor.x += value;
                            break;
                        case 'D': // Backward
                            this.cursor.x -= value;
                            break;
                        case 'E': // Cursor Next Line
                            this.cursor.x = 0;
                            this.cursor.y += value;
                            break;
                        case 'F': // Cursor Previous Line
                            this.cursor.x = 0;
                            this.cursor.y -= value;
                            break;
                        case 'H':
                            // -1 since CUP is 1-based
                            this.cursor.y = Math.min(params[0] || 1, ROWS) - 1;
                            this.cursor.x = Math.min(params[1] || 1, COLS) - 1;
                            break;
                        case 'm':
                            code = format_ansi(params, this.state, ansi_art);
                            var empty = params.length === 1 && params[0] === 0;
                            if (inside) {
                                if (empty) {
                                    inside = false;
                                    format = null;
                                } else {
                                    format = '[[' + code.join(';') + ']';
                                }
                            } else if (empty) {
                                format = null;
                            } else {
                                format = '[[' + code.join(';') + ']';
                                inside = true;
                            }
                            break;
                    }
                    if (this.cursor.x < 0) {
                        this.cursor.x = 0;
                    }
                    if (this.cursor.y < 0) {
                        this.cursor.y = 0;
                    }
                }
            };
            // extra parser options not used by unix_formatting
            Object.keys(settings.ansiParser).forEach(function(name) {
                var original = parser_events[name];
                var fn = settings.ansiParser[name];
                if (typeof fn === 'function') {
                    parser_events[name] = original ? function() {
                        if (fn.apply(parser_events, arguments) !== false) {
                            return original.apply(parser_events, arguments);
                        }
                    } : function() {
                        return fn.apply(parser_events, arguments);
                    };
                    settings.ansiParser[name] = parser_events[name];
                }
            });
            var parser = new AnsiParser(parser_events);
            parser.parse(input);
            var output = parser_events.result.join('\n');
            if (input !== output) {
                return output;
            }
            if (typeof options !== 'undefined' && typeof options.position === 'number') {
                return [input, options.position];
            }
            return input;
        };
    })();
    $.terminal.from_ansi.__no_warn__ = true;
    $.terminal.defaults.formatters.unshift($.terminal.from_ansi);
    $.terminal.defaults.formatters.unshift($.terminal.overtyping);
});
