/**
 * @license RequireJS i18n 2.0.6 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
 * Available via the MIT or new BSD license.
 * see: http://github.com/requirejs/i18n for details
 */
/*jslint regexp: true */
/*global require: false, navigator: false, define: false */

/**
 * This plugin handles i18n! prefixed modules. It does the following:
 *
 * 1) A regular module can have a dependency on an i18n bundle, but the regular
 * module does not want to specify what locale to load. So it just specifies
 * the top-level bundle, like 'i18n!nls/colors'.
 *
 * This plugin will load the i18n bundle at nls/colors, see that it is a root/master
 * bundle since it does not have a locale in its name. It will then try to find
 * the best match locale available in that master bundle, then request all the
 * locale pieces for that best match locale. For instance, if the locale is 'en-us',
 * then the plugin will ask for the 'en-us', 'en' and 'root' bundles to be loaded
 * (but only if they are specified on the master bundle).
 *
 * Once all the bundles for the locale pieces load, then it mixes in all those
 * locale pieces into each other, then finally sets the context.defined value
 * for the nls/colors bundle to be that mixed in locale.
 *
 * 2) A regular module specifies a specific locale to load. For instance,
 * i18n!nls/fr-fr/colors. In this case, the plugin needs to load the master bundle
 * first, at nls/colors, then figure out what the best match locale is for fr-fr,
 * since maybe only fr or just root is defined for that locale. Once that best
 * fit is found, all of its locale pieces need to have their bundles loaded.
 *
 * Once all the bundles for the locale pieces load, then it mixes in all those
 * locale pieces into each other, then finally sets the context.defined value
 * for the nls/fr-fr/colors bundle to be that mixed in locale.
 */
(function () {
    'use strict';

    //regexp for reconstructing the master bundle name from parts of the regexp match
    //nlsRegExp.exec('foo/bar/baz/nls/en-ca/foo') gives:
    //['foo/bar/baz/nls/en-ca/foo', 'foo/bar/baz/nls/', '/', '/', 'en-ca', 'foo']
    //nlsRegExp.exec('foo/bar/baz/nls/foo') gives:
    //['foo/bar/baz/nls/foo', 'foo/bar/baz/nls/', '/', '/', 'foo', '']
    //so, if match[5] is blank, it means this is the top bundle definition.
    var nlsRegExp = /(^.*(^|\/)nls(\/|$))([^\/]*)\/?([^\/]*)/;

    //Helper function to avoid repeating code. Lots of arguments in the
    //desire to stay functional and support RequireJS contexts without having
    //to know about the RequireJS contexts.
    function addPart(locale, master, needed, toLoad, prefix, suffix) {
        if (master[locale]) {
            needed.push(locale);
            if (master[locale] === true || master[locale] === 1) {
                toLoad.push(prefix + locale + '/' + suffix);
            }
        }
    }

    function addIfExists(req, locale, toLoad, prefix, suffix) {
        var fullName = prefix + locale + '/' + suffix;
        if (require._fileExists(req.toUrl(fullName + '.js'))) {
            toLoad.push(fullName);
        }
    }

    /**
     * Simple function to mix in properties from source into target,
     * but only if target does not already have a property of the same name.
     * This is not robust in IE for transferring methods that match
     * Object.prototype names, but the uses of mixin here seem unlikely to
     * trigger a problem related to that.
     */
    function mixin(target, source, force) {
        var prop;
        for (prop in source) {
            if (source.hasOwnProperty(prop) && (!target.hasOwnProperty(prop) || force)) {
                target[prop] = source[prop];
            } else if (typeof source[prop] === 'object') {
                if (!target[prop] && source[prop]) {
                    target[prop] = {};
                }
                mixin(target[prop], source[prop], force);
            }
        }
    }

    define('i18n',['module'], function (module) {
        var masterConfig = module.config ? module.config() : {};
        masterConfig = masterConfig || {};

        return {
            version: '2.0.6',
            /**
             * Called when a dependency needs to be loaded.
             */
            load: function (name, req, onLoad, config) {
                config = config || {};

                if (config.locale) {
                    masterConfig.locale = config.locale;
                }

                var masterName,
                    match = nlsRegExp.exec(name),
                    prefix = match[1],
                    locale = match[4],
                    suffix = match[5],
                    parts = locale.split('-'),
                    toLoad = [],
                    value = {},
                    i, part, current = '';

                //If match[5] is blank, it means this is the top bundle definition,
                //so it does not have to be handled. Locale-specific requests
                //will have a match[4] value but no match[5]
                if (match[5]) {
                    //locale-specific bundle
                    prefix = match[1];
                    masterName = prefix + suffix;
                } else {
                    //Top-level bundle.
                    masterName = name;
                    suffix = match[4];
                    locale = masterConfig.locale;
                    if (!locale) {
                        locale = masterConfig.locale =
                            typeof navigator === 'undefined' ? 'root' :
                            ((navigator.languages && navigator.languages[0]) ||
                             navigator.language ||
                             navigator.userLanguage || 'root').toLowerCase();
                    }
                    parts = locale.split('-');
                }

                if (config.isBuild) {
                    //Check for existence of all locale possible files and
                    //require them if exist.
                    toLoad.push(masterName);
                    addIfExists(req, 'root', toLoad, prefix, suffix);
                    for (i = 0; i < parts.length; i++) {
                        part = parts[i];
                        current += (current ? '-' : '') + part;
                        addIfExists(req, current, toLoad, prefix, suffix);
                    }

                    if(config.locales) {
                    	var j, k; 
                    	for (j = 0; j < config.locales.length; j++) {
                    		locale = config.locales[j];
                    		parts = locale.split("-");
                    		current = "";
	                    	for (k = 0; k < parts.length; k++) {
		                        part = parts[k];
		                        current += (current ? "-" : "") + part;
		                        addIfExists(req, current, toLoad, prefix, suffix);
	                    	}
                    	}
                    }

                    req(toLoad, function () {
                        onLoad();
                    });
                } else {
                    //First, fetch the master bundle, it knows what locales are available.
                    req([masterName], function (master) {
                        //Figure out the best fit
                        var needed = [],
                            part;

                        //Always allow for root, then do the rest of the locale parts.
                        addPart('root', master, needed, toLoad, prefix, suffix);
                        for (i = 0; i < parts.length; i++) {
                            part = parts[i];
                            current += (current ? '-' : '') + part;
                            addPart(current, master, needed, toLoad, prefix, suffix);
                        }

                        //Load all the parts missing.
                        req(toLoad, function () {
                            var i, partBundle, part;
                            for (i = needed.length - 1; i > -1 && needed[i]; i--) {
                                part = needed[i];
                                partBundle = master[part];
                                if (partBundle === true || partBundle === 1) {
                                    partBundle = req(prefix + part + '/' + suffix);
                                }
                                mixin(value, partBundle);
                            }

                            //All done, notify the loader.
                            onLoad(value);
                        });
                    });
                }
            }
        };
    });
}());

/*******************************************************************************
 * @license
 * Copyright (c) 2012 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 * 
 ******************************************************************************/
/*eslint-env browser, amd*/
define('orion/shell/nls/messages',{
	root:true
});

/*******************************************************************************
 * @license
 * Copyright (c) 2012 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 * 
 ******************************************************************************/
/*eslint-env browser, amd*/
define('orion/shell/nls/root/messages',{//Default message bundle
	"Shell": "Shell",
	"ShellLinkWorkspace": "Shell",
	"Changed to: ": "Changed to: ",
	"Initial directory: ": "Initial directory: ",
	"ChangeCurrDir": "Changes the current directory",
	"DirName": "The name of the directory",
	"EditFile": "Edits a file",
	"FileName": "The name of the file",
	"CurDirFileList": "Lists the files in the current directory",
	"CurDirLocation": "Prints the current directory location",
	"ClearShellScreen": "Clears the shell screen",
	"notValid": "'${0}' is not valid",
	"Err": "Error: ${0}",
	"NoResponseFromServer": "No response from server for ${0}. Check your internet connection and try again.",
	"ServerError": "Server error: ${0} returned ${1} ${2}",
	"Succeeded": "Succeeded",
	"Aborted": "Aborted",
	"PlugName": "The name of the plug-in",
	"ContributedPlugName": "The name of the contributed plug-in",
	"RegisteredPlugsList": "Lists all registered plug-ins",
	"Reloads a plug-in": "Reloads a plug-in",
	"DisableContributedPlug": "Disables a contributed plug-in",
	"EnableContributedPlug": "Enables a contributed plug-in",
	"UninstallContributedPlugFrmConfig": "Uninstalls a contributed plug-in from the configuration",
	"PlugAlreadyInstalled": "Plug-in is already installed",
	"Invalid plug-in URL": "Invalid plug-in URL",
	"InstallPlugFrmURL": "Installs a plug-in from a URL",
	"The plug-in URL": "The plug-in URL",
	"CmdForPlugs": "Commands for working with plug-ins",
	"UninstallAllPlugsMsg": "Are you sure you want to uninstall all contributed plug-ins?",
	"DisplayPlugServices": "Displays a plug-in's services",
	"CmdsForService": "Commands for working with a service",
	"DisplayPlugsForService": "Displays all plug-in contributions for a service",
	"The service identifier": "The service identifier",
	"disabled": "disabled",
	"Open Shell": "Open Shell",
	"Open Shell page": "Open the Shell page with this folder as the current directory.",
	"AlreadyExist": "'${0}' already exists",
	"NotSupportFileSystem": "${0} is not supported in this file system",
	"SrcNotSupportBinRead": "Source file service does not support binary read",
	"TargetNotSupportBinWrite": "Target file service does not support binary write",
	"AlreadyExistsInDirErr": "Cannot create file, it already exists as a directory",
	"WroteMsg": "Wrote ${0}",
	"WriteFailMsg": "Failed to write ${0}",
	"WriteFailNotDescendentOfOutputDir": "Cannot write ${0}, it is not a descendent of the output directory",
	"FileOrDirRedirectOutput": "The file or directory to re-direct output to"
});


/*******************************************************************************
 * @license
 * Copyright (c) 2012 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 * 
 ******************************************************************************/
/*eslint-env browser, amd*/
define('orion/nls/messages',["module"],function(module){
    var config = module.config();
    return config && config.root ? config : {root:true};
});
/*******************************************************************************
 * @license
 * Copyright (c) 2012, 2016 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made
 * available under the terms of the Eclipse Public License v1.0
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html).
 *
 ******************************************************************************/
/*eslint-env browser, amd*/
define('orion/nls/root/messages',{//Default message bundle
	"Navigator": "Navigator",
	"Sites": "Sites",
	"Shell": "Shell",
	"Get Plugins": "Get Plug-ins",
	"Global": "Global",
	"Editor": "Editor",
	"EditorRelatedLink": "Show Current Folder",
	"EditorRelatedLinkParent": "Show Enclosing Folder",
	"EditorLinkWorkspace": "Edit",
	"EditorRelatedLinkProj": "Show Project",
	"sidebar": "Sidebar",
	"toolbar": "Toolbar",
	"Key": "Key",
	"Value": "Value",
	"Type": "Type",
	"Key Bindings": "Key Bindings",
	"KeyBinding": "Key Binding",
	"Command": "Command",
	"Filter bindings:": "Filter bindings:",
	"Filter bindings": "Type characters to filter by name or key combination",
	"Bindings": "Bindings",
	"BindingPrompt": "Enter the new binding",
	"NoBinding": "---",
	"orionClientLabel": "Orion client repository",
	"Orion Editor": "Text Editor",
	"Orion Image Viewer": "Image Viewer",
	"Orion Markdown Editor": "Markdown Editor",
	"Orion Markdown Viewer": "Markdown Viewer",
	"Orion JSON Editor": "JSON Editor",
	"Orion System Editor": "System Editor",
	"View on Site": "View on Site",
	"View this file or folder on a web site hosted by Orion": "View this file or folder on a web site hosted by Orion.",
	"ShowAllKeyBindings": "Show a list of all the keybindings on this page",
	"Show Keys": "Show Keys",
	"HideShowBannerFooter": "Hide or show the page banner and footer",
	"Toggle Banner and Footer": "Toggle Banner and Footer",
	"ChooseFileOpenEditor": "Choose a file by name and open an editor on it",
	"FindFile": "Open File...",
	"System Editor Tooltip": "Open this file type in the desktop's default manner",
	"Background Operations": "Background Operations",
	"Background Operations Tooltip": "Go to the Background Operations page",
	"Operation status is unknown": "Operation status is unknown",
	"Unknown item": "Unknown item",
	"NoSearchAvailableErr": "Can't search: no search service is available",
	"Related": "Related",
	"Options": "Options",
	"LOG: ": "LOG: ",
	"View": "View",
	"SplashTitle": "Setting up Workspace",
	"SplashTitleSettings": "Loading Settings",
	"SplashTitleGit": "Loading Git Repositories",
	"LoadingPage": "Loading Page",
	"LoadingPlugins": "Loading Plugins",
	"AuthenticatingUser": "Authenticating user...",
	"AuthenticatedUser": "Authenticated user",
	"LoadingResources": "Loading Resources",
	"plugin_started": "\"${0}\" started",
	"plugin_lazy activation": "\"${0}\" lazily activated",
	"plugin_starting": "\"${0}\" starting",
	"no parent": "no parent",
	"no tree model": "no tree model",
	"no renderer": "no renderer",
	"could not find table row ": "could not find table row ",
	"Operations": "Operations",
	"Operations running": "Operations running",
	"SomeOpWarning": "Some operations finished with warning",
	"SomeOpErr": "Some operations finished with error",
	"no service registry": "no service registry",
	"Tasks": "Tasks",
	"Close": "Close",
	"Expand all": "Expand all",
	"Collapse all": "Collapse all",
	"Search" : "Search",
	"Advanced search" : "Advanced search",
	"Submit" : "Submit",
	"More" : "More",
	"Recent searches" : "Recent searches",
	"Regular expression" : "Regular expression",
	"Search options" : "Search options",
	"Global search" : "Global search",
	"Orion Home" : "Home",
	"Close notification" : "Close notification",
	"Toggle Side Panel" : "Toggle Side Panel",
	"Open or close the side panel": "Open or close the side panel",
	"Projects" : "Projects",
	"Toggle Sidebar" : "Toggle Sidebar",
	"Sample HTML5 Site": "Sample HTML5 Site",
	"Generate an HTML5 'Hello World' website, including JavaScript, HTML, and CSS files.": "Generate an HTML5 'Hello World' website, including JavaScript, HTML, and CSS files.",
	"Sample Orion Plugin": "Sample Orion Plug-in",
	"Generate a sample plugin for integrating with Orion.": "Generate a sample plug-in for integrating with Orion.",
	"Browser": "Web Browser",
	"Outline": "Outline",
	"OutlineProgress": "Getting outline for ${0} from ${1}",
	"FormatProgress" : "Formatting ${0} from ${1}",
	"outlineTimeout": "Outline service timed out. Try reloading the page and opening the outline again.",
	"UnknownError": "An unknown error occurred.",
	"Filter outline:": "Filter outline:",
	"Filter": "Type characters (* = any string, ? = any character)",
	"TemplateExplorerLabel": "Templates",
	"OpenTemplateExplorer": "Open Template Explorer",
	"Edit": "Edit",
	"CentralNavTooltip": "Toggle Navigation Menu",
	"Wrote: ${0}": "Wrote: ${0}",
	"GenerateHTML": "Generate HTML file",
	"GenerateHTMLTooltip": "Write an HTML file generated from the current Markdown editor content",
	"ShutdownWarning": "WARNING: This service will be shutdown permanently on ${0}. Please export your data before that date and time. There are no backups and all data will be destroyed.",
	"alt text": "alt text",
	"blockquote": "blockquote",
	"code": "code",
	"code (block)": "code (block)",
	"code (span)": "code (span)",
	"emphasis": "emphasis",
	"fenced code (${0})": "fenced code (${0})",
	"header (${0})": "header (${0})",
	"horizontal rule": "horizontal rule",
	"label": "label",
	"link (auto)": "link (auto)",
	"link (image)": "link (image)",
	"link (inline)": "link (inline)",
	"link label": "link label",
	"link label (optional)": "link label (optional)",
	"link (ref)": "link (ref)",
	"list item (bullet)": "list item (bullet)",
	"list item (numbered)": "list item (numbered)",
	"strikethrough (${0})": "strikethrough (${0})",
	"strong": "strong",
	"table (${0})": "table (${0})",
	"text": "text",
	"title (optional)": "title (optional)",
	"url": "url",
	"workedProgress": "${0} (${1}/${2})",
	"ConfirmLogout": "Do you want to logout?",
	"VerticalPaneOrientation": "Vertical pane orientation",
	"TogglePaneOrientationTooltip": "Toggle split pane orientation",
	"WarningDuplicateLinkId": "Duplicate link ID: ${0} (link IDs are not case-sensitive)",
	"WarningHeaderTooDeep": "Header level cannot exceed 6",
	"WarningLinkHasNoText": "Link has no text",
	"WarningLinkHasNoURL": "Link has no URL",
	"WarningOrderedListItem": "Ordered list item within unordered list",
	"WarningOrderedListShouldStartAt1": "The first item in an ordered list should have index 1",
	"WarningUndefinedLinkId": "Undefined link ID: ${0}",
	"WarningUnorderedListItem": "Unordered list item within ordered list",
	"PageTitleFormat": "${0} - ${1}", // ${0} is the file or resource being edited; ${1} is the task (eg. "Editor")
	// Display names for keys:
	"KeyCTRL": "Ctrl",
	"KeySHIFT": "Shift",
	"KeyALT": "Alt",
	"KeyBKSPC": "Backspace",
	"KeyDEL": "Del",
	"KeyEND": "End",
	"KeyENTER": "Enter",
	"KeyESCAPE": "Esc",
	"KeyHOME": "Home",
	"KeyINSERT": "Ins",
	"KeyPAGEDOWN": "Page Down",
	"KeyPAGEUP": "Page Up",
	"KeySPACE": "Space",
	"KeyTAB": "Tab",
	// Display elapsed time:
	"a year": "a year",
	"years": "${0} years",
	"a month": "a month",
	"months": "${0} months",
	"a day": "a day",
	"days": "${0} days",
	"an hour": "an hour",
	"hours": "${0} hours",
	"a minute": "a minute",
	"minutes": "${0} minutes",
	"timeAgo": "${0} ago", //${0} represent the time elapsed
	"justNow": "just now", //Represent that the time elapsed is less than 1 minute
	"fixAll": "Fix all",
	"nextSplitter" : "Next Splitter",
	"nextSplitterTooltip": "Move focus through the available splitters",
	"Confirm": "Confirm",
	"CONFIRM": "Confirm",
	"PROMPT": "Prompt",
	"ALERT": "Alert",
	"Up": "Up",
	"Down": "Down"
});


/*******************************************************************************
 * @license
 * Copyright (c) 2012 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 * 
 * Contributors: IBM Corporation - initial API and implementation
 ******************************************************************************/
/*eslint-env browser, amd, node*/
(function(root, factory) { // UMD
    if (typeof define === "function" && define.amd) { //$NON-NLS-0$
        define('orion/Deferred',factory);
    } else if (typeof exports === "object") { //$NON-NLS-0$
        module.exports = factory();
    } else {
        root.orion = root.orion || {};
        root.orion.Deferred = factory();
    }
}(this, function() {
    var queue = [],
        running = false;

    function run() {
        var fn;
        while ((fn = queue.shift())) {
            fn();
        }
        running = false;
    }

	var runAsync = (function() {
		if (typeof process !== "undefined" && typeof process.nextTick === "function") {
			var nextTick = process.nextTick;
    		return function() {
    			nextTick(run);
    		};
		} else if (typeof MutationObserver === "function") {
			var div = document.createElement("div");
			var observer = new MutationObserver(run);
			observer.observe(div, {
            	attributes: true
        	});
        	return function() {
        		div.setAttribute("class", "_tick");
        	};
		}
		return function() {
			setTimeout(run, 0);
		};
	})();

    function enqueue(fn) {
        queue.push(fn);
        if (!running) {
            running = true;
            runAsync();
        }
    }

    function noReturn(fn) {
        return function(result) {
            fn(result);
        };
    }
    
    function settleDeferred(fn, result, deferred) {
    	try {
    		var listenerResult = fn(result);
    		var listenerThen = listenerResult && (typeof listenerResult === "object" || typeof listenerResult === "function") && listenerResult.then;
    		if (typeof listenerThen === "function") {
    			if (listenerResult === deferred.promise) {
    				deferred.reject(new TypeError());
    			} else {
    				var listenerResultCancel = listenerResult.cancel;
    				if (typeof listenerResultCancel === "function") {
    					deferred._parentCancel = listenerResultCancel.bind(listenerResult);
    				} else {
    					delete deferred._parentCancel;
    				}
    				listenerThen.call(listenerResult, noReturn(deferred.resolve), noReturn(deferred.reject), noReturn(deferred.progress));
    			}
    		} else {
    			deferred.resolve(listenerResult);
    		}
    	} catch (e) {
    		deferred.reject(e);
    	}
    }


    /**
     * @name orion.Promise
     * @class Interface representing an eventual value.
     * @description Promise is an interface that represents an eventual value returned from the single completion of an operation.
     *
     * <p>For a concrete class that implements Promise and provides additional API, see {@link orion.Deferred}.</p>
     * @see orion.Deferred
     * @see orion.Deferred#promise
     */
    /**
     * @name then
     * @function
     * @memberOf orion.Promise.prototype
     * @description Adds handlers to be called on fulfillment or progress of this promise.
     * @param {Function} [onResolve] Called when this promise is resolved.
     * @param {Function} [onReject] Called when this promise is rejected.
     * @param {Function} [onProgress] May be called to report progress events on this promise.
     * @returns {orion.Promise} A new promise that is fulfilled when the given <code>onResolve</code> or <code>onReject</code>
     * callback is finished. The callback's return value gives the fulfillment value of the returned promise.
     */
    /**
     * Cancels this promise.
     * @name cancel
     * @function
     * @memberOf orion.Promise.prototype
     * @param {Object} reason The reason for canceling this promise.
     * @param {Boolean} [strict]
     */

    /**
     * @name orion.Deferred
     * @borrows orion.Promise#then as #then
     * @borrows orion.Promise#cancel as #cancel
     * @class Provides abstraction over asynchronous operations.
     * @description Deferred provides abstraction over asynchronous operations.
     *
     * <p>Because Deferred implements the {@link orion.Promise} interface, a Deferred may be used anywhere a Promise is called for.
     * However, in most such cases it is recommended to use the Deferred's {@link #promise} field instead, which exposes a 
     * simplified, minimally <a href="https://github.com/promises-aplus/promises-spec">Promises/A+</a>-compliant interface to callers.</p>
     */
    function Deferred() {
        var result, state, listeners = [],
            _this = this;

        function notify() {
            var listener;
            while ((listener = listeners.shift())) {
                var deferred = listener.deferred;
                var methodName = state === "fulfilled" ? "resolve" : "reject"; //$NON-NLS-0$ //$NON-NLS-1$ //$NON-NLS-2$
                var fn = listener[methodName];
                if (typeof fn === "function") { //$NON-NLS-0$
                	settleDeferred(fn, result, deferred);
                } else {
                    deferred[methodName](result);
                }
            }
        }

        function _reject(error) {
            delete _this._parentCancel;
            state = "rejected";
            result = error;
            if (listeners.length) {
                enqueue(notify);
            }
        }

        function _resolve(value) {
            function once(fn) {
                return function(result) {
                    if (!state || state === "assumed") {
                          fn(result);
                    }
                };
            }
            delete _this._parentCancel;
            try {
                var valueThen = value && (typeof value === "object" || typeof value === "function") && value.then;
                if (typeof valueThen === "function") {
                    if (value === _this) {
                        _reject(new TypeError());
                    } else {
                        state = "assumed";
                        var valueCancel = value && value.cancel;
                        if (typeof valueCancel !== "function") {
                            var deferred = new Deferred();
                            value = deferred.promise;
                            try {
                                valueThen(deferred.resolve, deferred.reject, deferred.progress);
                            } catch (thenError) {
                                deferred.reject(thenError);
                            }
                            valueCancel = value.cancel;
                            valueThen = value.then;
                        }
                        result = value;
                        valueThen.call(value, once(_resolve), once(_reject));
                        _this._parentCancel = valueCancel.bind(value);
                    }
                } else {
                    state = "fulfilled";
                    result = value;
                    if (listeners.length) {
                        enqueue(notify);
                    }
                }
            } catch (error) {
                once(_reject)(error);
            }
        }

        function cancel() {
            var parentCancel = _this._parentCancel;
            if (parentCancel) {
                delete _this._parentCancel;
                parentCancel();
            } else if (!state) {
                var cancelError = new Error("Cancel");
                cancelError.name = "Cancel";
                _reject(cancelError);
            }
        }


        /**
         * Resolves this Deferred.
         * @name resolve
         * @function
         * @memberOf orion.Deferred.prototype
         * @param {Object} value
         * @returns {orion.Promise}
         */
        this.resolve = function(value) {
            if (!state) {
                _resolve(value);
            }
            return _this;
        };

        /**
         * Rejects this Deferred.
         * @name reject
         * @function
         * @memberOf orion.Deferred.prototype
         * @param {Object} error
         * @param {Boolean} [strict]
         * @returns {orion.Promise}
         */
        this.reject = function(error) {
            if (!state) {
                _reject(error);
            }
            return _this;
        };

        /**
         * Notifies listeners of progress on this Deferred.
         * @name progress
         * @function
         * @memberOf orion.Deferred.prototype
         * @param {Object} update The progress update.
         * @returns {orion.Promise}
         */
        this.progress = function(update) {
            if (!state) {
                listeners.forEach(function(listener) {
                    if (listener.progress) {
                        try {
                            listener.progress(update);
                        } catch (ignore) {
                            // ignore
                        }
                    }
                });
            }
            return _this.promise;
        };

        this.cancel = function() {
            if (_this._parentCancel) {
                setTimeout(cancel, 0);
            } else {
                cancel();
            }
            return _this;
        };

        // Note: "then" ALWAYS returns before having onResolve or onReject called as per http://promises-aplus.github.com/promises-spec/
        this.then = function(onFulfill, onReject, onProgress) {
        	var deferred = new Deferred();
            deferred._parentCancel = _this.promise.cancel;
            listeners.push({
                resolve: onFulfill,
                reject: onReject,
                progress: onProgress,
                deferred: deferred
            });
            if (state === "fulfilled" || state === "rejected") {
                enqueue(notify);
            }
            return deferred.promise;
        };

        /**
         * The promise exposed by this Deferred.
         * @name promise
         * @field
         * @memberOf orion.Deferred.prototype
         * @type orion.Promise
         */
        this.promise = {
            then: _this.then,
            cancel: _this.cancel
        };
    }

    /**
     * Returns a promise that represents the outcome of all the input promises.
     * <p>When <code>all</code> is called with a single parameter, the returned promise has <dfn>eager</dfn> semantics,
     * meaning that if any input promise rejects, the returned promise immediately rejects, without waiting for the rest of the
     * input promises to fulfill.</p>
     *
     * To obtain <dfn>lazy</dfn> semantics (meaning the returned promise waits for every input promise to fulfill), pass the
     * optional parameter <code>optOnError</code>.
     * @name all
     * @function
     * @memberOf orion.Deferred
     * @static
     * @param {orion.Promise[]} promises The input promises.
     * @param {Function} [optOnError] Handles a rejected input promise. <code>optOnError</code> is invoked for every rejected
     * input promise, and is passed the reason the input promise was rejected. <p><code>optOnError</code> can return a value, which
     * allows it to act as a transformer: the return value serves as the final fulfillment value of the rejected promise in the 
     * results array generated by <code>all</code>.
     * @returns {orion.Promise} A new promise. The returned promise is generally fulfilled to an <code>Array</code> whose elements
     * give the fulfillment values of the input promises. <p>However, if an input promise rejects and eager semantics is used, the 
     * returned promise will instead be fulfilled to a single error value.</p>
     */
    Deferred.all = function(promises, optOnError) {
        var count = promises.length,
            result = [],
            rejected = false,
            deferred = new Deferred();

        deferred.then(undefined, function() {
            rejected = true;
            promises.forEach(function(promise) {
                if (promise.cancel) {
                    promise.cancel();
                }
            });
        });

        function onResolve(i, value) {
            if (!rejected) {
                result[i] = value;
                if (--count === 0) {
                    deferred.resolve(result);
                }
            }
        }

        function onReject(i, error) {
            if (!rejected) {
                if (optOnError) {
                    try {
                        onResolve(i, optOnError(error));
                        return;
                    } catch (e) {
                        error = e;
                    }
                }
                deferred.reject(error);
            }
        }

        if (count === 0) {
            deferred.resolve(result);
        } else {
            promises.forEach(function(promise, i) {
                promise.then(onResolve.bind(undefined, i), onReject.bind(undefined, i));
            });
        }
        return deferred.promise;
    };

    /**
     * Applies callbacks to a promise or to a regular object.
     * @name when
     * @function
     * @memberOf orion.Deferred
     * @static
     * @param {Object|orion.Promise} value Either a {@link orion.Promise}, or a normal value.
     * @param {Function} onResolve Called when the <code>value</code> promise is resolved. If <code>value</code> is not a promise,
     * this function is called immediately.
     * @param {Function} onReject Called when the <code>value</code> promise is rejected. If <code>value</code> is not a promise, 
     * this function is never called.
     * @param {Function} onProgress Called when the <code>value</code> promise provides a progress update. If <code>value</code> is
     * not a promise, this function is never called.
     * @returns {orion.Promise} A new promise.
     */
    Deferred.when = function(value, onResolve, onReject, onProgress) {
        var promise, deferred;
        if (value && typeof value.then === "function") { //$NON-NLS-0$
            promise = value;
        } else {
            deferred = new Deferred();
            deferred.resolve(value);
            promise = deferred.promise;
        }
        return promise.then(onResolve, onReject, onProgress);
    };

    return Deferred;
}));
/*******************************************************************************
 * @license
 * Copyright (c) 2012 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
/*eslint-env browser, amd*/
define('orion/EventTarget',[],function() {
	/**
	 * Creates an Event Target
	 *
	 * @name orion.EventTarget
	 * @class Base for creating an Orion event target
	 */
	function EventTarget() {
		this._namedListeners = {};
	}

	EventTarget.prototype = /** @lends orion.EventTarget.prototype */
	{
		/**
		 * Dispatches a named event along with an arbitrary set of arguments. Any arguments after <code>eventName</code>
		 * will be passed to the event listener(s).
		 * @param {Object} event The event to dispatch. The event object MUST have a type field
		 * @returns {boolean} false if the event has been canceled and any associated default action should not be performed
		 * listeners (if any) have resolved.
		 */
		dispatchEvent: function(event) {
			if (!event.type) {
				throw new Error("unspecified type");
			}
			var listeners = this._namedListeners[event.type];
			if (listeners) {
				listeners.forEach(function(listener) {
					try {
						if (typeof listener === "function") {
							listener(event);
						} else {
							listener.handleEvent(event);
						}
					} catch (e) {
						if (typeof console !== 'undefined') {
							console.log(e); // for now, probably should dispatch an ("error", e)
						}
					}			
				});
			}
			return !event.defaultPrevented;
		},

		/**
		 * Adds an event listener for a named event
		 * @param {String} eventName The event name
		 * @param {Function} listener The function called when an event occurs
		 */
		addEventListener: function(eventName, listener) {
			if (typeof listener === "function" || listener.handleEvent) {
				this._namedListeners[eventName] = this._namedListeners[eventName] || [];
				this._namedListeners[eventName].push(listener);
			}
		},

		/**
		 * Removes an event listener for a named event
		 * @param {String} eventName The event name
		 * @param {Function} listener The function called when an event occurs
		 */
		removeEventListener: function(eventName, listener) {
			var listeners = this._namedListeners[eventName];
			if (listeners) {
				for (var i = 0; i < listeners.length; i++) {
					if (listeners[i] === listener) {
						if (listeners.length === 1) {
							delete this._namedListeners[eventName];
						} else {
							listeners.splice(i, 1);
						}
						break;
					}
				}
			}
		}
	};
	EventTarget.prototype.constructor = EventTarget;
	
	EventTarget.attach = function(obj) {
		var eventTarget = new EventTarget();
		obj.dispatchEvent = eventTarget.dispatchEvent.bind(eventTarget);
		obj.addEventListener = eventTarget.addEventListener.bind(eventTarget);
		obj.removeEventListener = eventTarget.removeEventListener.bind(eventTarget);
	};
	
	return EventTarget;
});
/*******************************************************************************
 * @license
 * Copyright (c) 2011, 2013 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made
 * available under the terms of the Eclipse Public License v1.0
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html).
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
/*eslint-env browser, amd*/
define('orion/serviceregistry',["orion/Deferred", "orion/EventTarget"], function(Deferred, EventTarget) {

	/**
	 * @name orion.serviceregistry.ServiceReference
	 * @description Creates a new service reference.
	 * @class A reference to a service in the Orion service registry
	 * @param {String} serviceId The symbolic id of this service instance
	 * @param {String} name The service name
	 * @param {Object} properties A JSON object containing the service's declarative properties
	 */
	function ServiceReference(serviceId, objectClass, properties) {
		this._properties = properties || {};
		this._properties["service.id"] = serviceId;
		this._properties.objectClass = objectClass;
		this._properties["service.names"] = objectClass;
	}

	ServiceReference.prototype = /** @lends orion.serviceregistry.ServiceReference.prototype */
	{
		/**
		 * @name getPropertyKeys
		 * @description Returns the names of the declarative properties of this service.
		 * @function
		 * @public
		 * @memberof orion.serviceregistry.ServiceReference.prototype
		 * @returns the names of the declarative properties of this service
		 */
		getPropertyKeys: function() {
			var result = [];
			var name;
			for (name in this._properties) {
				if (this._properties.hasOwnProperty(name)) {
					result.push(name);
				}
			}
			return result;
		},
		/**
		 * @name getProperty
		 * @description Returns the declarative service property with the given name, or <code>undefined</code>
		 * if this service does not have such a property.
		 * @function
		 * @public
		 * @memberof orion.serviceregistry.ServiceReference.prototype
		 * @param {String} propertyName The name of the service property to return
		 * @returns The {String} property with the given name or <code>undefined</code>
		 */
		getProperty: function(propertyName) {
			return this._properties[propertyName];
		}
	};
	ServiceReference.prototype.constructor = ServiceReference;

	/**
	 * @name orion.serviceregistry.ServiceRegistration
	 * @description Creates a new service registration. This constructor is private and should only be called by the service registry.
	 * @class A reference to a registered service in the Orion service registry
	 * @param {String} serviceId The symbolic id of this service
	 * @param {String} serviceReference A reference to the service
	 * @param {Object} internalRegistry A JSON object containing the service's declarative properties
	 */
	function ServiceRegistration(serviceId, serviceReference, internalRegistry) {
		this._serviceId = serviceId;
		this._serviceReference = serviceReference;
		this._internalRegistry = internalRegistry;
	}

	ServiceRegistration.prototype = /** @lends orion.serviceregistry.ServiceRegistration.prototype */
	{
		/**
		 * @name unregister
		 * @description Unregister this service registration. Clients registered for <code>unregistering</code> service events
		 * will be notified of this change.
		 * @function
		 * @private
		 * @memberof orion.serviceregistry.ServiceRegistration.prototype
		 */
		unregister: function() {
			this._internalRegistry.unregisterService(this._serviceId);
		},

		/**
		 * @name getReference
		 * @description Returns the {@link orion.serviceregistry.ServiceReference} in this registration
		 * @function
		 * @private
		 * @memberof orion.serviceregistry.ServiceRegistration.prototype
		 * @param properties
		 * @returns the {@link orion.serviceregistry.ServiceReference} in this registration
		 * @throws An error is the service has been unregistered
		 */
		getReference: function() {
			if (!this._internalRegistry.isRegistered(this._serviceId)) {
				throw new Error("Service has already been unregistered: "+this._serviceId);
			}
			return this._serviceReference;
		},
		/**
		 * @name setProperties
		 * @description Sets the properties of this registration to the new given properties. Clients registered for <code>modified</code> service events
		 * will be notified of the change.
		 * @function
		 * @private
		 * @memberof orion.serviceregistry.ServiceRegistration.prototype
		 * @param {Object} properties
		 */
		setProperties: function(properties) {
			var oldProperties = this._serviceReference._properties;
			this._serviceReference._properties = properties || {};
			properties["service.id"] = this._serviceId;
			properties.objectClass = oldProperties.objectClass;
			properties["service.names"] = oldProperties["service.names"];
			this._internalRegistry.modifyService(this._serviceId);
		}
	};
	ServiceRegistration.prototype.constructor = ServiceRegistration;

	/**
	 * @name orion.serviceregistry.DeferredService
	 * @description Creates a new service promise to resolve the service at a later time.
	 * @class A service that is resolved later
	 * @private
	 * @param {orion.serviceregistry.ServiceReference} implementation The implementation of the service
	 * @param {Function} isRegistered A function to call to know if the service is already registered
	 */
	function DeferredService(implementation, isRegistered) {

		function _createServiceCall(methodName) {
			return function() {
					var d;
					try {
						if (!isRegistered()) {
							throw new Error("Service was unregistered");
						}
						var result = implementation[methodName].apply(implementation, Array.prototype.slice.call(arguments));
						if (result && typeof result.then === "function") {
							return result;
						} else {
							d = new Deferred();
							d.resolve(result);
						}
					} catch (e) {
							d = new Deferred();
							d.reject(e);
					}
					return d.promise;
			};
		}

		var method;
		for (method in implementation) {
			if (typeof implementation[method] === 'function') {
				this[method] = _createServiceCall(method);
			}
		}
	}

	/**
	 * @name orion.serviceregistry.ServiceEvent
	 * @description An event that is fired from the service registry. Clients must register to listen to events using 
	 * the {@link orion.serviceregistry.ServiceRegistry#addEventListener} function.
	 * <br> 
	 * There are three types of events that this registry will send:
	 * <ul>
	 * <li>modified - the service has been modified</li> 
	 * <li>registered - the service has been registered</li> 
	 * <li>unregistering - the service is unregistering</li>
	 * </ul> 
	 * @class A service event
	 * @param {String} type The type of the event, one of <code>modified</code>, <code>registered</code> or <code>unregistered</code>
	 * @param {orion.serviceregistry.ServiceReference} serviceReference the service reference the event is for
	 */
	function ServiceEvent(type, serviceReference) {
		this.type = type;
		this.serviceReference = serviceReference;
	}

	/**
	 * @name orion.serviceregistry.ServiceRegistry
	 * @description Creates a new service registry
	 * @class The Orion service registry
	 */
	function ServiceRegistry() {
		this._entries = [];
		this._namedReferences = {};
		this._serviceEventTarget = new EventTarget();
		var _this = this;
		this._internalRegistry = {
			/**
			 * @name isRegistered
			 * @description Returns if the service with the given identifier is registered or not.
			 * @function
			 * @private
			 * @memberof orion.serviceregistry.ServiceRegistry
			 * @param {String} serviceId the identifier of the service
			 * @returns <code>true</code> if the service with the given identifier is registered, <code>false</code> otherwise
			 */
			isRegistered: function(serviceId) {
				return _this._entries[serviceId] ? true : false;
			},
			
			/**
			 * @name unregisterService
			 * @description Unregisters a service with the given identifier. This function will notify
			 * clients registered for <code>unregistering</code> service events.
			 * @function
			 * @private
			 * @memberof orion.serviceregistry.ServiceRegistry
			 * @param {String} serviceId the identifier of the service
			 * @throws An error if the service has already been unregistered
			 * @see orion.serviceregistry.ServiceEvent
			 */
			unregisterService: function(serviceId) {
				var entry = _this._entries[serviceId];
				if (!entry) {
					throw new Error("Service has already been unregistered: "+serviceId);
				}
				var reference = entry.reference;
				_this._serviceEventTarget.dispatchEvent(new ServiceEvent("unregistering", reference));
				_this._entries[serviceId] = null;
				var objectClass = reference.getProperty("objectClass");
				objectClass.forEach(function(type) {
					var namedReferences = _this._namedReferences[type];
					for (var i = 0; i < namedReferences.length; i++) {
						if (namedReferences[i] === reference) {
							if (namedReferences.length === 1) {
								delete _this._namedReferences[type];
							} else {
								namedReferences.splice(i, 1);
							}
							break;
						}
					}
				});
			},
			/**
			 * @name modifyService
			 * @description Notifies that the service with the given identifier has been modified. This function will notify clients
			 * registered for <code>modified</code> service events.
			 * @function
			 * @private
			 * @memberof orion.serviceregistry.ServiceRegistry
			 * @param {String} serviceId the identifier of the service
			 * @throws An error if the service for the given identifier does not exist
			 * @see orion.serviceregistry.ServiceEvent
			 */
			modifyService: function(serviceId) {
				var entry = _this._entries[serviceId];
				if (!entry) {
					throw new Error("Service not found while trying to send modified event: "+serviceId);
				}
				var reference = entry.reference;
				_this._serviceEventTarget.dispatchEvent(new ServiceEvent("modified", reference));
			}
		};
	}

	ServiceRegistry.prototype = /** @lends orion.serviceregistry.ServiceRegistry.prototype */
	{
		/**
		 * @name getService
		 * @description Returns the service with the given name or reference.
		 * @function
		 * @public
		 * @memberof orion.serviceregistry.ServiceRegistry.prototype
		 * @param {String|orion.serviceregistry.ServiceReference} nameOrServiceReference The service name or a service reference
		 * @returns {orion.serviceregistry.ServiceReference|null} The service implementation, or <code>null</code> if no such service was found.
		 */
		getService: function(typeOrServiceReference) {
			var service;
			if (typeof typeOrServiceReference === "string") {
				var references = this._namedReferences[typeOrServiceReference];
				if (references) {
					references.some(function(reference) {
						service = this._entries[reference.getProperty("service.id")].service;
						return !!service;
					}, this);
				}
			} else {
				var entry = this._entries[typeOrServiceReference.getProperty("service.id")];
				if (entry) {
					service = entry.service;
				}
			}
			return service || null;
		},

		/**
		 * @name getServiceReferences
		 * @description Returns all references to the service with the given name.
		 * @function
		 * @public
		 * @memberof orion.serviceregistry.ServiceRegistry.prototype
		 * @param {String} name The name of the service to return
		 * @returns {orion.serviceregistry.ServiceReference[]} An array of service references
		 */
		getServiceReferences: function(name) {
			if (name) {
				return this._namedReferences[name] ? this._namedReferences[name] : [];
			}
			var result = [];
			this._entries.forEach(function(entry) {
				if (entry) {
					result.push(entry.reference);
				}
			});
			return result;
		},
		
		/**
		 * @name registerService
		 * @description Registers a service with this registry. This function will notify clients registered
		 * for <code>registered</code> service events.
		 * @function
		 * @public
		 * @memberof orion.serviceregistry.ServiceRegistry.prototype
		 * @param {String|String[]} names the name or names of the service being registered
		 * @param {Object} service The service implementation
		 * @param {Object} properties A JSON collection of declarative service properties
		 * @returns {orion.serviceregistry.ServiceRegistration} A service registration object for the service.
		 * @see orion.serviceregistry.ServiceEvent
		 */
		registerService: function(names, service, properties) {
			if (typeof service === "undefined" ||  service === null) {
				throw new Error("invalid service");
			}

			if (typeof names === "string") {
				names = [names];
			} else if (!Array.isArray(names)) {
				names = [];
			}

			var serviceId = this._entries.length;
			var reference = new ServiceReference(serviceId, names, properties);
			var namedReferences = this._namedReferences;
			names.forEach(function(name) {
				namedReferences[name] = namedReferences[name] || [];
				namedReferences[name].push(reference);
			});
			var deferredService = new DeferredService(service, this._internalRegistry.isRegistered.bind(null, serviceId));
			this._entries.push({
				reference: reference,
				service: deferredService
			});
			var internalRegistry = this._internalRegistry;
			this._serviceEventTarget.dispatchEvent(new ServiceEvent("registered", reference));
			return new ServiceRegistration(serviceId, reference, internalRegistry);
		},

		/**
		 * @name addEventListener
		 * @description Adds a listener for events on this registry.
		 * <br> 
		 * The events that this registry notifies about:
		 * <ul>
		 * <li>modified - the service has been modified</li> 
		 * <li>registered - the service has been registered</li> 
		 * <li>unregistering - the service is unregistering</li> 
		 * </ul> 
		 * @function
		 * @public
		 * @memberof orion.serviceregistry.ServiceRegistry.prototype
		 * @param {String} eventName The name of the event to be notified about.
		 * @param {Function} listener The listener to add
		 * @see orion.serviceregistry.ServiceEvent
		 */
		addEventListener: function(eventName, listener) {
			this._serviceEventTarget.addEventListener(eventName, listener);
		},

		/**
		 * @name removeEventListener
		 * @description Removes a listener for service events in this registry.
		 * @function
		 * @public
		 * @memberof orion.serviceregistry.ServiceRegistry.prototype
		 * @param {String} eventName The name of the event to stop listening for
		 * @param {Function} listener The listener to remove
		 * @see orion.serviceregistry.ServiceEvent
		 */
		removeEventListener: function(eventName, listener) {
			this._serviceEventTarget.removeEventListener(eventName, listener);
		}
	};
	ServiceRegistry.prototype.constructor = ServiceRegistry;

	//return the module exports
	return {
		ServiceRegistry: ServiceRegistry
	};
});
/*******************************************************************************
 * @license
 * Copyright (c) 2012, 2019 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 *
 * Contributors: IBM Corporation - initial API and implementation
 *******************************************************************************/

/*eslint-env browser, amd*/
define('orion/util',[],function() {

	var userAgent = navigator.userAgent;
	var isIE = (userAgent.indexOf("MSIE") !== -1 || userAgent.indexOf("Trident") !== -1) ? document.documentMode : undefined; //$NON-NLS-1$ //$NON-NLS-0$
	var isFirefox = parseFloat(userAgent.split("Firefox/")[1] || userAgent.split("Minefield/")[1]) || undefined; //$NON-NLS-1$ //$NON-NLS-0$
	var isOpera = userAgent.indexOf("Opera") !== -1 ? parseFloat(userAgent.split("Version/")[1]) : undefined; //$NON-NLS-0$
	var isChrome = parseFloat(userAgent.split("Chrome/")[1]) || undefined; //$NON-NLS-0$
	var isSafari = userAgent.indexOf("Safari") !== -1 && !isChrome; //$NON-NLS-0$
	var isWebkit = parseFloat(userAgent.split("WebKit/")[1]) || undefined; //$NON-NLS-0$
	var isAndroid = userAgent.indexOf("Android") !== -1; //$NON-NLS-0$
	var isIPad = userAgent.indexOf("iPad") !== -1; //$NON-NLS-0$
	var isIPhone = userAgent.indexOf("iPhone") !== -1; //$NON-NLS-0$
	var isIOS = isIPad || isIPhone;
	var isElectron = userAgent.indexOf("Electron") !== -1; //$NON-NLS-0$
	var isMac = navigator.platform.indexOf("Mac") !== -1; //$NON-NLS-0$
	var isWindows = navigator.platform.indexOf("Win") !== -1; //$NON-NLS-0$
	var isLinux = navigator.platform.indexOf("Linux") !== -1; //$NON-NLS-0$
	var isTouch = typeof document !== "undefined" && "ontouchstart" in document.createElement("input"); //$NON-NLS-1$ //$NON-NLS-0$
	
	var platformDelimiter = isWindows ? "\r\n" : "\n"; //$NON-NLS-1$ //$NON-NLS-0$

	function formatMessage(msg) {
		var args = arguments;
		return msg.replace(/\$\{([^\}]+)\}/g, function(str, index) { return args[(index << 0) + 1]; });
	}
	
	var XHTML = "http://www.w3.org/1999/xhtml"; //$NON-NLS-0$
	function createElement(document, tagName) {
		if (document.createElementNS) {
			return document.createElementNS(XHTML, tagName);
		}
		return document.createElement(tagName);
	}
	function confineDialogTab(firstElement, lastElement) {
		lastElement.addEventListener("keydown", function(evt) {
			if(evt.keyCode === 9 && !evt.shiftKey) {
				evt.preventDefault();
				firstElement.focus();
			}
		});
		firstElement.addEventListener("keydown", function(evt) {
			if(evt.keyCode === 9 && evt.shiftKey) {
				evt.preventDefault();
				lastElement.focus();
			}
		});
	}

	/**
	 * @description Save the setting to persistent storage.
	 * 
	 * Currently this function saves to localStorage
	 * @param {string} key 
	 * @param {string} value
	 * @since 20.0
	 */
	function saveSetting(key, value) {
		//TODO make this pluggable to not only work with localStorage
		localStorage.setItem(key, value);
	}

	/**
	 * @description Retrieve the setting from persistent storage.
	 * 
	 * Currently this function reads from localStorage
	 * @param {string} key 
	 * @since 20.0
	 */
	function readSetting(key) {
		//TODO make this pluggable to not only work with localStorage
		return localStorage.getItem(key);
	}

	/**
	 * @description Remove the setting from persistent storage.
	 * 
	 * Currently this function removes from localStorage
	 * @param {string} key 
	 * @since 20.0
	 */
	function deleteSetting(key) {
		//TODO make this pluggable to not only work with localStorage
		localStorage.removeItem(key);
	}

	/**
	 * @description Clears out the saved settings from persistent storage
	 * 
	 * @since 20.0
	 */
	function clearSettings() {
		//TODO make this pluggable to not only work with localStorage
		localStorage.clear();
	}

	function computeAuditId(fileClient, path, removeWorkspaceSegment) {
		var rootUrl = fileClient.fileServiceRootURL(path);
		var rootSegmentsCount = rootUrl.split('/').length;
		var segmentsToRemove = rootSegmentsCount + (removeWorkspaceSegment ? 1 : 0);
		return path.split('/').slice(segmentsToRemove).join('/');
	}

	return {
		readSetting: readSetting,
		saveSetting: saveSetting,
		deleteSetting: deleteSetting,
		clearSettings: clearSettings,

		formatMessage: formatMessage,
		
		createElement: createElement,
		confineDialogTab: confineDialogTab,
		
		computeAuditId: computeAuditId,
		
		/** Browsers */
		isIE: isIE,
		isFirefox: isFirefox,
		isOpera: isOpera,
		isChrome: isChrome,
		isSafari: isSafari,
		isWebkit: isWebkit,
		isAndroid: isAndroid,
		isIPad: isIPad,
		isIPhone: isIPhone,
		isIOS: isIOS,
		isElectron: isElectron,
		
		/** OSs */
		isMac: isMac,
		isWindows: isWindows,
		isLinux: isLinux,

		/** Capabilities */
		isTouch: isTouch,

		platformDelimiter: platformDelimiter
	};
});
/*******************************************************************************
 * Copyright (c) 2014 SAP AG and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     SAP AG - initial API and implementation
 *******************************************************************************/
define('orion/xsrfUtils',['module'],function(module){
	var XSRF_TOKEN = "x-csrf-token";//$NON-NLS-0$

	/**
	 * extracts value of xsrf cookie if available
	 */
	function getCSRFToken() {
		if (typeof document === "undefined") return null;
		
		var config = module.config && module.config() || {};
		if (config.CSRF_TOKEN) {
			return config.CSRF_TOKEN;
		}
		
		var cookies = document.cookie.split(";");//$NON-NLS-0$

		var i,n,v;
		for(i = 0; i<cookies.length; i++) {
			n = cookies[i].substr(0, cookies[i].indexOf("=")).trim();//$NON-NLS-0$
			v = cookies[i].substr(cookies[i].indexOf("=") + 1).trim();//$NON-NLS-0$

			if(n.endsWith(XSRF_TOKEN)) {
				return v;
			}
		}
	}

	/**
	 * adds xsrf nonce to header if set in cookies
	 * @param {Object} request header
	 */
	function setNonceHeader(headers) {
		var token = getCSRFToken();
		if (token) {
			headers[XSRF_TOKEN] = token;
		}
	}

	/**
	 * adds xsrf nonce to an XMLHTTPRequest object if set in cookies
	 * @param {Object} XMLHttpRequest object
	 */
	function addCSRFNonce(request) {
		var token = getCSRFToken();
		if(token) {
			request.setRequestHeader(XSRF_TOKEN, token);
		}
	}

	return {
		XSRF_TOKEN: XSRF_TOKEN,
		getCSRFToken: getCSRFToken,
		setNonceHeader: setNonceHeader,
		addCSRFNonce: addCSRFNonce
	};
});
/*******************************************************************************
 * @license
 * Copyright (c) 2017 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 *
 * Contributors: IBM Corporation - initial API and implementation
 *******************************************************************************/

/*eslint-env browser, amd*/
define('orion/urlModifier',[],function() {	
	function modifyUrl(value) {
		return value;
	}
	return modifyUrl;
});

/*******************************************************************************
 * @license
 * Copyright (c) 2012 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (https://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (https://www.eclipse.org/org/documents/edl-v10.html). 
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
/*eslint-env browser, amd*/
/*global StopIteration*/
// URL Shim -- see https://url.spec.whatwg.org/ and https://dvcs.w3.org/hg/url/raw-file/tip/Overview.html

/*eslint-disable no-extra-parens */
(function() {
    try {
        var testURL;
        if (typeof self.URL === "function" && self.URL.length !== 0 &&
                (testURL = new self.URL("https://www.w3.org?q")).protocol === "https:" && testURL.query) {
            return;
        }
    } catch (e) {}

    //[1]scheme, [2]authority, [3]path, [4]query, [5]fragment
    var _URI_RE = /^(?:([^:\/?#]+):)?(?:\/\/([^\/?#]*))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?$/;
    //[ userinfo "@" ] host [ ":" port ]
    var _AUTHORITY_RE = /^(?:(.*)@)?(\[[^\]]*\]|[^:]*)(?::(.*))?$/;

    var _NO_WS_RE = /^\S*$/;
    var _SCHEME_RE = /^([a-zA-Z](?:[a-zA-Z0-9+-.])*)$/;
    var _PORT_RE = /^\d*$/;
    var _HOST_RE = /^(\[[^\]\/?#\s]*\]|[^:\/?#\s]*)$/;
    var _HOSTPORT_RE = /^(\[[^\]\/?#\s]*\]|[^:\/?#\s]*)(?::(\d*))?$/;
    var _PATH_RE = /^([^?#\s]*)$/;
    var _QUERY_RE = /^([^\s]*)$/;
    var _FRAGMENT_RE = _NO_WS_RE;
    var _USERNAME_PASSWORD_RE = /([^:]*):?(.*)/;

    var STOP_ITERATION = typeof StopIteration !== "undefined" ? StopIteration : new Error("Stop Iteration");
    var DEFAULT_PORTS = {
        "ftp:": "21",
            "gopher:": "70",
            "http:": "80",
            "https:": "443",
            "ws:": "80",
            "wss:": "443"
    };

    function _checkString(txt) {
        if (typeof txt !== "string") {
            throw new TypeError();
        }
    }

    function _parseQuery(query) {
        return query ? query.split("&") : [];
    }

    function _stringifyQuery(pairs) {
        if (pairs.length === 0) {
            return "";
        }
        return pairs.join("&");
    }

    function _parsePair(pair) {
        var parsed = /([^=]*)(?:=?)(.*)/.exec(pair);
        var key = parsed[1] ? decodeURIComponent(parsed[1]) : "";
        var value = parsed[2] ? decodeURIComponent(parsed[2]) : "";
        return [key, value];
    }

    function _stringifyPair(entry) {
        var pair = encodeURIComponent(entry[0]);
        if (entry[1]) {
            pair += "=" + encodeURIComponent(entry[1]);
        }
        return pair;
    }

    function _createMapIterator(url, kind) {
        var query = "";
        var pairs = [];
        var index = 0;
        return {
            next: function() {
                if (query !== url.query) {
                    query = url.query;
                    pairs = _parseQuery(query);
                }
                if (index < pairs.length) {
                    var entry = _parsePair(pairs[index++]);
                    switch (kind) {
                        case "keys":
                            return entry[0];
                        case "values":
                            return entry[1];
                        case "keys+values":
                            return [entry[0], entry[1]];
                        default:
                            throw new TypeError();
                    }
                }
                throw STOP_ITERATION;
            }
        };
    }

    // See https://url.spec.whatwg.org/#interface-urlquery
    function URLQuery(url) {
        Object.defineProperty(this, "_url", {
            get: function() {
                return url._url;
            }
        });
    }

    Object.defineProperties(URLQuery.prototype, {
        get: {
            value: function(key) {
                _checkString(key);
                var result;
                var pairs = _parseQuery(this._url.query);
                pairs.some(function(pair) {
                    var entry = _parsePair(pair);
                    if (entry[0] === key) {
                        result = entry[1];
                        return true;
                    }
                });
                return result;
            },
            enumerable: true
        },
        set: {
            value: function(key, value) {
                _checkString(key);
                _checkString(value);
                var pairs = _parseQuery(this._url.query);
                var found = pairs.some(function(pair, i) {
                    var entry = _parsePair(pair);
                    if (entry[0] === key) {
                        entry[1] = value;
                        pairs[i] = _stringifyPair(entry);
                        return true;
                    }
                });
                if (!found) {
                    pairs.push(_stringifyPair([key, value]));
                }
                this._url.query = _stringifyQuery(pairs);
            },
            enumerable: true
        },
        has: {
            value: function(key) {
                _checkString(key);
                var pairs = _parseQuery(this._url.query);
                return pairs.some(function(pair) {
                    var entry = _parsePair(pair);
                    if (entry[0] === key) {
                        return true;
                    }
                });
            },
            enumerable: true
        },
            "delete": {
            value: function(key) {
                _checkString(key);
                var pairs = _parseQuery(this._url.query);
                var filtered = pairs.filter(function(pair) {
                    var entry = _parsePair(pair);
                    return entry[0] !== key;
                });
                if (filtered.length !== pairs.length) {
                    this._url.query = _stringifyQuery(filtered);
                    return true;
                }
                return false;
            },
            enumerable: true
        },
        clear: {
            value: function() {
                this._url.query = "";
            },
            enumerable: true
        },
        forEach: {
            value: function(callback, thisArg) {
                if (typeof callback !== "function") {
                    throw new TypeError();
                }
                var iterator = _createMapIterator(this._url, "keys+values");
                try {
                    while (true) {
                        var entry = iterator.next();
                        callback.call(thisArg, entry[1], entry[0], this);
                    }
                } catch (e) {
                    if (e !== STOP_ITERATION) {
                        throw e;
                    }
                }
            },
            enumerable: true
        },
        keys: {
            value: function() {
                return _createMapIterator(this._url, "keys");
            },
            enumerable: true
        },
        values: {
            value: function() {
                return _createMapIterator(this._url, "values");
            },
            enumerable: true
        },
        items: {
            value: function() {
                return _createMapIterator(this._url, "keys+values");
            }
        },
        size: {
            get: function() {
                return _parseQuery(this._url.query).length;
            },
            enumerable: true
        },
        getAll: {
            value: function(key) {
                _checkString(key);
                var result = [];
                var pairs = _parseQuery(this._url.query);
                pairs.forEach(function(pair) {
                    var entry = _parsePair(pair);
                    if (entry[0] === key) {
                        result.push(entry[1]);
                    }
                });
                return result;
            },
            enumerable: true
        },
        append: {
            value: function(key, value) {
                _checkString(key);
                _checkString(value);
                var pairs = _parseQuery(this._url.query);
                pairs.push(_stringifyPair([key, value]));
                this._url.query = _stringifyQuery(pairs);
            },
            enumerable: true
        }
    });

    function _makeAbsoluteURL(url, base) {
        if (!url.scheme && base) {
            url.scheme = base.scheme;
            if (!url.host && base.host) {
                url.userinfo = base.userinfo;
                url.host = base.host;
                url.port = base.port;
                url.pathRelative = true;
            }
        }
        if (url.pathRelative) {
            if (!url.path) {
                url.path = base.path;
            } else if (url.path[0] !== "/") {
                var basePath = /^(.*\/)[^\/]*$/.exec(base.path)[1] || "/";
                url.path = basePath + url.path;
            }
        }
    }

    function _normalizeScheme(scheme) {
        return scheme.toLowerCase();
    }

    function _normalizePort(port) {
        return port ? (/[1-9]\d*$/).exec(port)[0] : "";
    }

    function _normalizePath(path) {
        var result = [];
        path.split("/").forEach(function(segment) {
            if (segment === "..") {
            	if (result.length > 1) {
                	result.pop();
            	}
            } else if (segment !== ".") {
                result.push(segment);
            }
        });
        return result.join("/");
    }


    function _normalizeURL(url) {
        if (url.scheme) {
            url.scheme = _normalizeScheme(url.scheme);
        }
        if (url.port) {
            url.port = _normalizePort(url.port);
        }
        if (url.host && url.path) {
            url.path = _normalizePath(url.path);
        }
    }

    function _encodeWhitespace(text) {
        return text.replace(/\s/g, function(c) {
            return "%" + c.charCodeAt(0).toString(16);
        });
    }

    function _parseURL(input, base) {
        if (typeof input !== "string") {
            throw new TypeError();
        }

        input = _encodeWhitespace(input);

        var parsedURI = _URI_RE.exec(input);
        if (!parsedURI) {
            return null;
        }
        var url = {};
        url.scheme = parsedURI[1] || "";
        if (url.scheme && !_SCHEME_RE.test(url.scheme)) {
            return null;
        }
        var authority = parsedURI[2];
        if (authority) {
            var parsedAuthority = _AUTHORITY_RE.exec(authority);
            url.userinfo = parsedAuthority[1];
            url.host = parsedAuthority[2];
            url.port = parsedAuthority[3];
            if (url.port && !_PORT_RE.test(url.port)) {
                return null;
            }
        }
        url.path = parsedURI[3];
        url.query = parsedURI[4];
        url.fragment = parsedURI[5];

        _makeAbsoluteURL(url, base);
        _normalizeURL(url);
        return url;
    }

    function _serialize(url) {
        var result = (url.scheme ? url.scheme + ":" : "");
        if (url.host) {
            result += "//";
            if (url.userinfo) {
                result += url.userinfo + "@";
            }
            result += url.host;
            if (url.port) {
                result += ":" + url.port;
            }
        }
        result += url.path;
        if (url.query) {
            result += "?" + url.query;
        }
        if (url.fragment) {
            result += "#" + url.fragment;
        }
        return result;
    }

    // See https://url.spec.whatwg.org/#api
    function URL(input, base) {
        var baseURL;
        if (base) {
            base = base.href || base;
            baseURL = _parseURL(base);
            if (!baseURL || !baseURL.scheme) {
                throw new SyntaxError();
            }
            Object.defineProperty(this, "_baseURL", {
                value: baseURL
            });
        }

        var url = _parseURL(input, baseURL);
        if (!url) {
            throw new SyntaxError();
        }

        Object.defineProperty(this, "_input", {
            value: input,
            writable: true
        });

        Object.defineProperty(this, "_url", {
            value: url,
            writable: true
        });

        var query = new URLQuery(this);
        Object.defineProperty(this, "query", {
            get: function() {
                return this._url ? query : null;
            },
            enumerable: true
        });
    }

    Object.defineProperties(URL.prototype, {
    	toString: {
    		value: function() {
    			return this.href;
    		}		
    	},
        href: {
            get: function() {
                return this._url ? _serialize(this._url) : this._input;
            },
            set: function(value) {
                _checkString(value);
                this._input = value;
                this._url = _parseURL(this._input, this._baseURL);
            },
            enumerable: true
        },
        origin: {
            get: function() {
                return (this._url && this._url.host ? this.protocol + "//" + this.host : "");
            },
            enumerable: true
        },
        protocol: {
            get: function() {
                return this._url ? this._url.scheme + ":" : ":";
            },
            set: function(value) {
                _checkString(value);
                if (!this._url) {
                    return;
                }
                var scheme = (value.slice(-1) === ":") ? value.substring(0, value.length - 1) : value;
                if (scheme === "" || _SCHEME_RE.test(scheme)) {
                    this._url.scheme = _normalizeScheme(scheme);
                }

            },
            enumerable: true
        },
        _userinfo: { // note: not part of spec so not enumerable
            get: function() {
                return this._url ? this._url.userinfo : "";
            },
            set: function(value) {
                _checkString(value);
                if (!this._url) {
                    return;
                }
                this._url.userinfo = value;
            }
        },
        username: {
            get: function() {
                if (!this._url) {
                    return "";
                }
                var parsed = _USERNAME_PASSWORD_RE.exec(this._userinfo);
                var username = decodeURIComponent(parsed[1] || "");
                return username;
            },
            set: function(value) {
                _checkString(value);
                if (!this._url) {
                    return;
                }
                var parsed = _USERNAME_PASSWORD_RE.exec(this._userinfo);
                var userpass = [encodeURIComponent(value || "")];
                if (parsed[2]) {
                    userpass.push(parsed[2]);
                }
                this._userinfo = userpass.join(":");
            },
            enumerable: true
        },
        password: {
            get: function() {
                if (!this._url) {
                    return "";
                }
                var parsed = _USERNAME_PASSWORD_RE.exec(this._userinfo);
                var password = decodeURIComponent(parsed[2] || "");
                return password;
            },
            set: function(value) {
                _checkString(value);
                if (!this._url) {
                    return;
                }
                var parsed = _USERNAME_PASSWORD_RE.exec(this._userinfo);
                var userpass = [parsed[1] || ""];
                if (value) {
                    userpass.push(encodeURIComponent(value));
                }
                this._userinfo = userpass.join(":");
            },
            enumerable: true
        },
        host: {
            get: function() {
                var result = "";
                if (this._url && this._url.host) {
                    result += this._url.host;
                    if (this._url.port) {
                        result += ":" + this._url.port;
                    }
                }
                return result;
            },
            set: function(value) {
                _checkString(value);
                if (!this._url) {
                    return;
                }
                var result = _HOSTPORT_RE.exec(value);
                if (result) {
                    this._url.host = result[1];
                    this._url.port = _normalizePort(result[2]);
                }
            },
            enumerable: true
        },
        hostname: {
            get: function() {
                return this._url ? this._url.host : "";
            },
            set: function(value) {
                _checkString(value);
                if (!this._url) {
                    return;
                }
                var result = _HOST_RE.exec(value);
                if (result) {
                    this._url.host = value;
                }
            },
            enumerable: true
        },
        port: {
            get: function() {
                var port = this._url ? this._url.port || "" : "";
                if (port && port === DEFAULT_PORTS[this.protocol]) {
                    port = "";
                }
                return port;
            },
            set: function(value) {
                _checkString(value);
                if (!this._url) {
                    return;
                }
                var result = _PORT_RE.exec(value);
                if (result) {
                    this._url.port = _normalizePort(value);
                }
            },
            enumerable: true
        },
        pathname: {
            get: function() {
                return this._url ? this._url.path : "";
            },
            set: function(value) {
                _checkString(value);
                if (!this._url) {
                    return;
                }
                var result = _PATH_RE.exec(value);
                if (result) {
                    if (this._url.host && value && value[0] !== "/") {
                        value = "/" + value;
                    }
                    this._url.path = value ? _normalizePath(value) : "";
                }
            },
            enumerable: true
        },
        search: {
            get: function() {
                return (this._url && this._url.query ? "?" + this._url.query : "");
            },
            set: function(value) {
                _checkString(value);
                if (!this._url) {
                    return;
                }
                if (value && value[0] === "?") {
                    value = value.substring(1);
                }
                var result = _QUERY_RE.exec(value);
                if (result) {
                    this._url.query = value;
                }
            },
            enumerable: true
        },
        hash: {
            get: function() {
                return (this._url && this._url.fragment ? "#" + this._url.fragment : "");
            },
            set: function(value) {
                _checkString(value);
                if (!this._url) {
                    return;
                }
                if (value && value[0] === "#") {
                    value = value.substring(1);
                }
                var result = _FRAGMENT_RE.exec(value);
                if (result) {
                    this._url.fragment = value;
                }
            },
            enumerable: true
        }
    });

	var _URL = self.URL || self.webkitURL;
    if (_URL && _URL.createObjectURL) {
        Object.defineProperty(URL, "createObjectURL", {
            value: _URL.createObjectURL.bind(_URL),
            enumerable: false
        });

        Object.defineProperty(URL, "revokeObjectURL", {
            value: _URL.revokeObjectURL.bind(_URL),
            enumerable: false
        });
    }
    self.URL = URL;
}());
define("orion/URL-shim", function(){});

/*******************************************************************************
 * @license
 * Copyright (c) 2012, 2019 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
/*eslint-env browser, amd*/
/*global URL*/
/**
 * @name orion.xhr
 * @namespace Provides a promise-based API to {@link XMLHttpRequest}.
 */
define('orion/xhr',[
	'orion/Deferred',
	'orion/util',
	'orion/xsrfUtils',
	'orion/urlModifier',
	'orion/URL-shim', // no exports, must come last
], function(Deferred, util, xsrfUtils, urlModifier) {

	/**
	 * @name orion.xhr.Result
	 * @class Wraps an XHR response or failure.
	 * @property {Object} args Arguments passed to the {@link orion.xhr.xhr} call.
	 * @property {Object|ArrayBuffer|Blob|Document|String} response The <code>response</code> object returned by the XMLHttpRequest.
	 * It is typed according to the <code>responseType</code> passed to the XHR call (by default it is a {@link String}).
	 * @property {String} [responseText] The <code>response</code> returned by the XMLHttpRequest, if it is a {@link String}.
	 * If the <code>response</code> is not a String, this property is <code>null</code>.
	 * @property {Number} status The HTTP status code returned by the XMLHttpRequest.
	 * @property {String} url The URL that the XHR request was made to.
	 * @property {XMLHttpRequest} xhr The underlying XMLHttpRequest object.
	 * @property {String|Error} error <i>Optional</i>. If a timeout occurred or an error was thrown while performing the
	 * XMLHttpRequest, this field contains information about the error.
	 */

	/**
	 * @param {String} url
	 * @param {Object} options
	 * @param {XMLHttpRequest} xhr
	 * @param {String|Error} [error]
	 */
	function makeResult(url, options, xhr, error) {
		var response = typeof xhr.response !== 'undefined' ? xhr.response : xhr.responseText; //$NON-NLS-0$
		var responseText = typeof response === 'string' ? response : null; //$NON-NLS-0$
		var status;
		try {
			status = xhr.status;
		} catch (e) {
			status = 0;
		}
		var result = {
			args: options,
			response: response,
			responseText: responseText,
			status: status,
			url: url,
			xhr: xhr
		};
		if (typeof error !== 'undefined') { //$NON-NLS-0$
			result.error = error;
		}
		return result;
	}

	function isSameOrigin(url) {
		return new URL(location.href).origin === new URL(url, location.href).origin;
	}

	/**
	 * Wrapper for {@link XMLHttpRequest} that returns a promise.
	 * @name xhr
	 * @function
	 * @memberOf orion.xhr
	 * @param {String} method One of 'GET', 'POST', 'PUT', 'DELETE'.
	 * @param {String} url The URL to request.
	 * @param {Object} [options]
	 * @param {Object|ArrayBuffer|Blob|Document} [options.data] The raw data to send as the request body. (Only allowed for POST and PUT).
	 * @param {Object} [options.headers] A map of header names and values to set on the request.
	 * @param {Boolean} [options.log=false] If <code>true</code>, failed requests will be logged to the JavaScript console.
	 * @param {String} [options.responseType=''] Determines the type of the response object returned. Value must be one of the following:
	 * <ul><li><code>'arraybuffer'</code>
	 * <li><code>'blob'</code>
	 * <li><code>'document'</code>
	 * <li><code>'json'</code>
	 * <li><code>'text'</code>
	 * <li><code>''</code> (same as <code>'text'</code>)</ul>
	 * @param {Number} [options.timeout=0] Timeout in milliseconds. Defaults to 0 (no timeout).
	 * @returns {Deferred} A deferred for the result. The deferred will resolve on 2xx, 3xx status codes or reject on 4xx, 5xx status codes.
	 * In both cases a {@link orion.xhr.Result} is provided to the listener.
	 */
	// TODO: upload progress, user/password
	function _xhr(method, url, options/*, XMLHttpRequestImpl */) {
		options = options || {};
		url = urlModifier(url);

		var xhr = (arguments.length > 3 && arguments[3]) ? arguments[3] : new XMLHttpRequest(); //$NON-NLS-0$
		var d = new Deferred();
		var headers = options.headers || {};
		if (isSameOrigin(url)) {
			xsrfUtils.setNonceHeader(headers);
		}
		var log = options.log || false;
		var data;
		if (typeof headers['X-Requested-With'] === 'undefined') { //$NON-NLS-1$ //$NON-NLS-0$
			headers['X-Requested-With'] = 'XMLHttpRequest'; //$NON-NLS-1$ //$NON-NLS-0$
		}
		if (typeof options.data !== 'undefined' && (method === 'POST' || method === 'PUT')) { //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
			data = options.data;
		}
		
		var cancelled = false;
		var aborted = false;
		d.promise.then(undefined, function(error) {
			cancelled = true;
			if (!aborted && error instanceof Error && error.name === "Cancel") {
				xhr.abort();
			}
		});
		
		var eventSource = options.upload ? xhr.upload : xhr;
		eventSource.onabort = function() {
			aborted = true;
			if (!cancelled) {
				var cancelError = new Error("Cancel");
				cancelError.name = "Cancel";
				d.reject(cancelError);
			}
		};
		xhr.onload = function() {
			var result = makeResult(url, options, xhr);
			if (200 <= xhr.status && xhr.status < 400) {
				d.resolve(result);
			} else {
				d.reject(result);
				if(log && typeof console !== 'undefined') { //$NON-NLS-0$
					console.log(new Error(xhr.statusText));
				}
			}
		};
		eventSource.onerror = function() {
			var result = makeResult(url, options, xhr);
			d.reject(result);
			if (log && typeof console !== 'undefined') { //$NON-NLS-0$
				console.log(new Error(xhr.statusText));
			}
		};
		eventSource.onprogress = function(progressEvent) {
			progressEvent.xhr = xhr;
			d.progress(progressEvent);
		};
	
		try {
			xhr.open(method, url, true /* async */);
			if (typeof options.responseType === 'string') { //$NON-NLS-0$
				xhr.responseType = options.responseType;
			}
			if (typeof options.timeout === 'number' && util.readSetting("noTimeout") !== "true") {
				if (typeof xhr.timeout === 'number') { //$NON-NLS-0$
					// Browser supports XHR timeout
					xhr.timeout = options.timeout;
					xhr.addEventListener('timeout', function(e) { //$NON-NLS-0$
						d.reject(makeResult(url, options, xhr, 'Timeout exceeded')); //$NON-NLS-0$
					});
				} else {
					// Use our own timer
					var timeoutId = setTimeout(function() {
						d.reject(makeResult(url, options, xhr, 'Timeout exceeded')); //$NON-NLS-0$
					}, options.timeout);
					d.promise.then(clearTimeout.bind(null, timeoutId), clearTimeout.bind(null, timeoutId));
				}
			}
			Object.keys(headers).forEach(function(key) {
				xhr.setRequestHeader(key, headers[key]);
			});
			xhr.send(data || null);
		} catch (e) {
			d.reject(makeResult(url, options, xhr, e));
		}

		return d.promise;
	}
	return _xhr;
});
/*******************************************************************************
 * @license
 * Copyright (c) 2010, 2019 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 * 
 * Contributors: IBM Corporation - initial API and implementation
 ******************************************************************************/

/*eslint-env browser, amd*/
define('orion/preferences',[
	'require', 
	'orion/Deferred', 
	'orion/EventTarget', 
	'orion/xhr',
	'orion/util'], 
function(require, Deferred, _EventTarget, xhr, util) {
	
	function _mixin(target/*, source..*/) {
		var hasOwn = Object.prototype.hasOwnProperty;
		for (var j = 1, len = arguments.length; j < len; j++) {
			var source = arguments[j];
			for (var key in source) {
				if (hasOwn.call(source, key)) {
					target[key] = source[key];
				}
			}
		}
		return target;
	}

	function Cache(prefix, expiresSeconds) {
		return {
			get: function(namespace, ignoreExpires) {
				if (expiresSeconds === 0) {
					return null;
				}
				
				var item = util.readSetting(prefix + namespace);
				if (item === null) {
					return null;
				}
				
				try {
					var cached = JSON.parse(item);
					if (ignoreExpires || expiresSeconds === -1 || (cached._expires && cached._expires > Date.now())) {
						delete cached._expires;
						return cached;
					}
				} catch (e) {
					//invalid value; remove from cache.
					util.deleteSetting(prefix + namespace);
				}
				
				return null;
			},
			set: function(namespace, data) {
				if (expiresSeconds === 0) {
					return;
				}
				
				if (expiresSeconds !== -1) {
					data._expires = Date.now() + 1000 * expiresSeconds;
				}
				if (Object.keys(data).length === 0) {
					util.deleteSetting(prefix + namespace);
				} else {
					var jsonData = JSON.stringify(data);
					util.saveSetting(prefix + namespace, jsonData);
					delete data._expires;
				}
			},
			remove: function(namespace) {
				util.deleteSetting(prefix + namespace);
			}
		};
	}

	function UserPreferencesProvider(serviceRegistry) {
		this._currentPromises = {};
		this._cache = new Cache("/orion/preferences/user", 60*60); //$NON-NLS-0$
		
		this._service = null;
		this.available = function() {
			if (!this._service) {
				var references = serviceRegistry.getServiceReferences("orion.core.preference.provider"); //$NON-NLS-0$
				if (references.length > 0) {
					this._service = serviceRegistry.getService(references[0]);
				}
			}
			return !!this._service;
		};
	}

	UserPreferencesProvider.prototype = {
		get: function(namespace, optForce) {
			if (this._currentPromises[namespace]) {
				return this._currentPromises[namespace];
			}
			var d = new Deferred();
			var cached = null;
			if (optForce) {
				this._cache.remove(namespace);
			} else {
				cached = this._cache.get(namespace);
			}
			if (cached !== null) {
				d.resolve(cached);
			} else {
				this._currentPromises[namespace] = d;
				var that = this;
				this._service.get(namespace).then(function(data) {
					data = data || {};
					that._cache.set(namespace, data);
					delete that._currentPromises[namespace];
					d.resolve(data);
				}, function (error) {
					if (error.status === 404 || error.status === 410) {
						var data = {};
						that._cache.set(namespace, data);
						delete that._currentPromises[namespace];
						d.resolve(data);
					} else  {
						delete that._currentPromises[namespace];
						d.resolve(that._cache.get(namespace, true) || {});
					}
				});
			}
			return d;
		},
		
		put: function(namespace, data) {
			this._cache.set(namespace, data);
			return this._service.put(namespace, data);
		},
		
		remove: function(namespace, key){
			var cached = this._cache.get(namespace);
			delete cached[key];
			this._cache.set(namespace, cached);
			return this._service.remove(namespace, key);
		}
	};

	function DefaultPreferencesProvider(_location) {
		_location = _location || "defaults.pref"; //$NON-NLS-0$
		if (_location.indexOf("://") === -1) { //$NON-NLS-0$
			_location = require.toUrl ? require.toUrl(_location) : _location;
		}
		this._location = _location;
		this._currentPromise = null;
		this._cache = new Cache("/orion/preferences/default", 60*60); //$NON-NLS-0$
	}

	DefaultPreferencesProvider.prototype = {
		
		get: function(namespace, optForce) {
			var cached = null;
			var that = this;
			if (this._currentPromise) {
				return this._currentPromise.then(function() {
					cached = that._cache.get(namespace);
					if (cached === null) {
						cached = {};
						that._cache.set(namespace, cached);
					}
					return cached;
				});
			}
			var d = new Deferred();
			if (optForce) {
				this._cache.remove(namespace);
			} else {
				cached = this._cache.get(namespace);
			}
			if (cached !== null) {
				d.resolve(cached);
			} else {
				this._currentPromise = d;
				xhr("GET", this._location, { //$NON-NLS-0$
					headers: {
						"Orion-Version": "1" //$NON-NLS-0$
					},
					timeout: 15000
				}).then(function(result) {
					var data = JSON.parse(result.response);
					Object.keys(data).forEach(function(key) {
						that._cache.set(key, data[key] || {});
					});
					cached = data[namespace];
					if (!cached) {
						cached = {};
						that._cache.set(namespace, cached);
					}
					that._currentPromise = null;
					d.resolve(cached);
				}, function(error) {
					if (error.xhr.status === 401 || error.xhr.status === 491 || error.xhr.status === 404 ) {
						that._cache.set(namespace, {});
						that._currentPromise = null;
						d.resolve({});
					} else {
						that._currentPromise = null;
						var data = that._cache.get(namespace, true);
						if (data !== null) {
							d.resolve(data[namespace] || {});
						} else {
							d.resolve({});
						}
					}
				});
			}
			return d;
		},
		/**
		 * @callback
		 */
		put: function(namespace, data) {
			var d = new Deferred();
			d.resolve();
			return d;
		},
		remove: function(namespace, key){
			var cached = this._cache.get(namespace);
			delete cached[key];
			this.put(namespace, cached);
		}
	};
	
	function LocalPreferencesProvider() {
		this._cache = new Cache("/orion/preferences/local", -1); //$NON-NLS-0$
	}

	LocalPreferencesProvider.prototype = {
		get: function(namespace) {
			var d = new Deferred();
			var cached = this._cache.get(namespace);
			if (cached !== null) {
				d.resolve(cached);
			} else {
				d.resolve({});
			}
			return d;
		},
		put: function(namespace, data) {
			var d = new Deferred();
			this._cache.set(namespace, data);
			d.resolve();
			return d;
		},
		remove: function(namespace, key){
			var cached = this._cache.get(namespace);
			delete cached[key];
			this.put(namespace, cached);
		}
	};
	
	function PreferencesEvent(type, namespace, scope) {
		this.type = type;
		this.namespace = namespace;
		this.scope = scope;
	}

	/**
	 * Dispatched when a preferences node has been changed. The type of this event is <code>"changed"</code>.
	 * @name orion.PreferencesService#changed
	 * @event
	 */
	/**
	 * Constructs a new preference service. Clients should obtain a preference service
	 * by requesting the service <tt>orion.core.preference</tt> from the service registry.
	 * This service constructor is only intended to be used by page service registry
	 * initialization code.
	 * @class The preferences service manages a hierarchical set of preference
	 * nodes. Each node consists of preference key/value pairs. 
	 * @name orion.preferences.PreferencesService
	 * @see orion.preferences.Preferences
	 * @borrows orion.serviceregistry.EventTarget#addEventListener as #addEventListener
	 * @borrows orion.serviceregistry.EventTarget#removeEventListener as #removeEventListener
	 */
	function PreferencesService(serviceRegistry, options) {
		options = options || {};
		this._changeListeners = [];
		this._userProvider = options.userProvider || new UserPreferencesProvider(serviceRegistry);
		this._localProvider = options.localProvider || new LocalPreferencesProvider();
		this._defaultsProvider = options.defaultsProvider || new DefaultPreferencesProvider(options.defaultPreferencesLocation);
		_EventTarget.attach(this);
		window.addEventListener("storage", function(evt) {
			var key = evt.key;
			var prefix = "/orion/preferences/"; //$NON-NLS-1$
			if (!key || key.indexOf(prefix) !== 0) return;
			var index = key.indexOf("/", prefix.length);
			var namespace = key.substring(index);
			var scope = {"default": PreferencesService.DEFAULT_SCOPE, local: PreferencesService.LOCAL_SCOPE, user: PreferencesService.USER_SCOPE}[key.substring(prefix.length, index)];
			this.dispatchEvent(new PreferencesEvent("changed", namespace, scope)); //$NON-NLS-1$
		}.bind(this), false);
		this._serviceRegistration = serviceRegistry.registerService("orion.core.preference", this); //$NON-NLS-0$
	}

	PreferencesService.DEFAULT_SCOPE = 1;
	PreferencesService.LOCAL_SCOPE = 2;
	PreferencesService.USER_SCOPE = 4;
	
	PreferencesService.prototype = /** @lends orion.preferences.PreferencesService.prototype */ {

		/**
		 * @private this is intended to be used by the metrics services
		 * @name addChangeListener
		 * @description description
		 * @function
		 * @param callback
		 * @returns returns
		 */
		addChangeListener: function(callback) {
			if (typeof(callback) === "function") { //$NON-NLS-0$
				this._changeListeners.push(callback);
			}
		},

		/**
		 * @name get
		 * @description Gets one or more preferences from the node specified by <code>namespace</code>.
		 * @function
		 * @param {String} namespace A slash-delimited path to the preference node to get
		 * @param {String|Array|Object} [key=undefined] the key, or array of keys, or an object specifying the default
		 *         values of the keys to get. An empty array or object will return an empty object. Pass in <code>null</code> or <code>undefined</code
		 *         to get all the preferences of the specified node.
		 * @param options the options object
		 * @returns A promise that will resolve when the preferences has been retrivied. The promise result is an object with key-value mappings.
		 */
		get: function(namespace, key, options) {
			options = options || {};
			var providers = this._getProviders(options.scope);
			var gets = [];
			providers.reverse().forEach(function(provider) {
				gets.push(provider.get(namespace, options.noCache));
			});
			return Deferred.all(gets).then(function(stores) {
				var result = {};
				if (key && typeof key !== "string" && !Array.isArray(key)) { result = _mixin(result, key); }
				stores.forEach(function(store) {
					if (!store) { return; }
					function addKey(key) {
						if (key in store) {
							if(typeof store[key] === 'object' && store[key] !== null) {
								if(typeof result[key] === 'undefined') {
									result[key] = store[key];
								} else {
									result[key] = _mixin(result[key], store[key]);
								}
							} else {
								result[key] = store[key];
							}
						}
					}
					if (!key) {
						Object.keys(store).forEach(addKey);
					} else if (typeof key === "string") {
						addKey(key);
					} else if (Array.isArray(key)) {
						key.forEach(addKey);
					} else {
						Object.keys(key).forEach(addKey);
					}
				});
				return result;
			});
		},

		/**
		 * @name put
		 * @description Sets multiple preferences in the node specified by <code>namespace</code>.
		 * @function
		 * @param {String} namespace A slash-delimited path to the preference node to update
		 * @param data An object with key-value pairs to update. Any other key/value pairs in the node will not be affected unless the
		 *        options <code>clear</code> is set.
		 * @param options the options object
		 * @returns A promise that will resolve when the preferences has been updated.
		 */
		put: function(namespace, data, options) {
			var that = this;
			options = options || {};
			var provider = this._getProviders(options.scope)[0];
			return provider.get(namespace).then(function(store) {
				var newStore = data;
				if (!options.clear) {
					newStore  = _mixin({}, store, newStore);
				}
				if (JSON.stringify(store) === JSON.stringify(newStore)) return;
				
				that._valueChanged(namespace, data, store);
				
				return provider.put(namespace, newStore);
			});
		},

		/**
		 * @name remove
		 * @description Removes one or more preferences in the node specified by <code>namespace</code>.
		 * @function
		 * @param {String} namespace A slash-delimited path to the preference node to update
		 * @param {String|Array|Object} [key=undefined] the key, or array of keys, or an object specifying the
		 *         the keys to remove. An empty array or object will remove nothing. Pass in <code>null</code> or <code>undefined</code>
		 *         to remove all the preferences of the specified node.
		 * @param options the options object
		 * @returns A promise that will resolve when the preferences has been updated.
		 */
		remove: function(namespace, key, options) {
			options = options || {};
			var provider = this._getProviders(options.scope)[0];
			return provider.get(namespace).then(function(store) {
				function deleteKey(key) {
					if (key in store) {
						delete store[key];
					}
				}
				if (!key) {
					Object.keys(store).forEach(deleteKey);
				} else if (typeof key === "string") {
					deleteKey(key);
				} else if (Array.isArray(key)) {
					key.forEach(deleteKey);
				} else {
					Object.keys(key).forEach(deleteKey);
				}
				return provider.put(namespace, store);
			});
		},
		
		/**
		 * @private
		 */
		_getProviders: function(optScope) {
			if (!optScope || typeof(optScope) !== "number" || optScope > 7 || optScope < 1) { //$NON-NLS-0$
				optScope = PreferencesService.DEFAULT_SCOPE;
				optScope |= this._userProvider.available() ? PreferencesService.USER_SCOPE : PreferencesService.LOCAL_SCOPE;
			}
			var providers = [];
			if ((PreferencesService.USER_SCOPE & optScope) && this._userProvider.available()) {
				providers.push(this._userProvider);
			}
			if (PreferencesService.LOCAL_SCOPE & optScope) {
				providers.push(this._localProvider);
			}
			if (PreferencesService.DEFAULT_SCOPE & optScope) {
				providers.push(this._defaultsProvider);
			}
			return providers;
		},

		/**
		 * @private
		 */
		_valueChanged: function(namespace, data, store) {
			if (!this._changeListeners.length) return;
			var that = this;
			function callChangeListener(key, value) {
				that._changeListeners.forEach(function(current) {
					current(key, value);
				});
			}
			for (var key in data) {
				var changeKey = namespace + "/" + key; //$NON-NLS-0$
				var value = data[key];
				if (typeof(value) === "string") { //$NON-NLS-0$
					callChangeListener(changeKey, value);
				} else {
					for (var current in value) {
						if (current !== "pid" && (!store || !store[key] || store[key][current] !== value[current])) { //$NON-NLS-0$
							var stringValue = String(value[current]);
							callChangeListener(changeKey + "/" + current, stringValue); //$NON-NLS-0$
						} 
					}
				}
			}
		},

		/**
		 * @private this is intended to be used by the metrics services
		 * @name removeChangeListener
		 * @description description
		 * @function
		 * @param callback
		 * @returns returns
		 */
		removeChangeListener: function(callback) {
			if (typeof(callback) === "function") { //$NON-NLS-0$
				for (var i = 0; i < this._changeListeners.length; i++) {
					if (this._changeListeners[i] === callback) {
						this._changeListeners.splice(i, 1);
						return;
					}
				}
			}
		}
	};
	return {
		PreferencesService: PreferencesService,
		Cache: Cache
	};
});

/*******************************************************************************
 * @license
 * Copyright (c) 2010, 2019 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
/* eslint-disable missing-nls */
/*eslint-env browser, amd*/
/*global URL*/
define('orion/pluginregistry',[
    "orion/Deferred",
    "orion/util",
    "orion/EventTarget", 
    "orion/urlModifier", 
    "orion/URL-shim"
], function(Deferred, util, EventTarget, urlModifier) {
    
    function _equal(obj1, obj2) {
        var keys1 = Object.keys(obj1);
        var keys2 = Object.keys(obj2);
        if (keys1.length !== keys2.length) {
            return false;
        }
        keys1.sort();
        keys2.sort();
        for (var i = 0, len = keys1.length; i < len; i++) {
            var key = keys1[i];
            if (key !== keys2[i]) {
                return false;
            }
            var value1 = obj1[key],
                value2 = obj2[key];
            if (value1 === value2) {
                continue;
            }
            if (JSON.stringify(value1) !== JSON.stringify(value2)) {
                return false;
            }
        }
        return true;
    }
    
    function _mixin(target/*, source..*/) {
		var hasOwnProperty = Object.prototype.hasOwnProperty;
		for (var j = 1, len = arguments.length; j < len; j++) {
			var source = arguments[j];
			for (var key in source) {
				if (hasOwnProperty.call(source, key)) {
					target[key] = source[key];
				}
			}
		}
		return target;
	}

    var httpOrHttps = new RegExp("^http[s]?", "i");

    function _normalizeURL(url) {
        if (url.indexOf("://") === -1) { //$NON-NLS-0$
            try {
                return new URL(url, location.href).href;
            } catch (e) {
                // URL SyntaxError, etc.
            }
        }
        return url;
    }

    function _asStorage(obj) {
        var _keys = null;

        function _getKeys() {
            return (_keys = _keys || Object.keys(obj));
        }

        var result = {
            key: function(index) {
                return _getKeys()[index];
            },
            getItem: function(key) {
                return obj[key];
            },
            setItem: function(key, value) {
                obj[key] = value;
                _keys = null;
            },
            removeItem: function(key) {
                delete obj[key];
                _keys = null;
            },
            clear: function() {
                _getKeys().forEach(function(key) {
                    delete obj[key];
                }.bind(this));
                _keys = null;
            }
        };
        Object.defineProperty(result, "length", {
            get: function() {
                return _getKeys().length;
            }
        });
        return result;
    }

    function _jsonXMLHttpRequestReplacer(name, value) {
        if (value && value instanceof XMLHttpRequest) {
            var status, statusText;
            try {
                status = value.status;
                statusText = value.statusText;
            } catch (e) {
                // https://bugs.webkit.org/show_bug.cgi?id=45994
                status = 0;
                statusText = ""; //$NON-NLS-0
            }
            return {
                status: status || 0,
                statusText: statusText
            };
        }
        return value;
    }

    function _serializeError(error) {
        var result = error ? JSON.parse(JSON.stringify(error, _jsonXMLHttpRequestReplacer)) : error; // sanitizing Error object
        if (error instanceof Error) {
            result.__isError = true;
            result.message = result.message || error.message;
            result.name = result.name || error.name;
        }
        return result;
    }

    function PluginEvent(type, plugin) {
        this.type = type;
        this.plugin = plugin;
    }

    function ObjectReference(objectId, methods) {
        this.__objectId = objectId;
        this.__methods = methods;
    }
    
    var VERSION = 15.0; // This version is used to flush plugin metadata

    /**
     * Creates a new plugin. This constructor is private and should only be called by the plugin registry.
     * @class Represents a single plugin in the plugin registry.
     * @description
     * <p>At any given time, a plugin is in exactly one of the following six states:</p>
     *
     * <dl>
     *
     * <dt><code>"uninstalled"</code></dt>
     * <dd>The plugin has been uninstalled and may not be used.
     * <p>The <code>uninstalled</code> state is only visible after a plugin has been uninstalled; the plugin is unusable, but
     * references to its <code>Plugin</code> object may still be available and used for introspection.
     * </dd>
     *
     * <dt><code>"installed"</code></dt>
     * <dd>The plugin is installed, but not yet resolved.
     * <p></p>
     * </dd>
     *
     * <dt><code>"resolved"</code></dt>
     * <dd>The plugin is resolved and is able to be started.
     * <p>Note that the plugin is not active yet. A plugin must be in the <code>resolved</code> state before it can be started.</p>
     * <p>The <code>resolved</code> state is reserved for future use. Future versions of the framework may require successful
     * dependency resolution before moving a plugin to the <code>resolved</code> state.</p>
     * </dd>
     *
     * <dt><code>"starting"</code></dt>
     * <dd>The plugin is in the process of starting.
     * <p>A plugin is in the <code>starting</code> state when its {@link #start} method has been called but has not yet resolved.
     * Once the start call resolves, the plugin has successfully started and moves to the <code>active</code> state.</p>
     * <p>If the plugin has a lazy activation policy, it may remain in the <code>starting</code> state for some time until the
     * activation is triggered.</p>
     * </dd>
     *
     * <dt><code>"stopping"</code></dt>
     * <dd>The plugin is in the process of stopping. 
     * <p>A plugin is in the <code>stopping</code> state when its {@link #stop} method has been called but not yet resolved.
     * Once the stop call resolves, the plugin moves to the <code>resolved</code> state.</dd>
     *
     * <dt><code>"active"</code></dt>
     * <dd>The plugin is running. It has been successfully started and activated.
     * <p>In the <code>active</code> state, any services the plugin provides are available for use.</p></dd>
     *
     * </dl>
     *
     * @name orion.pluginregistry.Plugin
     */
    function Plugin(_url, _manifest, _internalRegistry) {
        var _this = this;
        _manifest = _manifest || {};
        var _created = _manifest.created || Date.now();
        var _headers = _manifest.headers || {};
        var _services = _manifest.services || [];
        var _autostart = _manifest.autostart;
        var _lastModified = _manifest.lastModified || 0;
        var _metadataVersion = _manifest.metadataVersion;

        var _state = "installed";

        var _deferredStateChange;
        var _deferredLoad;

        var _channel;
        var _parent;
        var _remoteServices = {};

        var _currentMessageId = 0;
        var _currentObjectId = 0;

        var _requestReferences = {};
        var _responseReferences = {};
        var _objectReferences = {};
        var _serviceReferences;


        function _notify(message) {
            if (!_channel) {
                return;
            }
            _internalRegistry.postMessage(message, _channel);
        }

        function _request(message) {
            if (!_channel) {
                return new Deferred().reject(new Error("plugin not connected"));
            }

            message.id = String(_currentMessageId++);
            var d = new Deferred();
            _responseReferences[message.id] = d;
            d.then(null, function(error) {
                if (_state === "active" && error instanceof Error && error.name === "Cancel") {
                    _notify({
                        requestId: message.id,
                        method: "cancel",
                        params: error.message ? [error.message] : []
                    });
                }
            });

            var toStr = Object.prototype.toString;
            message.params.forEach(function(param, i) {
                if (toStr.call(param) === "[object Object]" && !(param instanceof ObjectReference)) {
                    var candidate, methods;
                    for (candidate in param) {
                        if (toStr.call(param[candidate]) === "[object Function]") {
                            methods = methods || [];
                            methods.push(candidate);
                        }
                    }
                    if (methods) {
                        var objectId = _currentObjectId++;
                        _objectReferences[objectId] = param;
                        var removeReference = function() {
                            delete _objectReferences[objectId];
                        };
                        d.then(removeReference, removeReference);
                        message.params[i] = new ObjectReference(objectId, methods);
                    }
                }
            });
            _internalRegistry.postMessage(message, _channel);
            return d.promise;
        }

        function _throwError(messageId, error) {
            if (messageId || messageId === 0) {
                _notify({
                    id: messageId,
                    result: null,
                    error: error
                });
            } else {
                console.log(error);
            }
        }

        function _callMethod(messageId, implementation, method, params) {
            params.forEach(function(param, i) {
                if (param && typeof param.__objectId !== "undefined") {
                    var obj = {};
                    param.__methods.forEach(function(method) {
                        obj[method] = function() {
                            return _request({
                                objectId: param.__objectId,
                                method: method,
                                params: Array.prototype.slice.call(arguments)
                            });
                        };
                    });
                    params[i] = obj;
                }
            });

            var response = typeof messageId === "undefined" ? null : {
                id: messageId,
                result: null,
                error: null
            };
            try {
                var promiseOrResult = method.apply(implementation, params);
                if (!response) {
                    return;
                }

                if (promiseOrResult && typeof promiseOrResult.then === "function") { //$NON-NLS-0$
                    _requestReferences[messageId] = promiseOrResult;
                    promiseOrResult.then(function(result) {
                        delete _requestReferences[messageId];
                        response.result = result;
                        _notify(response);
                    }, function(error) {
                        if (_requestReferences[messageId]) {
                            delete _requestReferences[messageId];
                            response.error = _serializeError(error);
                            _notify(response);
                        }
                    }, function() {
                        _notify({
                            responseId: messageId,
                            method: "progress",
                            params: Array.prototype.slice.call(arguments)
                        }); //$NON-NLS-0$
                    });
                } else {
                    response.result = promiseOrResult;
                    _notify(response);
                }
            } catch (error) {
                if (response) {
                    response.error = _serializeError(error);
                    _notify(response);
                }
            }
        }


        var _update; // this is a forward reference to a function declared above this.update

        function _messageHandler(message) {
            try {
                if (message.method) { // request
                    var method = message.method,
                        params = message.params || [];
                    if ("serviceId" in message) {
                        var service = _serviceReferences[message.serviceId];
                        if (!service) {
                            _throwError(message.id, "service not found");
                        } else if (_isTrusted(service)) {
                        	var serviceRegistry = _internalRegistry.serviceRegistry;
	                        service = serviceRegistry.getService(service);
	                        if (method in service) {
	                            _callMethod(message.id, service, service[method], params);
	                        } else {
	                            _throwError(message.id, "method not found");
	                        }
                    	} else {
                    		_throwError(message.id, "not trusted");
                    	}
                    } else if ("objectId" in message) {
                        var object = _objectReferences[message.objectId];
                        if (!object) {
                            _throwError(message.id, "object not found");
                        } else if (method in object) {
                            _callMethod(message.id, object, object[method], params);
                        } else {
                            _throwError(message.id, "method not found");
                        }
                    } else if ("requestId" in message) {
                        var request = _requestReferences[message.requestId];
                        if (request && method === "cancel" && request.cancel) {
                            request.cancel.apply(request, params);
                        }
                    } else if ("responseId" in message) {
                        var response = _responseReferences[message.responseId];
                        if (response && method === "progress" && response.progress) {
                            response.progress.apply(response, params);
                        }
                    } else if ("loading" === message.method) {
                        _channel.loading();
                    } else {
                        if ("plugin" === message.method) { //$NON-NLS-0$
                            _channel.connected();
                            var manifest = message.params[0];
                            _update({
                                headers: manifest.headers,
                                services: manifest.services
                            }).then(function() {
                                if (_deferredLoad) {
                                    _deferredLoad.resolve(_this);
                                }
                            });
                            if (manifest.updateRegistry) {
                            	_updateRemoteRegistry();
                        	}
                        } else if ("timeout" === message.method || "error" === message.method) {
                            if (_deferredLoad) {
                                _deferredLoad.reject(message.error);
                            }
                        } else {
                            throw new Error("Bad method: " + message.method);
                        }
                    }
                } else if (message.id) {
                    var deferred = _responseReferences[String(message.id)];
                    if (deferred) {
	                    delete _responseReferences[String(message.id)];
	                    if (message.error) {
	                        var error = _internalRegistry.handleServiceError(_this, message.error);
	                        deferred.reject(error);
	                    } else {
	                        deferred.resolve(message.result);
	                    }
                    }
                }
            } catch (e) {
                console.log("Plugin._messageHandler " + e);
            }
        }

        function _createServiceProxy(service) {
            var serviceProxy = {};
            if (service.methods) {
                service.methods.forEach(function(method) {
                    serviceProxy[method] = function() {
                        var message = {
                            serviceId: service.serviceId,
                            method: method,
                            params: Array.prototype.slice.call(arguments)
                        };
                        if (_state === "active") {
                            return _request(message);
                        } else {
                            return _this.start({
                                "transient": true
                            }).then(function() {
                                return _request(message);
                            });
                        }
                    };
                });

                if (serviceProxy.addEventListener && serviceProxy.removeEventListener) {
                    var eventTarget = new EventTarget();
                    var objectId = _currentObjectId++;
                    _objectReferences[objectId] = {
                        handleEvent: eventTarget.dispatchEvent.bind(eventTarget)
                    };
                    var listenerReference = new ObjectReference(objectId, ["handleEvent"]);

                    var _addEventListener = serviceProxy.addEventListener;
                    serviceProxy.addEventListener = function(type, listener) {
                        if (!eventTarget._namedListeners[type]) {
                            _addEventListener(type, listenerReference);
                        }
                        eventTarget.addEventListener(type, listener);
                    };
                    var _removeEventListener = serviceProxy.removeEventListener;
                    serviceProxy.removeEventListener = function(type, listener) {
                        eventTarget.removeEventListener(type, listener);
                        if (!eventTarget._namedListeners[type]) {
                            _removeEventListener(type, listenerReference);
                        }
                    };
                }
            }
            return serviceProxy;
        }

        function _createServiceProperties(service) {
            var properties = JSON.parse(JSON.stringify(service.properties));
            properties.__plugin__ = _url; //TODO: eliminate
            var objectClass = service.names || service.type || [];
            if (!Array.isArray(objectClass)) {
                objectClass = [objectClass];
            }
            properties.objectClass = objectClass;
            return properties;
        }

        function _registerService(service) {
            var serviceProxy = _createServiceProxy(service);
            var properties = _createServiceProperties(service);
            var registration = _internalRegistry.registerService(service.names || service.type, serviceProxy, properties);
            _remoteServices[service.serviceId] = {
                registration: registration,
                proxy: serviceProxy
            };
        }
        
        function _getPluginData() {
            var services = [];
            Object.keys(_serviceReferences).forEach(function(serviceId) {
                var serviceReference = _serviceReferences[serviceId];
                var properties = {};
                serviceReference.getPropertyKeys().forEach(function(key) {
                	properties[key] = serviceReference.getProperty(key);
                });
                ["service.id", "service.names", "objectClass", "__plugin__"].forEach(function(key) {
	                delete properties[key];
                });
                var methods = [];
                var serviceRegistry = _internalRegistry.serviceRegistry;
                var implementation = serviceRegistry.getService(serviceReference);
	            for (var method in implementation) {
	                if (typeof implementation[method] === 'function') {
	                    methods.push(method);
	                }
	            }
                services.push({
                    serviceId: String(serviceReference.getProperty('service.id')),
                    names: serviceReference.getProperty('service.names'),
                    methods: methods,
                    properties: properties
                });
            });
            return {
                services: services
            };
        }
        
        function _isTrusted(serviceReference) {
        	var pluginUrl = new URL(_url);
        	// if plugin is from same origin of host page, it has access to all references
        	if (pluginUrl.origin === location.origin) return true;
        	var refUrl = serviceReference.getProperty("__plugin__");
        	// if plugin is from same origin of reference, it has access to this reference
        	return pluginUrl.origin === (refUrl ? new URL(refUrl) : location).origin;
        }
        
        var _registerListener, _unregisterListener, _modifiedListerner;
        function _updateRemoteRegistry() {
        	if (!_serviceReferences) {
        		_serviceReferences = {};
        		var serviceRegistry = _internalRegistry.serviceRegistry;
        		serviceRegistry.getServiceReferences().forEach(function(serviceReference) {
		        	if (_isTrusted(serviceReference)) {
		        		_serviceReferences[serviceReference.getProperty('service.id')] = serviceReference;
	        		}
        		});
        		function updateReference(add, remove, evt) {
        			var serviceReference = evt.serviceReference;
		        	var id = serviceReference.getProperty('service.id');
		        	if (!_serviceReferences[id] && _isTrusted(serviceReference)) {
		        		if (add) _serviceReferences[id] = serviceReference;
		        		if (remove) delete _serviceReferences[id];
			        	_updateRemoteRegistry();
		        	}
		        }
		        serviceRegistry.addEventListener("registered", _registerListener = updateReference.bind(null, true, false));
		        serviceRegistry.addEventListener("unregistered", _unregisterListener = updateReference.bind(null, false, true));
		        serviceRegistry.addEventListener("modified", _modifiedListerner = updateReference.bind(null, false, false));
        	}
    		_request({
                method: "plugin",
                params: [_getPluginData()]
             });
        }
        
        function _removeListeners() {
    		var serviceRegistry = _internalRegistry.serviceRegistry;
    		if (_registerListener) serviceRegistry.removeEventListener("registered", _registerListener);
	        if (_unregisterListener) serviceRegistry.removeEventListener("unregistered", _unregisterListener);
	        if (_modifiedListerner) serviceRegistry.removeEventListener("modified", _modifiedListerner);
	        _registerListener = _unregisterListener = _modifiedListerner = null;
        }

        function _persist() {
            _internalRegistry.persist(_url, {
                created: _created,
                headers: _headers,
                services: _services,
                autostart: _autostart,
                metadataVersion: VERSION,
                lastModified: _lastModified
            });
        }
        
        this._default = false; // used to determine if a plugin is part of the configuration

        this._persist = _persist;

        this._resolve = function() {
            // check manifest dependencies when we support them
            _state = "resolved";
            _internalRegistry.dispatchEvent(new PluginEvent("resolved", _this));
        };

        this._getAutostart = function() {
            return _autostart;
        };

        this._getCreated = function() {
            return _created;
        };

        /**
         * Returns the URL location of this plugin.
         * @name orion.pluginregistry.Plugin#getLocation
         * @return {String} The URL of this plugin.
         * @function
         */
        this.getLocation = function() {
            return _url;
        };

        /**
         * Returns the headers of this plugin.
         * @name orion.pluginregistry.Plugin#getHeaders
         * @return {Object} The plugin headers.
         * @function
         */
        this.getHeaders = function() {
            return JSON.parse(JSON.stringify(_headers));
        };

        this.getName = function() {
            var headers = this.getHeaders();
            if (headers) {
                return headers.name || "";
            }
            return null;
        };

        this.getVersion = function() {
            var headers = this.getHeaders();
            if (headers) {
                return headers.version || "0.0.0";
            }
            return null;
        };

        this.getLastModified = function() {
            return _lastModified;
        };

        /**
         * Returns the service references provided by this plugin.
         * @name orion.pluginregistry.Plugin#getServiceReferences
         * @return {orion.serviceregistry.ServiceReference[]} The service references provided by this plugin.
         * @function 
         */
        this.getServiceReferences = function() {
            var result = [];
            Object.keys(_remoteServices).forEach(function(serviceId) {
                result.push(_remoteServices[serviceId].registration.getReference());
            });
            return result;
        };

        /**
         * Sets the parent of this plugin.
         * @name orion.pluginregistry.Plugin#setParent
         * @param {DOMElement} [parent=null] the plugin parent. <code>null</code> puts the plugin in the default parent of the plugin registry
         * @return {orion.Promise} A promise that will resolve when the plugin parent has been set.
         * @function 
         */
        this.setParent = function(parent) {
            if (_parent !== parent) {
                _parent = parent;
                return _this.stop({
                    "transient": true
                }).then(function() {
                    if ("started" === _autostart) {
                        return _this.start({
                            "transient": true
                        });
                    } else if ("lazy" === _autostart) {
                        return _this.start({    
                            "lazy": true,
                            "transient": true
                        });
                    }
                });    
            }
            return new Deferred().resolve();
        };

        /**
         * Returns this plugin's current state.
         * @name orion.pluginregistry.Plugin#getState
         * @returns {String} This plugin's state.
         * @function
         */
        this.getState = function() {
            return _state;
        };
        
         /**
         * @name orion.pluginregistry.Plugin#getProblemLoading
         * @description Returns true if there was a problem loading this plug-in, false otherwise. This function is not API and may change in future releases.
         * @private
         * @function
         * @returns {String} Return an true if there was a problem loading this plug-in.
         */
        this.getProblemLoading = function() {
            if (_this._problemLoading){
                return true;
            }
            return false;
        };

        this.start = function(optOptions) {
            if (_state === "uninstalled") {
                return new Deferred().reject(new Error("Plugin is uninstalled"));
            }

            if (_deferredStateChange) {
                return _deferredStateChange.promise.then(this.start.bind(this, optOptions));
            }

            if (_state === "active") {
                return new Deferred().resolve();
            }

            if (!optOptions || !optOptions.transient) {
                var autostart = optOptions && optOptions.lazy ? "lazy" : "started";
                if (autostart !== _autostart) {
                    _autostart = autostart;
                    _persist();
                }
            }

            var frameworkState = _internalRegistry.getState();
            if (frameworkState !== "starting" && frameworkState !== "active") {
                if (optOptions.transient) {
                    return new Deferred().reject(new Error("start transient error"));
                }
                return new Deferred().resolve();
            }

            if (_state === "installed") {
                try {
                    this._resolve();
                } catch (e) {
                    return new Deferred().reject(e);
                }
            }

            if (_state === "resolved") {
                _services.forEach(function(service) {
                    _registerService(service);
                });
            }

            if (optOptions && optOptions.lazy) {
                if (_state !== "starting") {
                    _state = "starting";
                    _internalRegistry.dispatchEvent(new PluginEvent("lazy activation", _this));
                }
                var now = Date.now();
		        if (!this.getLastModified() || now > this.getLastModified() + 86400000 || _metadataVersion !== VERSION) { // 24 hours
	                 return this.update();
                }
                return new Deferred().resolve();
            }
            
            var deferredStateChange = new Deferred();
            _deferredStateChange = deferredStateChange;
            _state = "starting";
            _this._problemLoading = null;
            _internalRegistry.dispatchEvent(new PluginEvent("starting", _this));
            _deferredLoad = new Deferred();
            _channel = _internalRegistry.connect(_url, _messageHandler, _parent);
            _deferredLoad.then(function() {
                _deferredLoad = null;
                _state = "active";
                _internalRegistry.dispatchEvent(new PluginEvent("started", _this));
                _deferredStateChange = null;
                deferredStateChange.resolve();
            }, function(error) {
                _deferredLoad = null;
                _state = "stopping";
                _internalRegistry.dispatchEvent(new PluginEvent("stopping", _this));
                Object.keys(_remoteServices).forEach(function(serviceId) {
                    _remoteServices[serviceId].registration.unregister();
                    delete _remoteServices[serviceId];
                });
                _internalRegistry.disconnect(_channel);
                _channel = null;
                _state = "resolved";
                _deferredStateChange = null;
                _internalRegistry.dispatchEvent(new PluginEvent("stopped", _this));
                _this._problemLoading = true;
                deferredStateChange.reject(new Error("Failed to load plugin: " + _url + (error && error.message ? "\n    Reason: " + error.message : "")));
                if (_this._default) {
                    _lastModified = 0;
                    _persist();
                }
            });
            return deferredStateChange.promise;
        };

        this.stop = function(optOptions) {
            if (_state === "uninstalled") {
                return new Deferred().reject(new Error("Plugin is uninstalled"));
            }

            if (_deferredStateChange) {
                return _deferredStateChange.promise.then(this.stop.bind(this, optOptions));
            }

            if (!optOptions || !optOptions.transient) {
                if ("stopped" !== _autostart) {
                    _autostart = "stopped";
                    _persist();
                }
            }

            if (_state !== "active" && _state !== "starting") {
                return new Deferred().resolve();
            }

            var deferredStateChange = new Deferred();
            _deferredStateChange = deferredStateChange;

            _state = "stopping";
            _internalRegistry.dispatchEvent(new PluginEvent("stopping", _this));
            Object.keys(_remoteServices).forEach(function(serviceId) {
                _remoteServices[serviceId].registration.unregister();
                delete _remoteServices[serviceId];
            });
            if (_channel) {
                _internalRegistry.disconnect(_channel);
                _channel = null;
                _removeListeners();
            }
            _state = "resolved";
            _deferredStateChange = null;
            _internalRegistry.dispatchEvent(new PluginEvent("stopped", _this));
            deferredStateChange.resolve();

            return deferredStateChange.promise;
        };

        _update = function(input) {
            _this.problemLoading = null;
            
            if (_state === "uninstalled") {
                return new Deferred().reject(new Error("Plugin is uninstalled"));
            }

            if (!input) {
                if (_lastModified === 0) {
                    _lastModified = Date.now();
                    _persist();
                }
                return _internalRegistry.loadManifest(_url).then(_update, function() {
                    _this._problemLoading = true;
                    if (_this._default) {
                        _lastModified = 0;
                        _persist();
                    }
                    console.log("Failed to load plugin: " + _url);
                });
            }

            var oldHeaders = _headers;
            var oldServices = _services;
            var oldAutostart = _autostart;
            _headers = input.headers || {};
            _services = input.services || [];
            _autostart = input.autostart || _autostart;

            if (input.lastModified) {
                _lastModified = input.lastModified;
            } else {
                _lastModified = Date.now();
                _persist();
            }

            if (_equal(_headers, oldHeaders) && _equal(_services, oldServices) && _autostart === oldAutostart) {
                return new Deferred().resolve();
            }

            if (_state === "active" || _state === "starting") {
                var serviceIds = [];
                Object.keys(_services).forEach(function(serviceId) {
                    var service = _services[serviceId];
                    serviceIds.push(serviceId);
                    var remoteService = _remoteServices[serviceId];
                    if (remoteService) {
                        if (_equal(service.methods, Object.keys(remoteService.proxy))) {
                            var properties = _createServiceProperties(service);
                            var reference = remoteService.registration.getReference();
                            var currentProperties = {};
                            reference.getPropertyKeys().forEach(function(name) {
                                currentProperties[name] = reference.getProperty(name);
                            });
                            if (!_equal(properties, currentProperties)) {
                                remoteService.registration.setProperties(properties);
                            }
                            return;
                        }
                        remoteService.registration.unregister();
                        delete _remoteServices[serviceId];
                    }
                    _registerService(service);
                });
                Object.keys(_remoteServices).forEach(function(serviceId) {
                    if (serviceIds.indexOf(serviceId) === -1) {
                        _remoteServices[serviceId].registration.unregister();
                        delete _remoteServices[serviceId];
                    }
                });
            }

            if (_state === "active") {
                _internalRegistry.disconnect(_channel);
                _deferredLoad = new Deferred();
                _channel = _internalRegistry.connect(_url, _messageHandler, _parent);
                _deferredLoad.then(function() {
                    _deferredLoad = null;
                }, function() {
                    _deferredLoad = null;
                    _state = "stopping";
                    _internalRegistry.dispatchEvent(new PluginEvent("stopping"), _this);
                    Object.keys(_remoteServices).forEach(function(serviceId) {
                        _remoteServices[serviceId].registration.unregister();
                        delete _remoteServices[serviceId];
                    });
                    _internalRegistry.disconnect(_channel);
                    _channel = null;
                    _state = "resolved";
                    _internalRegistry.dispatchEvent(new PluginEvent("stopped", _this));
                });
            }
            return new Deferred().resolve();
        };

        this.update = function(input) {
            return _update(input).then(function() {
                _internalRegistry.dispatchEvent(new PluginEvent("updated", _this));
            });
        };
        
        /**
         * Uninstalls this plugin.
         * @name orion.pluginregistry.Plugin#uninstall
         * @return {orion.Promise} A promise that will resolve when the plugin has been uninstalled.
         * @function
         */
        this.uninstall = function() {
            if (_state === "uninstalled") {
                return new Deferred().reject(new Error("Plugin is uninstalled"));
            }

            if (_state === "active" || _state === "starting" || _state === "stopping") {
                return this.stop().then(this.uninstall.bind(this), this.uninstall.bind(this));
            }

            _internalRegistry.removePlugin(this);
            _state = "uninstalled";
            _internalRegistry.dispatchEvent(new PluginEvent("uninstalled", _this));
            return new Deferred().resolve();
        };
    }

    var workerRegex = /Worker\.js$/;
    var sharedWorkerRegex = /SharedWorker\.js$/;
    var pluginHtml = "Plugin.html"; //$NON-NLS-0$
    var workerJS = "Worker.js"; //$NON-NLS-0$

    /**
     * Dispatched when a plugin has been installed. The type of this event is <code>"installed"</code>.
     * @name orion.pluginregistry.PluginRegistry#installed
     * @event
     */
    /**
     * Dispatched when a plugin has been resolved. The type of this event is <code>"resolved"</code>.
     * @name orion.pluginregistry.PluginRegistry#resolved
     * @event
     */
    /**
     * Dispatched when a plugin is starting due to a lazy activation. The type of this event is <code>"lazy activation"</code>.
     * @name orion.pluginregistry.PluginRegistry#lazy_activation
     * @event
     */
    /**
     * Dispatched when a plugin is starting. The type of this event is <code>"starting"</code>.
     * @name orion.pluginregistry.PluginRegistry#starting
     * @event
     */
    /**
     * Dispatched when a plugin is started. The type of this event is <code>"started"</code>.
     * @name orion.pluginregistry.PluginRegistry#started
     * @event
     */
    /**
     * Dispatched when a plugin is stopping. The type of this event is <code>"stopping"</code>.
     * @name orion.pluginregistry.PluginRegistry#stopping
     * @event
     */
    /**
     * Dispatched when a plugin is stopped. The type of this event is <code>"stopped"</code>.
     * @name orion.pluginregistry.PluginRegistry#stopped
     * @event
     */
    /**
     * Dispatched when a plugin has been updated. The type of this event is <code>"updated"</code>.
     * @name orion.pluginregistry.PluginRegistry#updated
     * @event
     */
    /**
     * Dispatched when a plugin has been uninstalled. The type of this event is <code>"uninstalled"</code>.
     * @name orion.pluginregistry.PluginRegistry#uninstalled
     * @event
     */

    /**
     * Creates a new plugin registry.
     * @class The Orion plugin registry
     * @name orion.pluginregistry.PluginRegistry
     * @description The plugin registry maintains a list of {@link orion.pluginregistry.Plugin}s, which can provide services
     * to the given <code>serviceRegistry</code>.
     *
     * <p>The plugin registry dispatches plugin events when one of its plugins changes state. Each such event contains a
     * <code>plugin</code> field giving the affected {@link orion.pluginregistry.Plugin}.
     * </p>
     *
     * @param {orion.serviceregistry.ServiceRegistry} serviceRegistry The service registry to register plugin-provided services with.
     * @param {Object} [opt_storage=localStorage] Target object to read and write plugin metadata from.
     * @param {Boolean} [opt_visible=false] Whether a loaded plugin's iframe will be displayed. By default it is not displayed.
     * @borrows orion.serviceregistry.EventTarget#addEventListener as #addEventListener
     * @borrows orion.serviceregistry.EventTarget#removeEventListener as #removeEventListener
     */
    function PluginRegistry(serviceRegistry, configuration) {
        configuration = configuration || {};
        var _storage = configuration.storage || localStorage;
        if (!_storage.getItem) {
            _storage = _asStorage(_storage);
        }
        var _defaultTimeout = parseInt(_storage.getItem("pluginregistry.default.timeout"), 10) || undefined;
        var _state = "installed";
        var _parent;
        var _plugins = [];
        var _channels = [];
        var _pluginEventTarget = new EventTarget();
        var _installing = {};

        var internalRegistry = {
            serviceRegistry: serviceRegistry,
            registerService: serviceRegistry.registerService.bind(serviceRegistry),
            connect: function(url, handler, parent, timeout) {
                var channel = {
                    handler: handler,
                    url: url
                };

                function log(state) {
                    if (util.readSetting("pluginLogging")) {
                        console.log(state + "(" + (Date.now() - channel._startTime) + "ms)=" + url);
                    }
                }

                function sendTimeout(message) {
                    log("timeout"); //$NON-NLS-0$
                    var error = new Error(message);
                    error.name = "timeout";
                    handler({
                        method: "timeout",
                        error: error
                    });
                }
                
                timeout = timeout || _defaultTimeout;
                
                channel._updateTimeout = function() {
                    var message, newTimeout;
                    if (!this._connected && !this._closed) {
                        if (this._handshake) {
                            // For each plugin being loaded add 1000 ms extra time to the handshake timeout
                            var extraTimeout = 0;
                            _channels.forEach(function(c) {
                                if (!c._connected && !c._closed) {
                                    extraTimeout += 1000;
                                }
                            });
                            message = "Plugin handshake timeout for: " + url;
                           newTimeout = this._loading ? 5000 : (timeout || 60000) + extraTimeout;
                        } else {
                            message = "Plugin load timeout for: " + url;
                            newTimeout = timeout || 15000;
                        }
                    }
                    if (this._loadTimeout) clearTimeout(this._loadTimeout);
                    this._loadTimeout = 0;
                    if (newTimeout) this._loadTimeout = setTimeout(sendTimeout.bind(null, message), newTimeout);
                };

                var isWorker = !!(url.match(workerRegex) && typeof(Worker) !== "undefined");
                var isSharedWorker = !!(url.match(sharedWorkerRegex) && typeof(SharedWorker) !== "undefined");
                if ((!util.readSetting("useSharedWorkers") || !isSharedWorker) && url.match(sharedWorkerRegex)) {
                    url = url.replace(sharedWorkerRegex, workerJS);
                    isSharedWorker = false;
                }
                if ((!util.readSetting("useWorkers") || !isWorker) && url.match(workerRegex)) {
                    url = url.replace(workerRegex, pluginHtml);
                    isWorker = isSharedWorker = false;
                }               

                channel.url = url;
                channel._updateTimeout();
                channel._startTime = Date.now();
                if (isWorker) {
                    var worker;
                    if (isSharedWorker) {
                        worker = new SharedWorker(url);
                        channel.target = worker.port;
                        worker.port.start();
                        channel._close = function() {
                            worker.port.close();
                        };
                    } else {
                        worker = new Worker(url);
                        channel.target = worker;
                        channel._close = function() {
                            worker.terminate();
                        };
                    }
                    channel.postMessage = function(message) {
                        this.target.postMessage((this.useStructuredClone ? message : JSON.stringify(message)), []);
                    };
                    channel.target.addEventListener("message", function(evt) {
                    	_channelHandler(channel, evt);
                    });
                } else {
                   	var iframe = document.createElement("iframe"); //$NON-NLS-0$
                    iframe.name = url + "_" + channel._startTime;
					iframe.src = urlModifier(url);
                    iframe.onload = function() {
                        log("handshake"); //$NON-NLS-0$
                        channel._handshake = true;
                        channel._updateTimeout();
                    };
                    iframe.sandbox = "allow-scripts allow-same-origin allow-forms allow-popups"; //$NON-NLS-0$
                    iframe.style.width = iframe.style.height = "100%"; //$NON-NLS-0$
                    iframe.frameBorder = 0;
                    iframe.title = (parent || _parent).title;
                    (parent || _parent).appendChild(iframe);
                    channel.target = iframe.contentWindow;
                    channel.postMessage = function(message) {
                        this.target.postMessage((this.useStructuredClone ? message : JSON.stringify(message)), this.url);
                    };
                    channel._close = function() {
                        if (iframe) {
                            var frameParent = iframe.parentNode;
                            if (frameParent) {
                                frameParent.removeChild(iframe);
                            }
                            iframe = null;
                        }
                    }; 
                }
                channel.connected = function() {
                    log("connected"); //$NON-NLS-0$
                    this._connected = true;
                    this._updateTimeout();
                    
                };
                channel.loading = function() {
                    log("loading"); //$NON-NLS-0$
                    this._loading = true;
                    this._updateTimeout();
                };
                channel.close = function() {
                    log("closed"); //$NON-NLS-0$
                    this._closed = true;
                    this._updateTimeout();
                    this._close();
                };
                _channels.push(channel);
                return channel;
            },
            disconnect: function(channel) {
                for (var i = 0; i < _channels.length; i++) {
                    if (channel === _channels[i]) {
                        _channels.splice(i, 1);
                        try {
                            channel.close();
                        } catch (e) {
                            // best effort
                        }
                        break;
                    }
                }
            },
            removePlugin: function(plugin) {
                for (var i = 0; i < _plugins.length; i++) {
                    if (plugin === _plugins[i]) {
                        _plugins.splice(i, 1);
                        break;
                    }
                }
                _storage.removeItem("plugin." + plugin.getLocation());
            },
            getPersisted: function(url) {
            	var key = "plugin." + url;
            	var manifest = _storage.getItem(key);
            	if (manifest) {
            		manifest = JSON.parse(manifest);
            		if (manifest.created) {
            			return manifest;
            		}
            	}
            	return null;
            },
            persist: function(url, manifest) {
            	if (!manifest || !manifest.services || !manifest.services.length) {
            		_storage.removeItem("plugin." + url);
            		return;
            	}
                _storage.setItem("plugin." + url, JSON.stringify(manifest)); //$NON-NLS-0$
            },
            postMessage: function(message, channel) {
                channel.postMessage(message);
            },
            dispatchEvent: function(event) {
                try {
                    _pluginEventTarget.dispatchEvent(event);
                } catch (e) {
                    if (console) {
                        console.log("PluginRegistry.dispatchEvent " + e);
                    }
                }
            },
            loadManifest: function(url) {
                var d = new Deferred();
                var channel = internalRegistry.connect(url, function(message) {
                    if (!channel || !message.method) {
                        return;
                    }
                    if ("manifest" === message.method || "plugin" === message.method) { //$NON-NLS-0$
                        var manifest = message.params[0];
                        internalRegistry.disconnect(channel);
                        channel = null;
                        d.resolve(manifest);
                    } else if ("timeout" === message.method || "error" === message.method) {
                        internalRegistry.disconnect(channel);
                        channel = null;
                        d.reject(message.error);
                    } else if ("loading" === message.method) {
                        channel.loading();
                    }
                });
                return d.promise;
            },
            getState: function() {
                return _state;
            },
            handleServiceError: function(plugin, error) {
                if (error && (error.status === 401 || error.status === 491)) {
                    var headers = plugin.getHeaders();
                    var name = plugin.getName() || plugin.getLocation();
                    var span = document.createElement("span");
                    span.appendChild(document.createTextNode("Authentication required for: " + name + "."));
                    if (headers.login) {
                        span.appendChild(document.createTextNode(" "));
                        var anchor = document.createElement("a");
                        anchor.target = "_blank";
                        anchor.textContent = "Login";
                        anchor.href = headers.login;
                        if (!httpOrHttps.test(anchor.href)) {
                            console.log("Illegal Login URL: " + headers.login);
                        } else {
                            span.appendChild(anchor);
                            span.appendChild(document.createTextNode(" and re-try the request."));
                        }
                    }
                    var serializer = new XMLSerializer();
                    return {
                        Severity: "Error",
                        HTML: true,
                        Message: serializer.serializeToString(span)
                    };
                }
                if (error.__isError) {
                    var original = error;
                    error = new Error(original.message);
                    Object.keys(original).forEach(function(key) {
                        error[key] = original[key];
                    });
                    delete error.__isError;
                }
                return error;
            }
        };

        this.getLocation = function() {
            return "System";
        };

        this.getHeaders = function() {
            return {};
        };

        this.getName = function() {
            return "System";
        };

        this.getVersion = function() {
            return "0.0.0";
        };

        this.getLastModified = function() {
            return 0;
        };

        this.getState = internalRegistry.getState;

		function _channelHandler(channel, event) {
			try {
                var message;
                if (typeof channel.useStructuredClone === "undefined") {
                    var useStructuredClone = typeof event.data !== "string"; //$NON-NLS-0$
                    message = useStructuredClone ? event.data : JSON.parse(event.data);
                    channel.useStructuredClone = useStructuredClone;
                } else {
                    message = channel.useStructuredClone ? event.data : JSON.parse(event.data);
                }
                channel.handler(message);
            } catch (e) {
                // not a valid message -- ignore it
            }
		}

        function _messageHandler(event) {
            var source = event.source;
            _channels.some(function(channel) {
                if (source === channel.target) {
                    _channelHandler(channel, event);
                    return true; // e.g. break
                }
            });
        }


        this.init = function() {
            if (_state === "starting" || _state === "active" || _state === "stopping") {
                return;
            }
            addEventListener("message", _messageHandler, false);
            
            if (configuration.parent) {
                _parent = configuration.parent;
            } else {
                _parent = document.createElement("div"); //$NON-NLS-0$
                if (!configuration.visible) {
                    _parent.style.display = "none"; //$NON-NLS-0$
                    _parent.style.visibility = "hidden"; //$NON-NLS-0$
                }
                document.body.appendChild(_parent);
            }

            if (configuration.plugins) {
                Object.keys(configuration.plugins).forEach(function(key) {
		            var url = _normalizeURL(key);
		            //                    if (!httpOrHttps.test(url)) {
		            //                        console.log("Illegal Plugin URL: " + url);
		            //                        return;
		            //                    }
		            var plugin = this.getPlugin(url);
		            if (!plugin) {
		                var manifest = configuration.plugins[key];
		                if (typeof manifest !== "object") {
		                	manifest = internalRegistry.getPersisted(url) || {};
		                }
		                manifest.autostart = manifest.autostart || configuration.defaultAutostart || "lazy";
		                plugin = new Plugin(url, manifest, internalRegistry);
		                plugin._default = true;
		                _plugins.push(plugin);
		            } else {
		                plugin._default = true;
		            }
                }.bind(this));
            }
            _plugins.sort(function(a, b) {
                return a._getCreated() < b._getCreated() ? -1 : 1;
            });
            _state = "starting";
        };

        /**
         * Starts the plugin registry.
         * @name orion.pluginregistry.PluginRegistry#start
         * @return {orion.Promise} A promise that will resolve when the registry has been fully started.
         * @function 
         */
        this.start = function() {
            if (_state !== "starting") {
                this.init();
            }
            if (_state !== "starting") {
                return new Deferred().reject("Cannot start framework. Framework is already " + _state + ".");
            }
            var deferreds = [];
            _plugins.forEach(function(plugin) {
                var autostart = plugin._getAutostart();
                if ("started" === autostart || "active" === autostart) {
                    deferreds.push(plugin.start({
                        "transient": true
                    }));
                } else if ("lazy" === autostart) {
                    deferreds.push(plugin.start({
                        "lazy": true,
                            "transient": true
                    }));
                } else {
                    plugin._resolve();
                }
            });
            return Deferred.all(deferreds, function(e) {
                console.log("PluginRegistry.stop " + e);
            }).then(function() {
                _state = "active";
            });
        };

        /**
         * Shuts down the plugin registry.
         * @name orion.pluginregistry.PluginRegistry#stop
         * @function 
         * @returns {orion.Promise} A promise that will resolve when the registry has been stopped.
         */
        this.stop = function() {
            if (_state !== "starting" && _state !== "active") {
                return new Deferred().reject("Cannot stop registry. Registry is already " + _state + ".");
            }
            _state = "stopping";
            var deferreds = [];
            _plugins.forEach(function(plugin) {
                deferreds.push(plugin.stop({
                    "transient": true
                }));
            });
            return Deferred.all(deferreds, function(e) {
                console.log("PluginRegistry.stop " + e);
            }).then(function() {
                if (!configuration.parent) {
                    var parentNode = _parent.parentNode;
                    if (parentNode) {
                        parentNode.removeChild(_parent);
                    }
                }
                _parent = null;
                removeEventListener("message", _messageHandler);
                _state = "resolved";
            });
        };

        this.update = function() {
            this.stop().then(this.start.bind(this));
        };

        this.uninstall = function() {
            return new Deferred().reject("Cannot uninstall registry");
        };


        /**
         * Installs the plugin at the given location into the plugin registry.
         * @name orion.pluginregistry.PluginRegistry#installPlugin
         * @param {String} url The location of the plugin.
         * @param {Object} [optManifest] The plugin metadata.
         * @returns {orion.Promise} A promise that will resolve when the plugin has been installed.
         * @function 
         */
        this.installPlugin = function(url, optManifest) {
            url = _normalizeURL(url);
            //            if (!httpOrHttps.test(url)) {
            //                return new Deferred().reject("Illegal Plugin URL: " + url);
            //            }
            var plugin = this.getPlugin(url);
            if (plugin) {
                return new Deferred().resolve(plugin);
            }

            if (_installing[url]) {
                return _installing[url];
            }
            
            if (optManifest) {
            	if (optManifest.autostart === "lazy") {
	                optManifest = _mixin({}, internalRegistry.getPersisted(url), optManifest);
            	}
                plugin = new Plugin(url, optManifest, internalRegistry);
                _plugins.push(plugin);
                plugin._persist();
                internalRegistry.dispatchEvent(new PluginEvent("installed", plugin));
                return new Deferred().resolve(plugin);
            }

            var promise = internalRegistry.loadManifest(url).then(function(manifest) {
                plugin = new Plugin(url, manifest, internalRegistry);
                _plugins.push(plugin);
                plugin._persist();
                delete _installing[url];
                internalRegistry.dispatchEvent(new PluginEvent("installed", plugin));
                return plugin;
            }, function(error) {
                delete _installing[url];
                throw error;
            });
            _installing[url] = promise;
            return promise;
        };

        /**
         * Returns all installed plugins.
         * @name orion.pluginregistry.PluginRegistry#getPlugins
         * @return {orion.pluginregistry.Plugin[]} An array of all installed plugins.
         * @function 
         */
        this.getPlugins = function() {
            return _plugins.slice();
        };

        /**
         * Returns the installed plugin with the given URL.
         * @name orion.pluginregistry.PluginRegistry#getPlugin
         * @return {orion.pluginregistry.Plugin} The installed plugin matching the given URL, or <code>null</code>
         * if no such plugin is installed.
         * @function 
         */
        this.getPlugin = function(url) {
            var result = null;
            url = _normalizeURL(url);
            _plugins.some(function(plugin) {
                if (url === plugin.getLocation()) {
                    result = plugin;
                    return true;
                }
            });
            return result;
        };

        this.addEventListener = _pluginEventTarget.addEventListener.bind(_pluginEventTarget);

        this.removeEventListener = _pluginEventTarget.removeEventListener.bind(_pluginEventTarget);

        this.resolvePlugins = function() {
            var allResolved = true;
            _plugins.forEach(function(plugin) {
                allResolved = allResolved && plugin._resolve();
            });
            return allResolved;
        };
    }
    return {
        Plugin: Plugin,
        PluginRegistry: PluginRegistry
    };
});

/*******************************************************************************
 * @license
 * Copyright (c) 2013 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 * 
 * Contributors: IBM Corporation - initial API and implementation
 ******************************************************************************/
/*eslint-env browser, amd*/
define('orion/objects',[], function() {
	function mixin(target/*, source..*/) {
		var hasOwnProperty = Object.prototype.hasOwnProperty;
		for (var j = 1, len = arguments.length; j < len; j++) {
			var source = arguments[j];
			for (var key in source) {
				if (hasOwnProperty.call(source, key)) {
					target[key] = source[key];
				}
			}
		}
		return target;
	}

	/**
	 * @name orion.objects
	 * @class Object-oriented helpers.
	 */
	return {
		/**
		 * Creates a shallow clone of the given <code>object</code>.
		 * @name orion.objects.clone
		 * @function
		 * @static
		 * @param {Object|Array} object The object to clone. Must be a "normal" Object or Array. Other built-ins,
		 * host objects, primitives, etc, will not work.
		 * @returns {Object|Array} A clone of <code>object</code>.
		 */
		clone: function(object) {
			if (Array.isArray(object)) {
				return Array.prototype.slice.call(object);
			}
			var clone = Object.create(Object.getPrototypeOf(object));
			mixin(clone, object);
			return clone;
		},
		/**
		 * Mixes all <code>source</code>'s own enumerable properties into <code>target</code>. Multiple source objects
		 * can be passed as varargs.
		 * @name orion.objects.mixin
		 * @function
		 * @static
		 * @param {Object} target
		 * @param {Object} source
		 */
		mixin: mixin,
		/**
		 * Wraps an object into an Array if necessary.
		 * @name orion.objects.toArray
		 * @function
		 * @static
		 * @param {Object} obj An object.
		 * @returns {Array} Returns <code>obj</code> unchanged, if <code>obj</code> is an Array. Otherwise returns a 1-element Array
		 * whose sole element is <code>obj</code>.
		 */
		toArray: function(o) {
			return Array.isArray(o) ? o : [o];
		}
	};
});
/*******************************************************************************
 * @license
 * Copyright (c) 2012 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 * 
 * Contributors: IBM Corporation - initial API and implementation
 ******************************************************************************/
/*eslint-env browser, amd*/
define('orion/serviceTracker',[], function() {

	var CLOSED = 0, OPENED = 1;
	/**
	 * @name orion.ServiceTracker
	 * @class Simplifies the use of services within a service registry.
	 * @description Creates a <code>ServiceTracker</code> against the given service registry.
	 * The returned <code>ServiceTracker</code> will track services whose <code>objectClass</code> property contains the
	 * given <code>objectClass</code> parameter.
	 *
	 * <p>After creating a <code>ServiceTracker</code>, it can then be {@link #open}ed to begin tracking services.</p>
	 * <p>The {@link #addingService} and {@link #removedService} methods can be overridden to customize the service objects
	 * being tracked.</p>
	 * @param {orion.serviceregistry.ServiceRegistry} serviceRegistry The service registry to track services of.
	 * @param {String} objectClass The objectClass of services to be tracked.
	 */
	function ServiceTracker(serviceRegistry, objectClass) {
		this.serviceRegistry = serviceRegistry;
		var refs = {};
		var services = {};
		var state = CLOSED;
		var addedListener, removedListener;

		function add(serviceRef) {
			var id = serviceRef.getProperty('service.id');
			var serviceObject = this.addingService(serviceRef);
			if (serviceObject) {
				refs[id] = serviceRef;
				services[id] = serviceObject;
			}
		}
		function remove(serviceRef) {
			var id = serviceRef.getProperty('service.id');
			var service = services[id];
			delete refs[id];
			delete services[id];
			this.removedService(serviceRef, service);
		}
		function isTrackable(serviceRef) {
			return serviceRef.getProperty('objectClass').indexOf(objectClass) !== -1; //$NON-NLS-0$
		}

		/**
		 * Stops tracking services.
		 * @name orion.ServiceTracker#close
		 * @function
		 */
		this.close = function() {
			if (state !== OPENED) {
				throw new Error('Already closed'); //$NON-NLS-0$
			}
			state = CLOSED;
			serviceRegistry.removeEventListener('registered', addedListener); //$NON-NLS-0$
			serviceRegistry.removeEventListener('unregistering', removedListener); //$NON-NLS-0$
			addedListener = null;
			removedListener = null;
			var self = this;
			this.getServiceReferences().forEach(function(serviceRef) {
				remove.call(self, serviceRef);
			});
			if (typeof this.onClose === 'function') {
				this.onClose();
			}
		};
		/**
		 * Returns service references to the services that are being tracked.
		 * @name orion.ServiceTracker#getServiceReferences
		 * @function
		 * @returns {orion.serviceregistry.ServiceReference[]} References to all services that are being tracked by this ServiceTracker.
		 */
		this.getServiceReferences = function() {
			var keys = Object.keys(refs);
			if (!keys.length) {
				return null;
			}
			return keys.map(function(serviceId) {
				return refs[serviceId];
			});
		};
		/**
		 * Begins tracking services.
		 * @name orion.ServiceTracker#open
		 * @function
		 * @param {Boolean} [all=true] When <tt>true</tt>, this ServiceTracker receives an initial block of serviceAdded
		 * calls for any services currently present in the registry, and then for any subsequent registrations.
		 * When <tt>false</tt>, this ServiceTracker is invoked only for subsequent serviceAdded events.
		 *
		 * <p>Clients can use <tt>all === false</tt> when they wish to respond only to future events, and
		 * <tt>all === true</tt> when they wish to quickly "catch up" with trackable services that were
		 * registered prior to {@link #open} being called.</p>
		 */
		this.open = function(all) {
			if (typeof all === 'undefined') { //$NON-NLS-0$
				all = true;
			}
			if (state !== CLOSED) {
				throw new Error('Already open'); //$NON-NLS-0$
			}
			state = OPENED;
			var self = this;
			addedListener = /** @ignore */ function(event) {
				if (isTrackable(event.serviceReference)) {
					add.call(self, event.serviceReference);
					if (typeof self.onServiceAdded === 'function') { //$NON-NLS-0$
						return self.onServiceAdded(event.serviceReference, self.serviceRegistry.getService(event.serviceReference));
					}
				}
			};
			removedListener = /** @ignore */ function(event) {
				if (isTrackable(event.serviceReference)) {
					remove.call(self, event.serviceReference);
				}
			};
			serviceRegistry.addEventListener('registered', addedListener); //$NON-NLS-0$
			serviceRegistry.addEventListener('unregistering', removedListener); //$NON-NLS-0$
			if (all) {
				serviceRegistry.getServiceReferences(objectClass).forEach(function(serviceRef) {
					add.call(self, serviceRef);
					if (typeof self.onServiceAdded === 'function') { //$NON-NLS-0$
						return self.onServiceAdded(serviceRef, serviceRegistry.getService(serviceRef));
					}
				});
			}
			if (typeof this.onOpen === 'function') {
				this.onOpen();
			}
		};
	}
	ServiceTracker.prototype = /** @lends orion.ServiceTracker.prototype */ {
		/**
		 * Called to customize a service object being added to this ServiceTracker. Subclasses may override this method.
		 * The default implementation returns the result of calling {@link orion.serviceregistry.ServiceRegistry#getService}
		 * passing the service reference.
		 * @param {orion.serviceregistry.ServiceReference} serviceRef The reference to the service being added.
		 * @returns {Object} The service object to be tracked for the given service reference. If <code>null</code> 
		 * is returned, the service reference will not be tracked.
		 */
		addingService: function(serviceRef) {
			return this.serviceRegistry.getService(serviceRef);
		},
		/**
		 * Called when this ServiceTracker has been opened. Subclasses can override this method.
		 * @function
		 */
		onOpen: null,
		/**
		 * Called when this ServiceTracker has been closed. Subclasses can override this method.
		 * @function
		 */
		onClose: null,
		/**
		 * Called when a service is being added to this ServiceTracker. Subclasses can override this method to take part
		 * in the service's <code>'serviceAdded'</code> phase.
		 * @function
		 * @param {orion.serviceregistry.ServiceReference} serviceRef The service reference for the service that is being added.
		 * @param {Object} service The service implementation object that is being added.
		 * @returns {orion.Promise|undefined} This method can optionally return a deferred. If it does, the returned deferred
		 * will be added to the service's <code>serviceAdded</code> listener queue; in other words, the returned deferred
		 * must resolve before any calls to the service's methods can proceed.
		 */
		onServiceAdded: null,
		/**
		 * Called when a service has been removed from this ServiceTracker. Subclasses may override this method.
		 * The default implementation does nothing.
		 * @function
		 * @param {orion.serviceregistry.ServiceReference} serviceRef The reference to the removed service.
		 * @param {Object} service The service implementation object for the removed service.
		 */
		removedService: function(serviceRef, service) {
		}
	};

	return ServiceTracker;
});
/*******************************************************************************
 * @license
 * Copyright (c) 2012, 2013 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 * 
 * Contributors: IBM Corporation - initial API and implementation
 ******************************************************************************/
/*eslint-env browser, amd*/
define('orion/config',[
	'orion/Deferred',
	'orion/objects',
	'orion/preferences',
	'orion/serviceTracker',
], function(Deferred, objects, Preferences, ServiceTracker) {

var PreferencesService = Preferences.PreferencesService;
var ManagedServiceTracker, ConfigAdminFactory, ConfigStore, ConfigAdminImpl, ConfigImpl;

var DEFAULT_SCOPE = PreferencesService.DEFAULT_SCOPE;
var PROPERTY_PID = 'pid'; //$NON-NLS-0$
var MANAGED_SERVICE = 'orion.cm.managedservice'; //$NON-NLS-0$
var PREF_NAME = '/cm/configurations'; //$NON-NLS-0$

/**
 * @name orion.cm.impl.ManagedServiceTracker
 * @class Tracks ManagedServices in a ServiceRegistry. Delivers updated() notifications to tracked ManagedServices.
 * This class also tracks the loading of {@link orion.pluginregistry.Plugin}s in a PluginRegistry, and provides 
 * the following guarantee: if a Plugin is being loaded and it provides a ManagedService, its updated() method
 * will be called prior to any other service method.
 * @private
 */
ManagedServiceTracker = /** @ignore */ function(serviceRegistry, pluginRegistry, store) {
	ServiceTracker.call(this, serviceRegistry, MANAGED_SERVICE); //$NON-NLS-0$

	var managedServiceRefs = {};
	var managedServices = {};
	var pluginLoadedListener = function(event) {
		var managedServiceUpdates = [];
		event.plugin.getServiceReferences().forEach(function(serviceRef) {
			if (serviceRef.getProperty('objectClass').indexOf(MANAGED_SERVICE) !== -1) { //$NON-NLS-0$
				var pid = serviceRef.getProperty(PROPERTY_PID);
				var managedService = serviceRegistry.getService(serviceRef);
				if (pid && managedService) {
					var configuration = store._find(pid);
					var properties = configuration && configuration.getProperties();
					managedServiceUpdates.push(managedService.updated(properties));
				}
			}
		});
		return Deferred.all(managedServiceUpdates);
	};

	function add(pid, serviceRef, service) {
		if (!managedServiceRefs[pid]) {
			managedServiceRefs[pid] = [];
		}
		if (!managedServices[pid]) {
			managedServices[pid] = [];
		}
		managedServiceRefs[pid].push(serviceRef);
		managedServices[pid].push(service);
	}
	function remove(pid, serviceRef, service) {
		var serviceRefs = managedServiceRefs[pid];
		var services = managedServices[pid];
		if (serviceRefs.length > 1) {
			serviceRefs.splice(serviceRefs.indexOf(serviceRef), 1);
		} else {
			delete managedServiceRefs[pid];
		}
		if (services.length > 1) {
			services.splice(services.indexOf(service), 1);
		} else {
			delete managedServices[pid];
		}
	}
	function getManagedServiceReferences(pid) {
		return managedServiceRefs[pid] || [];
	}
	function getManagedServices(pid) {
		return managedServices[pid] || [];
	}
	function asyncUpdated(serviceRefs, services, properties) {
		services.forEach(function(service, i) {
			try {
				// Plugin load is expensive, so don't trigger it just to call updated() on a Managed Service.
				// pluginLoadedListener will catch the plugin when (if) it loads.
				var pluginUrl = serviceRefs[i].getProperty('__plugin__'); //$NON-NLS-0$
				var plugin = pluginUrl && pluginRegistry.getPlugin(pluginUrl);
				if (!pluginUrl || (plugin && plugin.getState() === 'active')) {
					services[i].updated(properties);
				}
			} catch(e) {
				if (typeof console !== 'undefined') { //$NON-NLS-0$
					console.log(e);
				}
			}
		});
	}
	this.addingService = function(serviceRef) {
		var pid = serviceRef.getProperty(PROPERTY_PID);
		var managedService = serviceRegistry.getService(serviceRef);
		if (!pid || !managedService) {
			return null;
		}
		add(pid, serviceRef, managedService);
		return managedService;
	};
	this.onServiceAdded = function(serviceRef, service) {
		var pid = serviceRef.getProperty(PROPERTY_PID);
		var configuration = store._find(pid);
		asyncUpdated([serviceRef], [service], (configuration && configuration.getProperties()));
	};
	this.onOpen = function() {
		pluginRegistry.addEventListener('started', pluginLoadedListener); //$NON-NLS-0$
	};
	this.onClose = function() {
		pluginRegistry.removeEventListener('started', pluginLoadedListener); //$NON-NLS-0$
	};
	this.notifyUpdated = function(configuration) {
		var pid = configuration.getPid();
		asyncUpdated(getManagedServiceReferences(pid), getManagedServices(pid), configuration.getProperties());
	};
	this.notifyDeleted = function(configuration) {
		var pid = configuration.getPid();
		asyncUpdated(getManagedServiceReferences(pid), getManagedServices(pid), null);
	};
	this.removedService = function(serviceRef, service) {
		var pid = serviceRef.getProperty(PROPERTY_PID);
		remove(pid, serviceRef, service);
	};
};
/**
 * @name orion.cm.impl.ConfigAdminFactory
 * @class
 * @private
 */
ConfigAdminFactory = /** @ignore */ (function() {
	/** @private */
	function ConfigAdminFactory(serviceRegistry, pluginRegistry, prefsService) {
		this.store = new ConfigStore(this, prefsService);
		this.configAdmin = new ConfigAdminImpl(this, this.store);
		this.tracker = new ManagedServiceTracker(serviceRegistry, pluginRegistry, this.store);
	}
	ConfigAdminFactory.prototype = {
		// TODO this should be synchronous but requires sync Prefs API
		getConfigurationAdmin: function() {
			var self = this;
			return this.configAdmin._init().then(function(configAdmin) {
				self.tracker.open();
				return configAdmin;
			});
		},
		notifyDeleted: function(configuration) {
			this.tracker.notifyDeleted(configuration);
		},
		notifyUpdated: function(configuration) {
			this.tracker.notifyUpdated(configuration);
		}
	};
	return ConfigAdminFactory;
}());

/**
 * @name orion.cm.ConfigAdminImpl
 * @class
 * @private
 */
ConfigAdminImpl = /** @ignore */ (function() {
	function ConfigAdminImpl(factory, store) {
		this.factory = factory;
		this.store = store;
	}
	ConfigAdminImpl.prototype = {
		_prefName: PREF_NAME,
		_init: function() {
			var self = this;
			return this.store._init().then(function() {
				return self;
			});
		},
		getConfiguration: function(pid) {
			return this.store.get(pid);
		},
		getDefaultConfiguration: function(pid) {
			return this.store._find(pid, DEFAULT_SCOPE);
		},
		listConfigurations: function() {
			return this.store.list();
		}
	};
	return ConfigAdminImpl;
}());

/**
 * @name orion.cm.ConfigStore
 * @class Manages Configurations and handles persisting them to preferences.
 * @private
 */
ConfigStore = /** @ignore */ (function() {
	function ConfigStore(factory, prefsService) {
		this.factory = factory;
		this.prefsService = prefsService;
		this.configs = this.defaultConfigs = null; // PID -> Configuration
		this.pref = null; // Preferences node. Maps String PID -> Object properties
		var _self = this;
		this.initPromise = Deferred.all([
			this.prefsService.get(PREF_NAME, undefined, {scope: DEFAULT_SCOPE}), // default scope only
			this.prefsService.get(PREF_NAME)
		]).then(function(result) {
			var defaultPref = result[0];
			_self.pref = result[1];
			_self.defaultConfigs = _self._toConfigs(defaultPref, true /* read only */);
			_self.configs = _self._toConfigs(_self.pref, false, defaultPref);
		});
	}
	ConfigStore.prototype = {
		_toConfigs: function(pref, isReadOnly, inheritPref) {
			var configs = Object.create(null), _self = this;
			Object.keys(pref).forEach(function(pid) {
				if (!configs[pid]) {
					var properties = pref[pid], inheritProps = inheritPref && inheritPref[pid];
					if (typeof properties === 'object' && properties !== null && Object.keys(properties).length > 0) { //$NON-NLS-0$
						properties[PROPERTY_PID] = pid;
						configs[pid] = new ConfigImpl(_self.factory, _self, properties, isReadOnly, inheritProps);
					}
				}
			});
			return configs;
		},
		_init: function() {
			return this.initPromise;
		},
		_find: function(pid, scope) {
			if(scope === PreferencesService.DEFAULT_SCOPE)
				return this.defaultConfigs[pid] || null;
			return this.configs[pid] || null;
		},
		get: function(pid) {
			var config = this._find(pid), defaultConfig = this._find(pid, DEFAULT_SCOPE);
			if (!config) {
				// Create a new Configuration with only pid in its (non-inherited) properties
				var inheritProps = defaultConfig && defaultConfig.getProperties(true);
				config = new ConfigImpl(this.factory, this, pid, false, inheritProps);
				this.configs[pid] = config;
			}
			return config;
		},
		list: function() {
			var self = this;
			var currentConfigs = [];
			Object.keys(this.pref).forEach(function(pid) {
				var config = self._find(pid);
				if (config && config.getProperties() !== null) {
					currentConfigs.push(config);
				}
			});
			return currentConfigs;
		},
		remove: function(pid) {
			delete this.configs[pid];
			delete this.pref[pid];
			return this.prefsService.remove(PREF_NAME, pid);
		},
		save: function(pid, configuration) {
			var props = configuration.getProperties(true) || {};
			var defaultConfig = this._find(pid, DEFAULT_SCOPE);
			if (defaultConfig) {
				// Filter out any properties that are inherited and unchanged from their default values
				var defaultProps = defaultConfig.getProperties(true);
				Object.keys(defaultProps).forEach(function(key) {
					if (Object.prototype.hasOwnProperty.call(props, key) && props[key] === defaultProps[key])
						delete props[key];
				});
			}
			var data = {};
			data[pid] = props;
			this.pref[pid] = props;
			return this.prefsService.put(PREF_NAME, data);
		}
	};
	return ConfigStore;
}());

/**
 * @name orion.cm.impl.ConfigImpl
 * @class 
 * @private
 */
ConfigImpl = /** @ignore */ (function() {
	function setProperties(configuration, newProps) {
		// Configurations cannot have nested properties, so a shallow clone is sufficient.
		newProps = objects.clone(newProps);
		delete newProps[PROPERTY_PID];
		configuration.properties = newProps;
	}
	function ConfigImpl(factory, store, pidOrProps, isReadOnly, inheritProperties) {
		this.factory = factory;
		this.store = store;
		this.readOnly = isReadOnly;
		if (pidOrProps !== null && typeof pidOrProps === 'object') { //$NON-NLS-0$
			this.pid = pidOrProps[PROPERTY_PID];
			setProperties(this, pidOrProps);
		} else if (typeof pidOrProps === 'string') { //$NON-NLS-0$
			this.pid = pidOrProps;
			this.properties = null;
		} else {
			throw new Error('Invalid pid/properties ' + pidOrProps); //$NON-NLS-0$
		}
		// Inherit any property values missing from this configuration
		if (inheritProperties) {
			this.properties = this.properties || Object.create(null);
			var _self = this;
			Object.keys(inheritProperties).forEach(function(key) {
				if (key === PROPERTY_PID || Object.prototype.hasOwnProperty.call(_self.properties, key))
					return;
				_self.properties[key] = inheritProperties[key];
			});
		}
	}
	ConfigImpl.prototype = {
		_checkReadOnly: function() {
			if (this.readOnly)
				throw new Error('Configuration is read only'); //$NON-NLS-0$
		},
		_checkRemoved: function() {
			if (this.removed)
				throw new Error('Configuration was removed'); //$NON-NLS-0$
		},
		getPid: function() {
			this._checkRemoved();
			return this.pid;
		},
		getProperties: function(omitPid) {
			this._checkRemoved();
			var props = null;
			if (this.properties) {
				props = objects.clone(this.properties);
				if (!omitPid) {
					props[PROPERTY_PID] = this.pid;
				}
			}
			return props;
		},
		remove: function() {
			this._checkReadOnly();
			this._checkRemoved();
			return this.store.remove(this.pid).then(function() {
				this.factory.notifyDeleted(this);
				this.removed = true;
			}.bind(this));
		},
		update: function(props) {
			this._checkReadOnly();
			this._checkRemoved();
			setProperties(this, props);
			return this.store.save(this.pid, this).then(function() {
				this.factory.notifyUpdated(this);
			}.bind(this));
		},
		toString: function() {
			return '[ConfigImpl pid: ' + this.pid + ', properties: ' + JSON.stringify(this.properties) + ']';
		}
	};
	return ConfigImpl;
}());

/**
 * @name orion.cm.Configuration
 * @class The configuration information for a {@link orion.cm.ManagedService}.
 * @description A <code>Configuration</code> object contains configuration properties. Services wishing to receive those
 * properties do not deal with Configurations directly, but instead register a {@link orion.cm.ManagedService} with the
 * Service Registry.
 */
	/**
	 * @name getPid
	 * @function
	 * @memberOf orion.cm.Configuration.prototype
	 * @returns {String} The PID of this Configuration.
	 */
	/**
	 * @name getProperties
	 * @function
	 * @memberOf orion.cm.Configuration.prototype
	 * @returns {orion.cm.ConfigurationProperties} A private copy of this Configuration's properties, or <code>null</code>
	 * if the configuration has never been updated.
	 */
	/**
	 * @name remove
	 * @function
	 * @memberOf orion.cm.Configuration.prototype
	 * @description Deletes this Configuration. Any {@link orion.cm.ManagedService} that registered interest in this 
	 * Configuration's PID will have its {@link orion.cm.ManagedService#updated} method called with <code>null</code> properties. 
	 */
	/**
	 * @name update
	 * @function
	 * @memberOf orion.cm.Configuration.prototype
	 * @param {Object} [properties] The new properties to be set in this Configuration. The <code>pid</code> 
	 * property will be added or overwritten and set to this Configuration's PID.
	 * @description Updates the properties of this Configuration. Any {@link orion.cm.ManagedService} that registered
	 * interest in this Configuration's PID will have its {@link orion.cm.ManagedService#updated} method called.
	 */

/**
 * @name orion.cm.ConfigurationAdmin
 * @class Service for managing configuration data.
 */
	/**
	 * @name getConfiguration
	 * @memberOf orion.cm.ConfigurationAdmin.prototype
	 * @description Gets the configuration having the given PID, creating a new one if necessary. Newly created configurations
	 * have <code>null</code> properties.
	 * @param {String} pid
	 * @returns {orion.cm.Configuration} The configuration.
	 */
	/**
	 * @name getDefaultConfiguration
	 * @memberOf orion.cm.ConfigurationAdmin.prototype
	 * @description Gets the configuration having the given PID if it is defined in the default preference scope.
	 * @param {String} pid
	 * @returns {orion.cm.Configuration} The configuration, or <tt>null</tt>.
	 */
	/**
	 * @name listConfigurations
	 * @memberOf orion.cm.ConfigurationAdmin.prototype
	 * @description Returns all Configurations having non-<code>null</code> properties.
	 * @returns {orion.cm.Configuration[]} An array of configurations.
	 */

/**
 * @name orion.cm.ManagedService
 * @class Interface for a service that needs configuration data.
 * @description A <code>ManagedService</code> is a service that needs configuration properties from a {@link orion.cm.ConfigurationAdmin}.
 * <p>A ManagedService is registered with the Service Registry using the service name <code>'orion.cm.managedservice'</code>.
 * The ManagedService's service properties must contain a <code>pid</code> property giving a unique identifier called a PID.
 * <p>When a change occurs to a Configuration object corresponding to the PID, the service's {@link #updated} method is 
 * called with the configuration's properties.
 */
	/**
	 * @name updated
	 * @memberOf orion.cm.ManagedService.prototype
	 * @description Invoked after a Configuration has been updated.
	 * @param {orion.cm.ConfigurationProperties} properties The properties of the {@link orion.cm.Configuration} that was
	 * updated. This parameter will be <code>null</code> if the Configuration does not exist or was deleted.
	 */
/**
 * @name orion.cm.ConfigurationProperties
 * @class A dictionary that holds configuration data.
 * @description A <code>ConfigurationProperties</code> carries the properties of a {@link orion.cm.Configuration}. Minimally a ConfigurationProperties
 * will have a {@link #pid} <code>pid</code> property. Other properties may also be present.
 * @property {String} pid Gives the PID of the {@link orion.cm.Configuration} whose properties this object represents.
 */
	return {
		ConfigurationAdminFactory: ConfigAdminFactory
	};
});
/*******************************************************************************
 * @license
 * Copyright (c) 2011, 2016 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
/*eslint-env browser, amd*/

define('orion/bootstrap',['require', 'i18n!orion/nls/messages',  'orion/Deferred', 'orion/serviceregistry', 'orion/preferences', 'orion/pluginregistry', 'orion/config', 'orion/urlModifier'], function(require, messages, Deferred, mServiceregistry, mPreferences, mPluginRegistry, mConfig, urlModifier) {

	var once; // Deferred

	function startup() {
		if (once) {
			return once;
		}
		var pageLoader = require.defined("orion/splash") && require("orion/splash").getPageLoader(); //$NON-NLS-1$
		if (pageLoader) pageLoader.nextStep();
		once = new Deferred();
		
		// initialize service registry and EAS services
		var serviceRegistry = new mServiceregistry.ServiceRegistry();
	
		// This is code to ensure the first visit to orion works
		// we read settings and wait for the plugin registry to fully startup before continuing
		var preferences = new mPreferences.PreferencesService(serviceRegistry);
		return preferences.get("/plugins").then(function(pluginsPreference) { //$NON-NLS-0$
			var configuration = {plugins:{}};
			Object.keys(pluginsPreference).forEach(function(key) {
				var url = require.toUrl(key);
				configuration.plugins[url] = pluginsPreference[key];
			});
			var pluginRegistry = new mPluginRegistry.PluginRegistry(serviceRegistry, configuration);
			if (pageLoader) {
				pageLoader.setPluginRegistry(pluginRegistry);
			}
			return pluginRegistry.start().then(function() {
				if (serviceRegistry.getServiceReferences("orion.core.preference.provider").length > 0) { //$NON-NLS-0$
					return preferences.get("/plugins", undefined, {scope: mPreferences.PreferencesService.USER_SCOPE}).then(function(pluginsPreference) { //$NON-NLS-0$
						var installs = [];
						Object.keys(pluginsPreference).forEach(function(key) {
							var url = require.toUrl(key);
							if (!pluginRegistry.getPlugin(url)) {
								var manifest = pluginsPreference[key];
								if (typeof manifest !== "object") {
									manifest = {autostart: "lazy"};
								}
								installs.push(pluginRegistry.installPlugin(url, manifest).then(function(plugin) { //$NON-NLS-1$
									return plugin.start({lazy: "lazy" === manifest.autostart});
								}));
							}
						});	
						return Deferred.all(installs, function(e){
							console.log(e);
						});
					});
				}
			}).then(function() {
				return new mConfig.ConfigurationAdminFactory(serviceRegistry, pluginRegistry, preferences).getConfigurationAdmin().then(
					serviceRegistry.registerService.bind(serviceRegistry, "orion.cm.configadmin") //$NON-NLS-0$
				);
			}).then(function() {
				if (pageLoader) pageLoader.nextStep();
				var auth = serviceRegistry.getService("orion.core.auth"); //$NON-NLS-0$
				if (auth) {
					if (pageLoader) {
						pageLoader.getStep().message = messages.AuthenticatingUser;
						pageLoader.update();
					}
					return auth.getUser().then(function(user) {
						if (!user) {
							return auth.getAuthForm(window.location.href).then(function(formURL) {
								setTimeout(function() {
									window.location = urlModifier(formURL);
								}, 0);
								return new Deferred().reject({});
							});
						}
						if (pageLoader) {
							pageLoader.getStep().message = messages.AuthenticatedUser;
							pageLoader.update();
						}
					});
				}
			}).then(function() {
				var result = {
					serviceRegistry: serviceRegistry,
					preferences: preferences,
					pluginRegistry: pluginRegistry
				};
				once.resolve(result);
				return result;
			});
		});
	}
	return {startup: startup};
});

/*******************************************************************************
 * @license
 * Copyright (c) 2012, 2015 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 *
 * Contributors: IBM Corporation - initial API and implementation
 *******************************************************************************/
/*eslint-env browser, amd*/
/*global requirejs*/
define('orion/i18nUtil',[], function() {
	/**
	 * Performs string substitution. Can be invoked in 2 ways:
	 *
	 * i) vargs giving numbered substition values:
	 *   formatMessage("${0} is ${1}", "foo", "bar")  // "foo is bar"
	 *
	 * ii) a map giving the substitutions:
	 *   formatMessage("${thing} is ${1}", {1: "bar", thing: "foo"})  // "foo is bar"
	 */
	function formatMessage(msg) {
		var pattern = /\$\{([^\}]+)\}/g, args = arguments;
		if (args.length === 2 && args[1] && typeof args[1] === "object") {
			return msg.replace(pattern, function(str, key) {
				return args[1][key];
			});
		}
		return msg.replace(pattern, function(str, index) {
			return args[(index << 0) + 1];
		});
	}
	return {
		formatMessage: formatMessage
	};
});
/*******************************************************************************
 * @license
 * Copyright (c) 2012, 2019 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 * 
 * Contributors: IBM Corporation - initial API and implementation
 ******************************************************************************/
/*eslint-env browser, amd*/
define('orion/webui/littlelib',["orion/util"], function(util) {
	/**
	 * @name orion.webui.littlelib
	 * @class A small library of DOM and UI helpers.
	 */

	/**
	 * Holds useful <code>keyCode</code> values.
	 * @name orion.webui.littlelib.KEY
	 * @static
	 */
	var KEY = {
		BKSPC: 8,
		TAB: 9,
		ENTER: 13,
		SHIFT: 16,
		CONTROL: 17,
		ALT: 18,
		ESCAPE: 27,
		SPACE: 32,
		PAGEUP: 33,
		PAGEDOWN: 34,
		END: 35,
		HOME: 36,
		LEFT: 37,
		UP: 38,
		RIGHT: 39,
		DOWN: 40,
		INSERT: 45,
		DEL: 46,
		COMMAND: 91
	};

	/**
	 * Alias for <code>node.querySelector()</code>.
	 * @name orion.webui.littlelib.$
	 * @function
	 * @static
	 * @param {String} selectors Selectors to match on.
	 * @param {Node} [node=document] Node to query under.
	 * @returns {Element}
	 */
	function $(selector, node) {
		if (!node) {
			node = document;
		}
		return node.querySelector(selector);
	}

	/**
	 * Alias for <code>node.querySelectorAll()</code>.
	 * @name orion.webui.littlelib.$$
	 * @function
	 * @static
	 * @param {String} selectors Selectors to match on.
	 * @param {Node} [node=document] Node to query under.
	 * @returns {NodeList}
	 */
	function $$(selector, node) {
		if (!node) {
			node = document;
		}
		return node.querySelectorAll(selector);
	}

	/**
	 * Identical to {@link orion.webui.littlelib.$$}, but returns an Array instead of a NodeList.
	 * @name orion.webui.littlelib.$$array
	 * @function
	 * @static
	 * @param {String} selectors Selectors to match on.
	 * @param {Node} [node=document] Node to query under.
	 * @returns {Element[]}
	 */
	function $$array(selector, node) {
		return Array.prototype.slice.call($$(selector,node));
	}

	/**
	 * Alias for <code>document.getElementById</code>, but returns the input unmodified when passed a Node (or other non-string).
	 * @function
	 * @param {String|Element} elementOrId
	 * @returns {Element}
	 */
	function node(either) {
		var theNode = either;
		if (typeof(either) === "string") { //$NON-NLS-0$
			theNode = document.getElementById(either);
		}	
		return theNode;
	}

	/**
	 * Returns whether <code>child</code> is a descendant of <code>parent</code> in the DOM order.
	 * @function
	 * @param {Node} parent
	 * @param {Node} child
	 * @returns {Boolean}
	 */
	function contains(parent, child) {
		if (!parent || !child) { return false; }
		if (parent === child) { return true; }
		var compare = parent.compareDocumentPosition(child);  // useful to break out for debugging
		return Boolean(compare & 16);
	}

	/**
	 * Returns the bounds of a node. The returned coordinates are absolute (not relative to the viewport).
	 * @function
	 * @param {Node} node
	 * @returns {Object}
	 */
	function bounds(node) {
		var clientRect = node.getBoundingClientRect();
		var scrollLeft = Math.max(document.documentElement.scrollLeft, document.body.scrollLeft);
		var scrollTop = Math.max(document.documentElement.scrollTop, document.body.scrollTop);
		return { 
			left: clientRect.left + scrollLeft,
			top: clientRect.top + scrollTop,
			width: clientRect.width,
			height: clientRect.height
		};
	}

	/**
	 * Removes all children of the given node.
	 * @name orion.webui.littlelib.empty
	 * @function
	 * @static
	 * @param {Node} node
	 */
	function empty(node) {
		while (node && node.hasChildNodes()) {
			var child = node.firstChild;
			node.removeChild(child);
		}
	}

	function _getTabIndex(node) {
		var result = node.tabIndex;
		if (result === 0 && util.isIE) {
			/*
			 * The default value of tabIndex is 0 on IE, even for elements that are not focusable
			 * by default (http://msdn.microsoft.com/en-us/library/ie/ms534654(v=vs.85).aspx).
			 * Handle this browser difference by treating this value as -1 if the node is a type
			 * that is not focusable by default according to the MS doc and has not had this
			 * attribute value explicitly set on it.
			 */
			var focusableElements = {
				a: true,
				body: true,
				button: true,
				frame: true,
				iframe: true,
				img: true,
				input: true,
				isindex: true,
				object: true,
				select: true,
				textarea: true
			};
			if (!focusableElements[node.nodeName.toLowerCase()] && !node.attributes.tabIndex) {
				result = -1;
			}
		}
		return result;
	}
	
	/* 
	 * Inspired by http://brianwhitmer.blogspot.com/2009/05/jquery-ui-tabbable-what.html
	 */
	function firstTabbable(node, allowFocusable) {
		var tabIndex = _getTabIndex(node);
		if ((tabIndex >= 0 || allowFocusable && tabIndex >= -1) && !node.disabled && node.offsetParent && window.getComputedStyle(node).visibility === "visible") {
			return node;
		}
		if (node.hasChildNodes()) {
			for (var i=0; i<node.childNodes.length; i++) {
				var result = firstTabbable(node.childNodes[i]);
				if (result) {
					return result;
				}
			}
		}
		return null;
	}

	function lastTabbable(node) {
		if (node.hasChildNodes()) {
			for (var i = node.childNodes.length-1; i >= 0; i--) {
				var result = lastTabbable(node.childNodes[i]);
				if (result) {
					return result;
				}
			}
		}
		if (_getTabIndex(node) >= 0 && !node.disabled && node.offsetParent && window.getComputedStyle(node).visibility === "visible") {
			return node;
		}
		return null;
	}

	/*
	 * Special hook to show the context menu on Shift + F10 (macs only)
	 */
	function installShowContextMenu() {
		if (util.isMac) {
			document.addEventListener("keydown", function (evt) {
				if (evt.keyCode === 121 && evt.shiftKey) {
					var rect, xPos, yPos;
					var focusElement = document.activeElement;
	
					if (focusElement.contentEditable === "true") {
						var selection = window.getSelection();
						var range = selection.getRangeAt(0); //get the text range
						rect = range.getBoundingClientRect();
						xPos = rect.left;
						yPos = rect.top + rect.height;
						
					} else {
						rect = bounds(focusElement);
						xPos = rect.left + (rect.width/2);
						yPos = rect.top + (rect.height/2);
					}
	
					var e = focusElement.ownerDocument.createEvent("MouseEvents");
					e.initMouseEvent("contextmenu", true, true,
						focusElement.ownerDocument.defaultView, 1, 0, 0, xPos, yPos, false,
						false, false, false,2, null);
					return !focusElement.dispatchEvent(e);				
				}
			}, true);
		}
	}
	installShowContextMenu();
	
	/* Trap the tabs within the given parent */
	function trapTabs(parentElement) {
		if (parentElement.tabTrapInstalled)
			return;
		
		parentElement.addEventListener("keydown", function (e) { //$NON-NLS-0$
			if(e.keyCode === KEY.TAB) {
				var first = firstTabbable(parentElement);
				var last = lastTabbable(parentElement);
				
				if (first && last) {
					if (e.target === last && !e.shiftKey) {
						// wrap to first tabbable
						first.focus();
						stop(e);
					}
					else if (e.target === first && e.shiftKey) {
						// wrap to last tabbable
						last.focus();
						stop(e);
					}
				}
			} 
		}, true);
		parentElement.tabTrapInstalled = true;
	}
	
	var variableRegEx = /\$\{([^\}]+)\}/;
	// Internal helper
	function processNodes(node, replace) {
		if (node.nodeType === 3) { // TEXT_NODE
			var matches = variableRegEx.exec(node.nodeValue);
			if (matches && matches.length > 1) {
				replace(node, matches);
			}
		} else if (node.nodeType === 1) { // ELEMENT_NODE
			processElementNode(node, replace, "alt"); //$NON-NLS-0$
			//processElementNode(node, replace, "title"); //$NON-NLS-0$
			//processElementNode(node, replace, "placeholder"); //$NON-NLS-0$
			processElementNode(node, replace, "aria-label"); //$NON-NLS-0$
		}
		if (node.hasChildNodes()) {
			for (var i=0; i<node.childNodes.length; i++) {
				processNodes(node.childNodes[i], replace);
			}
		}
	}
	
	function processElementNode(node, replace, attribute) {
		var value = node.getAttribute(attribute);
		if (value) {
			var matches = variableRegEx.exec(value);
			if (matches && matches.length > 1) {
				replace(node, matches, attribute);
			}
		}		
	}

	/**
	 * @name pixelValueOf
	 * @description Returns the pixel value of the given CSS attribute
	 * @param node The element whose style is to be checked
	 * @param attrName The name of the attribute to check. Use the literal CSS name
	 * (i.e. 'padding-left' rather than 'paddingLeft').
	 * @returns returns The value (in pixels) of the attribute. If the value cannot be parsed to an int the zero is returned
	 */
	function pixelValueOf(node, attrName) {
		if (!node || !attrName) {
			return 0;
		}
		
		var doc = node.ownerDocument;
		var win =  doc.defaultView || doc.parentWindow;
		if (win.getComputedStyle) {
			var style = win.getComputedStyle(node, null);
			var value = style.getPropertyValue(attrName);
			// Ensure that value ends in "px"
			if (value.length > 2 && value.indexOf("px", value.length - 2) !== -1) {
				value = value.slice(0,-2);
				var intVal = parseInt(value,10);
				if (intVal !== intVal) {
					return 0;  // value was NaN
				} else {
					return intVal;
				}
			}
		}
		return 0;
	}
	
	/**
	 * Performs substitution of strings into textContent within the given node and its descendants. An occurrence of <code>${n}</code>
	 * in text content will be replaced with the string <code>messages[n]</code>.
	 * <p>This function is recommended for binding placeholder text in template-created DOM elements to actual display strings.</p>
	 * @name orion.webui.littlelib.processTextNodes
	 * @function
	 * @param {Node} node The node to perform replacement under.
	 * @param {String[]} messages The replacement strings.
	 */
	function processTextNodes(node, messages) {
		processNodes(node, function(targetNode, matches, attribute) {
			var replaceText = messages[matches[1]] || matches[1];
			if (targetNode.nodeType === 3) { // TEXT_NODE
				targetNode.parentNode.replaceChild(document.createTextNode(replaceText), targetNode);
			} else if (targetNode.nodeType === 1 && attribute) { // ELEMENT_NODE
				setSafeAttribute(targetNode, attribute, replaceText);
			}
		});
	}

	/**
	 * Performs substitution of DOM nodes into textContent within the given node and its descendants. An occurrence of <code>${n}</code>
	 * in text content will be replaced by the DOM node <code>replaceNodes[n]</code>.
	 * <p>This function is recommended for performing rich-text replacement within a localized string. The use of actual DOM nodes
	 * avoids the need for embedded HTML in strings.</p>
	 * @name orion.webui.littlelib.processDOMNodes
	 * @function
	 * @param {Node} node The node to perform replacement under.
	 * @param {Node[]} replaceNodes The replacement nodes.
	 */
	function processDOMNodes(node, replaceNodes) {
		processNodes(node, function(targetNode, matches) {
			var replaceNode = replaceNodes[matches[1]];
			if (replaceNode) {
				var range = document.createRange();
				var start = matches.index;
				range.setStart(targetNode, start);
				range.setEnd(targetNode, start + matches[0].length);
				range.deleteContents();
				range.insertNode(replaceNode);
			}
		});
	}

	/**
	 * Adds auto-dismiss functionality to the document. When a click event occurs whose <code>target</code> is not a descendant of
	 * one of the <code>excludeNodes</code>, the <code>dismissFunction</code> is invoked.
	 * @name orion.webui.littlelib.addAutoDismiss
	 * @function
	 * @static
	 * @param {Node[]} excludeNodes Clicks targeting any descendant of these nodes will not trigger the dismissFunction.
	 * @param {Function} dismissFunction The dismiss handler.
	 */
	
	var autoDismissNodes = null;

	function addAutoDismiss(excludeNodes, dismissFunction) {
		// auto dismissal.  Click anywhere else means close.
		function onclick(event) {
			autoDismissNodes.forEach(function(autoDismissNode) {
				var excludeNodeInDocument = false;
				var excluded = autoDismissNode.excludeNodes.some(function(excludeNode) {
					if(document.body.contains(excludeNode)) {
						excludeNodeInDocument = true;
						return excludeNode.contains(event.target);
					}
					return false;
				});
				if (excludeNodeInDocument && !excluded) {
					try {
						autoDismissNode.dismiss(event);
					} catch (e) {
						if (typeof console !== "undefined" && console) { //$NON-NLS-0$
							console.error(e && e.message);
						}
					}
				}
			});
			autoDismissNodes = autoDismissNodes.filter(function(autoDismissNode) {
				// true if at least one excludeNode is in document.body
				return autoDismissNode.excludeNodes.some(function(excludeNode) {
					return document.body.contains(excludeNode);
				});
			});
		}

		// Hook listener only once
		if (autoDismissNodes === null) {
			autoDismissNodes = [];
			document.addEventListener("click", onclick, true); //$NON-NLS-0$
			if (util.isIOS) {
				document.addEventListener("touchend", function(event){
					function unhook(){
						event.target.removeEventListener("click", unhook);
					}
					if (event.touches.length === 0) {
						// we need a click eventlistener on the target to have ios really trigger a click
						event.target.addEventListener("click", unhook);
					}	
				}, false);
			}
		}
		
		autoDismissNodes.push({excludeNodes: excludeNodes, dismiss: dismissFunction});
	}
	
	/**
	 * Removes all auto-dismiss nodes which trigger the specified dismiss function.
	 * 
	 * @name orion.webui.littlelib.removeAutoDismiss
	 * @function
	 * @static
	 * @param {Function} dismissFunction The dismiss function to look for.
	 */
	function removeAutoDismiss(dismissFunction) {
		autoDismissNodes = autoDismissNodes.filter(function(autoDismissNode) {
			return dismissFunction !== autoDismissNode.dismiss;
		});
	}
	
	/**
	 * Returns the parent of the node that has the vertical scroll bar.
	 * 
	 * @name orion.webui.littlelib.getOffsetParent
	 * @function
	 * @static
	 * @param {Element} node The node to lookup the offset parent
	 */
	function getOffsetParent(node) {
		var offsetParent = node.parentNode, documentElement = document.documentElement;
		while (offsetParent && offsetParent !== documentElement) {
			var style = window.getComputedStyle(offsetParent, null);
			if (!style) { break; }
			var overflow = style.getPropertyValue("overflow-y"); //$NON-NLS-0$
			if (overflow === "auto" || overflow === "scroll") { break; } //$NON-NLS-1$ //$NON-NLS-0$
			offsetParent = offsetParent.parentNode;
		}
		return offsetParent;
	}
	
	function getPathTo(element) {
		if (!element) return "";
		if (element.id !== "") {
			return 'id("' + element.id +'")';
		}
		if (element === document.body) {
			return element.tagName;
		}
		var ix= 0;
		var siblings = element.parentNode && element.parentNode.childNodes || [];
		for (var i= 0; i < siblings.length; i++) {
			var sibling = siblings[i];
			if (sibling === element) {
				return getPathTo(element.parentNode)+ '/'+ element.tagName+'['+(ix+1)+']';
			}
			if (sibling.nodeType === Node.ELEMENT_NODE && sibling.tagName === element.tagName) {
				ix++;
			}
		}
	}
	
	/**
	 * Return focus to the element that was active before the <code>hidingParent</code> was
	 * shown if the parent contains the active element. If the previous active node is no
	 * longer available, the first tabbable in the nearest ancestor is focused.
	 * 
	 * @name orion.webui.littlelib.returnFocus
	 * @function
	 * @static
	 * @param {Element} hidingParent The node that is hiding
	 * @param {Element} previousActiveElement The previously focus node
	 */
	function returnFocus(hidingParent, previousActiveElement, hideCallback) {
		var activeElement = document.activeElement;
		var focusPath = getPathTo(previousActiveElement);
		var hasFocus = hidingParent && (hidingParent === activeElement || (hidingParent.compareDocumentPosition(activeElement) & 16) !== 0);
		var deferred;
		if (hideCallback) {
			deferred = hideCallback();
		}
		function restore() {
			var temp = previousActiveElement;
			if (hasFocus) {
				while (temp && temp !== document.body) {
					if (document.compareDocumentPosition(temp) !== 1 && temp.offsetParent) {
						var tabbable = firstTabbable(temp, previousActiveElement === temp);
						if (tabbable) {
							temp = tabbable;
							break;
						}
					}
					if (temp.classList.contains("contextMenu")) {
						if (temp.triggerNode) {
							temp = temp.triggerNode;
							continue;
						}
						break;
					}
					temp = temp.parentNode;
				}
				if (!temp && focusPath) {
					temp = document.evaluate(focusPath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
				}
				if (temp) {
					temp.focus();
					return true;
				}
			}
			return false;
		}
		return deferred && deferred.then ? deferred.then(restore) : restore();
	}
	
	/**
	 * Cancels the default behavior of an event and stops its propagation.
	 * @name orion.webui.littlelib.stop
	 * @function
	 * @static
	 * @param {Event} event
	 */
	function stop(event) {
		if (window.document.all) { 
			event.keyCode = 0;
		}
		if (event.preventDefault) {
			event.preventDefault();
			event.stopPropagation();
		}
	}
	
	function setFramesEnabled(enable) {
		var frames = document.getElementsByTagName("iframe"); //$NON-NLS-0$
		for (var i = 0; i<frames.length; i++) {
			if (frames[i].parentNode === document.body) continue;
			frames[i].parentNode.style.pointerEvents = enable ? "" : "none"; //$NON-NLS-0$
		}
	}
	
	/**
	 * Given a non-empty string, returns a string with no spaces in it (valid HTML5 id attribute).
	 * Also removes any punctuation except for '_', '-', and '.' for compatibility with HTML4.
	 * @name orion.webui.littlelib.validId
	 * @function
	 * @static
	 * @param {String} str	A non-empty string
	 * @returns A valid html id string
	 */
	function validId(str) {
		return str.replace(/\s/g, '-').replace(/[^A-Za-z0-9_.-]/g, '.');
	}
	
	/**
	 * Maps a <code>keyCode</code> to <tt>KEY</tt> name. This is the inverse of {@link orion.webui.littlelib.KEY}.
	 * @private
	 */
	var KEY_CODE = Object.create(null);
	Object.keys(KEY).forEach(function(name) {
		KEY_CODE[KEY[name]] = name;
	});

	/**
	 * @param {Number} keyCode
	 * @returns The name of the <code>lib.KEY</code> entry for keyCode, or null.
	 */
	function keyName(keyCode) {
		return KEY_CODE[keyCode] || null;
	}

	/**
	 * Creates DOM nodes from the specified template string.
	 * 
	 * @param {String} templateString 	A string containing the HTML template to use
	 * @param {Node} parentNode 		Optional. The parent node to insert the new nodes into. 
	 * 									The parent's contents will be completely replaced.
	 * @returns If the template string contains a single node or a wrapper node which
	 * 			wraps all the other nodes that single DOM node will be returned. 
	 * 			Otherwise if the template string contains multiple top-level nodes an
	 * 			{HTMLCollection} object containing all the top-level nodes will be returned.
	 */
	function createNodes(templateString, parentNode) {
		var parent = parentNode;
		var newNodes = null;
		
		if (undefined === parent) {
			parent = document.createElement("div"); //$NON-NLS-0$
		}

		setSafeInnerHTML(parent, templateString);	
		if (parent.children.length > 1) {
			newNodes = parent.children;
		} else {
			newNodes = parent.firstChild;
		}
		
		return newNodes;
	}

  /**
   * @description This function is a delegate to set the value of an attribute on a given node
   * @param {Element} node
   * @param {string} name
   * @param {?} value
   * @since 20.0
   */
  function setSafeAttribute(node, name, value) {
	if(node instanceof Element && name !== null && name !== undefined) {
			//TODO - add more checks, this is not sufficient
	  node.setAttribute(name, value);
	}
	}
	
	/**
   * @description This function is a delegate to set the value of innerHTML on a given node
   * @param {Element} node
   * @param {string} value
   * @since 20.0
   */
  function setSafeInnerHTML(node, value) {
	if(node instanceof Element && (value instanceof String || typeof value === "string")) {
			//TODO - we do not allow third party content, so not a problem currently
	  node.innerHTML = value;
	}
  }

	//return module exports
	return {
		$: $,
		$$: $$,
		$$array: $$array,
		node: node,
		contains: contains,
		bounds: bounds,
		empty: empty,
		firstTabbable: firstTabbable,
		lastTabbable: lastTabbable,
		trapTabs: trapTabs,
		pixelValueOf: pixelValueOf,
		stop: stop,
		processTextNodes: processTextNodes,
		processDOMNodes: processDOMNodes,
		addAutoDismiss: addAutoDismiss,
		setFramesEnabled: setFramesEnabled,
		validId: validId,
		getOffsetParent: getOffsetParent,
		removeAutoDismiss: removeAutoDismiss,
		returnFocus: returnFocus,
		keyName: keyName,
		KEY: KEY,
		createNodes: createNodes,
		setSafeAttribute: setSafeAttribute,
		setSafeInnerHTML: setSafeInnerHTML
	};
});

/*******************************************************************************
 * @license
 * Copyright (c) 2010,2012 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 * 
 * Contributors: IBM Corporation - initial API and implementation
 ******************************************************************************/
/*eslint-env browser, amd*/
 
define('orion/commandsProxy',[
	'orion/util',
	'orion/webui/littlelib'
], function(util, lib) {
	
	function handleKeyEvent(evt, processKeyFunc) {
		function isContentKey(e) {
			// adapted from handleKey in http://git.eclipse.org/c/platform/eclipse.platform.swt.git/plain/bundles/org.eclipse.swt/Eclipse%20SWT%20Custom%20Widgets/common/org/eclipse/swt/custom/StyledText.java
			if (util.isMac) {
				// COMMAND+ALT combinations produce characters on the mac, but COMMAND or COMMAND+SHIFT do not.
				if (e.metaKey && !e.altKey) {  //command without alt
					// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=390341
					// special case for select all, cut, copy, paste, and undo.  A slippery slope...
					if (!e.shiftKey && !e.ctrlKey && (e.keyCode === 65 || e.keyCode === 67 || e.keyCode === 86 || e.keyCode === 88 || e.keyCode === 90)) {
						return true;
					}
					return false;
				}
				if (e.ctrlKey) {
					return false;
				}
			} else {
				// CTRL or ALT combinations are not characters, however both of them together (CTRL+ALT)
				// are the Alt Gr key on some keyboards.  See Eclipse bug 20953. If together, they might
				// be a character. However there aren't usually any commands associated with Alt Gr keys.
				if (e.ctrlKey && !e.altKey) {
					// special case for select all, cut, copy, paste, and undo.  
					if (!e.shiftKey && (e.keyCode === 65 || e.keyCode === 67 || e.keyCode === 86 || e.keyCode === 88 || e.keyCode === 90)) {
						return true;
					}
					return false;
				}
				if (e.altKey && !e.ctrlKey) {
					return false;
				}
				if (e.ctrlKey && e.altKey){
					return false;
				}
			}
			if (e['char']) { //$NON-NLS-0$
				return e['char'].length > 0;  // empty string for non characters //$NON-NLS-0$
			} else if (e.charCode || e.keyCode) {
				var keyCode= e.charCode || e.keyCode;
				// anything below SPACE is not a character except for line delimiter keys, tab, and delete.
				switch (keyCode) {
					case 8:  // backspace
					case 9:  // tab
					case 13: // enter
					case 46: // delete
						return true;
					default:
						return (keyCode >= 32 && keyCode < 112) || // space key and above until function keys
							keyCode > 123; // above function keys  
				}
			}
			// If we can't identify as a character, assume it's not
			return false;
		}
		
		evt = evt || window.event;
		if (isContentKey(evt)) {
			// bindings that are text content keys are ignored if we are in a text field or editor
			// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=375058
			if (evt.target.contentEditable === "true") { //$NON-NLS-0$
				return;
			}
			var tagType = evt.target.nodeName.toLowerCase();
			if (tagType === 'input') { //$NON-NLS-0$
				var inputType = evt.target.type.toLowerCase();
				// Any HTML5 input type that involves typing text should be ignored
				switch (inputType) {
					case "text": //$NON-NLS-0$
					case "password": //$NON-NLS-0$
					case "search": //$NON-NLS-0$
					case "color": //$NON-NLS-0$
					case "date": //$NON-NLS-0$
					case "datetime": //$NON-NLS-0$
					case "datetime-local": //$NON-NLS-0$
					case "email": //$NON-NLS-0$
					case "month": //$NON-NLS-0$
					case "number": //$NON-NLS-0$
					case "range": //$NON-NLS-0$
					case "tel": //$NON-NLS-0$
					case "time": //$NON-NLS-0$
					case "url": //$NON-NLS-0$
					case "week": //$NON-NLS-0$
						return;
				}
			} else if (tagType === 'textarea') { //$NON-NLS-0$
				return;
			}
		}
		processKeyFunc(evt);
	}
		
	function CommandsProxy() {
		this._init();
	}
	CommandsProxy.prototype = {
		destroy: function() {
			if (this._listener) {
				document.removeEventListener("keydown", this._listener); //$NON-NLS-0$
				this._listener = null;
			}
		},
		setProxy: function(proxy) {
			this.proxy = proxy;
		},
		setKeyBindings: function(bindings) {
			this.bindings = bindings;
		},
		_init: function() {
			var self = this;
			document.addEventListener("keydown", this._listener = function(evt) { //$NON-NLS-0$
				return handleKeyEvent(evt, function(evt) {
					var proxy = self.proxy;
					var bindings = self.bindings;
					if (!bindings || !proxy) {
						return;
					}
					for (var i=0; i<bindings.length; i++) {
						if (bindings[i].match(evt)) {
							proxy.processKey({
								type: evt.type,
								keyCode: evt.keyCode,
								altKey: evt.altKey,
								ctrlKey: evt.ctrlKey,
								metaKey: evt.metaKey,
								shiftKey: evt.shiftKey
							});
							lib.stop(evt);
						}
					}
				});
			});
		}
	};
	
	//return the module exports
	return {
		handleKeyEvent: handleKeyEvent,
		CommandsProxy: CommandsProxy
	};
});

/*******************************************************************************
 * @license
 * Copyright (c) 2012, 2019 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 * 
 * Contributors: IBM Corporation - initial API and implementation
 ******************************************************************************/
/*eslint-env browser, amd*/
define('orion/webui/dropdown',['orion/webui/littlelib', 'orion/EventTarget'], function(lib, EventTarget) {

	/**
	 * Attaches dropdown behavior to a given node.  Assumes the triggering node and dropdown node
	 * have the same parent.  Trigger should have "dropdownTrigger" class, and the dropdown node should 
	 * have "dropdownMenu" class.  Dropdown items should be <li> elements, so typically the dropdown node
	 * supplied is a <ul>.
	 *
	 * "dropdowntriggerbutton.html" contains an appropriate HTML fragment for a triggering button and associated
	 * dropdown.  Clients can add this fragment to the DOM and then attach Dropdown behavior to it.
	 * 
	 * Nested ("sub") menu behavior is accomplished by adding the class "dropdownSubMenu" to one of the <li> items.
	 * This item can then parent another trigger and <ul>.
	 *
	 * "submenutriggerbutton.html" contains an appropriate HTML fragment for a menu item that triggers a sub menu.
	 * Clients can add this fragment to a dropdown menu and then attach Dropdown behavior to the sub menu item.
	 *
	 * The items inside each <li> item in a dropdown can be almost any type of node.  The class "dropdownMenuItem" is
	 * used on the node inside the li to find items and style them appropriately.  There are HTML fragments for some
	 * common menu types.  For example, "checkedmenuitem.html" is a fragment appropriate for checked menu items.
	 *
	 * @param {Object} options The options object, which must minimally specify the dropdown dom node
	 * @param options.dropdown The node for the dropdown presentation.  Required.
	 * @param options.populate A function that should be called to populate the dropdown before it
	 * opens each time.  Optional.
	 * @param options.triggerNode The node which will listen for events that trigger the 
	 * opening of this drop down. If it is not specified the parent of the dropdown node will be searched
	 * for a node containing the dropdownTrigger class. Optional.
	 * @param options.parentDropdown The Dropdown that is the parent of this one if this is a sub-dropdown. Optional.
	 * @param options.positioningNode The Node that the dropdown uses so that it always renders under the positioningNode's left bottom corner. Optional.
	 * @param options.skipTriggerEventListeners A boolean indicating whether or not to skip adding event
	 * listeners to the triggerNode. Optional.
	 * 
	 * @name orion.webui.dropdown.Dropdown
	 *
	 */
	function Dropdown(options) {
		EventTarget.attach(this);
		this._init(options);		
	}
	Dropdown.prototype = /** @lends orion.webui.dropdown.Dropdown.prototype */ {
			
		_init: function(options) {
			this._dropdownNode = lib.node(options.dropdown);
			if (!this._dropdownNode) { throw "no dom node for dropdown found"; } //$NON-NLS-0$
			if (options.name) {
				lib.setSafeAttribute(this._dropdownNode, "aria-label", options.name);
			}
			this._populate = options.populate;
			this._selectionClass = options.selectionClass;
			this._parentDropdown = options.parentDropdown;
			this._positioningNode = options.positioningNode;
			this._trapTabs = options.trapTabs;
			
			if (!this._parentDropdown) {
				//if a parentDropdown isn't specified move up in dom tree looking for one
				var parentNode = this._dropdownNode.parentNode;
				while(parentNode && (document !== parentNode)) {
					if (parentNode.classList && parentNode.classList.contains("dropdownMenu")) { //$NON-NLS-0$
						this._parentDropdown = parentNode.dropdown;
						break;
					}
					parentNode = parentNode.parentNode;
				}
			}
			this._dropdownNode.tabIndex = -1;

			if (options.triggerNode) {
				this._triggerNode = options.triggerNode;
			} else {
				this._triggerNode = lib.$(".dropdownTrigger", this._dropdownNode.parentNode); //$NON-NLS-0$	
			}
			if (!this._triggerNode) { throw "no dom node for dropdown trigger found"; } //$NON-NLS-0$
			
			var triggerClickHandler = function(event) {
				var actionTaken = false;
				
				if (this._triggerNode.classList.contains("dropdownMenuItem")) { //$NON-NLS-0$
					// if the trigger is a dropdownMenuItem we only want it to open the submenu
					actionTaken = this.open(event);
				} else {
					actionTaken = this.toggle(event);
				}
				
				if (actionTaken) {
					lib.stop(event);
				}
			}.bind(this);
			
			if (!options.skipTriggerEventListeners) {
				// click on trigger opens or closes.
				this._triggerNode.addEventListener("click", triggerClickHandler, false); //$NON-NLS-0$

				// if trigger node is not key enabled, then add key handler for ENTER, SPACE and DOWN arrow
				if (this._triggerNode.tagName.toLowerCase() === "span") { //$NON-NLS-0$
					this._triggerNode.addEventListener("keydown", function(event) { //$NON-NLS-0$
						if (event.keyCode === lib.KEY.ENTER || event.keyCode === lib.KEY.SPACE) {
							triggerClickHandler(event);
						}
					}.bind(this), false);
				} else {
					// add key handler for DOWN arrow
					this._triggerNode.addEventListener("keydown", function(event) { //$NON-NLS-0$
						if (event.keyCode === lib.KEY.DOWN) {
							triggerClickHandler(event);
						}
					}.bind(this), false);
				}
			}
			
			var self = this;
			this._dropdownNode.addEventListener("mouseover", function(event) {
				if (event.target === event.currentTarget)
					return;
					
				var item = event.target;
				while (item !== event.currentTarget && item.tagName.toLowerCase() !== "li")  {
					item = item.parentNode;
				}
				
				var isMenuBarItem = item.parentNode.getAttribute("role") === "menubar";
				item = item.childNodes[0]; // the 'trigger'
				
				if (!item) return;
				
				if (isMenuBarItem) {
					var openMBItem = null;
					var menuBar = item.parentNode.parentNode;
					var mbItems = menuBar.dropdown.getItems();
					for (var i = 0; i < mbItems.length; i++) {
						var mbItem = mbItems[i];
						if (mbItem.classList.contains("dropdownTriggerOpen")) { //$NON-NLS-0$
							openMBItem = mbItem;
						}
					}
					
					// only open if there's already an opened menu bar item
					if (openMBItem && openMBItem !== item) {
						openMBItem.dropdown._closeSelectedSubmenu();
						openMBItem.dropdown.close(false);
						item.dropdown.open(event);
					}
				} else {
					if (item.dropdown) {
						item.dropdown.open(event);
					} else {
						self._closeSelectedSubmenu();
						lib.stop(event);
					}
					self._selectItem(item); // select the item on mouseover
				}
			}, false);
						
			// keys
			this._dropdownNode.addEventListener("keydown", this._dropdownKeyDown.bind(this), false); //$NON-NLS-0$
		},
		
		addTriggerNode: function(node){
			var self = this;
			node.addEventListener("click", function(event) { //$NON-NLS-0$
				if (self.toggle(event))  {
					lib.stop(event);
				}
			}, false);			
		},
		
		/**
		 * Toggle the open/closed state of the dropdown.  Return a boolean that indicates whether action was taken.
		 */			
		toggle: function(mouseEvent /* optional */) {
			if (this.isVisible()) {
				return this.close(true);
			}
			return this.open(mouseEvent);
		},
		
		/**
		 * Answers whether the dropdown is visible.
		 */			
		isVisible: function() {
			return this._isVisible;
		},
		
		/**
		 * Open the dropdown.
		 */			
		open: function(mouseEvent /* optional */) {
			var actionTaken = false;
			if (!this.isVisible()) {
				this.dispatchEvent({type: "triggered", dropdown: this, event: mouseEvent}); //$NON-NLS-0$
				if (this._populate) {
					this.empty();
					this._populate(this._dropdownNode);
				}
				var items = this.getItems();
				if (items.length > 0) {
					lib.setFramesEnabled(false);
					if (this._boundAutoDismiss) {
						lib.removeAutoDismiss(this._boundAutoDismiss);
					} 
					this._boundAutoDismiss = this._autoDismiss.bind(this);

					this._triggerNode.classList.add("dropdownTriggerOpen"); //$NON-NLS-0$
					lib.setSafeAttribute(this._triggerNode, "aria-expanded", "true");
					if (this._selectionClass) {
						this._triggerNode.classList.add(this._selectionClass);
					}
					this._dropdownNode.classList.add("dropdownMenuOpen"); //$NON-NLS-0$
					this._isVisible = true;
					
					if (this._dropdownNode.scrollHeight > this._dropdownNode.offsetHeight) {
						this._buttonsAdded = addScrollButtons.call(this);
					}

					// add auto dismiss.  Clicking anywhere but trigger or a submenu item means close.
					var submenuNodes = lib.$$array(".dropdownSubMenu", this._dropdownNode); //$NON-NLS-0$
					var list = [this._triggerNode].concat(submenuNodes);
					if (this._buttonsAdded) {
						list.push(this._topScrollButton);
						list.push(this._bottomScrollButton);
					}
					lib.addAutoDismiss(list, this._boundAutoDismiss);
					this._positionDropdown(mouseEvent);
					
					if (this._buttonsAdded) {
						positionScrollButtons.call(this);
					}					
					
					this._focusDropdownNode();
					actionTaken = true;
					
					if (this._parentDropdown) {
						this._parentDropdown.submenuOpen(this);
					}
					
					if (this._trapTabs) {
						lib.trapTabs(this._dropdownNode);
					}
				}
			}
			return actionTaken;
		},
		
		_focusDropdownNode :function() {//Sub classes can override this to set focus on different items.
			this._dropdownNode.focus();
		},
		
		_autoDismiss: function(event) {
			if (this.close(false)) {
				// only trigger dismissal of parent menus if
				// this dropdown's node contains the event.target
				if (this._dropdownNode.contains(event.target)) {
					// Dismiss parent menus
					var temp = this._parentDropdown;
					while (temp) {
						temp.close(false);
						temp = temp._parentDropdown;
					}
				}
			}
		},
		
		/**
		 * This method positions the dropdown menu.
		 * The specified mouseEvent is ignored. However, subclasses 
		 * can override this method if they wish to take the mouse 
		 * position contained in the mouse event into account.
		 * 
		 * @param {MouseEvent} mouseEvent
		 */
		_positionDropdown: function(mouseEvent) {//Sub classes can override this to position the drop down differently.
			this._dropdownNode.style.left = "";
			this._dropdownNode.style.top = "";
			
			if(this._positioningNode) {
				this._dropdownNode.style.left = this._positioningNode.offsetLeft + "px";
				return;
			}
			
			var bounds = lib.bounds(this._dropdownNode);
			var bodyBounds = lib.bounds(document.body);
			if (bounds.left + bounds.width > (bodyBounds.left + bodyBounds.width)) {
				if (this._triggerNode.classList.contains("dropdownMenuItem")) { //$NON-NLS-0$
					this._dropdownNode.style.left = -bounds.width + "px"; //$NON-NLS-0$
				} else {
					var totalBounds = lib.bounds(this._boundingNode(this._triggerNode));
					var triggerBounds = lib.bounds(this._triggerNode);
					this._dropdownNode.style.left = (triggerBounds.left - totalBounds.left - bounds.width + triggerBounds.width) + "px"; //$NON-NLS-0$
				}
			}
			
			//ensure menu fits on page vertically
			var overflowY = (bounds.top + bounds.height) - (bodyBounds.top + bodyBounds.height);
			if (0 < overflowY) {
				this._dropdownNode.style.top = Math.floor(this._dropdownNode.style.top - overflowY) + "px"; //$NON-NLS-0$
			}
		},
		
		_boundingNode: function(node) {
			var style = window.getComputedStyle(node, null);
			if (style === null) {
				return node;
			}
			var position = style.getPropertyValue("position"); //$NON-NLS-0$
			if (position === "absolute" || !node.parentNode || node === document.body) { //$NON-NLS-0$
				return node;
			}
			return this._boundingNode(node.parentNode);
		},
		
		/**
		 * Close the dropdown.
		 */			
		close: function(restoreFocus) {
			var actionTaken = false;
			if (this.isVisible()) {
				this._triggerNode.classList.remove("dropdownTriggerOpen"); //$NON-NLS-0$
				lib.setSafeAttribute(this._triggerNode, "aria-expanded", "false");
				if (this._selectionClass) {
					this._triggerNode.classList.remove(this._selectionClass);
				}
				this._dropdownNode.classList.remove("dropdownMenuOpen"); //$NON-NLS-0$
				lib.setFramesEnabled(true);
				if (restoreFocus) {
					lib.returnFocus(this._dropdownNode, this._triggerNode);
				}
				
				this._isVisible = false;
				if (this._selectedItem) {
					this._selectedItem.classList.remove("dropdownMenuItemSelected"); //$NON-NLS-0$		
					this._selectedItem = null;	
				}
				
				if (this._boundAutoDismiss) {
					lib.removeAutoDismiss(this._boundAutoDismiss);
					this._boundAutoDismiss = null;
				} 
				updateScrollButtonVisibility.call(this, true);
				actionTaken = true;
			}
			return actionTaken;
		},
		
		/**
		 *
		 */
		getItems: function() {
			var items = lib.$$array("li:not(.dropdownSeparator) [role^='menuitem']", this._dropdownNode, true); //$NON-NLS-0$
			// We only want the direct li children, not any descendants.  But we can't preface a query with ">"
			// So we do some reachy filtering here.
			var filtered = [];
			var self = this;
			items.forEach(function(item) {
				var menuitem = item;
				if (menuitem.parentNode.tagName.toLowerCase() === "label") {
					// if the parent is a label, go up one more (this can happen with input menu items, such as checkbox)
					menuitem = item.parentNode;
				}
				if (menuitem.parentNode.parentNode === self._dropdownNode) {
					filtered.push(menuitem);
				}
			});
			
			return filtered;
		},
		
		/**
		 *
		 */
		empty: function() {
			var items = lib.$$array("li", this._dropdownNode); //$NON-NLS-0$
			var self = this;
			// We only want the direct li children, not any descendants. 
			items.forEach(function(item) {
				if (item.parentNode === self._dropdownNode) {
					item.parentNode.removeChild(item);
				}
			});
		},
		
		 
		/**
		 * A key is down in the dropdown node
		 */
		 _dropdownKeyDown: function(event) {
		 	if (event.keyCode === lib.KEY.TAB && !this._trapTabs) {
		 		if (this._selectedItem || this._isVisible) {
		 			var keepIterating = true;
		 			while (keepIterating) {
						keepIterating = this.close(true);
						if (this._parentDropdown && keepIterating) {
							this._parentDropdown._dropdownNode.focus();
						}
					}
		 		}
		 		return;  // Allow the TAB to propagate
		 	}
			if (event.keyCode === lib.KEY.UP || event.keyCode === lib.KEY.DOWN || event.keyCode === lib.KEY.RIGHT || event.keyCode === lib.KEY.LEFT || event.keyCode === lib.KEY.ENTER || event.keyCode === lib.KEY.SPACE) {
				var items = this.getItems();
				var isMenuBar = this._dropdownNode.getAttribute("role") === "menubar";
				if (items.length && items.length > 0) {
					if (this._selectedItem) {
						var index = items.indexOf(this._selectedItem);
						// for inputs nested in labels, we should check the parent node since the label is the item
						if (index < 0) {
							index = items.indexOf(this._selectedItem.parentNode);
						}
						if (index >= 0) {
							if (event.keyCode === lib.KEY.UP) {
								if (isMenuBar) {
									if (this._selectedItem.classList.contains("dropdownTrigger") && this._selectedItem.dropdown) { //$NON-NLS-0$
										var dropdown = this._selectedItem.dropdown;
										dropdown.open();
										var menuitems = dropdown.getItems();
										dropdown._selectItem(menuitems[menuitems.length - 1]); // select last item in submenu
									}
								} else {
									this._selectItem(items[index > 0 ? index - 1 : items.length - 1]);
								}
							} else if (event.keyCode === lib.KEY.DOWN) {
								if (isMenuBar) {
									if (this._selectedItem.classList.contains("dropdownTrigger") && this._selectedItem.dropdown) { //$NON-NLS-0$
										this._selectedItem.dropdown.open();
										this._selectedItem.dropdown._selectItem(); // select first item in submenu
									}
								} else {
									this._selectItem(items[index < items.length - 1 ? index + 1 : 0]);
								}
							} else if (event.keyCode === lib.KEY.RIGHT) {
								if (isMenuBar) {
									this._selectItem(items[index < items.length - 1 ? index + 1 : 0]);
								} else {
									if (this._selectedItem.classList.contains("dropdownTrigger") && this._selectedItem.dropdown) { //$NON-NLS-0$
										this._selectedItem.dropdown.open();
										this._selectedItem.dropdown._selectItem(); // select first item in submenu
									} else {
										this._closeThenOpen(this._selectedItem, event.keyCode, true);
									}
								}
							} else if (event.keyCode === lib.KEY.LEFT) {
								if (isMenuBar) {
									this._selectItem(items[index > 0 ? index - 1 : items.length - 1]);
								} else {
									if (this._parentDropdown) {
										this.close(true);
										this._parentDropdown._dropdownNode.focus();
									} else {
										this._closeThenOpen(this._selectedItem, event.keyCode, true);
									}
								}
							} else if (event.keyCode === lib.KEY.ENTER || event.keyCode === lib.KEY.SPACE) {
								if (!(event.target === this._dropdownNode || event.target.getAttribute("role") === "menuitem")) {
									return;
								}
								if (this._selectedItem.classList.contains("dropdownTrigger") && this._selectedItem.dropdown) { //$NON-NLS-0$
									this._selectedItem.dropdown.open();
									this._selectedItem.dropdown._selectItem(); // select first item in submenu
								} else {
									this._selectedItem.click();
									// click handling auto closes menus without restoring focus to trigger, so need to restore here
									lib.returnFocus(this._dropdownNode, this._triggerNode);
								}
							}
						}
					} else {
						if (event.keyCode === lib.KEY.UP) {
							this._selectItem(items[items.length - 1]); // select last item in menu
						} else if (event.keyCode === lib.KEY.RIGHT || event.keyCode === lib.KEY.LEFT) {
							this._closeThenOpen(this._triggerNode, event.keyCode, false);
						} else {
							// DOWN, ENTER, or SPACE: select first item in menu
							if (event.keyCode === lib.KEY.ENTER || event.keyCode === lib.KEY.SPACE) {
								if (!(event.target === this._dropdownNode || event.target.getAttribute("role") === "menuitem")) {
									return;
								}
							}
							this._selectItem(items[0]);
						}
					}
					lib.stop(event);
				}
			} else if (event.keyCode === lib.KEY.ESCAPE) {
				this.close(true);
				if (this._parentDropdown) {
					this._parentDropdown._dropdownNode.focus();
				}
				lib.stop(event);
			}
		 },
		 
		 /**
		  * Closes the menubar menu containing the specified item
		  * and opens the menu next to it in the specified direction.
		  * @param {Object} item An item within a menu
		  * @param {Integer} direction Either KEY.RIGHT or KEY.LEFT typed by user
		  * @param {Boolean} select If true, select the first item
		  */
		 _closeThenOpen: function(item, direction, select) {
			while (item.parentNode && (document !== item.parentNode) && item.parentNode.getAttribute("role") !== "menubar")  {
				item = item.parentNode;
			}
			if (!item.parentNode || document === item.parentNode) {
				return; // item is not in a menubar
			}
			var trigger = item.childNodes[0];
			var menuBar = item.parentNode;
			var mbItems = menuBar.dropdown.getItems();
			var mbItem = null;
			for (var i = 0; i < mbItems.length; i++) {
				if (mbItems[i] === trigger) {
					if (direction === lib.KEY.LEFT) {
						mbItem = i > 0 ? mbItems[i - 1] : mbItems[mbItems.length - 1];
					} else {
						mbItem = i < mbItems.length - 1 ? mbItems[i + 1] : mbItems[0];
					}
					break;
				}
			}
			trigger.dropdown._closeSelectedSubmenu();
			trigger.dropdown.close(false);
			if (mbItem) {
				mbItem.dropdown.open();
				if (select) {
					mbItem.dropdown._selectItem();
				}

			}
		 },
		 
		 /**
		  * Selects the specified dropdown menu item or the first
		  * dropdown menu item if none is specified.
		  * @param {Object} item The dropdown menu item that should be selected. See @ref getItems() for details. Optional.
		  */
		 _selectItem: function(item) {
		 	var itemToSelect = item || this.getItems()[0];
		 	if (itemToSelect) {
		 		if (this._selectedItem) {
		 			this._selectedItem.classList.remove("dropdownMenuItemSelected"); //$NON-NLS-0$
			 	}
			 	this._selectedItem = itemToSelect;
			 	this._selectedItem.classList.add("dropdownMenuItemSelected"); //$NON-NLS-0$	
			 	this._selectedItem.focus();
			 	if (this._buttonsAdded) {
			 		var itemBounds = this._selectedItem.getBoundingClientRect();
			 		var menuBounds = this._dropdownNode.getBoundingClientRect();
			 		if (this._selectedItem.offsetTop < this._dropdownNode.scrollTop) {
		 				this._selectedItem.scrollIntoView(true);
		 				if (this._dropdownNode.scrollTop < 5) {
		 					this._dropdownNode.scrollTop = 0;
		 				}
		 			}
		 			else if (itemBounds.bottom > menuBounds.bottom) {
		 				this._selectedItem.scrollIntoView(false);
		 				if ((this._dropdownNode.scrollHeight - this._dropdownNode.scrollTop - this._dropdownNode.clientHeight) < 5) {
		 					this._dropdownNode.scrollTop = this._dropdownNode.scrollHeight - this._dropdownNode.clientHeight;
		 				}
		 			}
		 			updateScrollButtonVisibility.call(this);
				}
		 	}
		 },
		 
		 /**
		  * Closes this._selectedSubmenu, and its children, if it is open.
		  * Sets the this._selectedSubmenu to the one that's passed in.
		  * @param submenu The submenu that was opened and should be set as the next this._selectedSubmenu
		  */
		submenuOpen: function(submenu) {
			if (submenu !== this._selectedSubmenu) {
				//close the current menu and all its children
				this._closeSelectedSubmenu();
				this._selectedSubmenu = submenu;
			}
		 },
		 
		_closeSelectedSubmenu: function() {
			var currentSubmenu = this._selectedSubmenu;
			while(currentSubmenu) {
				currentSubmenu.close();
				currentSubmenu = currentSubmenu._selectedSubmenu;
			}
		 },
		 
		destroy: function() {
			this.empty();
			if (this._boundAutoDismiss) {
				lib.removeAutoDismiss(this._boundAutoDismiss);
				this._boundAutoDismiss = null;
			}
		},
		
		/**
		 * Creates a new menu item and appends it to the bottom of this dropdown.
		 * @param {String} text The text to display inside the new menu item. Optional.
		 * @param {String} innerNodeType The type of the inner node to create. The default is "span". Optional.
		 * @returns {Object} The top-most new element that was created
		 */
		appendMenuItem: function(text, innerNodeType) {
			var li = createMenuItem(text, innerNodeType);
			this._dropdownNode.appendChild(li);
			return li;
		},
		
		/**
		 * Creates a new separator and appends it to the bottom of this dropdown.
		 */
		appendSeparator: function() {
			// Add a separator
			var li = createSeparator();
			this._dropdownNode.appendChild(li);
			return li;
		}
	};
	
	/**
	 * Creates a new menu item and returns it to the caller.
	 * @param {String} text The text to display inside the new menu item. Optional.
	 * @param {String} innerNodeType The type of the inner node to create. The default is "span". Optional.
	 * @returns {Object} The top-most new element that was created
	 */
	function createMenuItem(text, innerNodeType) {
		innerNodeType = innerNodeType === undefined ? "span" : innerNodeType; //$NON-NLS-0$
	 	
	 	var element = document.createElement(innerNodeType); //$NON-NLS-0$
		element.className = "dropdownMenuItem"; //$NON-NLS-0$
		lib.setSafeAttribute(element, "role", "menuitem");
		element.tabIndex = -1;
		element.style.outline = "none";
		
		if (text) {
			var span = document.createElement("span");  //$NON-NLS-0$
			span.appendChild(document.createTextNode(text));
			span.classList.add("dropdownCommandName"); //$NON-NLS-0$
			element.appendChild(span);
		}
	 	
	 	var li = document.createElement("li"); //$NON-NLS-0$
		lib.setSafeAttribute(li, "role", "none");
	 	li.appendChild(element); //$NON-NLS-0$
		
		return li;
	}
	
	/**
	 * Creates a new separator menu item and returns it to the caller.
	 * @returns {Object} The new separator element that was created
	 */
	function createSeparator() {
		var li = document.createElement("li"); //$NON-NLS-0$
		li.classList.add("dropdownSeparator"); //$NON-NLS-0$
		return li;
	}
	
	/**
	 * Appends the specified keyBindingString to the specified menu item.
	 * @param {Object} element The menu item to append the keybinding string to. Required.
	 * @param {String} keyBindingString The keybinding string to append. Required.
	 */
	function appendKeyBindingString(element, keyBindingString) {
		var span = document.createElement("span"); //$NON-NLS-0$
		span.classList.add("dropdownKeyBinding"); //$NON-NLS-0$
		span.appendChild(document.createTextNode(keyBindingString));
		element.appendChild(span);
	}
	
	/**
	 * Adds scrolling feature to a list
	*/
	function addScrollButtons() {
		var dropdown = this;

		if(!this._topScrollButton && !this._bottomScrollButton) { // if scroll buttons haven't been made yet
			this._topScrollButton = document.createElement("button");
			this._bottomScrollButton = document.createElement("button");
			this._topScrollButton.classList.add("menuScrollButton", "menuTopScrollButton", "core-sprite-openarrow");
			this._bottomScrollButton.classList.add("menuScrollButton", "menuBottomScrollButton", "core-sprite-openarrow");

			this._topScrollButton.addEventListener("mousedown", function(evt){ //$NON-NLS-0$
				if (this._activeScrollInterval) {
					window.clearInterval(this._activeScrollInterval);
				}
				this._activeScrollInterval = window.setInterval(scrollUp.bind(null, evt.shiftKey ? 20 : 2), 10);
			}.bind(this));
			this._topScrollButton.addEventListener("mouseup", function(){ //$NON-NLS-0$
				if (this._activeScrollInterval) {
					window.clearInterval(this._activeScrollInterval);
					this._activeScrollInterval = null;
				}
			}.bind(this));
			
			this._bottomScrollButton.addEventListener("mousedown", function(evt){ //$NON-NLS-0$
				if (this._activeScrollInterval) {
					window.clearInterval(this._activeScrollInterval);
				}
				this._activeScrollInterval = window.setInterval(scrollDown.bind(null, evt.shiftKey ? 20 : 2), 10);
			}.bind(this));
			this._bottomScrollButton.addEventListener("mouseup", function(){ //$NON-NLS-0$
				if (this._activeScrollInterval) {
					window.clearInterval(this._activeScrollInterval);
					this._activeScrollInterval = null;
				}
			}.bind(this));
		
			this._dropdownNode.parentNode.insertBefore(this._topScrollButton, this._dropdownNode);
			this._dropdownNode.parentNode.insertBefore(this._bottomScrollButton, this._dropdownNode.nextElementSibling);
			this._dropdownNode.style.overflow = "hidden";
		}
		
		updateScrollButtonVisibility.call(this);
		return true;
		
		function scrollDown(increment) {
			dropdown._dropdownNode.scrollTop+=increment;
			updateScrollButtonVisibility.call(dropdown);
		}
		
		function scrollUp(increment) {
			dropdown._dropdownNode.scrollTop-=increment;
			updateScrollButtonVisibility.call(dropdown);
		}
	}
	
	/**
	 * Hides or shows the scroll buttons
	 * @param {Boolean} hideAll True if hiding both buttons. Required.
	 */
	function updateScrollButtonVisibility(hideAll) {
		if (hideAll && this._topScrollButton && this._bottomScrollButton) {
			this._topScrollButton.style.display = "none";
			this._bottomScrollButton.style.display = "none";	
		}
		else if (!hideAll) {
			if (this._dropdownNode.scrollTop > 0) {
				this._topScrollButton.style.display = "block";
			} 
			else {
				this._topScrollButton.style.display = "none";
			}	
			if (this._dropdownNode.scrollHeight > this._dropdownNode.scrollTop + this._dropdownNode.offsetHeight) {
				this._bottomScrollButton.style.display = "block";
			}	 
			else {
				this._bottomScrollButton.style.display = "none";
			}
		}
	}
	
	/**
	 * Positions the top and bottom scroll buttons according to where the dropdown list is positioned
	*/
	function positionScrollButtons() {
		this._topScrollButton.style.width = this._dropdownNode.clientWidth + 1 + "px";
		this._bottomScrollButton.style.width = this._dropdownNode.clientWidth + 1 + "px";
		this._topScrollButton.style.top = this._dropdownNode.style.top;
		this._topScrollButton.style.left = this._topScrollButton.parentNode.clientWidth + "px";
		this._bottomScrollButton.style.top = Number(this._dropdownNode.style.top.replace("px", "")) + (this._dropdownNode.clientHeight-this._bottomScrollButton.clientHeight + 1)+"px";
		this._bottomScrollButton.style.left = this._bottomScrollButton.parentNode.clientWidth + "px";
	}
		
	Dropdown.prototype.constructor = Dropdown;
	//return the module exports
	return {Dropdown: Dropdown,
			appendKeyBindingString: appendKeyBindingString,
			createMenuItem: createMenuItem,
			createSeparator: createSeparator};
});

/**
 * @license text 2.0.15 Copyright jQuery Foundation and other contributors.
 * Released under MIT license, http://github.com/requirejs/text/LICENSE
 */
/*jslint regexp: true */
/*global require, XMLHttpRequest, ActiveXObject,
  define, window, process, Packages,
  java, location, Components, FileUtils */

define('text',['module'], function (module) {
    'use strict';

    var text, fs, Cc, Ci, xpcIsWindows,
        progIds = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'],
        xmlRegExp = /^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im,
        bodyRegExp = /<body[^>]*>\s*([\s\S]+)\s*<\/body>/im,
        hasLocation = typeof location !== 'undefined' && location.href,
        defaultProtocol = hasLocation && location.protocol && location.protocol.replace(/\:/, ''),
        defaultHostName = hasLocation && location.hostname,
        defaultPort = hasLocation && (location.port || undefined),
        buildMap = {},
        masterConfig = (module.config && module.config()) || {};

    function useDefault(value, defaultValue) {
        return value === undefined || value === '' ? defaultValue : value;
    }

    //Allow for default ports for http and https.
    function isSamePort(protocol1, port1, protocol2, port2) {
        if (port1 === port2) {
            return true;
        } else if (protocol1 === protocol2) {
            if (protocol1 === 'http') {
                return useDefault(port1, '80') === useDefault(port2, '80');
            } else if (protocol1 === 'https') {
                return useDefault(port1, '443') === useDefault(port2, '443');
            }
        }
        return false;
    }

    text = {
        version: '2.0.15',

        strip: function (content) {
            //Strips <?xml ...?> declarations so that external SVG and XML
            //documents can be added to a document without worry. Also, if the string
            //is an HTML document, only the part inside the body tag is returned.
            if (content) {
                content = content.replace(xmlRegExp, "");
                var matches = content.match(bodyRegExp);
                if (matches) {
                    content = matches[1];
                }
            } else {
                content = "";
            }
            return content;
        },

        jsEscape: function (content) {
            return content.replace(/(['\\])/g, '\\$1')
                .replace(/[\f]/g, "\\f")
                .replace(/[\b]/g, "\\b")
                .replace(/[\n]/g, "\\n")
                .replace(/[\t]/g, "\\t")
                .replace(/[\r]/g, "\\r")
                .replace(/[\u2028]/g, "\\u2028")
                .replace(/[\u2029]/g, "\\u2029");
        },

        createXhr: masterConfig.createXhr || function () {
            //Would love to dump the ActiveX crap in here. Need IE 6 to die first.
            var xhr, i, progId;
            if (typeof XMLHttpRequest !== "undefined") {
                return new XMLHttpRequest();
            } else if (typeof ActiveXObject !== "undefined") {
                for (i = 0; i < 3; i += 1) {
                    progId = progIds[i];
                    try {
                        xhr = new ActiveXObject(progId);
                    } catch (e) {}

                    if (xhr) {
                        progIds = [progId];  // so faster next time
                        break;
                    }
                }
            }

            return xhr;
        },

        /**
         * Parses a resource name into its component parts. Resource names
         * look like: module/name.ext!strip, where the !strip part is
         * optional.
         * @param {String} name the resource name
         * @returns {Object} with properties "moduleName", "ext" and "strip"
         * where strip is a boolean.
         */
        parseName: function (name) {
            var modName, ext, temp,
                strip = false,
                index = name.lastIndexOf("."),
                isRelative = name.indexOf('./') === 0 ||
                             name.indexOf('../') === 0;

            if (index !== -1 && (!isRelative || index > 1)) {
                modName = name.substring(0, index);
                ext = name.substring(index + 1);
            } else {
                modName = name;
            }

            temp = ext || modName;
            index = temp.indexOf("!");
            if (index !== -1) {
                //Pull off the strip arg.
                strip = temp.substring(index + 1) === "strip";
                temp = temp.substring(0, index);
                if (ext) {
                    ext = temp;
                } else {
                    modName = temp;
                }
            }

            return {
                moduleName: modName,
                ext: ext,
                strip: strip
            };
        },

        xdRegExp: /^((\w+)\:)?\/\/([^\/\\]+)/,

        /**
         * Is an URL on another domain. Only works for browser use, returns
         * false in non-browser environments. Only used to know if an
         * optimized .js version of a text resource should be loaded
         * instead.
         * @param {String} url
         * @returns Boolean
         */
        useXhr: function (url, protocol, hostname, port) {
            var uProtocol, uHostName, uPort,
                match = text.xdRegExp.exec(url);
            if (!match) {
                return true;
            }
            uProtocol = match[2];
            uHostName = match[3];

            uHostName = uHostName.split(':');
            uPort = uHostName[1];
            uHostName = uHostName[0];

            return (!uProtocol || uProtocol === protocol) &&
                   (!uHostName || uHostName.toLowerCase() === hostname.toLowerCase()) &&
                   ((!uPort && !uHostName) || isSamePort(uProtocol, uPort, protocol, port));
        },

        finishLoad: function (name, strip, content, onLoad) {
            content = strip ? text.strip(content) : content;
            if (masterConfig.isBuild) {
                buildMap[name] = content;
            }
            onLoad(content);
        },

        load: function (name, req, onLoad, config) {
            //Name has format: some.module.filext!strip
            //The strip part is optional.
            //if strip is present, then that means only get the string contents
            //inside a body tag in an HTML string. For XML/SVG content it means
            //removing the <?xml ...?> declarations so the content can be inserted
            //into the current doc without problems.

            // Do not bother with the work if a build and text will
            // not be inlined.
            if (config && config.isBuild && !config.inlineText) {
                onLoad();
                return;
            }

            masterConfig.isBuild = config && config.isBuild;

            var parsed = text.parseName(name),
                nonStripName = parsed.moduleName +
                    (parsed.ext ? '.' + parsed.ext : ''),
                url = req.toUrl(nonStripName),
                useXhr = (masterConfig.useXhr) ||
                         text.useXhr;

            // Do not load if it is an empty: url
            if (url.indexOf('empty:') === 0) {
                onLoad();
                return;
            }

            //Load the text. Use XHR if possible and in a browser.
            if (!hasLocation || useXhr(url, defaultProtocol, defaultHostName, defaultPort)) {
                text.get(url, function (content) {
                    text.finishLoad(name, parsed.strip, content, onLoad);
                }, function (err) {
                    if (onLoad.error) {
                        onLoad.error(err);
                    }
                });
            } else {
                //Need to fetch the resource across domains. Assume
                //the resource has been optimized into a JS module. Fetch
                //by the module name + extension, but do not include the
                //!strip part to avoid file system issues.
                req([nonStripName], function (content) {
                    text.finishLoad(parsed.moduleName + '.' + parsed.ext,
                                    parsed.strip, content, onLoad);
                });
            }
        },

        write: function (pluginName, moduleName, write, config) {
            if (buildMap.hasOwnProperty(moduleName)) {
                var content = text.jsEscape(buildMap[moduleName]);
                write.asModule(pluginName + "!" + moduleName,
                               "define(function () { return '" +
                                   content +
                               "';});\n");
            }
        },

        writeFile: function (pluginName, moduleName, req, write, config) {
            var parsed = text.parseName(moduleName),
                extPart = parsed.ext ? '.' + parsed.ext : '',
                nonStripName = parsed.moduleName + extPart,
                //Use a '.js' file name so that it indicates it is a
                //script that can be loaded across domains.
                fileName = req.toUrl(parsed.moduleName + extPart) + '.js';

            //Leverage own load() method to load plugin value, but only
            //write out values that do not have the strip argument,
            //to avoid any potential issues with ! in file names.
            text.load(nonStripName, req, function (value) {
                //Use own write() method to construct full module value.
                //But need to create shell that translates writeFile's
                //write() to the right interface.
                var textWrite = function (contents) {
                    return write(fileName, contents);
                };
                textWrite.asModule = function (moduleName, contents) {
                    return write.asModule(moduleName, fileName, contents);
                };

                text.write(pluginName, nonStripName, textWrite, config);
            }, config);
        }
    };

    if (masterConfig.env === 'node' || (!masterConfig.env &&
            typeof process !== "undefined" &&
            process.versions &&
            !!process.versions.node &&
            !process.versions['node-webkit'] &&
            !process.versions['atom-shell'])) {
        //Using special require.nodeRequire, something added by r.js.
        fs = require.nodeRequire('fs');

        text.get = function (url, callback, errback) {
            try {
                var file = fs.readFileSync(url, 'utf8');
                //Remove BOM (Byte Mark Order) from utf8 files if it is there.
                if (file[0] === '\uFEFF') {
                    file = file.substring(1);
                }
                callback(file);
            } catch (e) {
                if (errback) {
                    errback(e);
                }
            }
        };
    } else if (masterConfig.env === 'xhr' || (!masterConfig.env &&
            text.createXhr())) {
        text.get = function (url, callback, errback, headers) {
            var xhr = text.createXhr(), header;
            xhr.open('GET', url, true);

            //Allow plugins direct access to xhr headers
            if (headers) {
                for (header in headers) {
                    if (headers.hasOwnProperty(header)) {
                        xhr.setRequestHeader(header.toLowerCase(), headers[header]);
                    }
                }
            }

            //Allow overrides specified in config
            if (masterConfig.onXhr) {
                masterConfig.onXhr(xhr, url);
            }

            xhr.onreadystatechange = function (evt) {
                var status, err;
                //Do not explicitly handle errors, those should be
                //visible via console output in the browser.
                if (xhr.readyState === 4) {
                    status = xhr.status || 0;
                    if (status > 399 && status < 600) {
                        //An http 4xx or 5xx error. Signal an error.
                        err = new Error(url + ' HTTP status: ' + status);
                        err.xhr = xhr;
                        if (errback) {
                            errback(err);
                        }
                    } else {
                        callback(xhr.responseText);
                    }

                    if (masterConfig.onXhrComplete) {
                        masterConfig.onXhrComplete(xhr, url);
                    }
                }
            };
            xhr.send(null);
        };
    } else if (masterConfig.env === 'rhino' || (!masterConfig.env &&
            typeof Packages !== 'undefined' && typeof java !== 'undefined')) {
        //Why Java, why is this so awkward?
        text.get = function (url, callback) {
            var stringBuffer, line,
                encoding = "utf-8",
                file = new java.io.File(url),
                lineSeparator = java.lang.System.getProperty("line.separator"),
                input = new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream(file), encoding)),
                content = '';
            try {
                stringBuffer = new java.lang.StringBuffer();
                line = input.readLine();

                // Byte Order Mark (BOM) - The Unicode Standard, version 3.0, page 324
                // http://www.unicode.org/faq/utf_bom.html

                // Note that when we use utf-8, the BOM should appear as "EF BB BF", but it doesn't due to this bug in the JDK:
                // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058
                if (line && line.length() && line.charAt(0) === 0xfeff) {
                    // Eat the BOM, since we've already found the encoding on this file,
                    // and we plan to concatenating this buffer with others; the BOM should
                    // only appear at the top of a file.
                    line = line.substring(1);
                }

                if (line !== null) {
                    stringBuffer.append(line);
                }

                while ((line = input.readLine()) !== null) {
                    stringBuffer.append(lineSeparator);
                    stringBuffer.append(line);
                }
                //Make sure we return a JavaScript string and not a Java string.
                content = String(stringBuffer.toString()); //String
            } finally {
                input.close();
            }
            callback(content);
        };
    } else if (masterConfig.env === 'xpconnect' || (!masterConfig.env &&
            typeof Components !== 'undefined' && Components.classes &&
            Components.interfaces)) {
        //Avert your gaze!
        Cc = Components.classes;
        Ci = Components.interfaces;
        Components.utils['import']('resource://gre/modules/FileUtils.jsm');
        xpcIsWindows = ('@mozilla.org/windows-registry-key;1' in Cc);

        text.get = function (url, callback) {
            var inStream, convertStream, fileObj,
                readData = {};

            if (xpcIsWindows) {
                url = url.replace(/\//g, '\\');
            }

            fileObj = new FileUtils.File(url);

            //XPCOM, you so crazy
            try {
                inStream = Cc['@mozilla.org/network/file-input-stream;1']
                           .createInstance(Ci.nsIFileInputStream);
                inStream.init(fileObj, 1, 0, false);

                convertStream = Cc['@mozilla.org/intl/converter-input-stream;1']
                                .createInstance(Ci.nsIConverterInputStream);
                convertStream.init(inStream, "utf-8", inStream.available(),
                Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);

                convertStream.readString(inStream.available(), readData);
                convertStream.close();
                inStream.close();
                callback(readData.value);
            } catch (e) {
                throw new Error((fileObj && fileObj.path || '') + ': ' + e);
            }
        };
    }
    return text;
});


define('text!orion/webui/dropdowntriggerbutton.html',[],function () { return '<button class="dropdownTrigger" aria-haspopup="menu" aria-expanded="false">${ButtonText}</button><ul class="dropdownMenu" role="menu"></ul>';});


define('text!orion/webui/dropdowntriggerbuttonwitharrow.html',[],function () { return '<button class="dropdownTrigger dropdownDefaultButton" aria-haspopup="menu" aria-expanded="false">${ButtonText}<span class="dropdownArrowDown core-sprite-openarrow"></span></button><ul class="dropdownMenu" role="menu"></ul>';});


define('text!orion/webui/checkedmenuitem.html',[],function () { return '<li role="none"><label class="dropdownMenuItem" tabindex="-1" style="outline:none;"><input class="checkedMenuItem" type="checkbox" role="menuitemcheckbox" />${ItemText}</label></li>';});

/*******************************************************************************
 * @license
 * Copyright (c) 2012, 2019 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 * 
 * Contributors: IBM Corporation - initial API and implementation
 ******************************************************************************/
/*eslint-env browser, amd*/
define('orion/webui/tooltip',['orion/webui/littlelib'], function(lib) {
	
	var ID_INDEX = 0;
	var RANDOM = Date.now();

	/**
	 * Attaches tooltip behavior to a given node.  The tooltip will be assigned class "tooltip" which can be
	 * used to control appearance.  Uses the "CSS Triangle Trick" 
	 * http://css-tricks.com/snippets/css/css-triangle/
	 * for the tooltip shape and CSS transitions for fade in and fade out.
	 *
	 * Clients should destroy the tooltip if removing the node from the document.
	 *
	 * @param {Object} options The options object, which must minimally specify the tooltip dom node
	 * @param options.node The node showing the tooltip.  Required.
	 * @param options.text The text in the tooltip.  Optional.  If not specified, the client is expected to add content
	 * to the tooltip prior to triggering it.
	 * @param options.trigger The event that triggers the tooltip.  Optional.  Defaults to "mouseover".  Can be one of "mouseover",
	 * "click", "focus", or "none".  If "none" then the creator will be responsible for showing, hiding, and destroying the tooltip.
	 * If "mouseover" then the aria attributes for tooltips will be set up.
	 * @param options.position An array specifying the preferred positions to try positioning the tooltip.  Positions can be "left", "right", 
	 * "above", or "below".  If no position will fit on the screen, the first position specified is used.  Optional.  Defaults to 
	 * ["right", "above", "below", "left"].
	 * @param options.showDelay Specifies the number of millisecond delay before the tooltip begins to appear.
	 * Optional.  Valid only for "mouseover" trigger.  Defaults to 1000.
	 * @param options.hideDelay Specifies the number of millisecond delay before the tooltip begins to disappear.
	 * Optional.  Defaults to 200.  Valid only for "mouseover" trigger.
	 * @param options.tailSize Specifies the number of pixels to allocate for the tail.  Optional.  Defaults to 10.
	 * @param options.afterShowing Specifies a function to call after showing the tooltip.  Optional.
	 * @param options.afterHiding Specifies a function to call after hiding the tooltip.  Optional.
	 * @name orion.webui.tooltip.Tooltip
	 *
	 */
	function Tooltip(options) {
		this._init(options);
	}
	Tooltip.prototype = /** @lends orion.webui.tooltip.Tooltip.prototype */ {
			
		_init: function(options) {
			this._node = lib.node(options.node);
			if (!this._node) { throw "no dom node for tooltip found"; } //$NON-NLS-0$
			this._position = options.position || ["right", "above", "below", "left"]; //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
			this._text = options.text;
			this._hideDelay = options.hideDelay === undefined ? 200 : options.hideDelay;
			this._tailSize = options.tailSize || 10;
			this._trigger = options.trigger || "mouseover"; //$NON-NLS-0$
			this._afterShowing = options.afterShowing;
			this._afterHiding = options.afterHiding;
			
			var self = this;
			// set up events
			if (this._trigger === "click") { //$NON-NLS-0$
				this._showDelay = 0;
				this._node.addEventListener("click", this._clickHandler = function(event) { //$NON-NLS-0$
					if (event.target === self._node) {
						self.show();
						lib.stop(event);
					}
				}, false);
			} else if (this._trigger === "mouseover") { //$NON-NLS-0$
				this._showDelay = options.showDelay === undefined ? 500 : options.showDelay;
				var leave = ["mouseout", "click"];  //$NON-NLS-1$ //$NON-NLS-0$
				this._node.addEventListener("mouseover", this._mouseoverHandler = function(event) { //$NON-NLS-0$
					if (lib.contains(self._node, event.target)) {
						self.show();
						//lib.stop(event);
					}
				}, false);
				
				this._leaveHandler = function(event) { //$NON-NLS-0$
					if (lib.contains(self._node, event.target)) {
						self.hide();
					}
				};

				for (var i=0; i<leave.length; i++) {
					this._node.addEventListener(leave[i], this._leaveHandler, false);
				}
			} else if (this._trigger === "focus") { //$NON-NLS-0$
				this._showDelay = options.showDelay === undefined ? 0 : options.showDelay;
				this._hideDelay = options.hideDelay === undefined ? 0 : options.hideDelay;
				this._node.addEventListener("focus", this._focusHandler = function(event) { //$NON-NLS-0$
					if (lib.contains(self._node, event.target)) {
						self.show();
					}
				}, false);
				
				this._blurHandler = function(event) { //$NON-NLS-0$
					if (lib.contains(self._node, event.target)) {
						self.hide();
					}
				};
				
				this._node.addEventListener("blur", this._blurHandler, false); //$NON-NLS-0$
			}						
		},
		
		_makeTipNode: function() {
			if (!this._tip) {
				this._tip = document.createElement("span"); //$NON-NLS-0$
				this._tip.classList.add("tooltipContainer"); //$NON-NLS-0$
				this._tipInner = document.createElement("div");  //$NON-NLS-0$
				this._tipInner.classList.add("tooltip");  //$NON-NLS-0$
				
				if (this._text) {
					this._tipTextContent = document.createElement("div");  //$NON-NLS-0$
					this._tipTextContent.classList.add("textContent");  //$NON-NLS-0$
					this._tipInner.appendChild(this._tipTextContent);
					var textNode = document.createTextNode(this._text);
					this._tipTextContent.appendChild(textNode);
				}
				this._tip.appendChild(this._tipInner);
				document.body.appendChild(this._tip);
				var self = this;
				lib.addAutoDismiss([this._tip, this._node], function() {self.hide();});

				this._tip.addEventListener("keydown", function (e) {
					if (e.keyCode === lib.KEY.ESCAPE) {
						lib.returnFocus(self._tipInner, self._originalFocus, function() {
							self.hide(0);
						});
					}
				}, false);

				if (this._trigger === "mouseover") { //$NON-NLS-0$
					lib.setSafeAttribute(this._tipInner, "role", "tooltip");
					// if we are in an iframe dialog, need to use a different ID string to ensure unique id
					this._tipInner.id = "tooltip-" + RANDOM + "-" + ID_INDEX++; //$NON-NLS-1$ //$NON-NLS-0$
					var label = this._node.getAttribute("aria-label");
					if (this._text !== label) {
						lib.setSafeAttribute(this._node, "aria-describedby", this._tipInner.id);
				 	}

					// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=398960
					// mousing over the tip itself will cancel any pending timeout to close it, but then we must
					// also close it when we leave the tip.
					this._tip.addEventListener("mouseover", function(event) { //$NON-NLS-0$
						if (self._timeout) {
							window.clearTimeout(self._timeout);
							self._timeout = null;
						}
						self._tip.addEventListener("mouseout", function(event) { //$NON-NLS-0$
							if (lib.contains(self._tip, event.target)) {
								self.hide();
								lib.stop(event);
							}
						}, false);
					}, false);
				}
			}
			this._tipInner.tabIndex = this._showByKB ? 0 : -1;
			return this._tip;
		},
		
		/**
		 * @description Positions the tooltip relative to its parent
		 * @function
		 * @private
		 * @param position {String} above, below, left or right
		 * @param allowMove {Boolean} whether the tooltip can be shifted over to avoid extending over the browser window
		 * @param force {Boolean} whether to force the tooltip into the position even if it overlaps the parent
		 * @returns returns {Boolean} whether the tooltip was successfully positioned
		 */
		_positionTip: function(position, allowMove, force) {
			this._makeTipNode();  // lazy initialize
			
			this._tip.classList.add("tooltipShowing"); //$NON-NLS-0$
			
			// special case for left tooltip to ensure inner span is adjacent to tail.
			if (position === "left") { //$NON-NLS-0$
				this._tipInner.classList.add("left"); //$NON-NLS-0$
			} else {
				this._tipInner.classList.remove("left"); //$NON-NLS-0$
			}

			// Sometimes _node is not visible (eg. if _node is a dropdown menu item in a closed menu), so find
			// the nearest ancestor with a reasonable bound
			var posNode = this._node;
			var rect;
			for (rect = lib.bounds(posNode); posNode && !rect.width && !rect.height; posNode = posNode.parentNode) {
				rect = lib.bounds(posNode);
			}
			var tipRect = lib.bounds(this._tipInner);
			var top, left;
			
			switch (position) {
				case "above": //$NON-NLS-0$
					top = rect.top - tipRect.height - this._tailSize - 1;
					left = rect.left - this._tailSize;
					break;
				case "below": //$NON-NLS-0$
					top = rect.top + rect.height + this._tailSize + 1;
					left = rect.left - this._tailSize;
					break;
				case "left": //$NON-NLS-0$
					top = rect.top - this._tailSize / 2;
					left = rect.left - tipRect.width - this._tailSize - 1;
					break;
				default:  // right
					top = rect.top - this._tailSize / 2;
					left = rect.left + rect.width + this._tailSize + 1;
					break;
			}
			//Checking if the tooltip will fit inside the viewport of the browser
			var tailChanged = false;
			var body = document.body, html = document.documentElement;
			var vPortLeft = Math.max(html.scrollLeft, body.scrollLeft);
			var vPortTop = Math.max(html.scrollTop, body.scrollTop);
			var vPortRight = vPortLeft + html.clientWidth;
			var vPortBottom = vPortTop + html.clientHeight;			
			
			if (top + tipRect.height > vPortBottom) {
				if (force || (allowMove && (position === "left" || position === "right"))) {
					top = vPortBottom - tipRect.height - 1;
					tailChanged = true;
				} else {
					return false;
				}
			}
			if (left + tipRect.width > vPortRight) {
				if (force || (allowMove && (position === "above" || position === "below"))) {
					left = vPortRight - tipRect.width - 1;
					tailChanged = true;
				} else {
					return false;
				}
			}
			if (left < vPortLeft) {
				if (force) {
					left = vPortLeft + 4;
					tailChanged = true;
				} else {
					return false;
				}
			}
			if (top < vPortTop) {
				if (force) {
					top = vPortTop + 4;
					tailChanged = true;
				} else {
					return false;
				}
			}
			
			if (this._tail && (this._tail.previousPosition !== position || tailChanged)) {
				//position has changed, tail needs to be modified
				this._tip.removeChild(this._tail);
				this._tail = null;
			}
			
			if (!this._tail) {
				this._tail = document.createElement("span"); //$NON-NLS-0$
				this._tail.classList.add("tooltipTailFrom"+position); //$NON-NLS-0$
				if (position === "above" || position === "left") { //$NON-NLS-1$//$NON-NLS-0$
					// tip goes after content
					this._tip.appendChild(this._tail);
				} else {
					this._tip.insertBefore(this._tail, this._tipInner);
				}
				// Move the tail to match up with the anchor
				if (tailChanged){
					if (position === "above" || position === "below") { //$NON-NLS-1$//$NON-NLS-0$
						// tip goes after content
						this._tail.style.left = (rect.left - left + this._tailSize) + "px";
					} else {
						this._tail.style.top = (rect.top - top + this._tailSize) + "px";
					}
					this._tail.previousPosition = null;
				} else {
					this._tail.previousPosition = position;
				}
			}
			this._tip.style.top = top + "px"; //$NON-NLS-0$
			this._tip.style.left = left + "px"; //$NON-NLS-0$ 
			return true;
		},
		
		contentContainer: function() {
			this._makeTipNode();
			return this._tipInner;
		},
		
		/**
		 * @return True if this tooltip is visible, false otherwise
		 */
		isShowing: function() {
			return this._tip && this._tip.classList.contains("tooltipShowing"); //$NON-NLS-0$
		},
		
		/**
		 * Turn off(hide permanantly) the tooltip in purpose, and this tooltip won't show until it been turned on
		 */
		turnOff: function() {
			this.isTurnedOff = true;
		},
		
		/**
		 * Turn on the tooltip, and this tooltip will then work normally
		 */
		turnOn: function() {
			this.isTurnedOff = false;
		},
		
		/**
		 * Show the tooltip.
		 */			
		show: function(delay) {
			if(this.isTurnedOff){
				return;
			}
			if (this.isShowing()) { //$NON-NLS-0$
				return;
			}
			if (this._timeout) {
				window.clearTimeout(this._timeout);
				this._timeout = null;
			}
			var showDelay = delay !== undefined ? delay : this._showDelay;
			if (showDelay) {
				this._timeout = window.setTimeout(this._showImmediately.bind(this), showDelay);	
			} else {
				this._showImmediately();
			}
		},
		
		_showImmediately: function() {
			this._originalFocus = document.activeElement;
			var positioned = false;
			var index = 0;
			// See if the tooltip can fit anywhere around the anchor
			while (!positioned && index < this._position.length) {
				positioned = this._positionTip(this._position[index]);
				index++;
			}
			index = 0;
			// See if the tooltip can be moved over to fit around the anchor
			while (!positioned && index < this._position.length) {
				positioned = this._positionTip(this._position[index], true, false);
				index++;
			}
			// Place the tooltip even if it overlaps the anchor
			if (!positioned) {
				this._positionTip(this._position[0], false, true);  // force it in, it doesn't fit anywhere
			}
			
			if (this._showByKB) {
				this._tipInner.focus();
			}
			
			lib.trapTabs(this._tipInner);
			
			if (this._afterShowing) {
				this._afterShowing();
			}
		},
		
		/**
		 * Hide the tooltip.
		 */			
		hide: function(hideDelay) {
			this._showByKB = undefined;
			
			if (this._timeout) {
				window.clearTimeout(this._timeout);
				this._timeout = null;
			}
			if (!this.isShowing()) { //$NON-NLS-0$
				return;
			}
			if (hideDelay === undefined) {
				hideDelay = this._hideDelay;
			}
			var self = this;
			this._timeout = window.setTimeout(function() {
				self._tip.classList.remove("tooltipShowing"); //$NON-NLS-0$
				self._tip.removeAttribute("style"); //$NON-NLS-0$
				if (self._afterHiding) {
					self._afterHiding();
				}
			}, hideDelay);
		},
		
		destroy: function() {
			if (this._timeout) {
				window.clearTimeout(this._timeout);
				this._timeout = null;
			}
			if (this._tip) {
				document.body.removeChild(this._tip);
				this._tip = null;
				this._tipInner = null;
				this._tipTextContent = null;
				this._tail = null;
			}
			if (this._node) {
				this._node.removeAttribute("aria-describedby"); //$NON-NLS-0$
				this._node.removeEventListener("click", this._clickHandler, false); //$NON-NLS-0$
				this._node.removeEventListener("mouseover", this._mouseoverHandler, false); //$NON-NLS-0$
				this._node.removeEventListener("focus", this._focusHandler, false); //$NON-NLS-0$
				this._node.removeEventListener("blur", this._blurHandler, false); //$NON-NLS-0$
				var leave = ["mouseout", "click"];  //$NON-NLS-1$ //$NON-NLS-0$
				for (var i=0; i<leave.length; i++) {
					this._node.removeEventListener(leave[i], this._leaveHandler, false);
				}
			}
		}
	};
	Tooltip.prototype.constructor = Tooltip;
	//return the module exports
	return {Tooltip: Tooltip};
});
/*******************************************************************************
 * @license
 * Copyright (c) 2014, 2016 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made
 * available under the terms of the Eclipse Public License v1.0
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html).
 *
 * Contributors: IBM Corporation - initial API and implementation
 ******************************************************************************/
/*eslint-env browser, amd*/
define('orion/metrics',[
], function() {

	var _services = [];
	var timingVars = Object.create(null);

	/**
	 * @name Metrics
	 * @description Creates a new instance of the metrics service
	 * @param {Object} serviceRegistry The backing service registry to register the new service with
	 * @param {Object} args An object of additional arguments
	 * @param {Array} serviceArray An array of logging services (optional; for use when no service registry is present) 
	 * @returns {Metrics} A new Metrics instance
	 * @since 12.0
	 */
	function Metrics(serviceRegistry, args, serviceArray) {
		var services = serviceArray || [];
		if (serviceRegistry) {
			var refs = serviceRegistry.getServiceReferences("orion.metrics"); //$NON-NLS-0$
			refs.forEach(function(current) {
				services.push(serviceRegistry.getService(current));
			});
		}
		
		/* the following definitions are from https://developers.google.com/analytics/devguides/collection/analyticsjs/pages */
		var href = window.location.protocol + '//' + window.location.hostname + window.location.pathname + window.location.search; //$NON-NLS-0$
		var page = window.location.pathname + window.location.search;
		var title = document.title;

		_services = services;
		_services.forEach(function(current) {
			current.pageLoad(href, page, title, args);
		});

		if (serviceRegistry) {
			serviceRegistry.registerService("orion.core.metrics.client", this); //$NON-NLS-1$
		}
	}
	
	/** @callback */
	function _logTiming(timingCategory, timingVar, timingValue, timingLabel) {
		_services.forEach(function(current) {
			current.logTiming(timingCategory, timingVar, timingValue, timingLabel);
		});
	}

	/** @callback */
	function _logAudit(action, type, value, error) {
		_services.forEach(function(current) {
			if (current.logAudit) {
				current.logAudit(action, type, value, error);
			}
		});
	}

	/** @callback */
	function _logEvent(category, action, label, value, details) {
		_services.forEach(function(current) {
			current.logEvent(category, action, label || "", value, details);
		});
	}

	/** @callback */
	function _logPageLoadTiming(timingVar, timingLabel) {
		/* 
		 * The level of window.performance implementation varies across the browsers,
		 * so check for the existence of all utilized functions up-front.
		 */
		if (window.performance) {
			 /* ensure that no more timings of this type are logged for this page */
			if (window.performance.getEntriesByName && window.performance.mark) {
				if (window.performance.getEntriesByName(timingVar).length) {
					return;
				}
				window.performance.mark(timingVar);
			} else {
				if (timingVars[timingVar]) {
					return;
				}
				timingVars[timingVar] = Date.now();				
			}
			_logTiming("page", timingVar, window.performance.now(), timingLabel); //$NON-NLS-0$
		}
	}
	
	Metrics.prototype = {
		/**
		 * @description Log a timing
		 * @function
		 * @param {String} timingCategory The name of the category to log to
		 * @param {String} timingVar The name of the variable to log to
		 * @param {Number} timingValue The timing to log
		 * @param {String} timingLabel A label for the new timing
		 */
		logTiming: function(timingCategory, timingVar, timingValue, timingLabel) {
			_logTiming(timingCategory, timingVar, timingValue, timingLabel);
		},
		/**
		 * @description Log an event
		 * @function
		 * @param {String} category The name of the category to log to
		 * @param {String} action The name of the action logged
		 * @param {String} label A label for the event
		 * @param {String} value The event value to log
		 * @param {String} details Additional details about the event being logged
		 */
		logEvent: function(category, action, label, value, details) {
			_logEvent(category, action, label, value, details);
		},
		/**
		 * @description Log how long it took to load a page
		 * @function
		 * @param {Number} timingVar The timing to log
		 * @param {String} timingLabel A label for the new timing
		 */
		logPageLoadTiming: function(timingVar, timingLabel) {
			_logPageLoadTiming(timingVar, timingLabel);
		},
		/**
		 * @description Log an audit event
		 * @function
		 * @param {String} action The name of the action logged
		 * @param {String} type The type of target acted upon
		 * @param {String} value The event value to log
		 */
		logAudit: function(action, type, value, error) {
			_logAudit(action, type, value, error);
		}
	};
	
	return {
		Metrics: Metrics,
		logTiming: _logTiming,
		logEvent: _logEvent,
		logAudit: _logAudit,
		logPageLoadTiming: _logPageLoadTiming
	};
});

/*******************************************************************************
 * @license
 * Copyright (c) 2010, 2019 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 * 
 * Contributors: IBM Corporation - initial API and implementation
 ******************************************************************************/
/*eslint-env browser, amd*/
 
define('orion/commands',[
	'i18n!orion/nls/messages',
	'orion/i18nUtil',
	'orion/webui/littlelib',
	'orion/commandsProxy',
	'orion/webui/dropdown',
	'text!orion/webui/dropdowntriggerbutton.html',
	'text!orion/webui/dropdowntriggerbuttonwitharrow.html',
	'text!orion/webui/checkedmenuitem.html',
	'orion/webui/tooltip',
	'orion/metrics',
	'orion/urlModifier'
], function(messages, i18nUtil, lib, mCommandsProxy, Dropdown, DropdownButtonFragment, DropdownButtonWithArrowFragment, CheckedMenuItemFragment, Tooltip, mMetrics, urlModifier) {
		/**
		 * @name orion.commands.NO_IMAGE
		 * @description Image data for 16x16 transparent png.
		 * @property
		 */
		var NO_IMAGE = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA1BMVEUAAACnej3aAAAAAXRSTlMAQObYZgAAAAtJREFUCNdjIBEAAAAwAAFletZ8AAAAAElFTkSuQmCC"; //$NON-NLS-0$

		/* a function that can be set for retrieving bindings stored elsewhere, such as a command registry */
		var getBindings = null;
		
		/* key bindings registered locally
		 *
		 * object keyed by command id, value is { keyBinding: keyBinding, command: command, invocation: commandInvocation }
		 *
		 */
		var localKeyBindings = {};
		
		/*
		 * Set a function that will provide key bindings when key events are processed.  This is used when an external party
		 * (such as a command registry) wants its bindings to be honored by the command key listener.
		 */
		function setKeyBindingProvider(getBindingsFunction) {
			getBindings = getBindingsFunction;
		}

		/**
		 * Executes a binding if possible.
		 * @name orion.commands.executeBinding
		 * @function
		 * @static
		 * @param {Object} binding
		 * @returns {Boolean} <code>true</code> if the binding was executed, <code>false</code> otherwise.
		 */
		function executeBinding(binding) {
			var invocation = binding.invocation;
			if (invocation) {
				var command = binding.command;
				if (typeof(command.hrefCallback) === 'function') {
					var href = command.hrefCallback.call(invocation.handler || window, invocation);
					if (href.then){
						href.then(function(l){
							window.open(urlModifier(l));
						});
					} else {
						// We assume window open since there's no link gesture to tell us what to do.
						window.open(urlModifier(href));
					}
					return true;
				} else if (invocation.commandRegistry) {
					// See https://bugs.eclipse.org/bugs/show_bug.cgi?id=411282
					invocation.commandRegistry._invoke(invocation);
					return true;
				} else if (command.onClick || command.callback) {
					// TODO: what is this timeout for?
					window.setTimeout(function() {
						(command.onClick || command.callback).call(invocation.handler || window, invocation);
					}, 0);
					return true;
				}
			}
			return false;
		}

		/*
		 * Process a key event against the provided bindings.
		 */
		function _processKey(event, bindings) {
			for (var id in bindings) {
				if (bindings[id] && bindings[id].keyBinding && bindings[id].command) {
					if (bindings[id].keyBinding.match(event)) {
						var activeBinding = bindings[id];
						var keyBinding = activeBinding.keyBinding;
						// Check for keys that are scoped to a particular part of the DOM
						if (!keyBinding.domScope || lib.contains(lib.node(keyBinding.domScope), event.target)) {
							if (executeBinding(activeBinding)) {
								lib.stop(event);
								return;
							}
						}
					}
				}
			}
		}
		
		function getKeyBindings() {
			var allBindings = {};
			
			if (getBindings) {
				var i, keys, objectKey;
				keys = Object.keys(localKeyBindings);
				for (i=0; i<keys.length; i++) {
					objectKey = keys[i];
					allBindings[objectKey] = localKeyBindings[objectKey];
				}
				var otherBindings = getBindings();
				keys = Object.keys(otherBindings);
				for (i=0; i<keys.length; i++) {
					objectKey = keys[i];
					allBindings[objectKey] = otherBindings[objectKey];
				}
			} else {
				allBindings = localKeyBindings;
			}
			return allBindings;
		}
		
		function processKey(evt) {
			_processKey(evt, getKeyBindings());
		}
		
		window.document.addEventListener("keydown", function(evt) { //$NON-NLS-0$
			return mCommandsProxy.handleKeyEvent(evt, processKey);
		}, false);

	function _addImageToElement(command, element, name) {
		element.classList.add("commandImage"); //$NON-NLS-0$
		var node;
		if (command.imageClass) {
			if (command.addImageClassToElement) {
				element.classList.add(command.imageClass);
			} else {
				node = document.createElement("span"); //$NON-NLS-0$
				element.appendChild(node);
				node.classList.add(command.spriteClass);
				node.classList.add(command.imageClass);
			}
		} else {
			node = new Image();
			node.alt = command.name;
			node.name = name;
			node.id = name;
			node.src = command.image;
			element.appendChild(node);
		}
		return node;
	}

	function createDropdownMenu(parent, name, populateFunction, buttonClass, buttonIconClass, showName, selectionClass, positioningNode, displayDropdownArrow, extraClasses) {
		
		parent = lib.node(parent);
		if (!parent) {
			throw "no parent node was specified"; //$NON-NLS-0$
		}
		var range = document.createRange();
		range.selectNode(parent);
		var buttonFragment = displayDropdownArrow ? range.createContextualFragment(DropdownButtonWithArrowFragment) : range.createContextualFragment(DropdownButtonFragment);
		// bind name to fragment variable
		lib.processTextNodes(buttonFragment, {ButtonText: name});
		parent.appendChild(buttonFragment);

		var trigger = parent.firstChild;
		var inMenubar = false;
		var parentNode = parent.parentNode;
		while(parentNode && (document !== parentNode)) {
			if (parentNode.getAttribute("role") === "menubar") { //$NON-NLS-0$
				inMenubar = true;
				break;
			}
			parentNode = parentNode.parentNode;
		}
		if (inMenubar) {
			lib.setSafeAttribute(trigger, "role", "menuitem");
		} else {
			// menu button
			if (trigger.tagName.toLowerCase() !== "button") {
				lib.setSafeAttribute(trigger, "role", "button");
			}
		}

		var newMenu = parent.lastChild;
		var menuButton;
		var dropdownArrow;
		if (displayDropdownArrow) {
			menuButton = newMenu.previousSibling;
			dropdownArrow = menuButton.lastChild;
		} else {
			menuButton = newMenu.previousSibling;
		}
		if (buttonClass) {
			menuButton.classList.add(buttonClass); //$NON-NLS-0$
		} else {
			menuButton.classList.add("orionButton"); //$NON-NLS-0$
			menuButton.classList.add("commandButton"); //$NON-NLS-0$
		}
		if (extraClasses) {
			extraClasses.split(" ").forEach(menuButton.classList.add.bind(menuButton.classList));
		}
		
		if (buttonIconClass) {
			if(!showName) {
				menuButton.textContent = ""; //$NON-NLS-0$
				lib.setSafeAttribute(menuButton, "aria-label", name);
			}
			_addImageToElement({ spriteClass: "commandSprite", imageClass: buttonIconClass }, menuButton, name); //$NON-NLS-0$
			menuButton.classList.add("orionButton"); //$NON-NLS-0$
		}
		menuButton.dropdown = new Dropdown.Dropdown({
			dropdown: newMenu, 
			name: name,
			populate: populateFunction,
			selectionClass: selectionClass,
			skipTriggerEventListeners: !!dropdownArrow,
			positioningNode: positioningNode
		});
		newMenu.dropdown = menuButton.dropdown;
		return {menuButton: menuButton, menu: newMenu, dropdown: menuButton.dropdown, dropdownArrow: dropdownArrow};
	}
	
	function createCheckedMenuItem(parent, name, checked, onChange) {
		parent = lib.node(parent);
		if (!parent) {
			throw "no parent node was specified"; //$NON-NLS-0$
		}
		var range = document.createRange();
		range.selectNode(parent);
		var buttonFragment = range.createContextualFragment(CheckedMenuItemFragment);
		// bind name to fragment variable
		lib.processTextNodes(buttonFragment, {ItemText: name});
		parent.appendChild(buttonFragment);
		var itemParent = parent.lastChild;
		var checkbox = lib.$(".checkedMenuItem", itemParent); //$NON-NLS-0$
		checkbox.checked = checked;
		lib.setSafeAttribute(checkbox, "aria-checked", checked);
		checkbox.addEventListener("change", onChange, false); //$NON-NLS-0$
		return checkbox;
	}

	function createQuickfixItem(parentElement, command, commandInvocation, callback, prefService) {
		var element;
		var button;
		var clickTarget;
		var fixAllCheckbox;
		var fixAllLabel;
		
		var quickfixSettings = '/languageTools/quickfix'; //$NON-NLS-1$
		
		element = document.createElement("div");
		
		button = clickTarget = document.createElement("button");
		button.className = "orionButton"; //$NON-NLS-1$
		if (command.extraClass) {
			button.classList.add(command.extraClass);
		}
		button.classList.add("commandButton"); //$NON-NLS-1$
		
		var buttonText = command.name;
		if (commandInvocation.userData.annotation.data && commandInvocation.userData.annotation.data.ruleId){
			buttonText = i18nUtil.formatMessage(command.name, commandInvocation.userData.annotation.data.ruleId);
		}
		var text = document.createTextNode(buttonText);
		button.appendChild(text);
		
		var onClick = callback || command.callback;
		if (onClick) {
			var done = function() {
				if (fixAllCheckbox){
					if (fixAllCheckbox.checked){
						commandInvocation.userData.annotation.doFixAll = true;
					}
					if (prefService){
						prefService.get(quickfixSettings).then(function(prefs) {
							prefs[command.id] = fixAllCheckbox.checked;
							prefService.put(quickfixSettings, prefs);
						});
					}
				}
				onClick.call(commandInvocation.handler, commandInvocation);
				if (typeof commandInvocation.userData.postCallback === 'function'){
					commandInvocation.userData.postCallback();
				}
			};
			command.onClick = onClick;
			clickTarget.addEventListener("click", function(e) {
				var onClickThen;
				onClickThen = function (doIt) { if(doIt) {
						done();
					}
				};
				if(command.preCallback) {
					command.preCallback(commandInvocation).then( function(doIt) {
						onClickThen(doIt);
					});
				} else {
					onClickThen(true);
				}
				e.stopPropagation();
			}, false);
		}
		if (parentElement.nodeName.toLowerCase() === "ul") {
			var li = document.createElement("li");
			lib.setSafeAttribute(li, "role", "none");
			parentElement.appendChild(li);
			parentElement = li;
		} else {
			button.classList.add("commandMargins"); //$NON-NLS-0$
		}
		element.appendChild(button);
		
		// We check that the internal access to annotation model exists so if it breaks we don't show the checkbox at all rather than throw an error later
		if (command.fixAllEnabled && commandInvocation.userData.annotation._annotationModel){
			var id = command.id + 'fixAll'; //$NON-NLS-1$
			fixAllCheckbox = document.createElement('input');
			fixAllCheckbox.type = 'checkbox'; //$NON-NLS-1$
			fixAllCheckbox.className = "quickfixAllParameter"; //$NON-NLS-1$
			fixAllCheckbox.checked = true;
			fixAllCheckbox.id = id;
			
			fixAllLabel = document.createElement('label');
			fixAllLabel.htmlFor = id;
			fixAllLabel.className = "quickfixAllParameter"; //$NON-NLS-1$
			fixAllLabel.appendChild(document.createTextNode(messages['fixAll'])); 
			
			if (prefService){
				prefService.get(quickfixSettings).then(function(prefs) {
					if (typeof prefs[command.id] === 'boolean'){
						fixAllCheckbox.checked = prefs[command.id];
					}
					
				});
			}
			
			element.appendChild(fixAllCheckbox);
			element.appendChild(fixAllLabel);
		}
		parentElement.appendChild(element);
		return element;
	}
	
	function createCommandItem(parent, command, commandInvocation, id, keyBinding, useImage, callback) {
		var element;
		var clickTarget;
		useImage = useImage || (!command.name && command.hasImage && command.hasImage());
		
		var renderButton = function() {
				if (useImage) {
					if (command.hasImage && command.hasImage()) {
						_addImageToElement(command, element, id);
						// ensure there is accessible text describing this image
						if (command.name) {
							lib.setSafeAttribute(element, "aria-label", command.name);
						}
					} else {
						element.classList.add("commandButton"); //$NON-NLS-0$
						element.classList.add("commandMissingImageButton"); //$NON-NLS-0$
						element.appendChild(document.createTextNode(command.name));
					}
				} else {
					element.classList.add("commandButton"); //$NON-NLS-0$
					var text = document.createTextNode(command.name);
					element.appendChild(text);
				}
		};
		
		if (typeof(command.hrefCallback) === 'function') {
			element = clickTarget = document.createElement("a"); //$NON-NLS-0$
			element.id = id;
			if (useImage && command.hasImage()) {
				_addImageToElement(command, element, id);
				// ensure there is accessible text describing this image
				if (command.name) {
					lib.setSafeAttribute(element, "aria-label", command.name);
				}
			} else {
				element.className = "commandLink"; //$NON-NLS-0$
				element.appendChild(document.createTextNode(command.name));
			}
			var href = command.hrefCallback.call(commandInvocation.handler, commandInvocation);
			if (href.then){
				href.then(function(l){
					element.href = l;
				});
			} else if (href) {
				element.href = href; 
			} else {  // no href
				element.href = "#"; //$NON-NLS-0$
			}
			if(command.hrefTarget){
				element.target = command.hrefTarget;
			}
		} else {
			if (command.type === "switch") { //$NON-NLS-0$
				element = clickTarget = document.createElement("div"); //$NON-NLS-0$
				lib.setSafeAttribute(element, "role", "button");
				element.tabIndex = 0;
				element.className = "orionSwitch"; //$NON-NLS-0$
				if (command.name) {
					lib.setSafeAttribute(element, "aria-label", command.name);
				}
				lib.setSafeAttribute(element, "aria-pressed", command.checked ? "true" : "false");
				var span1 = document.createElement("span"); //$NON-NLS-0$
				span1.className = "orionSwitchInner"; //$NON-NLS-0$
				span1.classList.add(command.imageClass);
				var span2 = document.createElement("span"); //$NON-NLS-0$
				span2.className = "orionSwitchSwitch"; //$NON-NLS-0$
				element.appendChild(span1);
				element.appendChild(span2);
				element.addEventListener("keydown", function(e) { //$NON-NLS-0$
					if (e.keyCode === lib.KEY.ENTER || e.keyCode === lib.KEY.SPACE) {
						element.click();
						e.preventDefault();
					}
				}, false);
				element.addEventListener("click", function(e) { //$NON-NLS-0$
					toggleSwitch(element);
				}, false);
			} else if (command.type === "toggle") {  //$NON-NLS-0$
				element = clickTarget = document.createElement("button"); //$NON-NLS-0$
				element.className = "orionButton"; //$NON-NLS-0$
				element.classList.add(command.checked ? "orionToggleOn" : "orionToggleOff");  //$NON-NLS-1$ //$NON-NLS-0$
				if (command.extraClass) {
					element.classList.add(command.extraClass);
				}
				element.id = "orionToggle" + command.id; //$NON-NLS-0$
				if(parent.id) {
					element.id = element.id + parent.id;
				}
				renderButton();
			} else {
				element = clickTarget = document.createElement("button"); //$NON-NLS-0$
				element.className = "orionButton"; //$NON-NLS-0$
				if (command.extraClass) {
					element.classList.add(command.extraClass);
				}
				renderButton();
			}
			var onClick = callback || command.callback;
			if (onClick) {
				var done = function() {onClick.call(commandInvocation.handler, commandInvocation);};
				command.onClick = onClick;
				clickTarget.addEventListener("click", function(e) { //$NON-NLS-0$
					var onClickThen;
					if (command.type === "switch" || command.type === "toggle") { //$NON-NLS-1$ //$NON-NLS-0$
						onClickThen = function (doIt) {
							if (command.type === "toggle") { //$NON-NLS-0$
								if(doIt) {
									command.checked = !command.checked;
								}
								if (command.checked) {
									element.classList.remove("orionToggleOff"); //$NON-NLS-0$
									element.classList.add("orionToggleOn"); //$NON-NLS-0$
									element.classList.add("orionToggleAnimate"); //$NON-NLS-0$
								} else {
									element.classList.remove("orionToggleOn"); //$NON-NLS-0$
									element.classList.add("orionToggleOff"); //$NON-NLS-0$
									element.classList.add("orionToggleAnimate"); //$NON-NLS-0$
								}
							} else { // "switch"
								if(doIt) {
									command.checked = element.getAttribute("aria-pressed") === "true"; //$NON-NLS-0$ //$NON-NLS-1$
								} else {
									toggleSwitch(element); // don't do it, i.e. put it back
								}
							}
							if(doIt) {
								window.setTimeout(done, 250);
							}
						};
					} else {
						onClickThen = function (doIt) { if(doIt) {
								done();
							}
						};
					}
					if(command.preCallback) {
						command.preCallback(commandInvocation).then( function(doIt) {
							onClickThen(doIt);
						});
					} else {
						onClickThen(true);
					}
					e.stopPropagation();
				}, false);
			}
		}
		if (parent.nodeName.toLowerCase() === "ul") { //$NON-NLS-0$
			var li = document.createElement("li"); //$NON-NLS-0$
			lib.setSafeAttribute(li, "role", "none");
			parent.appendChild(li);
			parent = li;
		} else {
			element.classList.add("commandMargins"); //$NON-NLS-0$
		}
		parent.appendChild(element);
		if (command.tooltip) {
			element.commandTooltip = new Tooltip.Tooltip({
				node: element,
				text: command.tooltip,
				position: ["above", "below", "right", "left"] //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
			});
		}
		if (keyBinding) {
			localKeyBindings[command.id] = { keyBinding: keyBinding, command: command, invocation: commandInvocation };
		}
		return element;
	}
	
	function toggleSwitch(element) {
		if (element.getAttribute("aria-pressed") === "true") { //$NON-NLS-0$ //$NON-NLS-1$
			lib.setSafeAttribute(element, "aria-pressed", "false");
		} else {
			lib.setSafeAttribute(element, "aria-pressed", "true");
		}
	}

	function createCommandMenuItem(parent, command, commandInvocation, keyBinding, callback, keyBindingString) {
		var element, li;
		var dropdown = parent.dropdown;
		if (typeof(command.hrefCallback) === 'function') {
			li = Dropdown.createMenuItem(command.name, "a"); //$NON-NLS-0$
			commandInvocation.domNode = element = li.firstElementChild;
			var href = command.hrefCallback.call(commandInvocation.handler, commandInvocation);
			if (href.then){
				href.then(function(l){
					element.href = l;
				});
			} else if (href) {
				element.href = href;
			} else {  // no href
				element.href = "#"; //$NON-NLS-0$
			}
			if(command.hrefTarget){
				element.target = command.hrefTarget;
			}
			element.addEventListener("keydown", function(e) { //$NON-NLS-0$
				if (e.keyCode === lib.KEY.ENTER || e.keyCode === lib.KEY.SPACE) {
					element.click();
				}
			}, false);
		} else {
			li = Dropdown.createMenuItem(command.name); //$NON-NLS-0$
			element = li.firstElementChild;
			var onClick = callback || command.callback;
			if (onClick) {
				command.onClick = onClick;
				element.addEventListener("click", function(e) { //$NON-NLS-0$
					if (dropdown){
						dropdown.close(true);
					}
					onClick.call(commandInvocation.handler, commandInvocation);
				}, false);
				element.addEventListener("keydown", function(e) { //$NON-NLS-0$
					if (e.keyCode === lib.KEY.ENTER || e.keyCode === lib.KEY.SPACE) {
						e.preventDefault(); /* prevents dropdown from receiving event and re-opening */
						element.click();
					}
				}, false);
			}
		}

		if (command.tooltip) {
			/* nested menu items may represent commands, hence require tooltips */
			element.commandTooltip = new Tooltip.Tooltip({
				node: element,
				text: command.tooltip,
				position: ["right", "above", "below", "left"] //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
			});
		}
		
		if (keyBindingString) {
			Dropdown.appendKeyBindingString(element, keyBindingString);
		}
		
		parent.appendChild(li);
		
		if (keyBinding) {
			localKeyBindings[command.id] = { keyBinding: keyBinding, command: command, invocation: commandInvocation };
		}

		return element;
	}

	/**
	 * CommandInvocation is a data structure that carries all relevant information about a command invocation.
	 * It represents a unique invocation of a command by the user.  Each time a user invokes a command (by click, keystroke, URL),
	 * a new invocation is passed to the client.
	 * <p>Note:  When retrieving parameters from a command invocation, clients should always use {@link #parameters}
	 * rather than obtaining the parameter object originally specified for the command (using {@link #command}.parameters).
	 * This ensures that the parameter values for a unique invocation are used vs. any default parameters that may have been
	 * specified originally.  Similarly, if a client wishes to store data that will preserved across multiple invocations of a command,
	 * that data can be stored in the original parameters description and a reference maintained by the client.
	 * </p>
	 * 
	 * @name orion.commands.CommandInvocation
	 * @class Carries information about a command invocation.
	 * @param {Object} handler
	 * @param {Array} items
	 * @param {Object} [userData]
	 * @param {orion.commands.Command} command
	 * @param {orion.commandregistry.CommandRegistry} [commandRegistry]
	 */
	/**
	 * @name orion.commands.CommandInvocation#commandRegistry
	 * @type orion.commandregistry.CommandRegistry
	 */
	/**
	 * @name orion.commands.CommandInvocation#handler
	 * @type Object
	 */
	/**
	 * @name orion.commands.CommandInvocation#command
	 * @type orion.commands.Command
	 */
	/**
	 * @name orion.commands.CommandInvocation#items
	 * @type Array
	 */
	/**
	 * @name orion.commands.CommandInvocation#parameters
	 * @type orion.commands.ParametersDescription
	 */
	/**
	 * @name orion.commands.CommandInvocation#userData
	 * @type Object
	 */
	/**
	 * @name orion.commands.CommandInvocation#userData
	 * @type Object
	 */
	function CommandInvocation (handler, items, /* optional */userData, command, /* optional */ commandRegistry) {
		this.commandRegistry = commandRegistry;
		this.handler = handler;
		this.items = items;
		this.userData = userData;
		this.command = command;
		if (command.parameters) {
			this.parameters = command.parameters.makeCopy(); // so that we aren't retaining old values from previous invocations
		}
		this.id = command.id;
	}
	CommandInvocation.prototype = /** @lends orion.commands.CommandInvocation.prototype */ {
		/**
		 * Returns whether this command invocation can collect parameters.
		 * 
		 * @returns {Boolean} whether parameters can be collected
		 */
		collectsParameters: function() {
			return this.commandRegistry && this.commandRegistry.collectsParameters();
		},
	
		/**
		 * Makes and returns a (shallow) copy of this command invocation.
		 * @param {orion.commands.ParametersDescription} parameters A description of parameters to be used in the copy.  Optional.
		 * If not specified, then the existing parameters should be copied.
		 */
		makeCopy: function(parameters) {
			var copy =  new CommandInvocation(this.handler, this.items, this.userData, this.command, this.commandRegistry);
			copy.domNode = this.domNode;
			copy.domParent = this.domParent;
			if (parameters) {
				copy.parameters = parameters.makeCopy();
			} else if (this.parameters) {
				copy.parameters = this.parameters.makeCopy();
			}
			return copy;
		}

	};
	CommandInvocation.prototype.constructor = CommandInvocation;



	/**
	 * Constructs a new command with the given options.
	 * @param {Object} [options] The command options object.
	 * @param {String} [options.id] the unique id to be used when referring to the command in the command service.
	 * @param {String} [options.name] the name to be used when showing the command as text.
	 * @param {String} [options.tooltip] the tooltip description to use when explaining the purpose of the command.
	 * @param {Function} [options.callback] the callback to call when the command is activated.  The callback should either 
	 *  perform the command or return a deferred that represents the asynchronous performance of the command.  Optional.
	 * @param {Function} [options.hrefCallback] if specified, this callback is used to retrieve
	 *  a URL that can be used as the location for a command represented as a hyperlink.  The callback should return 
	 *  the URL.  In this release, the callback may also return a deferred that will eventually return the URL, but this 
	 *  functionality may not be supported in the future.  See https://bugs.eclipse.org/bugs/show_bug.cgi?id=341540.
	 *  Optional.
	 * @param {Function} [options.choiceCallback] a callback which retrieves choices that should be shown in a secondary
	 *  menu from the command itself.  Returns a list of choices that supply the name and image to show, and the callback
	 *  to call when the choice is made.  Optional.
	 * @param {String} [options.imageClass] a CSS class name suitable for showing a background image.  Optional.
	 * @param {Boolean} [options.addImageClassToElement] If true, the image class will be added to the element's
	 *  class list. Otherwise, a span element with the image class is created and appended to the element.  Optional.
	 * @param {String} [options.selectionClass] a CSS class name to be appended when the command button is selected. Optional.
	 * @param {String} [options.spriteClass] an additional CSS class name that can be used to specify a sprite background image.  This
	 *  useful with some sprite generation tools, where imageClass specifies the location in a sprite, and spriteClass describes the
	 *  sprite itself.  Optional.
	 * @param {Function} [options.visibleWhen] A callback that returns a boolean to indicate whether the command should be visible
	 *  given a particular set of items that are selected.  Optional, defaults to always visible.
	 * @param {orion.commands.ParametersDescription} [options.parameters] A description of parameters that should be collected before invoking
	 *  the command.
	 * @param {Image} [options.image] the image that may be used to represent the callback.  A text link will be shown in lieu
	 *  of an image if no image is supplied.  Optional.
	 * @class A command is an object that describes an action a user can perform, as well as when and
	 *  what it should look like when presented in various contexts.  Commands are identified by a
	 *  unique id.
	 * @name orion.commands.Command
	 */
	function Command (options) {
		this._init(options);
	}
	Command.prototype = /** @lends orion.commands.Command.prototype */ {
		_init: function(options) {
			this.id = options.id;  // unique id
			this.name = options.name;
			this.tooltip = options.tooltip;
			this.fixAllEnabled = options.fixAllEnabled; // optional toggle for quickfix command to apply to all annotations
			this.callback = options.callback; // optional callback that should be called when command is activated (clicked)
			this.preCallback = options.preCallback; // optional callback that should be called when command is activated (clicked)
			this.hrefCallback = options.hrefCallback; // optional callback that returns an href for a command link
			this.hrefTarget = options.hrefTarget; // optional href target determinds if a new tab should be opened
			this.choiceCallback = options.choiceCallback; // optional callback indicating that the command will supply secondary choices.  
														// A choice is an object with a name, callback, and optional image
			this.positioningNode = options.positioningNode; // optional positioning node choice command.
			this.image = options.image || NO_IMAGE;
			this.imageClass = options.imageClass;   // points to the location in a sprite
			this.addImageClassToElement = options.addImageClassToElement; // optional boolean if true will add the image class to the 
																		// element's class list
			this.extraClass = options.extraClass;
			this.selectionClass = options.selectionClass;
			this.spriteClass = options.spriteClass || "commandSprite"; // defines the background image containing sprites //$NON-NLS-0$
			this.visibleWhen = options.visibleWhen;
			this.parameters = options.parameters;  // only used when a command is used in the command registry. 
			this.isEditor = options.isEditor;
			this.type = options.type;
			this.checked = options.checked;
			this.track = options.track;
		},
		
		/**
		 * Populate the specified menu with choices using the choiceCallback.
		 * Used internally by the command service.  Not intended to be overridden or called
		 * externally.
		 */
		 populateChoicesMenu: function(parent, items, handler, userData, commandService) {
			var choices = this.getChoices(items, handler, userData);
			var addCheck = choices.some(function(choice) {
				return choice.checked;
			});
			choices.forEach(function(choice) {
				if (choice.name) {
					var itemNode = document.createElement("li"); //$NON-NLS-0$
					lib.setSafeAttribute(itemNode, "role", "none");
					parent.appendChild(itemNode);
					var node = document.createElement("span"); //$NON-NLS-0$
					node.tabIndex = -1; 
					node.classList.add("dropdownMenuItem"); //$NON-NLS-0$
					node.style.outline = "none";
					if (addCheck) {
						lib.setSafeAttribute(node, "role", "menuitemradio");
						lib.setSafeAttribute(node, "aria-checked", choice.checked ? "true" : "false");
						var check = document.createElement("span"); //$NON-NLS-0$
						check.classList.add("check"); //$NON-NLS-0$
						lib.setSafeAttribute(check, "role", "none");
						lib.setSafeAttribute(check, "aria-hidden", "true");
						check.appendChild(document.createTextNode(choice.checked ? "\u25CF" : "")); //$NON-NLS-1$ //$NON-NLS-0$
						node.appendChild(check);
					} else {
						lib.setSafeAttribute(node, "role", "menuitem");
					}
					if (choice.imageClass) {
						var image = document.createElement("span"); //$NON-NLS-0$
						image.classList.add(choice.imageClass);
						node.appendChild(image);
					}
					var span = document.createElement("span"); //$NON-NLS-0$
					var text = document.createTextNode(choice.name);
					span.appendChild(text);
					node.appendChild(span);
					itemNode.appendChild(node);
					node.choice = choice;
					node.addEventListener("click", function(event) { //$NON-NLS-0$
						mMetrics.logEvent("command", "invoke", this.id + ">" + choice.name); //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
						choice.callback.call(choice, items);
					}.bind(this), false); 
					node.addEventListener("keydown", function(event) { //$NON-NLS-0$
						if (event.keyCode === lib.KEY.ENTER || event.keyCode === lib.KEY.SPACE) {
							mMetrics.logEvent("command", "invoke", this.id + ">" + choice.name); //$NON-NLS-3$ //$NON-NLS-1$ //$NON-NLS-0$
							choice.callback.call(choice, items);
						}
					}.bind(this), false);
				} else {  // anything not named is a separator
					commandService._generateMenuSeparator(parent);
				}
			}.bind(this));
		},
		
		/**
		 * Get the appropriate choices using the choiceCallback.
		 * Used internally by the command service.  Not intended to be overridden or called
		 * externally.
		 */
		getChoices: function(items, handler, userData) {
			if (this.choiceCallback) {
				return this.choiceCallback.call(handler, items, userData);
			}
			return null;
		},
		
		/**
		 * Make a choice callback appropriate for the given choice and items.
		 * Used internally by the command service.  Not intended to be overridden or called
		 * externally.
		 */
		makeChoiceCallback: function(choice, items) {
			return function(event) {
				if (choice.callback) {
					choice.callback.call(choice, items, event);
				}
			};
		},
		
		/**
		 * Return a boolean indicating whether this command has a specific image associated
		 * with it. Used internally by the command service.  Not intended to be overridden or called
		 * externally.
		 */
		hasImage: function() {
			return this.imageClass || this.image !== NO_IMAGE; //$NON-NLS-0$
		}
	};  // end Command prototype
	Command.prototype.constructor = Command;
	
	//return the module exports
	return {
		Command: Command,
		CommandInvocation: CommandInvocation,
		createDropdownMenu: createDropdownMenu,
		createCheckedMenuItem: createCheckedMenuItem,
		createQuickfixItem: createQuickfixItem,
		createCommandItem: createCommandItem,
		createCommandMenuItem: createCommandMenuItem,
		executeBinding: executeBinding,
		setKeyBindingProvider: setKeyBindingProvider,
		localKeyBindings: localKeyBindings,
		getKeyBindings: getKeyBindings,
		processKey: processKey,
		NO_IMAGE: NO_IMAGE,
		_testMethodProcessKey: _processKey  // only exported for test cases
	};
});

/*******************************************************************************
 * @license
 * Copyright (c) 2010, 2013 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 * 
 * Contributors: 
 *		Felipe Heidrich (IBM Corporation) - initial API and implementation
 *		Silenio Quarti (IBM Corporation) - initial API and implementation
 ******************************************************************************/

/*eslint-env browser, amd*/
define("orion/keyBinding", ['orion/util'], function(util) { //$NON-NLS-1$ //$NON-NLS-0$

    /**
	 * @class A KeyBinding is an interface used to define keyboard shortcuts.
	 * @name orion.KeyBinding
	 * 
	 * @property {Function} match The function to match events.
	 * @property {Function} equals The funtion to compare to key bindings.
	 *
	 * @see orion.KeyStroke
	 * @see orion.KeySequence
	 */

	/**
	 * Constructs a new key stroke with the given key code, modifiers and event type.
	 * 
	 * @param {String|Number} keyCode the key code.
	 * @param {Boolean} mod1 the primary modifier (usually Command on Mac and Control on other platforms).
	 * @param {Boolean} mod2 the secondary modifier (usually Shift).
	 * @param {Boolean} mod3 the third modifier (usually Alt).
	 * @param {Boolean} mod4 the fourth modifier (usually Control on the Mac).
	 * @param {String} type the type of event that the keybinding matches; either "keydown" or "keypress".
	 * 
	 * @class A KeyStroke represents of a key code and modifier state that can be triggered by the user using the keyboard.
	 * @name orion.KeyStroke
	 * 
	 * @property {String|Number} keyCode The key code.
	 * @property {Boolean} mod1 The primary modifier (usually Command on Mac and Control on other platforms).
	 * @property {Boolean} mod2 The secondary modifier (usually Shift).
	 * @property {Boolean} mod3 The third modifier (usually Alt).
	 * @property {Boolean} mod4 The fourth modifier (usually Control on the Mac).
	 * @property {String} [type=keydown] The type of event that the keybinding matches; either "keydown" or "keypress"
	 *
	 * @see orion.editor.TextView#setKeyBinding
	 */
	function KeyStroke (keyCode, mod1, mod2, mod3, mod4, type) {
		this.type = type || "keydown"; //$NON-NLS-0$
		if (typeof(keyCode) === "string" && this.type === "keydown") { //$NON-NLS-1$ //$NON-NLS-0$
			this.keyCode = keyCode.toUpperCase().charCodeAt(0);
		} else {
			this.keyCode = keyCode;
		}
		this.mod1 = mod1 !== undefined && mod1 !== null ? mod1 : false;
		this.mod2 = mod2 !== undefined && mod2 !== null ? mod2 : false;
		this.mod3 = mod3 !== undefined && mod3 !== null ? mod3 : false;
		this.mod4 = mod4 !== undefined && mod4 !== null ? mod4 : false;
	}
	KeyStroke.prototype = /** @lends orion.KeyStroke.prototype */ {
		getKeys: function() {
			return [this];
		},
		/**
		 * Determines either this key stroke matches the specifed event.  It can match either a
		 * a whole sequence of key events or a single key event at a specified index.
		 * <p>
		 * <code>KeyStroke</code> only matches single key events. <code>KeySequence</code> handles
		 * matching a sequence of events.
		 * </p>
		 * TODO explain this better
		 * 
		 * @param {DOMEvent|DOMEvent[]} e the key event or list of events to match.
		 * @param index the key event to match.
		 * @returns {Boolean} <code>true</code> whether the key binding matches the key event.
		 *
		 * @see orion.KeySequence#match
		 */
		match: function (e, index) {
			if (index !== undefined) {
				if (index !== 0) {
					return false;
				}
			} else {
				if (e instanceof Array) {
					if (e.length > 1) {
						return false;
					}
					e = e[0];
				}
			}
			if (e.type !== this.type) {
				return false;
			}
			if (this.keyCode === e.keyCode || this.keyCode === String.fromCharCode(util.isOpera ? e.which : (e.charCode !== undefined ? e.charCode : e.keyCode))) {
				var mod1 = util.isMac ? e.metaKey : e.ctrlKey;
				if (this.mod1 !== mod1) { return false; }
				if (this.type === "keydown") { //$NON-NLS-0$
					if (this.mod2 !== e.shiftKey) { return false; }
				}
				if (this.mod3 !== e.altKey) { return false; }
				if (util.isMac && this.mod4 !== e.ctrlKey) { return false; }
				return true;
			}
			return false;
		},
		/**
		 * Returns whether this key stroke is the same as the given parameter.
		 * 
		 * @param {orion.KeyBinding} kb the key binding to compare with.
		 * @returns {Boolean} whether or not the parameter and the receiver describe the same key binding.
		 */
		equals: function(kb) {
			if (!kb) { return false; }
			if (this.keyCode !== kb.keyCode) { return false; }
			if (this.mod1 !== kb.mod1) { return false; }
			if (this.mod2 !== kb.mod2) { return false; }
			if (this.mod3 !== kb.mod3) { return false; }
			if (this.mod4 !== kb.mod4) { return false; }
			if (this.type !== kb.type) { return false; }
			return true;
		} 
	};
	
	/**
	 * Constructs a new key sequence with the given key strokes.
	 * 
	 * @param {orion.KeyStroke[]} keys the key strokes for this sequence.
	 * 
	 * @class A KeySequence represents of a list of key codes and a modifiers state that can be triggered by the user using the keyboard.
	 * @name orion.KeySequence
	 * 
	 * @property {orion.KeyStroke[]} keys the list of key strokes.
	 *
	 * @see orion.editor.TextView#setKeyBinding
	 */
	function KeySequence (keys) {
		this.keys = keys;
	}
	KeySequence.prototype = /** @lends orion.KeySequence.prototype */ {
		getKeys: function() {
			return this.keys.slice(0);
		},
		match: function (e, index) {
			var keys = this.keys;
			if (index !== undefined) {
				if (index > keys.length) {
					return false;
				}
				if (keys[index].match(e)) {
					if (index === keys.length - 1) {
						return true;
					}
					return index + 1;
				}
				return false;
			} else {
				if (!(e instanceof Array)) {
					e = [e];
				}
				if (e.length > keys.length) {
					return false;
				}
				var i;
				for (i = 0; i < e.length; i++) {
					if (!keys[i].match(e[i])) {
						return false;
					}
				}
				if (i === keys.length) {
					return true;
				}
				return i;
			}
		},
		/**
		 * Returns whether this key sequence is the same as the given parameter.
		 * 
		 * @param {orion.KeyBinding|orion.KeySequence} kb the key binding to compare with.
		 * @returns {Boolean} whether or not the parameter and the receiver describe the same key binding.
		 */
		equals: function(kb) {
			if (!kb.keys) { return false; }
			if (kb.keys.length !== this.keys.length) { return false; }
			for (var i=0; i<kb.keys.length; i++) {
				if (!kb.keys[i].equals(this.keys[i])) { return false; }
			}
			return true;
		}	
	};
	
	return {
		KeyBinding: KeyStroke, // for backwards compatibility
		KeyStroke: KeyStroke,
		KeySequence: KeySequence
	};
});

/*******************************************************************************
 * @license
 * Copyright (c) 2009, 2012 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 *
 * Contributors: IBM Corporation - initial API and implementation
 *******************************************************************************/
/*eslint-env browser, amd*/
define('orion/explorers/navigationUtils',[], function() {
	var userAgent = navigator.userAgent;
	var isPad = userAgent.indexOf("iPad") !== -1; //$NON-NLS-0$
	
	/**
	 * Generate a grid navigation item into a given array. A grid navigation item is presented by a wrapper object wrapping the domNode. 
	 *
	 * @param {Array} domNodeWrapperList the array that holds the grid navigation item. Normally the .gridChildren property from a row model.
	 * @param {Element} domNode the html dom element representing a grid. Normally left or right arrow keys on the current row highlight the dom element.
	 *        When a grid is rendered, the caller has to decide what dom element can be passed. 
	 */
	function generateNavGrid(domNodeWrapperList, domNode, widget, onClick, showOutline) {
		if(isPad){
			return;
		}
		if(!domNodeWrapperList){
			return;
		}
		domNodeWrapperList.push({domNode: domNode});
		domNode.tabIndex = -1;
		domNode.classList.add("treeTableGridCell"); //$NON-NLS-0$
		if (!showOutline) {
			domNode.style.outline = "none"; //$NON-NLS-0$
		}

	}
                
	/**
	 * Add a grid navigation item to the navigation dictionary. A row navigation model normally comes from any node in a {treeModelIterator}.
	 * The .gridChildren property will be lazily created on the row model as an array where all the grid navigation items live.
	 *
	 * @param {ExplorerNavDict} navDict the dictionary that holds the info of all navigation info from model id.
	 * @param {object} rowModel the row model from the {treeModelIterator}.
	 * @param {Element} domNode the html dom element representing a grid. Normally left or right arrow keys on the current row highlight the dom element.
	 *        When a grid is rendered, the caller has to decide what dom element can be passed. 
	 * @param {Boolean} showOutline if true, the domNode will have an outline when focused.
	 */
	function addNavGrid(navDict, rowModel, domNode, showOutline) {
		if(!navDict){
			return;
		}
		var navHolder = navDict.getGridNavHolder(rowModel, true);
		if(navHolder){
			generateNavGrid(navHolder, domNode, null, null, showOutline);
		}
	}
	
	/**
	 * Remove a grid navigation item from a given array. A grid navigation item is presented by a wrapper object wrapping the domNode, widget and onClick properties. 
	 *
	 * @param {Array} domNodeWrapperList the array that holds the grid navigation item. Normally the .gridChildren property from a row model.
	 * @param {DomNode} domNode the html dom node representing a grid. Normally left or right arrow keys on the current row highlight the dom node.
	 *        When a grid is rendered, the caller has to decide what dom node can be passed. 
	 */
	function removeNavGrid(domNodeWrapperList, domNode) {
		if(!domNodeWrapperList){
			return;
		}
		
		for(var i = 0; i < domNodeWrapperList.length ; i++){
			if(domNodeWrapperList[i].domNode === domNode){
				domNodeWrapperList.splice(i, 1);
				return;
			}
		}
	}
	//return module exports
	return {
		addNavGrid: addNavGrid,
		generateNavGrid: generateNavGrid,
		removeNavGrid: removeNavGrid
	};
});

/*******************************************************************************
 * @license
 * Copyright (c) 2011, 2019 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 *
 *******************************************************************************/
define ('orion/bidiFormat',['orion/webui/littlelib'], function(lib) {

    var TextSegment = (function() {
        var TextSegment = function (obj) {
            this.content = "";
            this.actual = "";
            this.textDirection = "";
            this.localGui = "";
            this.isVisible = true;
            this.isSeparator = false;
            this.isParsed = false;
            this.keep = false;
            this.inBounds = false;
            this.inPoints = false;
            var prop = "";
            for (prop in obj) {
                if (obj.hasOwnProperty(prop)) {
                    this[prop] = obj[prop];
                }
            }
        };
        return TextSegment;
    })();

    var tools = (function() {
        function initBounds(bounds) {
            if (!bounds) {
                return false;
            }
            if (typeof bounds.start === "undefined") {
                bounds.start = "";
            }
            if (typeof bounds.end === "undefined") {
                bounds.end = "";
            }
            if (typeof bounds.startAfter !== "undefined") {
                bounds.start = bounds.startAfter;
                bounds.after = true;
            } else {
                bounds.after = false;
            }
            if (typeof bounds.endBefore !== "undefined") {
                bounds.end = bounds.endBefore;
                bounds.before = true;
            } else {
                bounds.before = false;
            }
            var startPos = parseInt(bounds.startPos, 10);
            if (!isNaN(startPos)) {
                bounds.usePos = true;
            } else {
                bounds.usePos = false;
            }
            var bLength = parseInt(bounds.length, 10);
            if (!isNaN(bLength)) {
                bounds.useLength = true;
            } else {
                bounds.useLength = false;
            }
            bounds.loops = typeof bounds.loops !== "undefined" ? !!bounds.loops : true;
            return true;
        }

        function getBounds(segment, src) {
            var bounds = {};
            for (var prop in src) {
                if (src.hasOwnProperty(prop)) {
                    bounds[prop] = src[prop];
                }
            }
            var content = segment.content;
            var usePos = bounds.usePos && bounds.startPos < content.length;
            if (usePos) {
                bounds.start = "";
                bounds.loops = false;
            }
            bounds.bStart = usePos ? bounds.startPos : bounds.start.length > 0 ? content.indexOf(bounds.start) : 0;
            var useLength = bounds.useLength && bounds.length > 0 && bounds.bStart + bounds.length < content.length;
            if (useLength) {
                bounds.end = "";
            }
            bounds.bEnd = useLength ? bounds.bStart + bounds.length : bounds.end.length > 0 ?
                    content.indexOf(bounds.end, bounds.bStart + bounds.start.length) + 1 : content.length;
            if (!bounds.after) {
                bounds.start = "";
            }
            if (!bounds.before) {
                bounds.end = "";
            }
            return bounds;
        }

        return {
            handleSubcontents: function (segments, args, subs, origContent, locale) { // jshint unused: false
                if (!subs.content || typeof subs.content !== "string" || subs.content.length === 0) {
                    return segments;
                }
                var sLoops = true;
                if (typeof subs.loops !== "undefined") {
                    sLoops = !!subs.loops;
                }
                for (var j = 0; true; j++) {
                    if (j >= segments.length) {
                        break;
                    }
                    if (segments[j].isParsed || segments.keep || segments[j].isSeparator) {
                        continue;
                    }
                    var content = segments[j].content;
                    var start = content.indexOf(subs.content);
                    if (start < 0) {
                        continue;
                    }
                    var end;
                    var length = 0;
                    if (subs.continued) {
                        do {
                            length++;
                            end = content.indexOf(subs.content, start + length * subs.content.length);
                        } while (end === 0);
                    } else {
                        length = 1;
                    }
                    end = start + length * subs.content.length;
                    segments.splice(j, 1);
                    if (start > 0) {
                        segments.splice(j, 0, new TextSegment({
                            content: content.substring(0, start),
                            localGui: args.dir,
                            keep: true
                        }));
                        j++;
                    }
                    segments.splice(j, 0, new TextSegment({
                        content: content.substring(start, end),
                        textDirection: subs.subDir,
                        localGui: args.dir
                    }));
                    if (end < content.length) {
                        segments.splice(j + 1, 0, new TextSegment({
                            content: content.substring(end, content.length),
                            localGui: args.dir,
                            keep: true
                        }));
                    }
                    if (!sLoops) {
                        break;
                    }
                }
            },

            handleBounds: function (segments, args, aBounds, origContent, locale) {
                for (var i = 0; i < aBounds.length; i++) {
                    if (!initBounds(aBounds[i])) {
                        continue;
                    }
                    for (var j = 0; true; j++) {
                        if (j >= segments.length) {
                            break;
                        }
                        if (segments[j].isParsed || segments[j].inBounds || segments.keep || segments[j].isSeparator) {
                            continue;
                        }
                        var bounds = getBounds(segments[j], aBounds[i]);
                        var start = bounds.bStart;
                        var end = bounds.bEnd;
                        if (start < 0 || end < 0) {
                            continue;
                        }
                        var content = segments[j].content;

                        segments.splice(j, 1);
                        if (start > 0) {
                            segments.splice(j, 0, new TextSegment({
                                content: content.substring(0, start),
                                localGui: args.dir,
                                keep: true
                            }));
                            j++;
                        }
                        if (bounds.start) {
                            segments.splice(j, 0, new TextSegment({
                                content: bounds.start,
                                localGui: args.dir,
                                isSeparator: true
                            }));
                            j++;
                        }
                        segments.splice(j, 0, new TextSegment({
                            content: content.substring(start + bounds.start.length, end - bounds.end.length),
                            textDirection: bounds.subDir,
                            localGui: args.dir,
                            inBounds: true
                        }));
                        if (bounds.end) {
                            j++;
                            segments.splice(j, 0, new TextSegment({
                                content: bounds.end,
                                localGui: args.dir,
                                isSeparator: true
                            }));
                        }
                        if (end + bounds.end.length < content.length) {
                            segments.splice(j + 1, 0, new TextSegment({
                                content: content.substring(end + bounds.end.length, content.length),
                                localGui: args.dir,
                                keep: true
                            }));
                        }
                        if (!bounds.loops) {
                            break;
                        }
                    }
                }
                for (i = 0; i < segments.length; i++) {
                    segments[i].inBounds = false;
                }
                return segments;
            },

            handleCases: function (segments, args, cases, origContent, locale) {
                if (cases.length === 0) {
                    return segments;
                }
                var hArgs = {};
                for (var prop in args) {
                    if (args.hasOwnProperty(prop)) {
                        hArgs[prop] = args[prop];
                    }
                }
                for (var i =  0; i < cases.length; i++) {
                    if (!cases[i].handler || typeof cases[i].handler.handle !== "function") {
                        cases[i].handler = args.commonHandler;
                    }
                    if (cases[i].args) {
                        hArgs.cases = cases[i].args.cases;
                        hArgs.points = cases[i].args.points;
                        hArgs.bounds = cases[i].args.bounds;
                        hArgs.subs = cases[i].args.subs;
                    } else {
                        hArgs.cases = [];
                        hArgs.points = [];
                        hArgs.bounds = [];
                        hArgs.subs = {};
                    }
                    cases[i].handler.handle(origContent, segments, hArgs, locale);
                }
                return segments;
            },

            handlePoints: function (segments, args, points, origContent, locale) { //jshint unused: false
                for (var i = 0; i < points.length; i++) {
                    for (var j = 0; true; j++) {
                        if (j >= segments.length) {
                            break;
                        }
                        if (segments[j].isParsed || segments[j].keep || segments[j].isSeparator) {
                            continue;
                        }
                        var content = segments[j].content;
                        var pos = content.indexOf(points[i]);
                        if (pos >= 0) {
                            segments.splice(j, 1);
                            if (pos > 0) {
                                segments.splice(j, 0, new TextSegment({
                                    content: content.substring(0, pos),
                                    textDirection: args.subDir,
                                    localGui: args.dir,
                                    inPoints: true
                                }));
                                j++;
                            }
                            segments.splice(j, 0, new TextSegment({
                                content: points[i],
                                localGui: args.dir,
                                isSeparator: true
                            }));
                            if (pos + points[i].length + 1 <= content.length) {
                                segments.splice(j + 1, 0, new TextSegment({
                                    content: content.substring(pos + points[i].length),
                                    textDirection: args.subDir,
                                    localGui: args.dir,
                                    inPoints: true
                                }));
                            }
                        }
                    }
                }
                for (i = 0; i < segments.length; i++) {
                    if (segments[i].keep) {
                        segments[i].keep = false;
                    } else if(segments[i].inPoints){
                        segments[i].isParsed = true;
                        segments[i].inPoints = false;
                    }
                }
                return segments;
            }
        };
    })();

    var common = (function() {
        return {
            handle: function (content, segments, args, locale) {
                var cases = [];
                if (Array.isArray(args.cases)) {
                    cases = args.cases;
                }
                var points = [];
                if (typeof args.points !== "undefined") {
                    if (Array.isArray(args.points)) {
                        points = args.points;
                    } else if (typeof args.points === "string") {
                        points = args.points.split("");
                    }
                }
                var subs = {};
                if (typeof args.subs === "object") {
                    subs = args.subs;
                }
                var aBounds = [];
                if (Array.isArray(args.bounds)) {
                    aBounds = args.bounds;
                }

                tools.handleBounds(segments, args, aBounds, content, locale);
                tools.handleSubcontents(segments, args, subs, content, locale);
                tools.handleCases(segments, args, cases, content, locale);
                tools.handlePoints(segments, args, points, content, locale);
                return segments;
            }
        };
    })();

    var misc = (function() {
        var isBidiLocale = function (locale) {
            var lang = !locale ? "" : locale.split("-")[0];
            if (!lang || lang.length < 2) {
                return false;
            }
            return ["iw", "he", "ar", "fa", "ur"].some(function (bidiLang) {
                return bidiLang === lang;
            });
        };
        var LRE = "\u202A";
        var RLE = "\u202B";
        var PDF = "\u202C";
        var LRM = "\u200E";
        var RLM = "\u200F";
        var LRO = "\u202D";
        var RLO = "\u202E";

        return {
            LRE: LRE,
            RLE: RLE,
            PDF: PDF,
            LRM: LRM,
            RLM: RLM,
            LRO: LRO,
            RLO: RLO,

            getLocaleDetails: function (locale) {
                if (!locale) {
                    locale = typeof navigator === "undefined" ? "" :
                        (navigator.language ||
                        navigator.userLanguage ||
                        "");
                }
                locale = locale.toLowerCase();
                if (isBidiLocale(locale)) {
                    var full = locale.split("-");
                    return {lang: full[0], country: full[1] ? full[1] : ""};
                }
                return {lang: "not-bidi"};
            },

            removeUcc: function (text) {
                if (text) {
                    return text.replace(/[\u200E\u200F\u202A-\u202E]/g, "");
                }
                return text;
            },

            removeTags: function (text) {
                if (text) {
                    return text.replace(/<[^<]*>/g, "");
                }
                return text;
            },

            getDirection: function (text, dir, guiDir, checkEnd) {
                if (dir !== "auto" && (/^(rtl|ltr)$/i).test(dir)) {
                    return dir;
                }
                guiDir = (/^(rtl|ltr)$/i).test(guiDir) ? guiDir : "ltr";
                var txt = !checkEnd ? text : text.split("").reverse().join("");
                var fdc = /[A-Za-z\u05d0-\u065f\u066a-\u06ef\u06fa-\u07ff\ufb1d-\ufdff\ufe70-\ufefc]/.exec(txt);
                return fdc ? (fdc[0] <= "z" ? "ltr" : "rtl") : guiDir;
            },

            hasArabicChar: function (text) {
                var fdc = /[\u0600-\u065f\u066a-\u06ef\u06fa-\u07ff\ufb1d-\ufdff\ufe70-\ufefc]/.exec(text);
                return !!fdc;
            },

            showMarks: function (text, guiDir) {
                var result = "";
                for (var i = 0; i < text.length; i++) {
                    var c = "" + text.charAt(i);
                    switch (c) {
                    case LRM:
                        result += "<LRM>";
                        break;
                    case RLM:
                        result += "<RLM>";
                        break;
                    case LRE:
                        result += "<LRE>";
                        break;
                    case RLE:
                        result += "<RLE>";
                        break;
                    case LRO:
                        result += "<LRO>";
                        break;
                    case RLO:
                        result += "<RLO>";
                        break;
                    case PDF:
                        result += "<PDF>";
                        break;
                    default:
                        result += c;
                    }
                }
                var mark = typeof guiDir === "undefined" || !((/^(rtl|ltr)$/i).test(guiDir)) ? "" :
                    guiDir === "rtl" ? RLO : LRO;
                return mark + result + (mark === "" ? "" : PDF);
            },

            hideMarks: function (text) {
                var txt = text.replace(/<LRM>/g, this.LRM).replace(/<RLM>/g, this.RLM).replace(/<LRE>/g, this.LRE);
                return txt.replace(/<RLE>/g, this.RLE).replace(/<LRO>/g, this.LRO).replace(/<RLO>/g, this.RLO).replace(/<PDF>/g, this.PDF);
            },

            showTags: function (text) {
                return "<xmp>" + text + "</xmp>";
            },

            hideTags: function (text) {
                return text.replace(/<xmp>/g,"").replace(/<\/xmp>/g,"");
            }
        };
    })();

    var stext = (function() {
        var stt = {};

        // args
        //   handler: main handler (default - dbidi/stt/handlers/common)
        //   guiDir: GUI direction (default - "ltr")
        //   dir: main stt direction (default - guiDir)
        //   subDir: direction of subsegments
        //   points: array of delimiters (default - [])
        //   bounds: array of definitions of bounds in which handler works
        //   subs: object defines special handling for some substring if found
        //   cases: array of additional modules with their args for handling special cases (default - [])
        function parseAndDisplayStructure(content, fArgs, isHtml, locale) {
            if (!content || !fArgs) {
                return content;
            }
            return displayStructure(parseStructure(content, fArgs, locale), fArgs, isHtml);
        }

        function checkArguments(fArgs, fullCheck) {
            var args = Array.isArray(fArgs)? fArgs[0] : fArgs;
            if (!args.guiDir) {
                args.guiDir = "ltr";
            }
            if (!args.dir) {
                args.dir = args.guiDir;
            }
            if (!fullCheck) {
                return args;
            }
            if (typeof args.points === "undefined") {
                args.points = [];
            }
            if (!args.cases) {
                args.cases = [];
            }
            if (!args.bounds) {
                args.bounds = [];
            }
            args.commonHandler = common;
            return args;
        }

        function parseStructure(content, fArgs, locale) {
            if (!content || !fArgs) {
                return new TextSegment({content: ""});
            }
            var args = checkArguments(fArgs, true);
            var segments = [new TextSegment(
                {
                    content: content,
                    actual: content,
                    localGui: args.dir
                })];
            var parse = common.handle;
            if (args.handler && typeof args.handler === "function") {
                parse = args.handler.handle;
            }
            parse(content, segments, args, locale);
            return segments;
        }

        function displayStructure(segments, fArgs, isHtml) {
            var args = checkArguments(fArgs, false);
            if (isHtml) {
                return getResultWithHtml(segments, args);
            }
            else {
                return getResultWithUcc(segments, args);
            }
        }

        function getResultWithUcc(segments, args, isHtml) {
            var result = "";
            var checkedDir = "";
            var prevDir = "";
            var stop = false;
            for (var i = 0; i < segments.length; i++) {
                if (segments[i].isVisible) {
                    var dir = segments[i].textDirection;
                    var lDir = segments[i].localGui;
                    if (lDir !== "" && prevDir === "") {
                        result += (lDir === "rtl" ? misc.RLE : misc.LRE);
                    }
                    else if(prevDir !== "" && (lDir === "" || lDir !== prevDir || stop)) {
                        result += misc.PDF + (i == segments.length - 1 && lDir !== ""? "" : args.dir === "rtl" ? misc.RLM : misc.LRM);
                        if (lDir !== "") {
                            result += (lDir === "rtl" ? misc.RLE : misc.LRE);
                        }
                    }
                    if (dir === "auto") {
                        dir = misc.getDirection(segments[i].content, dir, args.guiDir);
                    }
                    if ((/^(rtl|ltr)$/i).test(dir)) {
                        result += (dir === "rtl" ? misc.RLE : misc.LRE) + segments[i].content + misc.PDF;
                        checkedDir = dir;
                    }
                    else {
                        result += segments[i].content;
                        checkedDir = misc.getDirection(segments[i].content, dir, args.guiDir, true);
                    }
                    if (i < segments.length - 1) {
                        var locDir = lDir && segments[i+1].localGui? lDir : args.dir;
                        result += locDir === "rtl" ? misc.RLM : misc.LRM;
                    }
                    else if(prevDir !== "") {
                        result += misc.PDF;
                    }
                    prevDir = lDir;
                    stop = false;
                }
                else {
                    stop = true;
                }
            }
            var sttDir = args.dir === "auto" ? misc.getDirection(segments[0].actual, args.dir, args.guiDir) : args.dir;
            if (sttDir !== args.guiDir) {
                result = (sttDir === "rtl" ? misc.RLE : misc.LRE) + result + misc.PDF;
            }
            return result;
        }

        function getResultWithHtml(segments, args, isHtml) {
            var result = "";
            var checkedDir = "";
            var prevDir = "";
            for (var i = 0; i < segments.length; i++) {
                if (segments[i].isVisible) {
                    var dir = segments[i].textDirection;
                    var lDir = segments[i].localGui;
                    if (lDir !== "" && prevDir === "") {
                        result += "<bdi dir='" + (lDir === "rtl" ? "rtl" : "ltr") + "'>";
                    }
                    else if(prevDir !== "" && (lDir === "" || lDir !== prevDir || stop)) {
                        result += "</bdi>" + (i == segments.length - 1 && lDir !== ""? "" : "<span style='unicode-bidi: embed; direction: " + (args.dir === "rtl" ? "rtl" : "ltr") + ";'></span>");
                        if (lDir !== "") {
                            result += "<bdi dir='" + (lDir === "rtl" ? "rtl" : "ltr") + "'>";
                        }
                    }

                    if (dir === "auto") {
                        dir = misc.getDirection(segments[i].content, dir, args.guiDir);
                    }
                    if ((/^(rtl|ltr)$/i).test(dir)) {
                        //result += "<span style='unicode-bidi: embed; direction: " + (dir === "rtl" ? "rtl" : "ltr") + ";'>" + segments[i].content + "</span>";
                        result += "<bdi dir='" + (dir === "rtl" ? "rtl" : "ltr") + "'>" + segments[i].content + "</bdi>";
                        checkedDir = dir;
                    }
                    else {
                        result += segments[i].content;
                        checkedDir = misc.getDirection(segments[i].content, dir, args.guiDir, true);
                    }
                    if (i < segments.length - 1) {
                        var locDir = lDir && segments[i+1].localGui? lDir : args.dir;
                        result += "<span style='unicode-bidi: embed; direction: " + (locDir === "rtl" ? "rtl" : "ltr") + ";'></span>";
                    }
                    else if(prevDir !== "") {
                        result += "</bdi>";
                    }
                    prevDir = lDir;
                    stop = false;
                }
                else {
                    stop = true;
                }
            }
            var sttDir = args.dir === "auto" ? misc.getDirection(segments[0].actual, args.dir, args.guiDir) : args.dir;
            if (sttDir !== args.guiDir) {
                result = "<bdi dir='" + (sttDir === "rtl" ? "rtl" : "ltr") + "'>" + result + "</bdi>";
            }
            return result;
        }

        //TBD ?
        function restore(text, isHtml) {
            return text;
        }

        stt.parseAndDisplayStructure = parseAndDisplayStructure;
        stt.parseStructure = parseStructure;
        stt.displayStructure = displayStructure;
        stt.restore = restore;

        return stt;
    })();

    var breadcrumb = (function() {
        return {
            format: function (text, args, isRtl, isHtml, locale, parseOnly) {
                var fArgs =
                {
                        guiDir: isRtl ? "rtl" : "ltr",
                        dir: args.dir ? args.dir : isRtl ? "rtl" : "ltr",
                        subs: {
                            content: ">",
                            continued: true,
                            subDir: isRtl ? "rtl" : "ltr"
                        },
                        cases: [{
                            args: {
                                subs: {
                                    content: "<",
                                    continued: true,
                                    subDir: isRtl ? "ltr" : "rtl"
                                }
                            }
                        }]
                };

                if (!parseOnly) {
                    return stext.parseAndDisplayStructure(text, fArgs, !!isHtml, locale);
                }
                else {
                    return stext.parseStructure(text, fArgs, !!isHtml, locale);
                }
            }
        };
    })();

    var comma = (function() {
        return {
            format: function (text, args, isRtl, isHtml, locale, parseOnly) {
                var fArgs =
                {
                        guiDir: isRtl ? "rtl" : "ltr",
                        dir: "ltr",
                        points: ","
                };
                if (!parseOnly) {
                    return stext.parseAndDisplayStructure(text, fArgs, !!isHtml, locale);
                }
                else {
                    return stext.parseStructure(text, fArgs, !!isHtml, locale);
                }
            }
        };
    })();

    var email = (function() {
        function getDir(text, locale) {
            if (misc.getLocaleDetails(locale).lang !== "ar") {
                return "ltr";
            }
            var ind = text.indexOf("@");
            if (ind > 0 && ind < text.length - 1) {
                return misc.hasArabicChar(text.substring(ind + 1)) ? "rtl" : "ltr";
            }
            return "ltr";
        }

        return {
            format: function (text, args, isRtl, isHtml, locale, parseOnly) {
                var fArgs =
                {
                        guiDir: isRtl ? "rtl" : "ltr",
                        dir: getDir(text, locale),
                        points: "<>.:,;@",
                        cases: [{
                            handler: common,
                            args: {
                                bounds: [{
                                    startAfter: "\"",
                                    endBefore: "\""
                                },
                                {
                                    startAfter: "(",
                                    endBefore: ")"
                                }
                                ],
                                points: ""
                            }
                        }]
                };
                if (!parseOnly) {
                    return stext.parseAndDisplayStructure(text, fArgs, !!isHtml, locale);
                }
                else {
                    return stext.parseStructure(text, fArgs, !!isHtml, locale);
                }
            }
        };
    })();

    var filepath = (function() {
        return {
            format: function (text, args, isRtl, isHtml, locale, parseOnly) {
                var fArgs =
                {
                        guiDir: isRtl ? "rtl" : "ltr",
                        dir: "ltr",
                        subDir : args.subDir,
                        points: "/\\:.&<>"
                };
                if (!parseOnly) {
                    return stext.parseAndDisplayStructure(text, fArgs, !!isHtml, locale);
                }
                else {
                    return stext.parseStructure(text, fArgs, !!isHtml, locale);
                }
            }
        };
    })();

    var formula = (function() {
        return {
            format: function (text, args, isRtl, isHtml, locale, parseOnly) {
                var fArgs =
                {
                        guiDir: isRtl ? "rtl" : "ltr",
                        dir: "ltr",
                        points: " /%^&[]<>=!?~:.,|()+-*{}",
                };
                if (!parseOnly) {
                    return stext.parseAndDisplayStructure(text, fArgs, !!isHtml, locale);
                }
                else {
                    return stext.parseStructure(text, fArgs, !!isHtml, locale);
                }
            }
        };
    })();


    var sql = (function() {
        return {
            format: function (text, args, isRtl, isHtml, locale, parseOnly) {
                var fArgs =
                {
                        guiDir: isRtl ? "rtl" : "ltr",
                        dir: "ltr",
                        points: "\t!#%&()*+,-./:;<=>?|[]{}",
                        cases: [{
                            handler: common,
                            args: {
                                bounds: [{
                                    startAfter: "/*",
                                    endBefore: "*/"
                                },
                                {
                                    startAfter: "--",
                                    end: "\n"
                                },
                                {
                                    startAfter: "--"
                                }
                                ]
                            }
                        },
                        {
                            handler: common,
                            args: {
                                subs: {
                                    content: " ",
                                    continued: true
                                }
                            }
                        },
                        {
                            handler: common,
                            args: {
                                bounds: [{
                                    startAfter: "'",
                                    endBefore: "'"
                                },
                                {
                                    startAfter: "\"",
                                    endBefore: "\""
                                }
                                ]
                            }
                        }
                        ]
                };
                if (!parseOnly) {
                    return stext.parseAndDisplayStructure(text, fArgs, !!isHtml, locale);
                }
                else {
                    return stext.parseStructure(text, fArgs, !!isHtml, locale);
                }
            }
        };
    })();

    var underscore = (function() {
        return {
            format: function (text, args, isRtl, isHtml, locale, parseOnly) {
                var fArgs =
                {
                        guiDir: isRtl ? "rtl" : "ltr",
                        dir: "ltr",
                        points: "_"
                };
                if (!parseOnly) {
                    return stext.parseAndDisplayStructure(text, fArgs, !!isHtml, locale);
                }
                else {
                    return stext.parseStructure(text, fArgs, !!isHtml, locale);
                }
            }
        };
    })();

    var url = (function() {
        return {
            format: function (text, args, isRtl, isHtml, locale, parseOnly) {
                var fArgs =
                {
                        guiDir: isRtl ? "rtl" : "ltr",
                        dir: "ltr",
                        points: ":?#/@.[]=&<>"
                };
                if (!parseOnly) {
                    return stext.parseAndDisplayStructure(text, fArgs, !!isHtml, locale);
                }
                else {
                    return stext.parseStructure(text, fArgs, !!isHtml, locale);
                }
            }
        };
    })();

    var word = (function() {
        return {
            format: function (text, args, isRtl, isHtml, locale, parseOnly) {
                var fArgs =
                {
                        guiDir: isRtl ? "rtl" : "ltr",
                        dir: args.dir ? args.dir : isRtl ? "rtl" : "ltr",
                        points: " ,.!?;:",
                };
                if (!parseOnly) {
                    return stext.parseAndDisplayStructure(text, fArgs, !!isHtml, locale);
                }
                else {
                    return stext.parseStructure(text, fArgs, !!isHtml, locale);
                }
            }
        };
    })();

    var xpath = (function() {
        return {
            format: function (text, args, isRtl, isHtml, locale, parseOnly) {
                var fArgs =
                {
                        guiDir: isRtl ? "rtl" : "ltr",
                        dir: "ltr",
                        points: " /[]<>=!:@.|()+-*",
                        cases: [{
                            handler: common,
                            args: {
                                bounds: [{
                                    startAfter: "\"",
                                    endBefore: "\""
                                },
                                {
                                    startAfter: "'",
                                    endBefore: "'"
                                }
                                ],
                                points: ""
                            }
                        }
                        ]
                };
                if (!parseOnly) {
                    return stext.parseAndDisplayStructure(text, fArgs, !!isHtml, locale);
                }
                else {
                    return stext.parseStructure(text, fArgs, !!isHtml, locale);
                }
            }
        };
    })();

    var custom = (function() {
        return {
            format: function (text, args, isRtl, isHtml, locale, parseOnly) {
                var hArgs = {};
                var prop = "";
                var sArgs = Array.isArray(args)? args[0] : args;
                for (prop in sArgs) {
                    if (sArgs.hasOwnProperty(prop)) {
                        hArgs[prop] = sArgs[prop];
                    }
                }
                hArgs.guiDir = isRtl ? "rtl" : "ltr";
                hArgs.dir = hArgs.dir ? hArgs.dir : hArgs.guiDir;
                if (!parseOnly) {
                    return stext.parseAndDisplayStructure(text, hArgs, !!isHtml, locale);
                }
                else {
                    return stext.parseStructure(text, hArgs, !!isHtml, locale);
                }
            }
        };
    })();

    var message = (function() {
        var params = {msgLang: "en", msgDir: "", phLang: "", phDir: "", phPacking: ["{","}"], phStt: {type: "none", args: {}}, guiDir: ""};
        var parametersChecked = false;

        function getDirectionOfLanguage(lang) {
            if (lang === "he" || lang === "iw" || lang === "ar") {
                return "rtl";
            }
            return "ltr";
        }

        function checkParameters(obj) {
            if (obj.msgDir.length === 0) {
                obj.msgDir = getDirectionOfLanguage(obj.msgLang);
            }
            obj.msgDir = obj.msgDir !== "ltr" && obj.msgDir !== "rtl" && obj.msgDir != "auto"? "ltr" : obj.msgDir;
            if (obj.guiDir.length === 0) {
                obj.guiDir = obj.msgDir;
            }
            obj.guiDir = obj.guiDir !== "rtl"? "ltr" : "rtl";
            if (obj.phDir.length === 0) {
                obj.phDir = obj.phLang.length === 0? obj.msgDir : getDirectionOfLanguage(obj.phLang);
            }
            obj.phDir = obj.phDir !== "ltr" && obj.phDir !== "rtl" && obj.phDir != "auto"? "ltr" : obj.phDir;
            if (typeof (obj.phPacking) === "string") {
                obj.phPacking = obj.phPacking.split("");
            }
            if (obj.phPacking.length < 2) {
                obj.phPacking = ["{","}"];
            }
        }

        return {
            setDefaults: function (args) {
                for (var prop in args) {
                    if (params.hasOwnProperty(prop)) {
                        params[prop] = args[prop];
                    }
                }
                checkParameters(params);
                parametersChecked = true;
            },

            format: function (text) {
                if (!parametersChecked) {
                    checkParameters(params);
                    parametersChecked = true;
                }
                var isHtml = false;
                var hasHtmlArg = false;
                var spLength = params.phPacking[0].length;
                var epLength = params.phPacking[1].length;
                if (arguments.length > 0) {
                    var last = arguments[arguments.length-1];
                    if (typeof (last) === "boolean") {
                        isHtml = last;
                        hasHtmlArg = true;
                    }
                }
                //Message
                var re = new RegExp(params.phPacking[0] + "\\d+" + params.phPacking[1]);
                var m;
                var tSegments = [];
                var offset = 0;
                var txt = text;
                while ((m = re.exec(txt)) != null) {
                    var lastIndex = txt.indexOf(m[0]) + m[0].length;
                    if (lastIndex > m[0].length) {
                        tSegments.push({text: txt.substring(0, lastIndex - m[0].length), ph: false});
                    }
                    tSegments.push({text: m[0], ph: true});
                    offset += lastIndex;
                    txt = txt.substring(lastIndex, txt.length);
                }
                if (offset < text.length) {
                    tSegments.push({text: text.substring(offset, text.length), ph: false});
                }
                //Parameters
                var tArgs = [];
                for (var i = 1; i < arguments.length - (hasHtmlArg? 1 : 0); i++) {
                    var arg = arguments[i];
                    var checkArr = arg;
                    var inLoop = false;
                    var indArr = 0;
                    if (Array.isArray(checkArr)) {
                        arg = checkArr[0];
                        if (typeof(arg) === "undefined") {
                            continue;
                        }
                        inLoop = true;
                    }
                    do {
                        if (typeof (arg) === "string") {
                            tArgs.push({text: arg, dir: params.phDir, stt: params.stt});
                        }
                        else if(typeof (arg) === "boolean") {
                            isHtml = arg;
                        }
                        else if(typeof (arg) === "object") {
                            tArgs.push(arg);
                            if (!arg.hasOwnProperty("text")) {
                                tArgs[tArgs.length-1].text = "{???}";
                            }
                            if (!arg.hasOwnProperty("dir") || arg.dir.length === 0) {
                                tArgs[tArgs.length-1].dir = params.phDir;
                            }
                            if (!arg.hasOwnProperty("stt") || (typeof (arg.stt) === "string" && arg.stt.length === 0) ||
                                (typeof (arg.stt) === "object" && Object.keys(arg.stt).length === 0)) {
                                tArgs[tArgs.length-1].stt = params.phStt;
                            }
                        }
                        else {
                            tArgs.push({text: "" + arg, dir: params.phDir, stt: params.phStt});
                        }
                        if (inLoop) {
                            indArr++;
                            if (indArr == checkArr.length) {
                                inLoop = false;
                            }
                            else {
                                arg = checkArr[indArr];
                            }
                        }
                    } while(inLoop);
                }
                //Indexing
                var segments = [];
                for (i = 0; i < tSegments.length; i++) {
                    var t = tSegments[i];
                    if (!t.ph) {
                        segments.push(new TextSegment({content: t.text, textDirection: params.msgDir}));
                    }
                    else {
                        var ind = parseInt(t.text.substring(spLength, t.text.length - epLength));
                        if (isNaN(ind) || ind >= tArgs.length) {
                            segments.push(new TextSegment({content: t.text, textDirection: params.msgDir}));
                            continue;
                        }
                        var sttType = "none";
                        if (!tArgs[ind].stt) {
                            tArgs[ind].stt = params.phStt;
                        }
                        if (tArgs[ind].stt) {
                            if (typeof (tArgs[ind].stt) === "string") {
                                sttType = tArgs[ind].stt;
                            }
                            else if(tArgs[ind].stt.hasOwnProperty("type")) {
                                sttType = tArgs[ind].stt.type;
                            }
                        }
                        if (sttType.toLowerCase() !== "none") {
                            var sttSegs =  getHandler(sttType).format(tArgs[ind].text, tArgs[ind].stt.args || {},
                                    params.msgDir === "rtl", false, params.msgLang, true);
                            for (var j = 0; j < sttSegs.length; j++) {
                                segments.push(sttSegs[j]);
                            }
                            segments.push(new TextSegment({isVisible: false}));
                        }
                        else {
                            segments.push(new TextSegment({content: tArgs[ind].text, textDirection: (tArgs[ind].dir? tArgs[ind].dir : params.phDir)}));
                        }
                    }
                }
                var result =  stext.displayStructure(segments, {guiDir: params.guiDir, dir: params.msgDir}, isHtml);
                return result;
            }
        };
    })();

    var event = null;

    function getHandler(type) {
        switch (type) {
        case "breadcrumb" :
            return breadcrumb;
        case "comma" :
            return comma;
        case "email" :
            return email;
        case "filepath" :
            return filepath;
        case "formula" :
            return formula;
        case "sql" :
            return sql;
        case "underscore" :
            return underscore;
        case "url" :
            return url;
        case "word" :
            return word;
        case "xpath" :
            return xpath;
        default:
            return custom;
        }
    }

    function isInputEventSupported(element) {
        var agent = window.navigator.userAgent;
        if (agent.indexOf("MSIE") >=0 || agent.indexOf("Trident") >=0 || agent.indexOf("Edge") >=0) {
            return false;
        }
        var checked = document.createElement(element.tagName);
        checked.contentEditable = true;
        var isSupported = ("oninput" in checked);
        if (!isSupported) {
          lib.setSafeAttribute(checked, 'oninput', 'return;');
          isSupported = typeof checked['oninput'] == 'function';
        }
        checked = null;
        return isSupported;
    }

    function attachElement(element, type, args, isRtl, locale) {
        //if (!element || element.nodeType != 1 || !element.isContentEditable)
        if (!element || element.nodeType != 1) {
            return false;
        }
        if (!event) {
            event = document.createEvent('Event');
            event.initEvent('TF', true, true);
        }
        lib.setSafeAttribute(element, "data-tf-type", type);
        var sArgs = args === "undefined"? "{}" : JSON.stringify(Array.isArray(args)? args[0] : args);
        lib.setSafeAttribute(element, "data-tf-args", sArgs);
        var dir = "ltr";
        if (isRtl === "undefined") {
            if (element.dir) {
                dir = element.dir;
            }
            else if(element.style && element.style.direction) {
                dir = element.style.direction;
            }
            isRtl = dir.toLowerCase() === "rtl";
        }
        lib.setSafeAttribute(element, "data-tf-dir", isRtl);
        lib.setSafeAttribute(element, "data-tf-locale", misc.getLocaleDetails(locale).lang);
        if (isInputEventSupported(element)) {
            var ehandler = element.oninput;
            element.oninput = function(event) {
                displayWithStructure(event.target);
            };
        }
        else {
            element.onkeyup = function(e) {
                displayWithStructure(e.target);
                element.dispatchEvent(event);
            };
            element.onmouseup = function(e) {
                displayWithStructure(e.target);
                element.dispatchEvent(event);
            };
        }
        displayWithStructure(element);

        return true;
    }

    function detachElement(element) {
        if (!element || element.nodeType != 1) {
            return;
        }
        element.removeAttribute("data-tf-type");
        element.removeAttribute("data-tf-args");
        element.removeAttribute("data-tf-dir");
        element.removeAttribute("data-tf-locale");
        lib.setSafeInnerHTML(element, element.textContent || "");
    }

    // This function is called for each user's input into the attached editable html element
    // (see function attachElement()). It controls correct display of the structured text
    // in the element, contents of which is changed dynamically.
    // Arguments, needed to display the structure, added previously as a custom attributes of 
    // the element. The main attribute is the type of the structure ("data-tf-type"), which can 
    // declare one of predefined types of text structure or CUSTOM type. Some types of text structure 
    // additionally require flow direction (e.g. direction, in which seprate segments of the text
    // are displayed) and locale(e.g. language of the text). CUSTOM structure can require some 
    // additional parameters.
    function displayWithStructure(element) {
        var txt = element.textContent || "";
        var selection = document.getSelection();
        if (txt.length === 0 || !selection || selection.rangeCount <= 0) {
            element.dispatchEvent(event);
            return;
        }
        
        var range = selection.getRangeAt(0);
        var tempRange = range.cloneRange(), startNode, startOffset;
        startNode = range.startContainer;
        startOffset = range.startOffset;
        var textOffset = 0;
        if (startNode.nodeType === 3) {
            textOffset += startOffset;
        }
        tempRange.setStart(element,0);
        tempRange.setEndBefore(startNode);
        var div = document.createElement('div');
        div.appendChild(tempRange.cloneContents());
        textOffset += div.textContent.length;
        lib.setSafeInnerHTML(element,
            getHandler(element.getAttribute("data-tf-type")).
            format(txt, JSON.parse(element.getAttribute("data-tf-args")), (element.getAttribute("data-tf-dir") === "true"? true : false),
            true, element.getAttribute("data-tf-locale")));
        var parent = element;
        var node = element;
        var newOffset = 0;
        var inEnd = false;
        selection.removeAllRanges();
        range.setStart(element,0);
        range.setEnd(element,0);
        while (node) {
            if (node.nodeType === 3) {
                if (newOffset + node.nodeValue.length >= textOffset) {
                    range.setStart(node, textOffset - newOffset);
                    break;
                }
                else {
                    newOffset += node.nodeValue.length;
                    node = node.nextSibling;
                }
            }
            else if(node.hasChildNodes()) {
                parent = node;
                node = parent.firstChild;
                continue;
            }
            else {
                node = node.nextSibling;
            }
            while (!node) {
                if (parent === element) {
                    inEnd = true;
                    break;
                }
                node = parent.nextSibling;
                parent = parent.parentNode;
            }
            if (inEnd) {
                break;
            }
        }

        selection.addRange(range);
        element.dispatchEvent(event);
    }

    return {
        /**
        * Returns the HTML representation of a given structured text
        * @param text - the structured text
        * @param type - could be one of filepath, url, email
        * @param args - pass additional arguments to the handler. generally null.
        * @param isRtl - indicates if the GUI is mirrored
        * @param locale - the browser locale
        */
        getHtml: function (text, type, args, isRtl, locale) {
            return getHandler(type).format(text, args, isRtl, true, locale);
        },
        /**
        * Handle Structured text correct display for a given HTML element.
        * @param element - the element  : should be of type div contenteditable=true
        * @param type - could be one of filepath, url, email
        * @param args - pass additional arguments to the handler. generally null.
        * @param isRtl - indicates if the GUI is mirrored
        * @param locale - the browser locale
        */
        attach: function (element, type, args, isRtl, locale) {
            return attachElement(element, type, args, isRtl, locale);
        },
        /**
         * Adds UCCs (Unicode Control Chars) to a given structured text for a correct display
         * @param text - the structured text
         * @param type - could be one of filepath, url, email
         * @param args - pass additional arguments to the handler. generally null.
         * @param isRtl - indicates if the GUI is mirrored
         * @param locale - the browser locale
         */
        getString:  function (text, type, args, isRtl, locale) {
			return getHandler(type).format(text, args, isRtl, false, locale);
		}      
    };
});

/*******************************************************************************
 * @license
 * Copyright (c) 2011, 2019 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 *
 *******************************************************************************/
define ('orion/bidiUtils',[
  "orion/webui/littlelib",
	"orion/util",
	"orion/bidiFormat"
],
function(lib, util, bidiFormat) { /* BDL */
	
	var bidiEnabledStorage = "/orion/preferences/bidi/bidiEnabled"; //$NON-NLS-0$
	var bidiLayoutStorage = "/orion/preferences/bidi/bidiLayout"; //$NON-NLS-0$	
	var LRE = "\u202A";	//$NON-NLS-0$
	var PDF = "\u202C"; //$NON-NLS-0$
	var RLE = "\u202B"; //$NON-NLS-0$
		
	function setBrowserLangDirection() {
		
		var lang;
		if (window.dojoConfig) {
			lang = window.dojoConfig.locale;
		}
		if (!lang) {
			lang = navigator.languages ? navigator.languages[0] : navigator.language || navigator.userLanguage;
		}
		var isBidi = lang && "ar iw he".indexOf(lang.substring(0, 2)) !== - 1;

		if (isBidi && isBidiEnabled()) {
			var htmlElement = document.getElementsByTagName("html")[0];
			if (htmlElement){ //should be always true
				lib.setSafeAttribute(htmlElement, "dir", "rtl");
			}
		}
	}
	
	setBrowserLangDirection();
	
	var bidiLayout = getBidiLayout();

	/**
	 * checks if directionality should be applied in Orion.
	 * @returns {Boolean} true if globalization settings exist and bidi is enabled.
	 */		
	function isBidiEnabled() {
		var bidiEnabled = util.readSetting(bidiEnabledStorage);
		if (bidiEnabled && bidiEnabled === "true") {		//$NON-NLS-0$
			return true;
		}
		return false;
	}
	
	/**
	 * returns bidiLayout value set in globalization settings.
	 * @returns {String} text direction.
	 */	
	function getBidiLayout() {
		var _bidiLayout = util.readSetting(bidiLayoutStorage);
		if (_bidiLayout && (_bidiLayout === "rtl" || _bidiLayout === "ltr" || _bidiLayout === "auto")) {	//$NON-NLS-0$ //$NON-NLS-1$ //$NON-NLS-2$
			return _bidiLayout;
		}
		return "ltr";	//$NON-NLS-0$
	}
	
	/**
	 * returns text direction.
	 * this method is used for handling direction by adding a dir attribute in an HTML element.
	 * if bidiLayout is set to ltr > return ltr
	 * if bidiLayout is set to rtl > return rtl
	 * if bidiLayout is set to auto > check for first strong character in text and return ltr or rtl accordingly.
	 * @param {String} the text on which to set directionality
	 * @returns {String} text direction. rtl or ltr.
	 */	
	function getTextDirection(text) {
		bidiLayout = getBidiLayout();
		if (!isBidiEnabled()) {
			return "";
		}
		if (bidiLayout === "auto" && util.isIE) {	//$NON-NLS-0$
			return checkContextual(text);
		}
		return bidiLayout;
	}
	
	/**
	 * Wraps text by UCC (Unicode control characters) according to text direction
	 * In some cases defining the dir attribute in a different direction than the GUI orientation, 
	 * changes the alignment of the text and/or adjacent elements such as icons.
	 * This doesn't follow the bidi standards (static text should be aligned following GUI direction).
	 * Therefore the only solution is to use UCC (Unicode control characters) to display the text in a correct orientation.
	 * (the text is changed for display purposes only. The original text in the repository remains unchanged)
	 * @param {String} the text to be wrapped
	 * @returns {String} text after adding ucc characters.
	 */		
	function enforceTextDirWithUcc ( text ) {
		if (isBidiEnabled() && text.trim()) {
			bidiLayout = getBidiLayout();
			var dir = bidiLayout === "auto" ? checkContextual( text ) : bidiLayout;	//$NON-NLS-0$
			return ( dir === "ltr" ? LRE : RLE ) + text + PDF;	//$NON-NLS-0$
		}
		return text;	
	}
	
	/**
	 * Finds the first strong (directional) character.
	 * If it is Latin, return ltr. If it is bidi, return rtl. Otherwise, return ltr as default. 
	 * @param {String} the text to be examined
	 * @returns {String} text direction. rtl or ltr.
	 */			
	function checkContextual ( text ) {
		// look for strong (directional) characters
		var fdc = /[A-Za-z\u05d0-\u065f\u066a-\u06ef\u06fa-\u07ff\ufb1d-\ufdff\ufe70-\ufefc]/.exec( text );
		// if found, return the direction that defined by the character, else return ltr as defult.
		return fdc ? fdc[0] <= "z" ? "ltr" : "rtl"  : "ltr";	//$NON-NLS-0$ //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
	}
	
	function addBidiEventListeners ( input ) {
		if (!input._hasBidiEventListeners) {
			input._hasBidiEventListeners = true;

			var eventTypes = ["keyup", "cut", "paste"];
			for (var i = 0; i < eventTypes.length; ++i) {
				input.addEventListener(eventTypes[i], handleInputEvent.bind(this),
					false);
			}
		}
	}
	
	function handleInputEvent ( event ) {
		var input = event.target;
		if (input) {
			input.dir = getTextDirection(input.value || input.textContent); // resolve dir attribute of the element
		}
	}
	
	function initInputField ( input ) {
		if (isBidiEnabled() && input) {
			input.dir = getTextDirection(input.value || input.textContent); // resolve dir attribute of the element

			if (util.isIE) {
				addBidiEventListeners(input);
			}
		}
	}
	
	function enforceTextDir(range) {
		var comments = [{name:"comment block"}, 
		                {name:"comment line double-slash"},
		                {name:"comment block documentation"},
		                {name:"comment line double-slash jade"},
		                {name:"comment line"},
		                {name:"comment line number-sign php"},
		                {name:"comment block xml"}
		];
		var text = range.text;
		var style = range.style;
		if (isBidiEnabled() && style && style.styleClass && style.styleClass.startsWith("comment") && text.length > 0) {
			for (var i = 0; i < comments.length; i++) {
				if (style.styleClass === comments[i].name) {
					var newStyle = style;
					if (typeof newStyle.attributes === "undefined") {
						newStyle.attributes = {};
					}
					newStyle.attributes.dir = getTextDirection(text);
					range.style = newStyle;		
					return range;
				}
			}
		}
		return range;
	}
	
	function enforceSTT(text, type) {
		if (isBidiEnabled() && text && type) {
			return bidiFormat.getString(text, type, {subDir : getBidiLayout()} , false, 'en');
		}
	    return text;
	}

		
	return {
		isBidiEnabled: isBidiEnabled,
		getTextDirection: getTextDirection,		
		enforceTextDirWithUcc: enforceTextDirWithUcc,
		initInputField: initInputField,
		enforceTextDir: enforceTextDir,
		enforceSTT: enforceSTT
	};
});
/*******************************************************************************
 * @license
 * Copyright (c) 2012 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
/*eslint-env browser, amd*/
define('orion/PageUtil',[],function(){
	function hash() {
		/* See https://bugzilla.mozilla.org/show_bug.cgi?id=483304 */
		var result = window.location.href.split("#")[1]; //$NON-NLS-0$
		result = result ? "#" + result : ""; //$NON-NLS-0$
		return result;
	}
	
	function matchResourceParameters(optURIText) {
		optURIText = optURIText || window.location.toString();
		var result = {resource:""};
		var hashIndex = optURIText.indexOf("#"); //$NON-NLS-0$
		if (hashIndex !== -1) {
			var text = optURIText.substring(hashIndex + 1);
			if (text.length !== 0) {
				var params = text.split(","); //$NON-NLS-0$
				result.resource = decodeURIComponent(params[0]);
				for (var i = 1; i < params.length; i++) {
					//We can not use params[i].split("=") here because a param's value may contain "=", which is not encoded.
					var pair = params[i];
					var parsed = /([^=]*)(=?)(.*)/.exec(pair);
					var name = decodeURIComponent(parsed[1] || ""); //$NON-NLS-0$
					var value = decodeURIComponent(parsed[3] || ""); //$NON-NLS-0$
					if(name !== "" && name !== "resource"){ //$NON-NLS-0$ //$NON-NLS-0$
						result[name] = value;
					}
				}
			}			
		}
		return result;
	}
	
	var httpOrHttps = new RegExp("^http[s]?","i");

	function validateURLScheme(url, optAllowedSchemes) {
		var absoluteURL = url;
		if (url.indexOf("://") === -1) { //$NON-NLS-0$
			var temp = document.createElement('a'); //$NON-NLS-0$
			temp.href = url;
	        absoluteURL = temp.href;
		}
		var match = false;
		if (optAllowedSchemes) {
			match = optAllowedSchemes.some(function(scheme){
				return new RegExp("^" + scheme + ":", "i").test(absoluteURL);
			});
		} else {
			match = httpOrHttps.test(absoluteURL);
		}
		if (match) {
			return url;
		} else {
			console.log("Illegal URL Scheme: '" + url + "'");
			return "";
		}
	}
	return {
		hash: hash,
		matchResourceParameters: matchResourceParameters,
		validateURLScheme: validateURLScheme	
	};
});
/*******************************************************************************
 * @license
 * Copyright (c) 2009, 2012, 2017 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 *
 * Contributors: IBM Corporation - initial API and implementation
 *******************************************************************************/
/*eslint-env browser, amd*/
define('orion/uiUtils',[
	'i18n!orion/nls/messages',
	'orion/webui/littlelib',
	'orion/i18nUtil',
	'orion/bidiUtils',
	'orion/urlModifier'
], function(messages, lib, i18nUtil, bidiUtils, urlModifier) {
	/**
	 * This class contains static utility methods. It is not intended to be instantiated.
	 * @class This class contains static utility methods.
	 * @name orion.uiUtils
	 */

	var isMac = navigator.platform.indexOf("Mac") !== -1; //$NON-NLS-0$

	// Maps keyCode to display symbol
	var keySymbols = Object.create(null);
	keySymbols[lib.KEY.DOWN]  = "\u2193"; //$NON-NLS-0$
	keySymbols[lib.KEY.UP]    = "\u2191"; //$NON-NLS-0$
	keySymbols[lib.KEY.RIGHT] = "\u2192"; //$NON-NLS-0$
	keySymbols[lib.KEY.LEFT]  = "\u2190"; //$NON-NLS-0$
	if (isMac) {
		keySymbols[lib.KEY.BKSPC]    = "\u232b"; //$NON-NLS-0$
		keySymbols[lib.KEY.DEL]      = "\u2326"; //$NON-NLS-0$
		keySymbols[lib.KEY.END]      = "\u21f2"; //$NON-NLS-0$
		keySymbols[lib.KEY.ENTER]    = "\u23ce"; //$NON-NLS-0$
		keySymbols[lib.KEY.ESCAPE]   = "\u238b"; //$NON-NLS-0$
		keySymbols[lib.KEY.HOME]     = "\u21f1"; //$NON-NLS-0$
		keySymbols[lib.KEY.PAGEDOWN] = "\u21df"; //$NON-NLS-0$
		keySymbols[lib.KEY.PAGEUP]   = "\u21de"; //$NON-NLS-0$
		keySymbols[lib.KEY.SPACE]    = "\u2423"; //$NON-NLS-0$
		keySymbols[lib.KEY.TAB]      = "\u21e5"; //$NON-NLS-0$
	}

	function getUserKeyStrokeString(binding) {
		var userString = "";

		if (isMac) {
			if (binding.mod4) {
				userString+= "\u2303"; //Ctrl //$NON-NLS-0$
			}
			if (binding.mod3) {
				userString+= "\u2325"; //Alt //$NON-NLS-0$
			}
			if (binding.mod2) {
				userString+= "\u21e7"; //Shift //$NON-NLS-0$
			}
			if (binding.mod1) {
				userString+= "\u2318"; //Command //$NON-NLS-0$
			}
		} else {
			var PLUS = "+"; //$NON-NLS-0$;
			if (binding.mod1)
				userString += messages.KeyCTRL + PLUS;
			if (binding.mod2)
				userString += messages.KeySHIFT + PLUS;
			if (binding.mod3)
				userString += messages.KeyALT + PLUS;
		}
		
		if (binding.alphaKey) {
			return userString+binding.alphaKey;
		}
		if (binding.type === "keypress") {
			return userString+binding.keyCode; 
		}

		// Check if it has a special symbol defined
		var keyCode = binding.keyCode;
		var symbol = keySymbols[keyCode];
		if (symbol) {
			return userString + symbol;
		}

		// Check if it's a known named key from lib.KEY
		var keyName = lib.keyName(keyCode);
		if (keyName) {
			// Some key names are translated, so check for that.
			keyName = messages["Key" + keyName] || keyName; //$NON-NLS-0$
			return userString + keyName;
		}

		var character;
		switch (binding.keyCode) {
			case 59:
				character = binding.mod2 ? ":" : ";"; //$NON-NLS-1$ //$NON-NLS-0$
				break;
			case 61:
				character = binding.mod2 ? "+" : "="; //$NON-NLS-1$ //$NON-NLS-0$
				break;
			case 188:
				character = binding.mod2 ? "<" : ","; //$NON-NLS-1$ //$NON-NLS-0$
				break;
			case 190:
				character = binding.mod2 ? ">" : "."; //$NON-NLS-1$ //$NON-NLS-0$
				break;
			case 191:
				character = binding.mod2 ? "?" : "/"; //$NON-NLS-1$ //$NON-NLS-0$
				break;
			case 192:
				character = binding.mod2 ? "~" : "`"; //$NON-NLS-1$ //$NON-NLS-0$
				break;
			case 219:
				character = binding.mod2 ? "{" : "["; //$NON-NLS-1$ //$NON-NLS-0$
				break;
			case 220:
				character = binding.mod2 ? "|" : "\\"; //$NON-NLS-1$ //$NON-NLS-0$
				break;
			case 221:
				character = binding.mod2 ? "}" : "]"; //$NON-NLS-1$ //$NON-NLS-0$
				break;
			case 222:
				character = binding.mod2 ? '"' : "'"; //$NON-NLS-1$ //$NON-NLS-0$
				break;
			}
		if (character) {
			return userString+character;
		}
		if (binding.keyCode >= 112 && binding.keyCode <= 123) {
			return userString+"F"+ (binding.keyCode - 111); //$NON-NLS-0$
		}
		return userString+String.fromCharCode(binding.keyCode);
	}

	function getUserKeyString(binding) {
		var result = "";
		var keys = binding.getKeys();
		for (var i = 0; i < keys.length; i++) {
			if (i !== 0) {
				result += " "; //$NON-NLS-0$
			}
			result += getUserKeyStrokeString(keys[i]);
		}
		return result;
	}

	/**
	 * @name orion.uiUtils.getUserText
	 * @function
	 * @param {Object} options The options object
	 * @param {String} options.id
	 * @param {Element} options.refNode
	 * @param {Boolean} options.hideRefNode
	 * @param {String} options.initialText
	 * @param {Function} options.onComplete
	 * @param {Function} options.onEditDestroy
	 * @param {String} options.selectTo
	 * @param {Boolean} options.isInitialValid
	 * @param {Boolean} options.insertAsChild
	 */
	function getUserText(options) {
		var id = options.id;
		var refNode = options.refNode;
		var hideRefNode = options.hideRefNode;
		var initialText = options.initialText;
		var onComplete = options.onComplete;
		var onEditDestroy = options.onEditDestroy;
		var selectTo = options.selectTo;
		var isInitialValid = options.isInitialValid;
		var insertAsChild = options.insertAsChild;
		var previousActiveElement = document.activeElement;
		
		var done = false;
		var handler = function(isKeyEvent) {
			return function(event) {
				if (done) {
					return;
				}
				var editBox = lib.node(id),
					newValue = editBox.value;
				if (!editBox) {
					return;
				}
				function hide() {
					done = true;
					lib.returnFocus(editBox, previousActiveElement, function() {
						if (hideRefNode) {
							refNode.style.display = "";
						}
					});
					// some clients remove temporary dom structures in the onComplete processing, so check that we are still in DOM
					if (editBox.parentNode) {
						editBox.parentNode.removeChild(editBox);
					}
					if (onEditDestroy) {
						onEditDestroy();
					}
				}
				if (isKeyEvent && event.keyCode === lib.KEY.ESCAPE) {
					hide();
					return;
				}
				if (isKeyEvent && event.keyCode !== lib.KEY.ENTER) {
					return;
				} else if (newValue.length === 0 || (!isInitialValid && newValue === initialText)) {
					// Do nothing
				} else {
					onComplete(newValue);
				}
				hide();
			};
		};
	
		// Swap in an editable text field
		var editBox = document.createElement("input"); //$NON-NLS-0$
		editBox.id = id;
		editBox.value = initialText || "";
		if (insertAsChild) {
			refNode.appendChild(editBox);
		} else {
			refNode.parentNode.insertBefore(editBox, refNode.nextSibling);
		}
		editBox.classList.add("userEditBoxPrompt"); //$NON-NLS-0$
		if (hideRefNode) {
			refNode.style.display = "none"; //$NON-NLS-0$
		}	
		bidiUtils.initInputField(editBox);
		editBox.addEventListener("keydown", handler(true), false); //$NON-NLS-0$
		editBox.addEventListener("blur", handler(false), false); //$NON-NLS-0$
		window.setTimeout(function() {
			editBox.focus(); 
			if (initialText) {
				var box = lib.node(id);
				var end = selectTo ? initialText.indexOf(selectTo) : -1;
				if (end > 0) {
					if(box.createTextRange) {
						var range = box.createTextRange();
						range.collapse(true);
						range.moveStart("character", 0); //$NON-NLS-0$
						range.moveEnd("character", end); //$NON-NLS-0$
						range.select();
					} else if(box.setSelectionRange) {
						box.setSelectionRange(0, end);
					} else if(box.selectionStart !== undefined) {
						box.selectionStart = 0;
						box.selectionEnd = end;
					}
				} else {
					box.select();
				}
			}
		}, 0);
	}
	
	/**
	 * Returns whether the given event should cause a reference
	 * to open in a new window or not.
	 * @param {Object} event The key event
	 * @name orion.util#openInNewWindow
	 * @function
	 */
	function openInNewWindow(event) {
		var isMac = window.navigator.platform.indexOf("Mac") !== -1; //$NON-NLS-0$
		return (isMac && event.metaKey) || (!isMac && event.ctrlKey);
	}
	
	/**
	 * Opens a link in response to some event. Whether the link
	 * is opened in the same window or a new window depends on the event
	 * @param {String} href The link location
	 * @name orion.util#followLink
	 * @function
	 */
	function followLink(href, event) {
		if (event && openInNewWindow(event)) {
			window.open(urlModifier(href));
		} else {
			window.location = urlModifier(href);
		}
	}
	
	function createButton(text, callback) {
		var button = document.createElement("button"); //$NON-NLS-0$
		button.className = "orionButton commandButton commandMargins"; //$NON-NLS-0$
		button.addEventListener("click", function(e) { //$NON-NLS-0$
			callback();
			lib.stop(e);
		}, false);
		if (text) {
			button.appendChild(document.createTextNode(text));
		}
		return button;	
	}
	
	function createDropdownButton(parent, name, populateFunction) {
	}

	/**
	 * Returns whether <code>element</code> or its parent is an HTML5 form element.
	 * @param {Element} element
	 * @param {Element} parentLimit
	 * @function
	 * @returns {Boolean}
	 */
	function isFormElement(element, parentLimit) {
		if (!element || !element.tagName) return false;
		switch (element.tagName.toLowerCase()) {
			case "button": //$NON-NLS-0$
			case "fieldset": //$NON-NLS-0$
			case "form": //$NON-NLS-0$
			case "input": //$NON-NLS-0$
			case "keygen": //$NON-NLS-0$
			case "label": //$NON-NLS-0$
			case "legend": //$NON-NLS-0$
			case "meter": //$NON-NLS-0$
			case "optgroup": //$NON-NLS-0$
			case "output": //$NON-NLS-0$
			case "progress": //$NON-NLS-0$
			case "select": //$NON-NLS-0$
			case "textarea": //$NON-NLS-0$
				return true;
		}
		if (element.parentNode === parentLimit) return false;
		return element.parentNode && isFormElement(element.parentNode, parentLimit);
	}

	/**
	 * Returns the folder name from path.
	 * @param {String} filePath
	 * @param {Boolean} keepTailSlash
	 * @returns {String}
	 */
	function path2FolderName(filePath, keepTailSlash){
		var pathSegs = filePath.split("/");
		pathSegs.splice(pathSegs.length -1, 1);
		return keepTailSlash ? pathSegs.join("/") + "/" : pathSegs.join("/");
	}
	
	function _timeDifference(timeStamp) {
		var commitDate = new Date(timeStamp);
	    var difference = Date.now() - commitDate.getTime();
	    var yearDiff = Math.floor(difference/1000/60/60/24/365);
	    difference -= yearDiff*1000*60*60*24*365;
	    var monthDiff = Math.floor(difference/1000/60/60/24/30);
	    difference -= monthDiff*1000*60*60*24*30;
	    var daysDifference = Math.floor(difference/1000/60/60/24);
	    difference -= daysDifference*1000*60*60*24;
		var hoursDifference = Math.floor(difference/1000/60/60);
	    difference -= hoursDifference*1000*60*60;
	    var minutesDifference = Math.floor(difference/1000/60);
	    difference -= minutesDifference*1000*60;
	    var secondsDifference = Math.floor(difference/1000);
	    return {year: yearDiff, month: monthDiff, day: daysDifference, hour: hoursDifference, minute: minutesDifference, second: secondsDifference};
	}
	
	function _generateTimeString(number, singleTerm, term) {
		if(number > 0) {
			if(number === 1) {
				return messages[singleTerm];
			}
			return i18nUtil.formatMessage(messages[term], number);
		}
		return "";
	}
	
	/**
	 * Returns the time duration passed by now. E.g. "2 minutes", "an hour", "a day", "3 months", "2 years"
	 * @param {String} timeStamp
	 * @returns {String} If the duration is less than 1 minute, it returns empty string "". Otherwise it returns a duration value.
	 */
	function timeElapsed(timeStamp) {
		var diff = _timeDifference(timeStamp);
		var yearStr = _generateTimeString(diff.year, "a year", "years");
		var monthStr = _generateTimeString(diff.month, "a month", "months");
		var dayStr = _generateTimeString(diff.day, "a day", "days");
		var hourStr = _generateTimeString(diff.hour, "an hour", "hours");
		var minuteStr = _generateTimeString(diff.minute, "a minute", "minutes");
		var disPlayStr = "";
		if(yearStr) {
			disPlayStr = diff.year > 0 ? yearStr : yearStr + monthStr;
		} else if(monthStr) {
			disPlayStr = diff.month > 0 ? monthStr : monthStr + dayStr;
		} else if(dayStr) {
			disPlayStr = diff.day > 0 ? dayStr : dayStr + hourStr;
		} else if(hourStr) {
			disPlayStr = diff.hour > 0 ? hourStr : hourStr + minuteStr;
		} else if(minuteStr) {
			disPlayStr = minuteStr;
		}
		return disPlayStr;	
	}
	/**
	 * Returns the displayable time duration passed by now. E.g. "just now", "2 minutes ago", "an hour ago", "a day ago", "3 months ago", "2 years ago"
	 * @param {String} timeStamp
	 * @returns {String} If the duration is less than 1 minute, it returns empty string "just now". Otherwise it returns a duration value.
	 */
	function displayableTimeElapsed(timeStamp) {
		var duration = timeElapsed(timeStamp);
		if(duration) {
			return i18nUtil.formatMessage(messages["timeAgo"], duration);
		}
		return messages["justNow"];
	}
	
	/**
	 * Returns the initial of given name.
	 * For standard names: "First [Midddles] Last", returns capital "FL";
	 * For others, returns substr(0, 2).
	 * 
	 * @param {string} name -
	 * @return {string} - initial
	 */
	function getNameInitial(name) {
		var namePart = name.split(' ');
		if (namePart.length >= 2) {
			return (namePart[0].charAt(0) + namePart[namePart.length - 1].charAt(0)).toUpperCase();
		} else {
			return name.substr(0, 2);
		}
	}
	//return module exports
	return {
		getUserKeyString: getUserKeyString,
		getUserText: getUserText,
		openInNewWindow: openInNewWindow,
		followLink: followLink,
		createButton: createButton,
		createDropdownButton: createDropdownButton,
		isFormElement: isFormElement,
		path2FolderName: path2FolderName,
		timeElapsed: timeElapsed,
		displayableTimeElapsed: displayableTimeElapsed,
		getNameInitial: getNameInitial
	};
});


define('text!orion/webui/submenutriggerbutton.html',[],function () { return '<li class="dropdownSubMenu" role="none"><span class="dropdownTrigger dropdownMenuItem" aria-expanded = "false" aria-haspopup="true" role="menuitem" tabindex="-1" style="outline:none"><span class="dropdownCommandName">${ButtonText}</span><span class="dropdownArrowRight core-sprite-closedarrow" aria-hidden="true"></span></span><ul class="dropdownMenu" role="menu"></ul></li>';});

/*******************************************************************************
 * @license
 * Copyright (c) 2010, 2019 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 * 
 * Contributors: IBM Corporation - initial API and implementation
 ******************************************************************************/
/*eslint-env browser, amd*/
 
define('orion/commandRegistry',[
	'i18n!orion/nls/messages',
	'orion/commands',
	'orion/keyBinding',
	'orion/explorers/navigationUtils',
	'orion/bidiUtils',
	'orion/PageUtil',
	'orion/uiUtils',
	'orion/webui/littlelib',
	'orion/webui/dropdown',
	'orion/webui/tooltip',
	'text!orion/webui/submenutriggerbutton.html',
	'orion/metrics',
	'orion/Deferred',
	'orion/EventTarget'
], function(messages, Commands, mKeyBinding, mNavUtils, bidiUtils, PageUtil, UIUtil, lib, mDropdown, mTooltip, SubMenuButtonFragment, mMetrics, mDeferred, mEventTarget) {

	/**
	 * Constructs a new command registry with the given options.
	 * @class CommandRegistry can render commands appropriate for a particular scope and DOM element.
	 * @name orion.commandregistry.CommandRegistry
	 * @param {Object} options The registry options object
	 * @param {orion.selection.Selection} [options.selection] Optional selection service.
	 */
	function CommandRegistry(options) {
		this._commandList = {};
		this._contributionsByScopeId = {};
		this._activeBindings = {};
		this._urlBindings = {};
		this._pendingBindings = {}; // bindings for as-yet-unknown commands
		this._parameterCollector = null;
		this._init(options || {});
	}
	CommandRegistry.prototype = /** @lends orion.commandregistry.CommandRegistry.prototype */ {
		_init: function(options) {
			this._selectionService = options.selection;
			var self = this;
			Commands.setKeyBindingProvider(function() { return self._activeBindings; });

			// Make the CommandRegistry an EventTarget. This is somewhat different from the normal pattern
			// so that we can override the normal 'addEventTarget' processing (see below)
			mEventTarget.attach(CommandRegistry.prototype);

			// Add a listener so our bindings get updated immediately
			this.addEventListener("bindingChanged", function(info) {
				this._handleBindingChanges(info);
			}.bind(this));

		
			/**
			 * @name addEventListener
			 * 
			 * @description This is an override of the normal addEventListener to allow it to
			 * keep listeners synch'd with the current binding overrides whether or not they get added before or
			 * after the actual binding overrides have been retrieved from the preference store.
			 * 
			 * Once the overrides preference is loaded any currently registered listeners are informed of the current
			 * binding overrides. Subsequent listeners are also informed when they get added.
			 * @param eventType The type of event being listened on.
			 * @param listener The listener to call when the event is dispatched.
			 */
			this.addEventListener = function(eventType, listener) {
				// if we've already received the overrides from the preference store then broadcast them to the new listener
				if (this._bindingOverrides && eventType === "bindingChanged") {
					this._updateBindingOverrides(listener);
				}
				
				// hook the listener for future changes
				CommandRegistry.prototype.addEventListener.call(this, eventType, listener);
			}
		},
		
		/**
		 * Process the provided URL to determine whether any commands should be invoked.  Note that we never
		 * invoke a command callback by URL, only its parameter collector.  If a parameter collector is not
		 * specified, commands in the URL will be ignored.
		 *
		 * @param {String} url a url that may contain URL bindings.
		 */
		processURL: function(url) {
			for (var id in this._urlBindings) {
				if (this._urlBindings[id] && this._urlBindings[id].urlBinding && this._urlBindings[id].command) {
					var match = this._urlBindings[id].urlBinding.match(url);
					if (match) {
						var urlBinding = this._urlBindings[id];
						var command = urlBinding.command;
						var invocation = urlBinding.invocation;
						// If the command has not rendered (visibleWhen=false, etc.) we don't have an invocation.
						if (invocation && invocation.parameters && command.callback) {
							invocation.parameters.setValue(match.parameterName, match.parameterValue);
							var self = this;
							window.setTimeout(function() {
								self._invoke(invocation);
							}, 0);
							return;
						}
					}
				}
			}
		},
		
		/**
		 * @param {String} commandId
		 * @returns {orion.commands.Command}
		 */
		findCommand: function(commandId) {
			return this._commandList[commandId];
		}, 
		
		/**
		 * Run the command with the specified commandId.
		 *
		 * @param {String} commandId the id of the command to run.
		 * @param {Object} item the item on which the command should run.
		 * @param {Object} handler the handler for the command.
		 * @param {orion.commands.ParametersDescription} [parameters] Parameters used on this invocation. Optional.
		 * @param {Object} [userData] Optional user data that should be attached to generated command callbacks.
		 * @param {DOMElement} [parent] Optional parent for the parameter collector.
		 *
		 * Note:  The current implementation will only run the command if a URL binding has been
		 * specified, or if an item to run the command against has been specified.  
		 */
		runCommand: function(commandId, item, handler, parameters, userData, parent) {
			var self = this;
			if (item) {
				var command = this._commandList[commandId];
				var enabled = command && (command.visibleWhen ? command.visibleWhen(item) : true);
				if (enabled && command.callback) {
					var commandInvocation = new Commands.CommandInvocation(handler, item, userData, command, self);
					commandInvocation.domParent = parent;
					return self._invoke(commandInvocation, parameters);
				}
			} else {
				//TODO should we be keeping invocation context for commands without bindings? 
				var binding = this._urlBindings[commandId];
				if (binding && binding.command) {
					if (binding.command.callback) {
						return self._invoke(binding.invocation, parameters);
					}
				}
			}
		},
		
		/**
		 * Return the default selection service that is being used when commands should apply against a selection.
		 */
		getSelectionService: function() {
			return this._selectionService;
		},


		/**
		 * Interface for a parameter collector.
		 * @name orion.commandregistry.ParameterCollector
		 * @class
		 */
		/**
		 * Open a parameter collector and return the dom node where parameter information should be inserted.
		 * @name orion.commandregistry.ParameterCollector#open
		 * @function
		 * @param {String|DOMElement} commandNode the node containing the triggering command
		 * @param {Function} fillFunction a function that will fill the parameter area
		 * @param {Function} onClose a function that will be called when the parameter area is closed
		 * @returns {Boolean} Whether the node is open.
		 */
		/**
		 * Closes any active parameter collectors.
		 * @name orion.commandregistry.ParameterCollector#close
		 * @function
		 */
		/**
		 * Returns a function that can be used to fill a specified parent node with parameter information.
		 * @name orion.commandregistry.ParameterCollector#getFillFunction
		 * @function
		 * @param {orion.commands.CommandInvocation} the command invocation used when gathering parameters
		 * @param {Function} closeFunction an optional function called when the area must be closed. 
		 * @returns {Function} a function that can fill the specified dom node with parameter collection behavior
		 */
		/**
		 * Collect parameters for the given command.
		 * @name orion.commandregistry.ParameterCollector#collectParameters
		 * @function
		 * @param {orion.commands.CommandInvocation} commandInvocation The command invocation
		 * @returns {Boolean} Whether or not required parameters were collected.
		 */
		/**
		 * Provide an object that can collect parameters for a given "tool" command.  When a command that
		 * describes its required parameters is shown in a toolbar (as an image, button, or link), clicking
		 * the command will invoke any registered parameterCollector before calling the command's callback.
		 * This hook allows a page to define a standard way for collecting required parameters that is 
		 * appropriate for the page architecture.  If no parameterCollector is specified, then the command callback
		 * will be responsible for collecting parameters.
		 *
		 * @param {orion.commandregistry.ParameterCollector} parameterCollector
		 */
		setParameterCollector: function(parameterCollector) {
			this._parameterCollector = parameterCollector;
		},

		/**
		 * Open a parameter collector suitable for collecting information about a command.
		 * Once a collector is created, the specified function is used to fill it with
		 * information needed by the command.  This method is used for commands that cannot
		 * rely on a simple parameter description to collect parameters.  Commands that describe
		 * their required parameters do not need to use this method because the command framework
		 * will open and close parameter collectors as needed and call the command callback with
		 * the values of those parameters.
		 *
		 * @param {DOMElement} node the dom node that is displaying the command, or a node in the parameter collector area
		 * @param {Function} fillFunction a function that will fill the parameter area
		 * @param {Function} onClose a function that will be called when the user closes the collector
		 * @param {String} name the label that will be used for the dialog title
		 */
		openParameterCollector: function(node, fillFunction, onClose, name) {
			if (this._parameterCollector) {
				this._parameterCollector.close();
				this._parameterCollector.open(node, fillFunction, onClose, name);
			}
		},
		
		/**
		 * Open a parameter collector to confirm a command.
		 *
		 * @param {DOMElement} node the dom node that is displaying the command
		 * @param {String} message the message to show when confirming the command
		 * @param {String} yesString the label to show on a yes/true choice
		 * @param {String} noString the label to show on a no/false choice
		 * @param {Boolean} modal indicates whether the confirmation prompt should be modal.
		 * @param {Function} onConfirm a function that will be called when the user confirms the command.  The function
		 * will be called with boolean indicating whether the command was confirmed.
		 */
		confirm: function(node, message, yesString, noString, modal, onConfirm) {
			this._popupDialog(modal,"CONFIRM", node, message, [{label:yesString,callback:onConfirm,type:"ok"},{label:noString,callback:null,type:"cancel"}]);
		},
		
		/**
		 * Open an alert tooltip
		 *
		 * @param {DOMElement} node the dom node that is displaying the command
		 * @param {String} message the message to show when confirming the command
		 * @param {String} yesString the label to show on a yes/true choice
		 * @param {Function} onConfirm a function that will be called when the user confirms the command.  The function
		 * will be called with boolean indicating whether the command was confirmed.
		 */
		alert: function(node, message, yesString, onConfirm) {
			this._popupDialog(false, "ALERT", node, message, [{label:yesString,callback:onConfirm,type:"ok"}]);
		},
		
		/**
		 * Open a parameter collector to confirm a command or collect user input.
		 *
		 * @param {Boolean} modal indicates whether the confirmation prompt should be modal.
		 * @param {String}  determines the popup dialog's type, could be "PROMPT", "CONFIRM" or "ALERT"
		 * @param {DOMElement} node the dom node that is displaying the command
		 * @param {String} message the message to show when confirming the command
		 * @param {Array} an array of button label, callback, type objects; if the type is "yes", either input.value or true will be passed to callback depends on the dialog's type
		 * @param {String} default message in the input box.
		 * @param [Optional]{String} postion of the popupDialog if specified, have to be one of "below", "right"
		 */
		_popupDialog: function(modal, style, node, message, buttonStringCallList, defaultInput, positionString) {
			var result;
			if (this._parameterCollector && !modal) {
				var self = this;
				var closeFunction = function(){self._parameterCollector.close();};
				var fillFunction = function(parent, buttonParent) {
					var label = document.createElement("span"); //$NON-NLS-0$
					label.classList.add("parameterPrompt"); //$NON-NLS-0$
					label.textContent = message;
					parent.appendChild(label);
					if(style === "PROMPT"){
						var input = document.createElement("input");
						lib.setSafeAttribute(input, "value", defaultInput);
						input.classList.add("parameterInput");
						bidiUtils.initInputField(input);
						parent.appendChild(input);
						input.addEventListener("keydown", function(evt){
							if(lib.KEY.ENTER === evt.keyCode){
								buttonStringCallList[0].callback && buttonStringCallList[0].callback(input.value);  // as defined in propmt method, the first button is ok button
								closeFunction();
							}else if(lib.KEY.ESCAPE === evt.keyCode){
								buttonStringCallList[1].callback && buttonStringCallList[1].callback("");   // as defined in propmt method, the second button is cancel button
								closeFunction();
							}
						}, false);
					}
					
					var buttons = Object.keys(buttonStringCallList).map(function(key){
						var button = document.createElement("button"); //$NON-NLS-0$
						button.addEventListener("click", function(event) { //$NON-NLS-0$
							if(buttonStringCallList[key].type === "ok"){
								result = style === "PROMPT" ? input.value : true;
							}else if(buttonStringCallList[key].type === "cancel"){
								result = style === "PROMPT" ? "" : false;
							}else{
								result = true;
							}
							buttonStringCallList[key].callback && buttonStringCallList[key].callback(result);
							closeFunction();
						}, false);
						buttonParent.appendChild(button);
						button.appendChild(document.createTextNode(buttonStringCallList[key]["label"])); //$NON-NLS-0$
						button.className = "dismissButton";
						return button;
					});
					return style === "PROMPT" ? input : buttons[0];
				};
				this._parameterCollector.close();
				if(!node){
					// Do this if this is a confirm or if this is a prompt but without node specified.
					var opened = this._parameterCollector.open(node, fillFunction, function(){}, messages[style]);
				}
				if (!opened) {
					var tooltip = new mTooltip.Tooltip({
						node: node,
						afterHiding: function() {
							this.destroy();
						},
						trigger: "click", //$NON-NLS-0$
						position: positionString ? positionString : style !== "PROMPT" ? ["below", "right", "above", "left"] : ["right","above", "below", "left"]//$NON-NLS-4$ //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$
					});
					var parameterArea = tooltip.contentContainer();
					parameterArea.classList.add("parameterPopup"); //$NON-NLS-0$
					var parent = parameterArea.parentNode;
					lib.setSafeAttribute(parent, "role", "dialog");
					lib.setSafeAttribute(parent, "aria-modal", "true");
					var dialogName = node.getAttribute("aria-label") || node.textContent || messages[style] || messages["Command"];
					lib.setSafeAttribute(parent, "aria-label", dialogName);
					var originalFocusNode = window.document.activeElement;
					closeFunction = function() {
						lib.returnFocus(parameterArea, originalFocusNode);
						tooltip.destroy();
					};
					var messageArea = document.createElement("div"); //$NON-NLS-0$
					messageArea.classList.add("parameterMessage"); //$NON-NLS-0$
					parameterArea.appendChild(messageArea);
					
					var buttonArea = document.createElement("div"); //$NON-NLS-0$
					parameterArea.appendChild(buttonArea);
					buttonArea.classList.add("layoutRight"); //$NON-NLS-0$
					buttonArea.classList.add("parametersDismiss"); //$NON-NLS-0$
				
					var focusNode = fillFunction(messageArea, buttonArea);
					tooltip.show();
					if (focusNode) {
						window.setTimeout(function() {
							focusNode.focus();
							if (focusNode.select) {
								focusNode.select();
							}
						}, 0);	
					}
				}
			}else{
				result = window.confirm(message);
				buttonStringCallList[0].callback(result);
			}
		},
		
		/**
		 * Open a tolltip parameter collector to collect user input.
		 *
		 * @param {DOMElement} node the dom node that is displaying the command
		 * @param {String} message the message to show when confirming the command
		 * @param {String} yesString the label to show on a yes/true choice
		 * @param {String} noString the label to show on a no/false choice
		 * @param {String} default message in the input box.
		 * @param {Boolean} modal indicates whether the confirmation prompt should be modal.
		 * @param {Function} onConfirm a function that will be called when the user confirms the command.  The function
		 * will be called with boolean indicating whether the command was confirmed.
		 * @param [Optional]{String} postion of the popupDialog if specified, have to be one of "below", "right"
		 */
		prompt: function(node, message, yesString, noString, defaultInput, modal, onConfirm, positionString) {
			var position = null;
			if(positionString === "below"){position = ["below", "right", "above", "left"];}
			else if(positionString === "right"){position = ["right", "above", "below", "left"];}
			this._popupDialog(modal,"PROMPT", node, message, [{label:yesString,callback:onConfirm,type:"ok"},{label:noString,callback:null,type:"cancel"}], defaultInput, position);
		},
		
		/**
		 * Open a dialog with several buttons.
		 *
		 * @param {DOMElement} node the dom node that is displaying the command
		 * @param {String} message the message to show when confirming the command
		 * @param {Array} an array of button label, callback, type objects;
		 */
		confirmWithButtons: function(node, message, buttonsCallbackList){
			this._popupDialog(false, "CONFIRM", node, message, buttonsCallbackList);
		},
		
		/**
		 * Close any active parameter collector.  This method should be used to deactivate a
		 * parameter collector that was opened with <code>openParameterCollector</code>.
		 * Commands that describe their required parameters do not need to use this method 
		 * because the command framework will open and close parameter collectors as needed and 
		 * call the command callback with the values of those parameters.
		 */
		closeParameterCollector: function() {
			if (this._parameterCollector) {
				this._parameterCollector.close();
			}
		},
		
		/**
		 * Returns whether this registry has been configured to collect command parameters
		 *
		 * @returns {Boolean} whether or not this registry is configured to collect parameters.
		 */
		collectsParameters: function() {
			return this._parameterCollector;
		},
		
		/*
		 * Invoke the specified command, collecting parameters if necessary.  This is used inside the framework
		 * when the user invokes a command. If parameters are specified, then these parameters should be used
		 * in lieu of the invocation's parameters.
		 *
		 */
		_invoke: function(commandInvocation, parameters) {
			return this._collectAndInvoke(commandInvocation.makeCopy(parameters), false);
		},
		
		/*
		 * This method is the actual implementation for collecting parameters and invoking a callback.
		 * "forceCollect" specifies whether we should always collect parameters or consult the parameters description to see if we should.
		 */
		_collectAndInvoke: function(commandInvocation, forceCollect, cancelCallback) {
			if (commandInvocation) {
				// Establish whether we should be trying to collect parameters. 
				if (this._parameterCollector && commandInvocation.parameters && commandInvocation.parameters.hasParameters() && 
					(forceCollect || commandInvocation.parameters.shouldCollectParameters())) {
					var collecting = false;
					commandInvocation.parameters.updateParameters(commandInvocation);
					// Consult shouldCollectParameters() again to verify we still need collection. Due to updateParameters(), the CommandInvocation
					// could have dynamically set its parameters to null (meaning no collection should be done).
					if (commandInvocation.parameters.shouldCollectParameters()) {
						var dialogName = messages["Command"]; // default name
						if (commandInvocation.domNode && commandInvocation.domNode.textContent) {
							dialogName = commandInvocation.domNode.textContent;
						}
						collecting = this._parameterCollector.collectParameters(commandInvocation,cancelCallback, dialogName);
						// The parameter collector cannot collect.  We will do a default implementation using a popup.
						if (!collecting) {
							var tooltip = new mTooltip.Tooltip({
								node: commandInvocation.domNode || commandInvocation.domParent,
								afterHiding: function() {
									this.destroy();
									if (commandInvocation.domParent) commandInvocation.domParent.classList.remove("parameterPopupOpen"); //$NON-NLS-1$
								},
								trigger: "click", //$NON-NLS-0$
								position: ["below", "right", "above", "left"] //$NON-NLS-4$ //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$
							});
							var parameterArea = tooltip.contentContainer();
							parameterArea.classList.add("parameterPopup"); //$NON-NLS-0$
							var parent = parameterArea.parentNode;
							lib.setSafeAttribute(parent, "role", "dialog");
							lib.setSafeAttribute(parent, "aria-modal", "true");
							lib.setSafeAttribute(parent, "aria-label", dialogName);
							var originalFocusNode = window.document.activeElement;
							var focusNode = this._parameterCollector.getFillFunction(commandInvocation, function() {
								lib.returnFocus(parameterArea, originalFocusNode);
								tooltip.destroy();
								if (commandInvocation.domParent) commandInvocation.domParent.classList.remove("parameterPopupOpen"); //$NON-NLS-0$
							}, cancelCallback)(parameterArea);
							tooltip.show();
							if (commandInvocation.domParent) commandInvocation.domParent.classList.add("parameterPopupOpen"); //$NON-NLS-0$
							if (focusNode) {
								window.setTimeout(function() {
									focusNode.focus();
									if (focusNode.select) {
										focusNode.select();
									}
								}, 0);
							}
							collecting = true;
						}
					}
					if (!collecting) {
						mMetrics.logEvent("command", "invoke", commandInvocation.command.id); //$NON-NLS-2$ //$NON-NLS-1$
						// Just call the callback with the information we had.
						return commandInvocation.command.callback.call(commandInvocation.handler || window, commandInvocation);
					}
				} else {
					mMetrics.logEvent("command", "invoke", commandInvocation.command.id); //$NON-NLS-2$ //$NON-NLS-1$
					// We should not be trying to collect parameters, just call the callback.
					return commandInvocation.command.callback.call(commandInvocation.handler || window, commandInvocation);
				}
			} else {
				window.console.log("Client attempted to invoke command without an available (rendered) command invocation"); //$NON-NLS-0$
			}
		},
		
		/**
		 * Collect the parameters specified in the given command invocation.  If parameters are
		 * collected successfully, invoke the command's callback. This method is used by clients who want to 
		 * control the timing of parameter collection.  For example, if a command must be executed before it can
		 * be determined what parameters are known, the client can try the command in the callback and then call
		 * this function if parameters are needed.  In this case, clients typically configure the parameters description
		 * options with "options.clientWillCollect" set to true.
		 *
		 * @see orion.commands.ParametersDescription
		 *
		 * @param {orion.commands.CommandInvocation} commandInvocation the current invocation of the command 
		 */
		collectParameters: function(commandInvocation,cancelCallback) {
			this._collectAndInvoke(commandInvocation, true, cancelCallback); 
		},
		
		/**
		 * Show the keybindings that are registered with the command registry inside the specified target node.
		 * @param {KeyAssistPanel} keyAssist the key assist panel
		 */
		showKeyBindings: function(keyAssist) {
			var scopes = {};
			var binding;
			// see commands.js _processKey
			function execute(activeBinding) {
				return function() {
					Commands.executeBinding(activeBinding);
				};
			}
			
			var bindings = [];
			for (var aBinding in this._activeBindings) {
				binding = this._activeBindings[aBinding];
				if (binding && binding.keyBinding && binding.command && (binding.command.name || binding.command.tooltip)) {
					bindings.push(binding);
				}
			}
			bindings.sort(function (a, b) {
				var ta = a.command.name || a.command.tooltip;
				var tb = b.command.name || b.command.tooltip;
				return ta.localeCompare(tb);
			});
			for (var i=0; i<bindings.length; i++) {
				binding = bindings[i];
				// skip scopes and process at end
				if (binding.keyBinding.scopeName) {
					if (!scopes[binding.keyBinding.scopeName]) {
						scopes[binding.keyBinding.scopeName] = [];
					}
					scopes[binding.keyBinding.scopeName].push(binding);
				} else {
					keyAssist.createItem(binding.keyBinding, binding.command.name || binding.command.tooltip, binding.command.id, execute(binding));
				}
			}
			for (var scopedBinding in scopes) {
				if (scopes[scopedBinding].length && scopes[scopedBinding].length > 0) {
					keyAssist.createHeader(scopedBinding, lib.validId(scopedBinding) + "Scope"); //$NON-NLS-0$
					scopes[scopedBinding].forEach(function(binding) {
						keyAssist.createItem(binding.keyBinding, binding.command.name || binding.command.tooltip, binding.command.id, execute(binding));
					});
				}	
			}
		},
		
		_handleBindingChanges: function(args) {
			// Change the command's current binding
			var command = this.findCommand(args.id);
			if (command) {
				// Add the new binding (overrides any existing one)
				var curBinding = this._activeBindings[args.id];
				if (curBinding) {
					curBinding.keyBinding = args.newBinding;
				} else {
					this._addBinding(command, "key", args.newBinding); //$NON-NLS-1$
				}
			}
			
			// Now see if we have any menu items to update
			if (this._renderedCommands && this._renderedCommands[args.id]) {
				var scopes = this._renderedCommands[args.id];
				var keys = Object.keys(scopes);
				for (var i=0; i<keys.length; i++) {
					var invocation = scopes[keys[i]];
					var bindingString = UIUtil.getUserKeyString(args.newBinding);
					var newElement = Commands.createCommandMenuItem(invocation.domParent, invocation.command, invocation, null, invocation.onClick, bindingString);
					invocation.domNode.parentNode.replaceChild(newElement, invocation.domNode);
					invocation.domNode = newElement;
				}
			}
		},
		
		/**
		 * @name createBindingOverride
		 * @description Creates an override for the binding of a particular Command or Text Action.
		 * @param id The id of the Command or Text Action being overridden
		 * @param newBinding The new binding to use
		 * @param prevBinding The binding (if any) being overridden. Note that this is needed to ensure that
		 * we override the correct Text Action (which can have multiple bindings for the same id).
		 */
		createBindingOverride: function(id, newBinding, prevBinding) {
			if (!this._bindingOverrides) {
				this._bindingOverrides = [];
			}

			// Capture this change			
			this._bindingOverrides.push ({id: id, newBinding: newBinding, prevBinding: prevBinding});

			// Update the preference store
			if (this._prefService) {
				var overridesStr = JSON.stringify(this._bindingOverrides);
				this._prefService.put("/KeyBindings", {overridesJSON: overridesStr}); //$NON-NLS-1$
			}
			
			// Handle the change locally
			var bindingChangeEvent = {type: "bindingChanged", id: id, newBinding: newBinding, prevBinding: prevBinding}; //$NON-NLS-1$
			this.dispatchEvent(bindingChangeEvent);
		},

		/**
		 * @name _registerRenderedCommand
		 * @description Keeps a record of the 'invocation' object for a rendered command. The invocation contains
		 * a lot of information about the rendered item (including the DOM element created to show it). This is currently
		 * used to update the menu item's key binding info if its binding changes.
		 * 
		 * @param actionID The actionID of the menu item
		 * @param scopeID The scopeID of this particular invocation (two different menus can be created using the same commands)
		 * @param invocation The invocation record to store
		 */
		_registerRenderedCommand: function(actionID, scopeID, invocation) {
			if (!this._renderedCommands) {
				this._renderedCommands = {};
			}
			var scopes = this._renderedCommands[actionID];
			if (!scopes) {
				scopes = this._renderedCommands[actionID] = {};
			}
			scopes[scopeID] = invocation;
		},
		
		_getBindingOverrides: function() {
			// Get the key binding overrides from the preference store
			return this._prefService.get("/KeyBindings").then(function(bindingPrefs) { //$NON-NLS-1$
				var overrides = [];
				
				var prefVal = bindingPrefs["overridesJSON"]; //$NON-NLS-1$
				if (prefVal) {
					// Sometimes we get the parsing done for us, sometimes not...wtf?
					if (typeof prefVal === "string") {
						overrides = JSON.parse(prefVal);
					} else {
						overrides = prefVal;
					}
				}
				
				// Turn the Objects back into KeyStrokes
				for (var i = 0; i < overrides.length; i++) {
					var bindingChange = overrides[i];
					if (bindingChange.newBinding) {
						var nb = bindingChange.newBinding;
						overrides[i].newBinding = new mKeyBinding.KeyStroke(nb.keyCode, nb.mod1, nb.mod2, nb.mod3, nb.mod4, nb.type);
					}
					if (bindingChange.prevBinding) {
						var pb = bindingChange.prevBinding;
						overrides[i].prevBinding = new mKeyBinding.KeyStroke(pb.keyCode, pb.mod1, pb.mod2, pb.mod3, pb.mod4, pb.type);
					}
				}
				
				return new mDeferred().resolve(overrides);
			}.bind(this));
		},
		
		/**
		 * @name getBindingOverride
		 * @description returns the binding that the given id should be overridden with (or null if no override exists). Note that
		 * this method is only valid for Commands, not Text Actions,
		 * @param cmdId The id of the Command to check
		 * @returns returns the new KeyStroke if there's an override else null
		 */
		getBindingOverride: function(cmdId) {
			// If we haven't recieved the overrides yet
			if (!this._bindingOverrides)
				return null;
			
			// Here we want the *last* override so we iterate backwards
			for (var i = (this._bindingOverrides.length - 1); i >= 0; i--) {
				var override = this._bindingOverrides[i];
				if (override.id === cmdId) {
					return override.newBinding;
				}
			}
			return null;
		},
		
		/** 
		 * Add a command to the command registry.  Nothing will be shown in the UI
		 * until this command is referenced in a contribution.
		 * @param {orion.commands.Command} command The command being added.
		 * @see registerCommandContribution
		 */
		addCommand: function(command) {
			this._commandList[command.id] = command;
			// Resolve any pending key/url bindings against this command
			var pending = this._pendingBindings[command.id];
			if (pending) {
				var _self = this;
				pending.forEach(function(binding) {
					_self._addBinding(command, binding.type, binding.binding, binding.bindingOnly);
				});
				delete this._pendingBindings[command.id];
			}
		},
		
		/**
		 * Registers a command group and specifies visual information about the group.
		 * @param {String} scopeId The id of a DOM element in which the group should be visible.  Required.
		 *  When commands are rendered for a particular element, the group will be shown only if its scopeId
		 *  matches the id being rendered.
		 * @param {String} groupId The id of the group, must be unique.  May be used for a dom node id of
		 *  the element representing the group
		 * @param {Number} position The relative position of the group within its parent.  Required.
		 * @param {String} [title] The title of the group, optional
		 * @param {String} [parentPath] The path of parent groups, separated by '/'.  For example,
		 *  a path of "group1Id/group2Id" indicates that the group belongs as a child of 
		 *  group2Id, which is itself a child of group1Id.  Optional.
		 * @param {String} [emptyGroupMessage] A message to show if the group is empty and the user activates the UI element
		 *  representing the group.  Optional.  If not specified, then the group UI element won't be shown when it is empty.
		 * @param {String} [imageClass] CSS class of an image to use for this group.
		 * @param {String} [tooltip] Tooltip to show on this group. If not provided, and the group uses an <code>imageClass</code>,
		 * the <code>title</code> will be used as the tooltip.
		 * @param {String} [selectionClass] CSS class to be appended when the command button is selected. Optional.
		 * @param {String} or {boolean} [defaultActionId] Id of an action from this group that should be invoked when the group is selected. This will add an
		 * arrow to the group that will open the dropdown. Optionally this can be set to <code>true</code> instead of adding a particular action.
		 * If set to <code>true</code> the group will be rendered as if there was a default action, but instead of invoking the default action it will
		 * open the dropdown. Optional.
		 * @param {String} [extraClasses] A string containing space separated css classes that will be applied to group button
		 */	
		addCommandGroup: function(scopeId, groupId, position, title, parentPath, emptyGroupMessage, imageClass, tooltip, selectionClass, defaultActionId, extraClasses) {
			if (!this._contributionsByScopeId[scopeId]) {
				this._contributionsByScopeId[scopeId] = {};
			}
			var parentTable = this._contributionsByScopeId[scopeId];
			if (parentPath) {
				parentTable = this._createEntryForPath(parentTable, parentPath);		
			}
			
			if (parentTable[groupId]) {
				// update existing group definition if info has been supplied
				if (title) {
					parentTable[groupId].title = title;
				}
				if (position) {
					parentTable[groupId].position = position;
				}
				if (imageClass) {
					parentTable[groupId].imageClass = imageClass;
				}
				if (tooltip) {
					parentTable[groupId].tooltip = tooltip;
				}
				if (selectionClass) {
					parentTable[groupId].selectionClass = selectionClass;
				}
				
				if (extraClasses) {
					parentTable[groupId].extraClass = extraClasses;
				}
				
				if(defaultActionId === true){
					parentTable[groupId].pretendDefaultActionId = true;
				} else {
					parentTable[groupId].defaultActionId = defaultActionId;
				}
				

				parentTable[groupId].emptyGroupMessage = emptyGroupMessage;
			} else {
				// create new group definition
				parentTable[groupId] = {title: title, 
										position: position, 
										emptyGroupMessage: emptyGroupMessage,
										imageClass: imageClass,
										tooltip: tooltip,
										selectionClass: selectionClass,
										defaultActionId: defaultActionId === true ? null : defaultActionId,
										pretendDefaultActionId: defaultActionId === true,
										children: {},
										extraClasses: extraClasses};
				parentTable.sortedContributions = null;
			}
		},
		
		_createEntryForPath: function(parentTable, parentPath) {
			if (parentPath) {
				var segments = parentPath.split("/"); //$NON-NLS-0$
				segments.forEach(function(segment) {
					if (segment.length > 1) {
						if (!parentTable[segment]) {
							// empty slot with children
							parentTable[segment] = {position: 0, children: {}};
							parentTable.sortedContributions = null;
						} 
						parentTable = parentTable[segment].children;
					}
				});
			}
			return parentTable;	
		},
		
		/**
		 * Register a selection service that should be used for certain command scopes.
		 * @param {String} scopeId The id describing the scope for which this selection service applies.  Required.
		 *  Only contributions made to this scope will use the selection service.
		 * @param {orion.selection.Selection} selectionService the selection service for the scope.
		 */
		registerSelectionService: function(scopeId, selectionService) {
			if (!this._contributionsByScopeId[scopeId]) {
				this._contributionsByScopeId[scopeId] = {};
			}
			this._contributionsByScopeId[scopeId].localSelectionService = selectionService;
		},
		
		/**
		 * Register the serviceRegistry. Use this gain access to any other services we need (i.e. the preferenceService)
		 * @param serviceRegistry {orion.serviceregistry.ServiceRegistry} the current service registry.
		 */
		setServiceRegistry: function(serviceRegistry) {
			this._serviceRegistry = serviceRegistry;
			this._prefService = serviceRegistry.getService("orion.core.preference"); //$NON-NLS-1$

			if (this._prefService) {
				// Get the overrides from the preference store
				this._getBindingOverrides().then(function(overrides) {
					this._bindingOverrides = overrides;
					
					// Update all folks that are listening
					this._updateBindingOverrides();
				}.bind(this));
	
				// listen for changes from other pages
				this._prefService.addEventListener("changed", function (e) {
					if (e.namespace === "/KeyBindings") { //$NON-NLS-1$
						// Refresh the binding overrides
						this._getBindingOverrides().then(function(overrides) {
							if (overrides.length > this._bindingOverrides.length) {
								// handle any new changes
								for (var i = this._bindingOverrides.length; i < overrides.length; i++) {
									var override = overrides[i];
									var bindingChangeEvent = {type: "bindingChanged", id: override.id, newBinding: override.newBinding,  //$NON-NLS-1$
																prevBinding: override.prevBinding};
									this.dispatchEvent(bindingChangeEvent);
								}
							}
							this._bindingOverrides = overrides;
						}.bind(this));
					}
				}.bind(this));
			}
		},

		_updateBindingOverrides: function(listener) {
			for(var i = 0; i < this._bindingOverrides.length; i++) {
				var override = this._bindingOverrides[i];
				var bindingChangeEvent = {type: "bindingChanged", id: override.id, newBinding: override.newBinding,  //$NON-NLS-1$
					prevBinding: override.prevBinding};
				if (listener) {
					listener(bindingChangeEvent);
				} else {
					this.dispatchEvent(bindingChangeEvent);
				}
			}
		},
		
		/**
		 * Register a command contribution, which identifies how a command appears
		 * on a page and how it is invoked.
		 * @param {String} scopeId The id describing the scope of the command.  Required.
		 *  This scope id is used when rendering commands.
		 * @param {String} commandId the id of the command.  Required.
		 * @param {Number} position the relative position of the command within its parent.  Required.
		 * @param {String} [parentPath=null] the path of any parent groups, separated by '/'.  For example,
		 *  a path of "group1Id/group2Id/command" indicates that the command belongs as a child of 
		 *  group2Id, which is itself a child of group1Id.  Optional.
		 * @param {boolean} [bindingOnly=false] if true, then the command is never rendered, but the key or URL binding is hooked.
		 * @param {orion.KeyBinding} [keyBinding] a keyBinding for the command.  Optional.
		 * @param {orion.commands.URLBinding} [urlBinding] a url binding for the command.  Optional.
		 * @param {Object} [handler] the object that should perform the command for this contribution.  Optional.
		 */
		registerCommandContribution: function(scopeId, commandId, position, parentPath, bindingOnly, keyBinding, urlBinding, handler) {
			if (!this._contributionsByScopeId[scopeId]) {
				this._contributionsByScopeId[scopeId] = {};
			}
			var parentTable = this._contributionsByScopeId[scopeId];
			if (parentPath) {
				parentTable = this._createEntryForPath(parentTable, parentPath);		
			} 
			
			// store the contribution
			parentTable[commandId] = {position: position, handler: handler};
			
			var command;
			if (this._bindingOverrides) {
				var bindingOverride = this.getBindingOverride(commandId, keyBinding);
				if (bindingOverride) {
					keyBinding = bindingOverride;
				}
			}
			// add to the bindings table now
			if (keyBinding) {
				command = this._commandList[commandId];
				if (command) {
					this._addBinding(command, "key", keyBinding, bindingOnly); //$NON-NLS-0$
				} else {
					this._addPendingBinding(commandId, "key", keyBinding, bindingOnly); //$NON-NLS-0$
				}
			}
			
			// add to the url key table
			if (urlBinding) {
				command = this._commandList[commandId];
				if (command) {
					this._addBinding(command, "url", urlBinding, bindingOnly); //$NON-NLS-0$
				} else {
					this._addPendingBinding(commandId, "url", urlBinding, bindingOnly); //$NON-NLS-0$
				}
			}
			// get rid of sort cache because we have a new contribution
			parentTable.sortedContributions = null;
		},
		
		unregisterCommandContribution: function(scopeId, commandId, parentPath){
			if (!this._contributionsByScopeId[scopeId]) {
				// scope does not exist
				return;
			}
			delete this._commandList[commandId];
			delete this._activeBindings[commandId];
			delete this._urlBindings[commandId];
			delete this._pendingBindings[commandId];
			var parentTable = this._contributionsByScopeId[scopeId];
			if(parentPath){
				var segments = parentPath.split("/"); //$NON-NLS-0$
				segments.forEach(function(segment) {
					if (segment.length > 1) {
						if (!parentTable[segment]) {
							// command does not exist in given path
							return;
						} 
						parentTable = parentTable[segment].children;
					}
				});
			}
			delete parentTable[commandId];
			
			parentTable.sortedContributions = null;
		},

		/**
		 * @param {String} type One of <code>"key"</code>, <code>"url"</code>.
		 */
		_addBinding: function(command, type, binding, bindingOnly) {
			if (!command.id) {
				throw new Error("No command id: " + command); //$NON-NLS-1$
			}
			if (type === "key") { //$NON-NLS-0$
				this._activeBindings[command.id] = {command: command, keyBinding: binding, bindingOnly: bindingOnly};
			} else if (type === "url") { //$NON-NLS-0$
				this._urlBindings[command.id] = {command: command, urlBinding: binding, bindingOnly: bindingOnly};
			}
		},

		/**
		 * Remembers a key or url binding that has not yet been resolved to a command.
		 * @param {String} type One of <code>"key"</code>, <code>"url"</code>.
		 */
		_addPendingBinding: function(commandId, type, binding, bindingOnly) {
			this._pendingBindings[commandId] = this._pendingBindings[commandId] || [];
			this._pendingBindings[commandId].push({
				type: type,
				binding: binding,
				bindingOnly: bindingOnly
			});
		},

		_checkForTrailingSeparator: function(parent, style, autoRemove) {
			var last;
			if (style === "tool" || style === "button") { //$NON-NLS-1$ //$NON-NLS-0$
				last = parent.childNodes.length > 0 ? parent.childNodes[parent.childNodes.length-1] : null;
				if (last && last.classList.contains("commandSeparator")) { //$NON-NLS-0$
					if (autoRemove) {
						parent.removeChild(last);
						return false;
					} 
					return true;
				}
			}
			if (style === "menu") { //$NON-NLS-0$
				var items = lib.$$array("li > *", parent); //$NON-NLS-0$
				if (items.length > 0 && items[items.length - 1].classList.contains("dropdownSeparator")) { //$NON-NLS-0$
					last = items[items.length - 1];
					if (autoRemove) {
						// reachy reachy.  Remove the anchor's li parent
						last.parentNode.parentNode.removeChild(last.parentNode);
						return false;
					} else {
						return true;
					}
				}
			}
			return false;
		},

		/**
		 * Render the commands that are appropriate for the given scope.
		 * @param {String} scopeId The id describing the scope for which we are rendering commands.  Required.
		 *  Only contributions made to this scope will be rendered.
		 * @param {DOMElement} parent The element in which commands should be rendered.  If commands have been
		 *  previously rendered into this element, it is up to the caller to empty any previously generated content.
		 * @param {Object} [items] An item or array of items to which the command applies.  Optional.  If no
		 *  items are specified and a selection service was specified at creation time, then the selection
		 *  service will be used to determine which items are involved. 
		 * @param {Object} handler The object that should perform the command
		 * @param {String} renderType The style in which the command should be rendered.  "tool" will render
		 *  a tool image in the dom.  "button" will render a text button.  "menu" will render menu items.  
		 * @param {Object} [userData] Optional user data that should be attached to generated command callbacks
		 * @param {Object[]} [domNodeWrapperList] Optional an array used to record any DOM nodes that are rendered during this call.
		 *  If an array is provided, then as commands are rendered, an object will be created to represent the command's node.  
		 *  The object will always have the property "domNode" which contains the node created for the command.  If the command is
		 *  rendered using other means (toolkit widget) then the optional property "widget" should contain the toolkit
		 *  object that represents the specified dom node.
		 */	
		renderCommands: function(scopeId, parent, items, handler, renderType, userData, domNodeWrapperList) {
			if (typeof(scopeId) !== "string") { //$NON-NLS-0$
				throw "a scope id for rendering must be specified"; //$NON-NLS-0$
			}
			parent = lib.node(parent);
			if (!parent) { 
				throw "no parent";  //$NON-NLS-0$
			}

			var contributions = this._contributionsByScopeId[scopeId];

			if (!items && contributions) {
				var selectionService = contributions.localSelectionService || this._selectionService;
				var self = this;
				if (selectionService) {
					selectionService.getSelections(function(selections) {
						self.renderCommands(scopeId, parent, selections, handler, renderType, userData);
					});
				}
				return;
			} 
			if (contributions) {
				this._render(scopeId, contributions, parent, items, handler, renderType || "button", userData, domNodeWrapperList); //$NON-NLS-0$
				
				// If the last thing we rendered was a group, it's possible there is an unnecessary trailing separator.
				this._checkForTrailingSeparator(parent, renderType, true);
			}
		},
		
		/**
		 * Destroy all DOM nodes and any other resources used by rendered commands.
		 * This call does not remove the commands from the command registry.  Clients typically call this
		 * function to empty a command area when a client wants to render the commands again due to some 
		 * change in state.  
		 * @param {String|DOMElement} parent The id or DOM node that should be emptied.
		 */
		destroy: function(parent) {
			parent = lib.node(parent);
			if (!parent) { 
				throw "no parent";  //$NON-NLS-0$
			}
			while (parent.hasChildNodes()) {
				var node = parent.firstChild;
				if (node.commandTooltip) {
					node.commandTooltip.destroy();
				}
				if (node.emptyGroupTooltip) {
					node.emptyGroupTooltip.destroy();
				}
				this.destroy(node);
				parent.removeChild(node);
			}
		},
		
		_render: function(scopeId, contributions, parent, items, handler, renderType, userData, domNodeWrapperList, extraClasses) {
			// sort the items
			var sortedByPosition = contributions.sortedContributions;
			
			if (!sortedByPosition) {
				sortedByPosition = [];
				var pushedItem = false;
				for (var key in contributions) {
					if (Object.prototype.hasOwnProperty.call(contributions, key)) {
						var item = contributions[key];
						if (item && typeof(item.position) === "number") { //$NON-NLS-0$
							item.id = key;
							sortedByPosition.push(item);
							pushedItem = true;
						}
					}
				}
				if (pushedItem) {
					sortedByPosition.sort(function(a,b) {
						return a.position-b.position;
					});
					contributions.sortedContributions = sortedByPosition;
				}
			}
			// now traverse the sorted contributions and render as we go
			var index = 0;
			var self = this;
			sortedByPosition.forEach(function(contribution) {
				var id, invocation;
				
				if( !contribution.imageClass ){
					contribution.imageClass = null;
				}
				
				if (contribution.children && Object.getOwnPropertyNames(contribution.children).length > 0) {
					
					var childContributions = contribution.children;
					var created;
					
					if (renderType === "tool" || renderType === "button" || renderType === "menubar") { //$NON-NLS-0$ //$NON-NLS-1$
						if (contribution.title) {
							// We need a named menu button.  We used to first render into the menu and only 
							// add a menu button in the dom when we knew items were actually rendered.
							// For performance, though, we need to be asynchronous in traversing children, so we will 
							// add the menu button always and then remove it if we don't need it.  
							// If we wait until the end of asynch processing to add the menu button, the layout will have 
							// to be redone. The down side to always adding the menu button is that we may find out we didn't
							// need it after all, which could cause layout to change.
							var defaultInvocation;
							if(contribution.defaultActionId){
								contribution.pretendDefaultActionId = contribution.defaultActionId === true;
								var defaultChild = self._commandList[contribution.defaultActionId];
								if(defaultChild && (defaultChild.visibleWhen ? defaultChild.visibleWhen(items) : true)){
									defaultInvocation = new Commands.CommandInvocation(handler, items, userData, defaultChild, self);
									defaultInvocation.domParent = parent;
								} else {
									contribution.pretendDefaultActionId = true;
								}
							}
						
							created = self._createDropdownMenu(parent, contribution.title, null /*nested*/, null /*populateFunc*/, contribution.imageClass, contribution.tooltip, contribution.selectionClass, null, defaultInvocation, contribution.pretendDefaultActionId, contribution.extraClasses);
							
							if(domNodeWrapperList){
								mNavUtils.generateNavGrid(domNodeWrapperList, created.menuButton);
							}

							// render the children asynchronously
							if (created) {
								// If this is the first dropdown in the menu bar then make it tabbable
								if (renderType === "menubar") {
									created.menuButton.tabIndex = parent.childElementCount === 1 ? "0" : "-1";
									created.menuButton.addEventListener("focus", function(evt) {
										var menuItem = evt.currentTarget;
										var menubarDropdown = menuItem.parentNode.parentNode.dropdown;
										menubarDropdown._selectItem(menuItem);
									}, true);
								}
								
//								window.setTimeout(function() {
									self._render(scopeId, contribution.children, created.menu, items, handler, "menu", userData, domNodeWrapperList);  //$NON-NLS-0$
									// special post-processing when we've created a menu in an image bar.  We want to get rid 
									// of a trailing separator in the menu first, and then decide if our menu is necessary
									self._checkForTrailingSeparator(created.menu, "menu", true);  //$NON-NLS-0$
									// now determine if we actually needed the menu or not
									
									if (created.menu.childNodes.length === 0) {
										if (contribution.emptyGroupMessage) {
											if (!created.menuButton.emptyGroupTooltip) {
												created.menuButton.emptyGroupTooltip = new mTooltip.Tooltip({
													node: created.menuButton,
													text: contribution.emptyGroupMessage,
													trigger: "click", //$NON-NLS-0$
													position: ["below", "right", "above", "left"] //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
												});
											}
										} else {
											if(domNodeWrapperList){
												mNavUtils.removeNavGrid(domNodeWrapperList, created.menuButton);
											}
											function remove(child) {
												if (child && child.parentNode) {
													child.parentNode.removeChild(child);
												}
											}
											remove(created.menu);
											remove(created.menuButton);
											remove(created.destroyButton);
										}
									} else {
										created.menuButton.style.visibility = "visible";  //$NON-NLS-0$
									}
//								}, 0);
							}
						} else {  
							// rendering a group using a separator on each end. We do it synchronously because order matters with
							// non grouped items.
							var sep;
							// Only draw a separator if there is a non-separator preceding it.
							if (parent.childNodes.length > 0 && !self._checkForTrailingSeparator(parent, renderType)) {
								sep = self.generateSeparatorImage(parent);
							}
							self._render(scopeId, childContributions, parent, items, handler, renderType, userData, domNodeWrapperList); 
	
							// make sure that more than just the separator got rendered before rendering a trailing separator
							if (parent.childNodes.length > 0) {
								var lastRendered = parent.childNodes[parent.childNodes.length - 1];
								if (lastRendered !== sep) {
									sep = self.generateSeparatorImage(parent);
								}
							}
						}
					} else {
						// group within a menu
						if (contribution.title) {
							var subMenu = self._createDropdownMenu(parent, contribution.title, true, null, null, contribution.imageClass);
							if (subMenu) {
								self._render(scopeId, childContributions, subMenu.menu, items, handler, "menu", userData, domNodeWrapperList);  //$NON-NLS-0$
								// special post-processing when we've created a menu in an image bar.  We want to get rid 
								// of a trailing separator in the menu first, and then decide if our menu is necessary
								self._checkForTrailingSeparator(subMenu.menu, "menu", true);  //$NON-NLS-0$
								// If no items rendered in the submenu, we don't need it.
								if (subMenu.menu.childNodes.length === 0 && subMenu.destroyButton) {
									parent.removeChild(subMenu.destroyButton);
								}
							}
						} else {  
							// menu items with leading and trailing separators
							// don't render a separator if there is nothing preceding
							if (parent.childNodes.length > 0) {
								self._generateMenuSeparator(parent);
							}
							// synchronously render the children since order matters
							self._render(scopeId, childContributions, parent, items, handler, renderType, userData, domNodeWrapperList); 
							// Add a trailing separator if children rendered.
							if (parent.childNodes.length > 0) {
								self._generateMenuSeparator(parent);
							}
						}
					}
				} else {
					// processing atomic commands
					var command = self._commandList[contribution.id];
					var render = command ? true : false;
					var keyBinding = null;
					var urlBinding = null;
					if (command) {
						invocation = new Commands.CommandInvocation(contribution.handler || handler, items, userData, command, self);
						invocation.domParent = parent;
						var enabled = false;
						try {
							enabled = render && (command.visibleWhen ? command.visibleWhen(items, invocation) : true);
						} catch (e) {
							console.log(e);
							throw e;
						}
						// ensure that keybindings are bound to the current handler, items, and user data
						if (self._activeBindings[command.id] && self._activeBindings[command.id].keyBinding) {
							keyBinding = self._activeBindings[command.id];
							if (enabled) {
								keyBinding.invocation = invocation;
							} else {
								keyBinding.invocation = null;
							}
							// if it is a binding only, don't render the command.
							if (keyBinding.bindingOnly) {
								render = false;
							}
						}
						
						// same for url bindings
						if (self._urlBindings[command.id] && self._urlBindings[command.id].urlBinding) {
							urlBinding = self._urlBindings[command.id];
							if (enabled) {
								urlBinding.invocation = invocation;
							} else {
								urlBinding.invocation = null;
							}
							if (urlBinding.bindingOnly) {
								render = false;
							}
						}
						render = render && enabled;
					}
					if (render) {
						if (command.choiceCallback) {
							// special case.  The item wants to provide a set of choices
							var menuParent;
							var nested;
							if (renderType === "tool" || renderType === "button") { //$NON-NLS-1$ //$NON-NLS-0$
								menuParent = parent;
								nested = false;
								if (parent.nodeName.toLowerCase() === "ul") { //$NON-NLS-0$
									menuParent = document.createElement("li"); //$NON-NLS-0$
									lib.setSafeAttribute(menuParent, "role", "none");
									parent.appendChild(menuParent);
								}
							} else {
								menuParent = parent;
								nested = true;
							}
							// dropdown button
							var populateFunction = function(menu) {
								command.populateChoicesMenu(menu, items, handler, userData, self);
							};
							self._createDropdownMenu(menuParent, command.name, nested, populateFunction.bind(command), command.imageClass, command.tooltip || command.title, command.selectionClass, command.positioningNode);
						} else {
							// Rendering atomic commands as buttons or menus
							invocation.handler = invocation.handler || this;
							invocation.domParent = parent;
							var element;
							/**
							 * @callback
							 */
							var onClick = function(e) {
								self._invoke(invocation);
							};
							if (renderType === "menu") {
								var bindingString = null;
								if (keyBinding && keyBinding.keyBinding) {
									bindingString = UIUtil.getUserKeyString(keyBinding.keyBinding);
								}
								element = Commands.createCommandMenuItem(parent, command, invocation, null, onClick, bindingString);
								
								// Register this command as being rendered (do we want to register all the commands ?)
								invocation.onClick = onClick;  // cache the handler
								self._registerRenderedCommand(command.id, scopeId, invocation);
							} else if (renderType === "quickfix") {
								id = renderType + command.id + index; // using the index ensures unique ids within the DOM when a command repeats for each item
								parent.classList.add('quickFixList'); //$NON-NLS-1$
								var QUICKFIX_ID = 'quickfixDetails'; //$NON-NLS-1$
								var quickfixDetails = parent.childNodes.item(QUICKFIX_ID);
								if (command.id === 'ignore.in.file.fix' || command.id === 'css.ignore.on-line.fix'){
									if (!quickfixDetails){
										quickfixDetails = document.createElement("div");
										quickfixDetails.id = QUICKFIX_ID;
										parent.appendChild(quickfixDetails);
									}
									element = Commands.createQuickfixItem(quickfixDetails, command, invocation, onClick, self._prefService);
								} else {
									var commandDiv = document.createElement("div");
									if (quickfixDetails){
										parent.insertBefore(commandDiv, quickfixDetails);
									} else {
										parent.appendChild(commandDiv);
									}
									element = Commands.createQuickfixItem(commandDiv, command, invocation, onClick, self._prefService);
								}
							} else {
								id = renderType + command.id + index;  // // using the index ensures unique ids within the DOM when a command repeats for each item
								element = Commands.createCommandItem(parent, command, invocation, id, null, renderType === "tool", onClick);
							}
							mNavUtils.generateNavGrid(domNodeWrapperList, element, null, null, true);
							invocation.domNode = element;
							index++;
						}
					} 
				}
			});
		},
		
		/*
		 * private.  Parent must exist in the DOM.
		 */
		_createDropdownMenu: function(parent, name, nested, populateFunction, icon, tooltip, selectionClass, positioningNode, defaultInvocation, pretendDefaultActionId, extraClasses) {
			parent = lib.node(parent);
			// We create dropdowns asynchronously so it's possible that the parent has been removed from the document 
			// by the time we are called.  If so, don't bother building a submenu for an orphaned menu.
			if (!parent || !lib.contains(document.body, parent)) {
				return null;
			}
			var menuButton, newMenu, dropdownArrow;
			var destroyButton, menuParent = parent;
			if (nested) {
				var range = document.createRange();
				range.selectNode(parent);
				var buttonFragment = range.createContextualFragment(SubMenuButtonFragment);
				// bind name to fragment variable
				lib.processTextNodes(buttonFragment, {ButtonText: name});
				parent.appendChild(buttonFragment);
				destroyButton = parent.lastChild;
				newMenu = destroyButton.lastChild;
				menuButton = newMenu.previousSibling;
				menuButton.dropdown = new mDropdown.Dropdown({dropdown: newMenu, name: name, populate: populateFunction, parentDropdown: parent.dropdown});
				newMenu.dropdown = menuButton.dropdown;
			} else {
				if (parent.nodeName.toLowerCase() === "ul") { //$NON-NLS-0$
					menuParent = document.createElement("li"); //$NON-NLS-0$
					lib.setSafeAttribute(menuParent, "role", "none");
					parent.appendChild(menuParent);
					destroyButton = menuParent;
				}
				var buttonCss = null;
				if (icon) {
					buttonCss = "dropdownButtonWithIcon"; //$NON-NLS-0$ // This class distinguishes dropdown buttons with an icon from those without
					tooltip = tooltip || name; // No text and no tooltip => fallback to name
				}
				tooltip = icon ? (tooltip || name) : tooltip;
				var created = Commands.createDropdownMenu(menuParent, name, populateFunction, buttonCss, icon, false, selectionClass, positioningNode, defaultInvocation || pretendDefaultActionId, extraClasses);
				dropdownArrow = created.dropdownArrow;
				menuButton = created.menuButton;
				if (dropdownArrow) {
					if (defaultInvocation) {
						defaultInvocation.domNode = created.menuButton;
					}
					var self = this;
					menuButton.onclick = function(evt){
						var bounds = lib.bounds(dropdownArrow);
						if ((evt.clientX >= bounds.left || pretendDefaultActionId === true) && created.dropdown) {
							created.dropdown.toggle(evt);
						} else {
							self._invoke(defaultInvocation);
						}
					};
					if (created.dropdown) {
						menuButton.onkeydown = function(evt) {
							if (lib.KEY.DOWN === evt.keyCode) {
								created.dropdown.toggle(evt);
								lib.stop(evt);
							}
						};
					}
				}
				newMenu = created.menu;
				var tooltipText, hasDefault = defaultInvocation && defaultInvocation.command && (defaultInvocation.command.tooltip || defaultInvocation.command.name);
				if (hasDefault) {
					tooltipText = defaultInvocation.command.tooltip || defaultInvocation.command.name;
				} else {
					tooltipText = tooltip;
				}
				if (tooltipText) {
					menuButton.commandTooltip = new mTooltip.Tooltip({
						node: menuButton,
						text: tooltipText,
						position: ["above", "below", "right", "left"] //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
					});					
				}
			}
			
			return {menuButton: menuButton, menu: newMenu, dropdown: menuButton.dropdown, destroyButton: destroyButton, dropdownArrow: dropdownArrow};
		},
		
		_generateMenuSeparator: function(dropdown) {
			if (!this._checkForTrailingSeparator(dropdown, "menu")) { //$NON-NLS-0$
				var item = document.createElement("li"); //$NON-NLS-0$
				item.classList.add("dropdownSeparator"); //$NON-NLS-0$
				lib.setSafeAttribute(item, "role", "none");
				var sep = document.createElement("span"); //$NON-NLS-0$
				sep.classList.add("dropdownSeparator"); //$NON-NLS-0$
				lib.setSafeAttribute(sep, "role", "separator");
				item.appendChild(sep);
				dropdown.appendChild(item);
			}
		},
		
				
		/**
		 * Add a dom node appropriate for using a separator between different groups
		 * of commands.  This function is useful when a page is precisely arranging groups of commands
		 * (in a table or contiguous spans) and needs to use the same separator that the command registry
		 * would use when rendering different groups of commands.
		 * @param {DOMElement} parent
		 */
		generateSeparatorImage: function(parent) {
			var sep;
			if (parent.nodeName.toLowerCase() === "ul") { //$NON-NLS-0$
				sep = document.createElement("li"); //$NON-NLS-0$
				lib.setSafeAttribute(sep, "role", "none");
				parent.appendChild(sep);
			} else {
				sep = document.createElement("span"); //$NON-NLS-0$
				parent.appendChild(sep);
			}
			sep.classList.add("core-sprite-sep");  // location in sprite //$NON-NLS-0$
			sep.classList.add("imageSprite");  // sets sprite background //$NON-NLS-0$
			sep.classList.add("commandSeparator"); //$NON-NLS-0$
			return sep;
		}

	};  // end command registry prototype
	CommandRegistry.prototype.constructor = CommandRegistry;

	/**
	 * A URL binding defines how a URL token is bound to a command, and what parameter
	 * is provided
	 * @param {String} token the token in a URL query parameter that identifies the command
	 * @param {String} parameterName the name of the parameter being specified in the value of the query 
	 * 
	 * @name orion.commands.URLBinding
	 * @class
	 */
	function URLBinding (token, parameterName) {
		this.token = token;
		this.parameterName = parameterName;
	}
	URLBinding.prototype = /** @lends orion.commands.URLBinding.prototype */ {
		/**
		 * Returns whether this URL binding matches the given URL
		 * 
		 * @param url the URL.
		 * @returns {Boolean} whether this URL binding matches
		 */
		match: function (url) {
			//ensure this is only the hash portion
			var params = PageUtil.matchResourceParameters(url);
			if (typeof params[this.token] !== "undefined") { //$NON-NLS-0$
				this.parameterValue = params[this.token];
				return this;
			}
			return null;
		}
	};
	URLBinding.prototype.constructor = URLBinding;
	
	/**
	 * A CommandEventListener defines an (optional) UI event listener.
	 * 
	 * @param {String} name the name of the event
	 * @param {Function} handler the event handler function. The handler is provided two parameters on invocation, i. e.
	 * 			the DOM event and the undergoing commandInvocation objects.
	 * @param {Boolean} [capture] the (optional) flag used to determine whether to capture the event or not
	 */
	function CommandEventListener (event, handler, capture) {
		this.event = event;
		this.handler = handler;
		this.capture = capture || false;
	}
	CommandEventListener.prototype.constructor = CommandEventListener;
	
	
	/**
	 * A CommandParameter defines a parameter that is required by a command.
	 *
	 * @param {String} name the name of the parameter
	 * @param {String} type the type of the parameter, one of the HTML5 input types, or "boolean"
	 * @param {String} [label] the (optional) label that should be used when showing the parameter
	 * @param {String} [value] the (optional) default value for the parameter
	 * @param {Number} [lines] the (optional) number of lines that should be shown when collecting the value.  Valid for type "text" only.
	 * @param {Object|Array} [eventListeners] the (optional) array or single command event listener
	 * @param {Function} [validator] a (optional) validator function
	 * 
	 * @name orion.commands.CommandParameter
	 * @class
	 */
	function CommandParameter (name, type, label, value, lines, eventListeners, validator) {
		this.name = name;
		this.type = type;
		this.label = label;
		this.value = value;
		this.lines = lines || 1;
		this.validator = validator;
		
		this.eventListeners = (Array.isArray(eventListeners)) ?
			eventListeners : (eventListeners ? [eventListeners] : []);
	}
	CommandParameter.prototype = /** @lends orion.commands.CommandParameter.prototype */ {
		/**
		 * Returns whether the user has requested to assign values to optional parameters
		 * 
		 * @returns {Boolean} whether the user has requested optional parameters
		 */
		optionsRequested: function () {
			return this.optionsRequested;
		}
	};
	CommandParameter.prototype.constructor = CommandParameter;
	
	/**
	 * A ParametersDescription defines the parameters required by a command, and whether there are additional
	 * optional parameters that can be specified.  The command registry will attempt to collect required parameters
	 * before calling a command callback.  The command is expected to provide UI for optional parameter, when the user has
	 * signaled a desire to provide optional information.
	 *
	 * @param {orion.commands.CommandParameter[]} parameters an array of CommandParameters that are required
	 * @param {Object} options The parameters description options object.
	 * @param {Boolean} options.hasOptionalParameters specifies whether there are additional optional parameters
	 *			that could be collected.  If true, then the collector will show an affordance for invoking an 
	 *			additional options collector and the client can use the optionsRequested flag to determine whether
	 *			additional parameters should be shown.  Default is false.
	 * @param {Boolean} options.clientCollect specifies whether the client will collect the parameters in its
	 *			callback.  Default is false, which means the callback will not be called until an attempt has
	 *			been made to collect parameters.
	 * @param {Function} options.getParameterElement a function used to look up the DOM element for a given parameter.
	 * @param {Function} options.getSubmitName a function used to return a name to use for the Submit button.
	 *
	 * @param {Function} [getParameters] a function used to define the parameters just before the command is invoked.  This is used
	 *			when a particular invocation of the command will change the parameters. The function will be passed
	 *          the CommandInvocation as a parameter. Any stored parameters will be ignored, and
	 *          replaced with those returned by this function. If no parameters (empty array or <code>null</code>) are returned,
	 *          then it is assumed that the command should not try to obtain parameters before invoking the command's callback
	 *          (similar to <code>options.clientCollect === true</code>).
	 * @name orion.commands.ParametersDescription
	 * @class
	 */
	function ParametersDescription (parameters, options, getParameters) {
		this._storeParameters(parameters);
		this._hasOptionalParameters = options && options.hasOptionalParameters;
		this._options = options;  // saved for making a copy
		this.optionsRequested = false;
		this.getParameters = getParameters;
		this.clientCollect = options && options.clientCollect;
		this.getParameterElement = options && options.getParameterElement;
		this.getSubmitName = options && options.getSubmitName;
		this.getCancelName = options && options.getCancelName;
		this.message = options && options.message;
	}
	ParametersDescription.prototype = /** @lends orion.commands.ParametersDescription.prototype */ {	
	
		_storeParameters: function(parameterArray) {
			this.parameterTable = null;
			if (parameterArray) {
				var table = this.parameterTable = {};
				parameterArray.forEach(function(parameter) {
					table[parameter.name] = parameter;
				});
			}
		},
		
		/**
		 * Update the stored parameters by running the stored function if one has been supplied.
		 */
		updateParameters: function(commandInvocation) {
			if (typeof this.getParameters === "function") { //$NON-NLS-0$
				this._storeParameters(this.getParameters(commandInvocation));
			}
		},
		
		/**
		 * Returns a boolean indicating whether any parameters have been specified.
		 *
		 * @returns {Boolean} whether there are parameters to collect.
		 */
		hasParameters: function() {
			return this.parameterTable !== null;
		},
		
		/**
		 * Returns a boolean indicating whether a collector should try to collect parameters.  If there
		 * are no parameters specified, or the client is expecting to collect them, this will return
		 * <code>false</code>.
		 *
		 * @returns {Boolean} indicating whether the caller should attempt to collect the parameters.
		 */
		shouldCollectParameters: function() {
			return !this.clientCollect && this.hasParameters();
		},
				
		/**
		 * Returns the CommandParameter with the given name, or <code>null</code> if there is no parameter
		 * by that name.
		 *
		 * @param {String} name the name of the parameter
		 * @returns {orion.commands.CommandParameter} the parameter with the given name
		*/
		parameterNamed: function(name) {
			return this.parameterTable[name];
		},
		
		/**
		 * Returns the value of the parameter with the given name, or <code>null</code> if there is no parameter
		 * by that name, or no value for that parameter.
		 *
		 * @param {String} name the name of the parameter
		 * @returns {String} the value of the parameter with the given name
		 */
		valueFor: function(name) {
			var parm = this.parameterTable[name];
			if (parm) {
				return parm.value;
			}
			return null;
		},
		
		/**
		 * Sets the value of the parameter with the given name.
		 *
		 * @param {String} name the name of the parameter
		 * @param {String} value the value of the parameter with the given name
		 */
		setValue: function(name, value) {
			var parm = this.parameterTable[name];
			if (parm) {
				parm.value = value;
			}
		},
		 
		/**
		 * Evaluate the specified function for each parameter.
		 *
		 * @param {Function} func a function which operates on a provided command parameter
		 *
		 */
		forEach: function(func) {
			for (var key in this.parameterTable) {
				if (this.parameterTable[key].type && this.parameterTable[key].name) {
					func(this.parameterTable[key]);
				}
			}
		},
		
		validate: function(name, value) {
			var parm = this.parameterTable[name];
			if (parm && parm.validator) {
				return parm.validator(value);
			}
			return true;
		},
		
		/**
		 * Make a copy of this description.  Used for collecting values when a client doesn't want
		 * the values to be persisted across different objects.
		 *
		 */
		 makeCopy: function() {
			var parameters = [];
			this.forEach(function(parm) {
				var newParm = new CommandParameter(parm.name, parm.type, parm.label, parm.value, parm.lines, parm.eventListeners, parm.validator);
				parameters.push(newParm);
			});
			var copy = new ParametersDescription(parameters, this._options, this.getParameters);
			// this value may have changed since the options
			copy.clientCollect = this.clientCollect;
			copy.message = this.message;
			return copy;
			
		 },
		 /**
		  * Return a boolean indicating whether additional optional parameters are available.
		  */
		 hasOptionalParameters: function() {
			return this._hasOptionalParameters;
		 }
	};
	ParametersDescription.prototype.constructor = ParametersDescription;

	//return the module exports
	return {
		CommandRegistry: CommandRegistry,
		URLBinding: URLBinding,
		ParametersDescription: ParametersDescription,
		CommandParameter: CommandParameter,
		CommandEventListener: CommandEventListener
	};
});

/*******************************************************************************
 * @license
 * Copyright (c) 2012 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 * 
 ******************************************************************************/
/*eslint-env browser, amd*/
define('orion/navigate/nls/messages',{
	root:true
});

/*******************************************************************************
 * @license
 * Copyright (c) 2012 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 * 
 ******************************************************************************/
/*eslint-env browser, amd*/
define('orion/navigate/nls/root/messages',{//Default message bundle
	"Navigator": "Navigator",
	"Strings Xtrnalizr": "Strings Xtrnalizr",
	"Externalize strings": "Externalize strings from JavaScript files in this folder.",
	"NotSupportFileSystem":"${0} is not supported in this file system",
	"SrcNotSupportBinRead":"Source file service does not support binary read",
	"TargetNotSupportBinWrite":"Target file service does not support binary write",
	"NoFileSrv": "No matching file service for location: ${0}",
	"Choose a Folder": "Choose a Folder",
	"Copy of ${0}": "Copy of ${0}",
	"EnterName": "Enter a new name for '${0}'",
	"ChooseFolder": "Choose folder...",
	"Rename": "Rename",
	"Refresh": "Refresh",
	"RenameFilesFolders": "Rename the selected files or folders",
	"CompareEach": "Compare with each other",
	"Compare 2 files": "Compare the selected 2 files with each other",
	"Compare with...": "Compare With...",
	"CompareFolders": "Compare the selected folder with a specified folder",
	"Delete": "Delete",
	"Unknown item": "Unknown item",
	"delete item msg": "Are you sure you want to delete these ${0} items?",
	"DeleteTrg": "Are you sure you want to delete '${0}'?",
	"Zip": "Zip",
	"ZipDL": "Create a zip file of the folder contents and download it",
	"New File": "File",
	"Create a new file": "Create a new file",
	"FailedToCreateProject":"Failed to create project: ${0}",
	"FailedToCreateFile": "Failed to create file: ${0}",
	"CopyFailed": "Copy operation failed",
	"MoveFailed": "Move operation failed",
	"Name:": "Name:",
	"New Folder": "Folder",
	"Folder name:": "Folder name:",
	"Create a new folder": "Create a new folder",
	"Creating folder": "Creating folder",
	"Folder": "Folder",
	"Create an empty folder": "Create an empty folder",
	"CreateEmptyMsg": "Create an empty folder on the Orion server. You can import, upload, or create content in the editor.",
	"Sample HTML5 Site": "Sample HTML5 Site",
	"Generate a sample": "Generate a sample",
	"Generate an HTML5 \"Hello World\" website, including JavaScript, HTML, and CSS files.": "Generate an HTML5 \"Hello World\" website, including JavaScript, HTML, and CSS files.",
	"Creating a folder for ${0}": "Creating a folder for ${0}",
	"SFTP Import": "SFTP Import",
	"Import content from SFTP": "Import content from SFTP",
	"Imported Content": "Imported Content",
	"Upload a Zip": "Upload a Zip",
	"Upload content from a local zip file": "Upload content from a local zip file",
	"Uploaded Content": "Uploaded Content",
	"Clone Git Repository": "Clone Git Repository",
	"Clone a git repository": "Clone a git repository",
	"LinkContent": "Link to existing content on the server",
	"CreateLinkedFolder": "Create a folder that links to an existing folder on the server.",
	"Server path:": "Server path:",
	"NameLocationNotClear": "The name and server location were not specified.",
	"Go Up": "Go Up",
	"GoUpToParent": "Move up to the parent folder",
	"Go Into": "Go Into",
	"GoSelectedFolder": "Move into the selected folder",
	"File or zip archive": "File or Zip Archive",
	"ImportLcFile": "Import a file or zip archive from your local file system",
	"SFTP from...": "SFTP",
	"CpyFrmSftp": "Copy files and folders from a specified SFTP connection",
	"Importing from ${0}": "Importing from ${0}",
	"SFTP to...": "SFTP",
	"CpyToSftp": "Copy files and folders to a specified SFTP location",
	"Exporting": "Exporting to ${0}",
	"Pasting ${0}": "Pasting ${0}",
	"Copy to": "Copy to",
	"Move to": "Move to",
	"Copying ${0}": "Copying ${0}",
	"Moving ${0}": "Moving ${0}",
	"Renaming ${0}": "Renaming ${0}",
	"Deleting ${0}": "Deleting ${0}",
	"Creating ${0}": "Creating ${0}",
	"Linking to ${0}": "Linking to ${0}",
	"MvToLocation": "Move files and folders to a new location",
	"Cut": "Cut",
	"Copy": "Copy",
	"Fetching children of ": "Fetching children of ",
	"Paste": "Paste",
	"Open With": "Open With",
	"Loading ${0}": "Loading ${0}",
	"New": "New",
	"File": "File",
	"Actions": "Actions",
	"Orion Content": "Orion Content",
	"File System": "File System",
	"Root": "Root",
	"Name": "Name",
	"Date Modified": "Date Modified",
	"Size": "Size",
	"Create new content": "Create new content",
	"Import from HTTP...": "HTTP",
	"File URL:": "File URL:",
	"ImportURL": "Import a file from a URL and optionally unzip it",
	"Unzip *.zip files": "Unzip *.zip files",
	"Extracted from:": "Extracted from:",
	"FolderDropNotSupported": "Did not drop ${0}. Folder drop is not supported in this browser.",
	"CreateFolderErr": "You cannot copy files directly into the workspace. Create a folder first.",
	"Unzip ${0}?": "Unzip ${0}?",
	"Upload progress: ": "Upload progress: ",
	"Uploading ": "Uploading ",
	"Cancel upload": "Cancel upload",
	"UploadingFileErr": "Uploading the following file failed: ",
	"Enter project name:": "Enter project name:",
	"Create new project" : "Create new project",
	"Creating project ${0}": "Creating project ${0}",
	"NoFile": "Use the ${0} menu to create new files and folders. Click a file to start coding, or go to the Git page to bring in existing code.",
	"Download": "Download",
	"Download_tooltips": "Download the file contents as the displayed name",
	"Downloading...": "Reading file contents...",
	"Download not supported": "Contents download is not supported in this browser.",
	"gettingContentFrom": "Getting content from ",
	"confirmLaunchDelete": "Delete Launch Configuration \"${0}\" ?",
	"deletingLaunchConfiguration": "Deleting launch configuration...",
	"deployTo": "Deploy to ",
	"deployItem": "Deploy \"${0}\"",
	"deploy": "Deploy",
	"connect": "Connect",
	"fetchContent": "Fetch content",
	"fetchContentOf": "Fetch content of ",
	"disconnectFromProject": "Disconnect from project",
	"doNotTreatThisFolder": "Do not treat this folder as a part of the project",
	"checkStatus": "Check status",
	"checkApplicationStatus": "Check application status",
	"checkApplicationState": "Check application state",
	"stop": "Stop",
	"start": "Start",
	"stopApplication": "Stop the App",
	"startApplication": "Start the application",
	"manage": "Manage",
	"manageThisApplicationOnRemote": "Manage this application on remote server",
	"deleteLaunchConfiguration": "Delete",
	"editLaunchConfiguration": "Edit",
	"deployThisApplication": "Deploy the App from the Workspace",
	"associatedFolder": "Associated Folder",
	"associateAFolderFromThe": "Associate a folder from the workspace with this project.",
	"convertToProject": "Convert to project",
	"convertThisFolderIntoA": "Convert this folder into a project",
	"thisFolderIsAProject": "This folder is a project already.",
	"basic": "Basic",
	"createAnEmptyProject.": "Create an empty project",
	"sFTP": "SFTP",
	"createAProjectFromAn": "Create a project from an SFTP site",
	'readMeCommandName': 'Readme File',  //$NON-NLS-0$  //$NON-NLS-1$
	'readMeCommandTooltip': 'Create a README.md file in this project',  //$NON-NLS-0$  //$NON-NLS-1$
	'zipArchiveCommandName': 'Zip Archive',  //$NON-NLS-0$  //$NON-NLS-1$
	'zipArchiveCommandTooltip': 'Create a project from a local zip archive',  //$NON-NLS-0$  //$NON-NLS-1$
	'Url:': 'Url:',  //$NON-NLS-0$  //$NON-NLS-1$
	'notZip' : 'The following files are not zip files: ${0}. Would you like to continue the import?', //$NON-NLS-0$  //$NON-NLS-1$
	'notZipMultiple' : 'There are multiple non-zip files being uploaded. Would you like to continue the import?', //$NON-NLS-0$  //$NON-NLS-1$
	"Cancel": "Cancel", //$NON-NLS-0$  //$NON-NLS-1$
	"Ok": "Ok", //$NON-NLS-0$  //$NON-NLS-1$
	"missingCredentials": "Enter the ${0} authentication credentials associated with ${1} to check its status.", //$NON-NLS-0$  //$NON-NLS-1$
	"deploying": "deploying", //$NON-NLS-0$  //$NON-NLS-1$
	"starting": "restarting", //$NON-NLS-0$  //$NON-NLS-1$
	"stopping": "stopping", //$NON-NLS-0$  //$NON-NLS-1$
	"checkingStateShortMessage": "checking status" //$NON-NLS-0$  //$NON-NLS-1$
});


/*******************************************************************************
 * @license
 * Copyright (c) 2010, 2017 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made
 * available under the terms of the Eclipse Public License v1.0
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html).
 *
 * Contributors: IBM Corporation - initial API and implementation
 ******************************************************************************/

/*eslint-env browser, amd*/
/** @namespace The global container for eclipse APIs. */
define('orion/fileClient',[
	'i18n!orion/navigate/nls/messages',
	"orion/Deferred",
	"orion/i18nUtil",
	'orion/EventTarget'
], function(messages, Deferred, i18nUtil, EventTarget) {
	/**
	 * This helper method implements invocation of the service call,
	 * with retry on authentication error if needed.
	 * @private
	 */
	function _doServiceCall(fileService, funcName, funcArgs) {
		//if the function is not implemented in the file service, we throw an exception to the caller
		if(!fileService[funcName]){
			throw new Error(i18nUtil.formatMessage(messages["NotSupportFileSystem"], funcName));
		}
		return fileService[funcName].apply(fileService, funcArgs);
	}

	/**
	 * @description Copy
	 * @private
	 * @param sourceService
	 * @param sourceLocation
	 * @param targetService
	 * @param targetLocation
	 * @returns returns
	 */
	function _copy(sourceService, sourceLocation, targetService, targetLocation) {

		if (!sourceService.readBlob) {
			throw new Error(messages["SrcNotSupportBinRead"]);
		}

		if (!targetService.writeBlob) {
			throw new Error(messages["TargetNotSupportBinWrite"]);
		}

		if (sourceLocation[sourceLocation.length -1] !== "/") {
			return _doServiceCall(sourceService, "readBlob", [sourceLocation]).then(function(contents) { //$NON-NLS-1$
				return _doServiceCall(targetService, "writeBlob", [targetLocation, contents]); //$NON-NLS-1$
			});
		}

		var temp = targetLocation.substring(0, targetLocation.length - 1);
		var targetName = decodeURIComponent(temp.substring(temp.lastIndexOf("/")+1));
		var parentLocation = temp.substring(0, temp.lastIndexOf("/")+1);

		return _doServiceCall(targetService, "createFolder", [parentLocation, targetName]).then(function() { //$NON-NLS-1$
			return;
		}, function() {
			return;
		}).then(function() {
			return _doServiceCall(sourceService, "fetchChildren", [sourceLocation]).then(function(children) { //$NON-NLS-1$
				var results = [];
				for(var i = 0; i < children.length; ++i) {
					var childSourceLocation = children[i].Location;
					var childTemp =  childSourceLocation;
					if (children[i].Directory) {
						childTemp = childSourceLocation.substring(0, childSourceLocation.length - 1);
					}
					var childName = decodeURIComponent(childTemp.substring(childTemp.lastIndexOf("/")+1));

					var childTargetLocation = targetLocation + encodeURIComponent(childName);
					if (children[i].Directory) {
						childTargetLocation += "/";
					}
					results[i] = _copy(sourceService, childSourceLocation, targetService, childTargetLocation);
				}
				return Deferred.all(results);
			});
		});
	}


	/**
	 * Creates a new file client.
	 * @class The file client provides a convenience API for interacting with file services
	 * provided by plugins. This class handles authorization, and authentication-related
	 * error handling.
	 * @name orion.fileClient.FileClient
	 */
	function FileClient(serviceRegistry, filter) {
		var _patterns;
		var _services;
		var _names;

		EventTarget.attach(this);
		/* @callback */
		function _noMatch(loc) {
			var d = new Deferred();
			d.reject(messages["No Matching FileService for location:"] + loc);
			return d;
		}

		var _fileSystemsRoots = [];
		var _allFileSystemsService = {
			/* @callback */
			fetchChildren: function() {
				var d = new Deferred();
				d.resolve(_fileSystemsRoots);
				return d;
			},
			/* @callback */
			createWorkspace: function() {
				var d = new Deferred();
				d.reject(messages["no file service"]);
				return d;
			},
			/* @callback */
			loadWorkspaces: function() {
				var d = new Deferred();
				d.reject(messages['no file service']);
				return d;
			},
			/* @callback */
			loadWorkspace: function(loc) {
				var d = new Deferred();
				window.setTimeout(function() {
					d.resolve({
						Directory: true,
						Length: 0,
						LocalTimeStamp: 0,
						Name: messages["File Servers"],
						Location: "/",
						Children: _fileSystemsRoots,
						ChildrenLocation: "/"
					});
				}, 100);
				return d;
			},
			/* @callback */
			read: function(loc) {
				if (loc === "/") {
					return this.loadWorkspace(loc);
				}
				return _noMatch(loc);
			},
			/**
			 * @description Computes the project context from the given location
			 * @param {String} context The resource context to find the project for
			 * @since 14.0
			 */
			getProject: _noMatch,
			search: _noMatch,
			createProject: _noMatch,
			createFolder: _noMatch,
			createFile: _noMatch,
			deleteFile: _noMatch,
			moveFile: _noMatch,
			copyFile: _noMatch,
			write: _noMatch
		};

		/**
		 * @description Initialize the service
		 * @private
		 */
		function init() {
			if (_services) { return; }
			_patterns = [];
			_services = [];
			_names = [];

			var allReferences = serviceRegistry.getServiceReferences("orion.core.file"); //$NON-NLS-1$
			var _references = allReferences;
			if (filter) {
				_references = [];
				for(var i = 0; i < allReferences.length; ++i) {
					if (filter(allReferences[i])) {
						_references.push(allReferences[i]);
					}
				}
			}
			_references.sort(function (ref1, ref2) {
				var ranking1 = ref1.getProperty("ranking") || 0; //$NON-NLS-1$
				var ranking2 = ref2.getProperty("ranking")  || 0; //$NON-NLS-1$
				return ranking1 - ranking2;
			});
			for(var j = 0; j < _references.length; ++j) {
				_fileSystemsRoots[j] = {
					Directory: true,
					Length: 0,
					LocalTimeStamp: 0,
					Location: _references[j].getProperty("top"), //$NON-NLS-1$
					ChildrenLocation: _references[j].getProperty("top"), //$NON-NLS-1$
					Name: _references[j].getProperty("Name") || _references[j].getProperty("NameKey") //$NON-NLS-1$ //$NON-NLS-2$
				};

				var filetop = _references[j].getProperty("top"); //$NON-NLS-1$
				var patternStringArray = _references[j].getProperty("pattern") || (filetop ? filetop.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1") : ""); //$NON-NLS-1$ //$NON-NLS-2$
				if (!Array.isArray(patternStringArray)) {
					patternStringArray = [patternStringArray];
				}
				var patterns = [];
				for (var k = 0; k < patternStringArray.length; k++) {
					var patternString = patternStringArray[k];
					if (patternString[0] !== "^") {
						patternString = "^" + patternString;
					}
					patterns.push(new RegExp(patternString));
				}
				_patterns[j] = patterns;
				_services[j] = serviceRegistry.getService(_references[j]);
				_names[j] = _references[j].getProperty("Name") || _references[j].getProperty("NameKey"); //$NON-NLS-1$ //$NON-NLS-2$
			}
		}

		/**
		 * @description Returns the index of the service for the given item location
		 * @function
		 * @private
		 * @param {String} itemLocation
		 * @returns returns
		 */
		this._getServiceIndex = function(itemLocation) {
			init();
			// client must specify via "/" when a multi file service tree is truly wanted
			if (itemLocation === "/") {
				return -1;
			} else if (!itemLocation || itemLocation.length && itemLocation.length === 0) {
				// TODO we could make the default file service a preference but for now we use the first one
				return _services[0] ? 0 : -1;
			}
			for(var i = 0; i < _patterns.length; ++i) {
				for (var j = 0; j < _patterns[i].length; j++) {
					if (_patterns[i][j].test(itemLocation)) {
						return i;
					}
				}
			}
			return -1;
			//throw new Error(i18nUtil.formatMessage(messages['NoFileSrv'], itemLocation));
		};
		/**
		 * Returns the file service managing this location
		 * @param {String} itemLocation The location of the item
		 * @private
		 * @returns {FileClient} The service for the given item
		 */
		this._getService = function(itemLocation) {
			var i = this._getServiceIndex(itemLocation);
			return i === -1 ? _allFileSystemsService : _services[i];
		};
		/**
		 * Returns the name of the file service managing this location
		 * @param {String} itemLocation The location of the item
		 * @private
		 * @return {String} The name of this file service
		 */
		this._getServiceName = function(itemLocation) {
			var i = this._getServiceIndex(itemLocation);
			return i === -1 ? _allFileSystemsService.Name : _names[i];
		};
		/**
		 * Returns the root url of the file service managing this location
		 * @param {String} itemLocation The location of the item
		 * @private
		 * @return {String} The root URL of the given item
		 */
		this._getServiceRootURL = function(itemLocation) {
			var i = this._getServiceIndex(itemLocation);
			return i === -1 ? _allFileSystemsService.Location : _fileSystemsRoots[i].Location;
		};

		this._frozenEvent = {type: "Changed"};
		this._eventFrozenMode = false;

		serviceRegistry.registerService("orion.core.file.client", this); //$NON-NLS-1$
	}

	FileClient.prototype = /**@lends orion.fileClient.FileClient.prototype */ {
		freezeChangeEvents: function() {
			this._frozenEvent = {type: "Changed"};
			this._eventFrozenMode = true;
		},
		thawChangeEvents: function() {
			this._eventFrozenMode = false;
			this.dispatchEvent(this._frozenEvent);
		},
		isEventFrozen: function() {
			return this._eventFrozenMode;
		},

		/**
		 * Returns the file service managing this location
		 * @param {String} itemLocation The location of the item
		 * @public
		 * @returns {FileClient} The service for the given item
		 */
		getService: function(itemLocation) {
			return this._getService(itemLocation);
		},

		/**
		 * Returns the name of the file service managing this location
		 * @param {String} itemLocation The location of the item
		 * @public
		 * @return {String} The name of this file service
		 */
		fileServiceName: function(itemLocation) {
			return this._getServiceName(itemLocation);
		},

		/**
		 * Returns the root url of the file service managing this location
		 * @param {String} itemLocation The location of the item
		 * @public
		 * @return {String} The root URL of the given item
		 */
		fileServiceRootURL: function(itemLocation) {
			return this._getServiceRootURL(itemLocation);
		},

		/**
		 * Obtains the children of a remote resource
		 * @param {string} parentLocation The location of the item to obtain children for
		 * @public
		 * @return {Deferred} A deferred that will provide the array of child objects when complete
		 */
		fetchChildren: function(parentLocation) {
			return _doServiceCall(this._getService(parentLocation), "fetchChildren", arguments); //$NON-NLS-1$
		},

		/**
		 * Creates a new workspace with the given name. The resulting workspace is
		 * passed as a parameter to the provided onCreate function.
		 * @param {String} workspaceName The name of the new workspace
		 * @public
		 * @return {Deferred} A deferred that will create a workspace with the given name
		 */
		createWorkspace: function(workspaceName) {
			return _doServiceCall(this._getService(), "createWorkspace", arguments); //$NON-NLS-1$
		},

		/**
		 * Loads all the user's workspaces for the specified file system. Returns a deferred
		 * that will provide the loaded workspaces when ready.
		 * @public
		 * @return {Deferred} A deferred that will load all workspaces
		 */
		loadWorkspaces: function(systemLocation) {
			return _doServiceCall(this._getService(systemLocation), "loadWorkspaces", arguments); //$NON-NLS-1$
		},

		/**
		 * Loads the workspace with the given id and sets it to be the current
		 * workspace for the IDE. The workspace is created if none already exists.
		 * @param {String} workspaceLocation the location of the workspace to load
		 * @param {Function} onLoad the function to invoke when the workspace is loaded
		 * @public
		 * @return {Deferred} A deferred that will load the specified workspace
		 */
		loadWorkspace: function(workspaceLocation) {
			return _doServiceCall(this._getService(workspaceLocation), "loadWorkspace", arguments); //$NON-NLS-1$
		},
		
		/**
		 * Gets the workspace of the specified resource location.
		 * 
		 * @param resourceLocation the resource to lookup the workspace
		 * @return {Deferred} A deferred that will load the specified workspace
		 */
		getWorkspace: function(resourceLocation) {
			return _doServiceCall(this._getService(resourceLocation), "getWorkspace", arguments); //$NON-NLS-1$
		},

		/**
		 * @callback
		 */
		changeWorkspace: function(workspaceLocation) {
			return _doServiceCall(this._getService(), "changeWorkspace", arguments); //$NON-NLS-1$
		},
		/**
		 * @description Computes the project context from the given location
		 * @param {String} context The resource context to find the project for
		 * @since 14.0
		 */
		getProject: function getProject(resource) {
			return _doServiceCall(this._getService(resource), "getProject", arguments);	
		},
		_createArtifact: function(parentLocation, funcName, eventData, funcArgs) {
			return _doServiceCall(this._getService(parentLocation), funcName, funcArgs).then(function(result){
				if(this.isEventFrozen()) {
					if(!this._frozenEvent.created) {
						this._frozenEvent.created = [];
					}
					this._frozenEvent.created.push({parent: parentLocation, result: result, eventData: eventData});
				} else {
					this.dispatchEvent({ type: "Changed", created: [{parent: parentLocation, result: result, eventData: eventData}]}); //$NON-NLS-0$
				}
				return result;
			}.bind(this));
		},

		/**
		 * Adds a project to a workspace.
		 * @param {String} url The workspace location
		 * @param {String} projectName the human-readable name of the project
		 * @param {String} serverPath The optional path of the project on the server.
		 * @param {Boolean} create If true, the project is created on the server file system if it doesn't already exist
		 * @public
		 * @return {Deferred} A deferred that will create a new project in the workspace
		 */
		createProject: function(url, projectName, serverPath, create) {
			return _doServiceCall(this._getService(url), "createProject", arguments); //$NON-NLS-1$
			//return this._createArtifact(url, "createProject", arguments);
		},
		/**
		 * Creates a folder.
		 * @param {String} parentLocation The location of the parent folder
		 * @param {String} folderName The name of the folder to create
		 * @param {Object} eventData The event data that will be sent back.
		 * @return {Object} JSON representation of the created folder
		 * @public
		 * @return {Deferred} A deferred that will create a new folder in the workspace
		 */
		createFolder: function(parentLocation, folderName, eventData) {
			//return _doServiceCall(this._getService(parentLocation), "createFolder", arguments); //$NON-NLS-1$
			return this._createArtifact(parentLocation, "createFolder", eventData, arguments);
		},
		/**
		 * Create a new file in a specified location. Returns a deferred that will provide
		 * The new file object when ready.
		 * @param {String} parentLocation The location of the parent folder
		 * @param {String} fileName The name of the file to create
		 * @param {Object} eventData The event data that will be sent back.
		 * @public
		 * @return {Deferred} A deferred that will provide the new file object
		 */
		createFile: function(parentLocation, fileName, eventData) {
			//return _doServiceCall(this._getService(parentLocation), "createFile", arguments); //$NON-NLS-1$
			return this._createArtifact(parentLocation, "createFile", eventData, arguments);
		},
		/**
		 * Deletes a file, directory, project or workspace.
		 * @param {String} deleteLocation The location of the file or directory to delete.
		 * @param {Object} eventData The event data that will be sent back.
		 * @public
		 * @returns {Deferred} A deferred that will delete the given file
		 */
		deleteFile: function(deleteLocation, eventData) {
			//return _doServiceCall(this._getService(deleteLocation), "deleteFile", arguments); //$NON-NLS-1$
			return _doServiceCall(this._getService(deleteLocation), "deleteFile", arguments).then(function(result){ //$NON-NLS-0$
				if(this.isEventFrozen()) {
					if(!this._frozenEvent.deleted) {
						this._frozenEvent.deleted = [];
					}
					this._frozenEvent.deleted.push({deleteLocation: deleteLocation, eventData: eventData});
				} else {
					this.dispatchEvent({ type: "Changed", deleted: [{deleteLocation: deleteLocation, eventData: eventData}]}); //$NON-NLS-0$
				}
				return result;
			}.bind(this));
		},

		/**
		 * Moves a file or directory.
		 * @param {String} sourceLocation The location of the file or directory to move.
		 * @param {String} targetLocation The location of the target folder.
		 * @param {String} targetName The name of the destination file or directory in the case of a rename
		 * @public
		 * @returns {Deferred} A deferred that will move the given file to its new location
		 */
		moveFile: function(sourceLocation, targetLocation, targetName) {
			var sourceService = this._getService(sourceLocation);
			var targetService = this._getService(targetLocation);

			if (sourceService === targetService) {
				//return _doServiceCall(sourceService, "moveFile", arguments);
				return _doServiceCall(sourceService, "moveFile", arguments).then(function(result){ //$NON-NLS-0$
					if(this.isEventFrozen()) {
						if(!this._frozenEvent.moved) {
							this._frozenEvent.moved = [];
						}
						this._frozenEvent.moved.push({source: sourceLocation, target: targetLocation, result: result});
					} else {
						this.dispatchEvent({ type: "Changed", moved: [{source: sourceLocation, target: targetLocation, result: result}]}); //$NON-NLS-0$
					}
					return result;
				}.bind(this));
			}

			var isDirectory = sourceLocation[sourceLocation.length -1] === "/";
			var target = targetLocation;

			if (target[target.length -1] !== "/") {
				target += "/";
			}

			if (targetName) {
				target += encodeURIComponent(targetName);
			} else {
				var temp = sourceLocation;
				if (isDirectory) {
					temp = temp.substring(0, temp.length - 1);
				}
				target += temp.substring(temp.lastIndexOf("/")+1);
			}

			if (isDirectory && target[target.length -1] !== "/") {
				target += "/";
			}

			return _copy(sourceService, sourceLocation, targetService, target).then(function() {
				return _doServiceCall(sourceService, "deleteFile", [sourceLocation]); //$NON-NLS-1$
			});

		},

		/**
		 * Copies a file or directory.
		 * @param {String} sourceLocation The location of the file or directory to copy.
		 * @param {String} targetLocation The location of the target folder.
		 * @param {String} targetName The name of the destination file or directory in the case of a rename
		 * @public
		 * @returns {Deferred} A deferred that will copy the given file to its new location
		 */
		copyFile: function(sourceLocation, targetLocation, targetName) {
			var sourceService = this._getService(sourceLocation);
			var targetService = this._getService(targetLocation);

			if (sourceService === targetService) {
				//return _doServiceCall(sourceService, "copyFile", arguments);				 //$NON-NLS-1$
				return _doServiceCall(sourceService, "copyFile", arguments).then(function(result){ //$NON-NLS-0$
					if(this.isEventFrozen()) {
						if(!this._frozenEvent.copied) {
							this._frozenEvent.copied = [];
						}
						this._frozenEvent.copied.push({source: sourceLocation, target: targetLocation, result: result});
					} else {
						this.dispatchEvent({ type: "Changed", copied: [{source: sourceLocation, target: targetLocation, result: result}]}); //$NON-NLS-0$
					}
					return result;
				}.bind(this));
			}

			var isDirectory = sourceLocation[sourceLocation.length -1] === "/";
			var target = targetLocation;

			if (target[target.length -1] !== "/") {
				target += "/";
			}

			if (targetName) {
				target += encodeURIComponent(targetName);
			} else {
				var temp = sourceLocation;
				if (isDirectory) {
					temp = temp.substring(0, temp.length - 1);
				}
				target += temp.substring(temp.lastIndexOf("/")+1);
			}

			if (isDirectory && target[target.length -1] !== "/") {
				target += "/";
			}

			return _copy(sourceService, sourceLocation, targetService, target);
		},

		/**
		 * Returns the contents or metadata of the file at the given location.
		 *
		 * @param {String} readLocation The location of the file to get contents for
		 * @param {Boolean} [isMetadata] If defined and true, returns the file metadata,
		 *   otherwise file contents are returned
		 * @public
		 * @return {Deferred} A deferred that will be provided with the contents or metadata when available
		 */
		read: function(readLocation, isMetadata) {
			return _doServiceCall(this._getService(readLocation), "read", arguments); //$NON-NLS-1$
		},

		/**
		 * Returns the blob contents of the file at the given location.
		 *
		 * @param {String} readLocation The location of the file to get contents for
		 * @public
		 * @return {Deferred} A deferred that will be provided with the blob contents when available
		 */
		readBlob: function(readLocation) {
			return _doServiceCall(this._getService(readLocation), "readBlob", arguments); //$NON-NLS-1$
		},

		/**
		 * Writes the contents or metadata of the file at the given location.
		 *
		 * @param {String} writeLocation The location of the file to set contents for
		 * @param {String|Object} contents The content string, or metadata object to write
		 * @param {String|Object} args Additional arguments used during write operation (i.e. ETag)
		 * @public
		 * @return {Deferred} A deferred for chaining events after the write completes with new metadata object
		 */
		write: function(writeLocation, contents, args) {
			//return _doServiceCall(this._getService(writeLocation), "write", arguments); //$NON-NLS-1$
			return _doServiceCall(this._getService(writeLocation), "write", arguments).then(function(result){ //$NON-NLS-0$
				if(this.isEventFrozen()) {
					if(!this._frozenEvent.modified) {
						this._frozenEvent.modified = [];
					}
					this._frozenEvent.modified.push(writeLocation);
				} else {
					this.dispatchEvent({ type: "Changed", modified: [writeLocation]}); //$NON-NLS-0$
				}
				return result;
			}.bind(this));
		},

		/**
		 * Imports file and directory contents from another server
		 *
		 * @param {String} targetLocation The location of the folder to import into
		 * @param {Object} options An object specifying the import parameters
		 * @public
		 * @return {Deferred} A deferred for chaining events after the import completes
		 */
		remoteImport: function(targetLocation, options, parentLocation) {
			//return _doServiceCall(this._getService(targetLocation), "remoteImport", arguments); //$NON-NLS-1$
			return _doServiceCall(this._getService(targetLocation), "remoteImport", arguments).then(function(result){ //$NON-NLS-0$
				if(this.isEventFrozen()) {
					if(!this._frozenEvent.copied) {
						this._frozenEvent.copied = [];
					}
					this._frozenEvent.copied.push({target: parentLocation});
				} else {
					this.dispatchEvent({ type: "Changed", copied: [{target: parentLocation}]}); //$NON-NLS-0$
				}
				return result;
			}.bind(this));
		},

		/**
		 * Exports file and directory contents to another server
		 *
		 * @param {String} sourceLocation The location of the folder to export from
		 * @param {Object} options An object specifying the export parameters
		 * @public
		 * @return {Deferred} A deferred for chaining events after the export completes
		 */
		remoteExport: function(sourceLocation, options) {
			return _doServiceCall(this._getService(sourceLocation), "remoteExport", arguments); //$NON-NLS-1$
		},

		/**
		 * Find a string inside a file
		 *
		 * @param {String} sourceLocation The location of the folder to export from
		 * @param {String} findStr The string to search
		 * @public
		 * @return {Deferred} A deferred for chaining events after the export completes
		 */
		find: function(sourceLocation, findStr, option) {
			return _doServiceCall(this._getService(location), "find", arguments); //$NON-NLS-0$
		},

		/**
		 * Performs a search with the given search parameters.
		 * @param {Object} searchParams The JSON object that describes all the search parameters.
		 * @param {String} searchParams.resource Required. The location where search is performed. Required. Normally a sub folder of the file system. Empty string means the root of the file system.
		 * @param {String} searchParams.keyword The search keyword. Required but can be empty string.  If fileType is a specific type and the keyword is empty, then list up all the files of that type. If searchParams.regEx is true then the keyword has to be a valid regular expression.
		 * @param {String} searchParams.sort Required. Defines the order of the return results. Should be either "Path asc" or "Name asc". Extensions are possible but not currently supported.
		 * @param {boolean} searchParams.nameSearch Optional. If true, the search performs only file name search.
		 * @param {String} searchParams.fileType Optional. The file type. If specified, search will be performed under this file type. E.g. "*.*" means all file types. "html" means html files.
		 * @param {Boolean} searchParams.regEx Optional. The option of regular expression search.
		 * @param {integer} searchParams.start Optional. The zero based start number for the range of the returned hits. E.g if there are 1000 hits in total, then 5 means the 6th hit.
		 * @param {integer} searchParams.rows Optional. The number of hits of the range. E.g if there are 1000 hits in total and start=5 and rows=40, then the return range is 6th-45th.
		 * @param {String} searchParams.fileNamePatterns Optional. The file name patterns within which to search. If specified, search will be performed under files which match the provided patterns. Patterns should be comma-separated and may use "*" and "?" as wildcards.
		 * @param {[String]} searchParams.exclude Optional. An array of file / folder names to exclude from searching
		 * @public
		 */
		search: function(searchParams) {
			return _doServiceCall(this._getService(searchParams.resource), "search", arguments); //$NON-NLS-1$
		}
	};
	FileClient.prototype.constructor = FileClient;

	return {
		FileClient: FileClient
	};
});

/*******************************************************************************
 * @license
 * Copyright (c) 2012 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 * 
 ******************************************************************************/
/*eslint-env browser, amd*/
define('orion/search/nls/messages',{
	root:true
});

/*******************************************************************************
 * @license
 * Copyright (c) 2012, 2015 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 * 
 ******************************************************************************/
/*eslint-env amd */
define('orion/search/nls/root/messages',{
	"Find": "Find",
	"Find:": "Find:",
	"FindWhat": "Find what",
	"ReplaceWith:": "ReplaceWith:",
	"Replace With": "Replace with",
	"Show all": "Show all",
	"Wrap search": "Wrap search",
	"Incremental search": "Incremental search",
	"Whole Word": "Whole Word",
	"Regular expression": "Regular expression",
	"Replace Mode": "Replace Mode",
	"Find after replace": "Find after replace",
	"Options": "Options",
	"Find next match": "Find next match",
	"Find previous match": "Find previous match",
	"Next": "Next",
	"Previous": "Previous",
	"Replace": "Replace",
	"Replace...": "Preview",
	"Replace All": "Replace All",
	"Search ${0}": "Search ${0}",
	"TypeKeyOrWildCard": "Type a keyword or wild card to search in ",
	"Search failed.": "Search failed.",
	"NoMatchFound": "No matches found for ${0}",
	"Searching...": "Searching...",
	"ResourceChanged.": "Resource has been changed by others.",
	"Failed to write file.": "Failed to write file.",
	"Results": "Results",
	"FilesAofBmatchingC": "Files ${0} of ${1} matching \"${2}\"",
	"ReplaceAwithBforCofD": "Replace \"${0}\" with \"${1}\" for files ${2} of ${3}",
	"Location": "Location",
	"Click to compare": "Click to compare",
	"Search again in this folder with \"${0}\"": "Search again in this folder with \"${0}\"",
	"Files replaced": "Files replaced",
	"Status": "Status",
	"matchesReplacedMsg": "${0} out of ${1}  matches replaced.",
	"Replace all matches with...": "Replace all matches with...",
	"Apply Changes": "Replace Selected",
	"Replace all selected matches": "Replace all selected matches",
	"Hide Compare": "Hide Compare",
	"Hide compare view of changes": "Hide compare view of changes",
	"Show Compare": "Show Compare",
	"Show compare view of changes": "Show compare view of changes",
	"Show All": "Show All",
	"Selected Lines": "Selected Lines",
	"Show all the results in one page": "Show all the results in one page",
	"< Previous Page": "< Previous Page",
	"Show previous page of search result": "Show previous page of search result",
	"Next Page >": "Next Page >",
	"Show next page of search result": "Show next page of search result",
	"Next result": "Next result",
	"Previous result": "Previous result",
	"Expand all results": "Expand all results",
	"Collapse all results": "Collapse all results",
	"Writing files...": "Writing files...",
	"Preparing preview...": "Preparing preview...",
	"Replaced File (${0})": "Replaced File (${0})",
	"Original File (${0})": "Original File (${0})",
	"Sort by Name": "Sort by Name",
	"Compare changes": "Compare changes",
	"Search Results": "Search Results",
	"Replace All Matches": "Replace All Matches",
	"No matches": "No matches",
	"Rename": "Rename",
	"Search": "Search",
	"All types": "All types",
	"File type": "File type",
	"All ${0} files": "All ${0} files",
	"${0} is already saved": "${0} is already saved",
	"Type a search term": "Type a search term",
	"Type a replace term": "Type a replace term",
	"Case sensitive": "Case sensitive",
	"File name": "File name",
	"Path name": "Path name",
	"Save": "Save",
	"Type filter text": "Type filter text",
	"Scope Search": "Scoped Search",
	"Open in Search page for this directory": "Open the Search page for this folder.",
	"${0}. Try your search again.": "${0}. Try your search again.",
	"DeleteSearchTrmMsg": "Click or use delete key to delete the search term",
	"${0} matches": "${0} matches",
	"regexOff" : "Regular expressions are off",
	"regexOn" : "Regular expressions are on",
	"regexOptionOff" : "Regular expressions are off. Click here or use the options to turn them on for replacement",
	"regexOptionOn" : "Regular expressions are on. Click here or use the options to turn them off",
	"Scope": "Find in:",
	"Show previous search terms": "Show previous search terms",
	"Show previous replace terms": "Show previous replace terms",
	"Preview Replace": "Preview Replace",
	"File name patterns (comma-separated)": "File name patterns (comma-separated):",
	"(* = any string, ? = any character)": "(* = any string, ? = any character)",
	"(${0})": "(${0} matches)",
	"singleMatch": "(1 match)",
	"Choose a Folder": "Choose a Folder",
	"Remove from search results": "Remove from search results",
	"^": "^ ",
	"Edit Search": "Edit Search",
	"Preview: " : "Preview: ",
	"fullPath": "Show Full Path",
	"switchFullPath": "Show/hide full path",
	"refsInProject": "${0} references to \'${1}\' in ${2}",
	"refsInWorkspace": "${0} references to \'${1}\' in the workspace",
	"viewByTypes" : "By types",
	"viewByFiles" : "By files",
	"viewByTypesTooltip": "View references grouped by categories",
	"viewByFilesTooltip": "View references grouped by files",
	"hidePerfectMatch": "Hide perfect matches",
	"showPerfectMatch": "Show perfect matches",
	"hideNonMatch": "Hide non-matches",
	"showNonMatch": "Show non-matches",
	"hidePossibleMatch": "Hide possible matches",
	"showPossibleMatch": "Show possible matches",
	"perfectMatch": "Perfect match",
	"notAMatch": "Not a match",
	"couldBeMatch": "Could be a match",
	"Scope All":"All Folders",
	"Scope Project":"Root Folder",
	"Scope Selected":"Current Folder",
	"Scope Other":"Other",
	"Search Label":"Search:",
	"Resource": "Resource",
	"Line": "Line",
	"Details": "Details",
	"Exclude Files":"Files to exclude (comma-separated):",
	"The following files are excluded from general setting":"The following files are excluded from general setting:",
	"Current Folder Tooltip": "Search in the closest parent folder of the target.",
	"Root Folder Tooltip": "Search in the root folder of the target.",
	"All Folders Tooltip": "Search in all folders of current workspace",
	"Other Folder Tooltip": "Search in a specified folder",
	"File Patterns Box Tooltip": "Search results are limited to the following file patterns",
	"Exclude Files Box Tooltip": "Search skips the following files, or all files of a folder of the name.",
	"To Replace Mode Tooltip": "Switch To Replace Mode",
	"To Search Mode Tooltip": "Switch To Search Mode"
});


/*******************************************************************************
 * @license
 * Copyright (c) 2011, 2013 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
/*eslint-env browser, amd*/
/**
 * @name orion.regex
 * @class Utilities for dealing with regular expressions.
 * @description Utilities for dealing with regular expressions.
 */
define("orion/regex", [], function() { //$NON-NLS-0$
	/**
	 * @memberOf orion.regex
	 * @function
	 * @static
	 * @description Escapes regex special characters in the input string.
	 * @param {String} str The string to escape.
	 * @returns {String} A copy of <code>str</code> with regex special characters escaped.
	 */
	function escape(str) {
		return str.replace(/([\\$\^*\/+?\.\(\)|{}\[\]])/g, "\\$&"); //$NON-NLS-0$
		//return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
	}

	/**
	 * @memberOf orion.regex
	 * @function
	 * @static
	 * @description Parses a pattern and flags out of a regex literal string.
	 * @param {String} str The string to parse. Should look something like <code>"/ab+c/"</code> or <code>"/ab+c/i"</code>.
	 * @returns {Object} If <code>str</code> looks like a regex literal, returns an object with properties
	 * <code><dl>
	 * <dt>pattern</dt><dd>{String}</dd>
	 * <dt>flags</dt><dd>{String}</dd>
	 * </dl></code> otherwise returns <code>null</code>.
	 */
	function parse(str) {
		var regexp = /^\s*\/(.+)\/([gim]{0,3})\s*$/.exec(str);
		if (regexp) {
			return {
				pattern : regexp[1],
				flags : regexp[2]
			};
		}
		return null;
	}

	return {
		escape: escape,
		parse: parse
	};
});

/*******************************************************************************
 * Copyright (c) 2010, 2016 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 * 
 * Contributors: 
 *		Felipe Heidrich (IBM Corporation) - initial API and implementation
 *		Silenio Quarti (IBM Corporation) - initial API and implementation
 ******************************************************************************/
 
/*eslint-env browser, amd*/
define("orion/editor/eventTarget", [], function() {
	/** 
	 * Constructs a new EventTarget object.
	 * 
	 * @class 
	 * @name orion.editor.EventTarget
	 */
	function EventTarget() {
	}
	/**
	 * Adds in the event target interface into the specified object.
	 *
	 * @param {Object} object The object to add in the event target interface.
	 */
	EventTarget.addMixin = function(object) {
		var proto = EventTarget.prototype;
		for (var p in proto) {
			if (proto.hasOwnProperty(p)) {
				object[p] = proto[p];
			}
		}
	};
	EventTarget.prototype = /** @lends orion.editor.EventTarget.prototype */ {
		/**
		 * Adds an event listener to this event target.
		 * 
		 * @param {String} type The event type.
		 * @param {Function|EventListener} listener The function or the EventListener that will be executed when the event happens. 
		 * @param {Boolean} [useCapture=false] <code>true</code> if the listener should be trigged in the capture phase.
		 * 
		 * @see orion.editor.EventTarget#removeEventListener
		 */
		addEventListener: function(type, listener, useCapture) {
			if (!this._eventTypes) { this._eventTypes = {}; }
			var state = this._eventTypes[type];
			if (!state) {
				state = this._eventTypes[type] = {level: 0, listeners: []};
			}
			var listeners = state.listeners;
			listeners.push({listener: listener, useCapture: useCapture});
		},
		/**
		 * Dispatches the given event to the listeners added to this event target.
		 * @param {Event} evt The event to dispatch.
		 */
		dispatchEvent: function(evt) {
			var type = evt.type;
			this._dispatchEvent("pre" + type, evt); //$NON-NLS-0$
			this._dispatchEvent(type, evt);
			this._dispatchEvent("post" + type, evt); //$NON-NLS-0$
		},
		/**
		 * Dispatches the given event to the listeners added to this event target.
		 * @private 
		 * @param {String} type The name of the event type to send
		 * @param {Event} evt The event to dispatch.
		 */
		_dispatchEvent: function(type, evt) {
			var state = this._eventTypes ? this._eventTypes[type] : null;
			if (state) {
				var listeners = state.listeners;
				try {
					state.level++;
					if (listeners) {
						for (var i=0, len=listeners.length; i < len; i++) {
							if (listeners[i]) {
								var l = listeners[i].listener;
								if (typeof l === "function") {
									l.call(this, evt);
								} else if (l.handleEvent && typeof l.handleEvent === "function") {
									l.handleEvent(evt);
								}
							}
						}
					}
				} finally {
					state.level--;
					if (state.compact && state.level === 0) {
						for (var j=listeners.length - 1; j >= 0; j--) {
							if (!listeners[j]) {
								listeners.splice(j, 1);
							}
						}
						if (listeners.length === 0) {
							delete this._eventTypes[type];
						}
						state.compact = false;
					}
				}
			}
		},
		/**
		 * Returns whether there is a listener for the specified event type.
		 * 
		 * @param {String} type The event type
		 * 
		 * @see orion.editor.EventTarget#addEventListener
		 * @see orion.editor.EventTarget#removeEventListener
		 */
		isListening: function(type) {
			if (!this._eventTypes) { return false; }
			return this._eventTypes[type] !== undefined;
		},		
		/**
		 * Removes an event listener from the event target.
		 * <p>
		 * All the parameters must be the same ones used to add the listener.
		 * </p>
		 * 
		 * @param {String} type The event type
		 * @param {Function|EventListener} listener The function or the EventListener that will be executed when the event happens. 
		 * @param {Boolean} [useCapture=false] <code>true</code> if the listener should be trigged in the capture phase.
		 * 
		 * @see orion.editor.EventTarget#addEventListener
		 */
		removeEventListener: function(type, listener, useCapture){
			if (!this._eventTypes) { return; }
			var state = this._eventTypes[type];
			if (state) {
				var listeners = state.listeners;
				for (var i=0, len=listeners.length; i < len; i++) {
					var l = listeners[i];
					if (l && l.listener === listener && l.useCapture === useCapture) {
						if (state.level !== 0) {
							listeners[i] = null;
							state.compact = true;
						} else {
							listeners.splice(i, 1);
						}
						break;
					}
				}
				if (listeners.length === 0) {
					delete this._eventTypes[type];
				}
			}
		}
	};
	return {EventTarget: EventTarget};
});

/*******************************************************************************
 * @license
 * Copyright (c) 2010, 2016 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 * 
 * Contributors: 
 *		Felipe Heidrich (IBM Corporation) - initial API and implementation
 *		Silenio Quarti (IBM Corporation) - initial API and implementation
 ******************************************************************************/
 
/*eslint-env browser, amd*/
define("orion/editor/textModel", ['orion/editor/eventTarget', 'orion/regex', 'orion/util'], function(mEventTarget, mRegex, util) {

	/**
	 * Constructs a new TextModel with the given text and default line delimiter.
	 *
	 * @param {String} [text=""] the text that the model will store
	 * @param {String} [lineDelimiter=platform delimiter] the line delimiter used when inserting new lines to the model.
	 *
	 * @name orion.editor.TextModel
	 * @class The TextModel is an interface that provides text for the view. Applications may
	 * implement the TextModel interface to provide a custom store for the view content. The
	 * view interacts with its text model in order to access and update the text that is being
	 * displayed and edited in the view. This is the default implementation.
	 * <p>
	 * <b>See:</b><br/>
	 * {@link orion.editor.TextView}<br/>
	 * {@link orion.editor.TextView#setModel}
	 * </p>
	 * @borrows orion.editor.EventTarget#addEventListener as #addEventListener
	 * @borrows orion.editor.EventTarget#removeEventListener as #removeEventListener
	 * @borrows orion.editor.EventTarget#dispatchEvent as #dispatchEvent
	 */
	function TextModel(text, lineDelimiter) {
		this._lastLineIndex = -1;
		this._text = [""];
		this._lineOffsets = [0];
		this.setText(text);
		this.setLineDelimiter(lineDelimiter);
	}

	/**
	 * @name setRange
	 * @description Sets the range attributes on the modelChang* events for VS code LSP compatibility
	 * @param {TextModel} textModel The backing text model
	 * @param {?} modelChangingEvent The event object to modify
	 * @since 17.0
	 */
	function setRange(textModel, modelChangingEvent) {
		var sl = textModel.getLineAtOffset(modelChangingEvent.start), 
			el = textModel.getLineAtOffset(modelChangingEvent.start + modelChangingEvent.removedCharCount);
		modelChangingEvent.range = {
			start: {
				line: sl,
				character: modelChangingEvent.start - textModel.getLineStart(sl)
			},
			end: {
				line: el,
				character: modelChangingEvent.start + modelChangingEvent.removedCharCount - textModel.getLineStart(el)
			}
		};	
	}
	
	TextModel.prototype = /** @lends orion.editor.TextModel.prototype */ {
		/**
		 * Destroys this text model.
		 */
		destroy: function() {
		},
		/**
		 * @class This object describes the options to use while finding occurrences of a string in a text model.
		 * @name orion.editor.FindOptions
		 *
		 * @property {String} string the search string to be found.
		 * @property {Boolean} [regex=false] whether or not the search string is a regular expression.
		 * @property {Boolean} [wrap=false] whether or not to wrap search.
		 * @property {Boolean} [wholeWord=false] whether or not to search only whole words.
		 * @property {Boolean} [caseInsensitive=false] whether or not search is case insensitive.
		 * @property {Boolean} [reverse=false] whether or not to search backwards.
		 * @property {Number} [start=0] The start offset to start searching
		 * @property {Number} [rangeStart] The range start offset of the search. Used to search in a given range.
		 * @property {Number} [rangeEnd] The range end offset of the search. Used to search in a given range.
		 */
		/**
		 * @class This object represents a find occurrences iterator.
		 * <p>
		 * <b>See:</b><br/>
		 * {@link orion.editor.TextModel#find}<br/>
		 * </p>		 
		 * @name orion.editor.FindIterator
		 * 
		 * @property {Function} hasNext Determines whether there are more occurrences in the iterator.
		 * @property {Function} next Returns the next matched range {start,end} in the iterator.
		 */	
		/**
		 * Finds occurrences of a string in the text model.
		 *
		 * @param {orion.editor.FindOptions} options the search options
		 * @return {orion.editor.FindIterator} the find occurrences iterator.
		 */
		find: function(options) {
			if (this._text.length > 1) {
				this._text = [this._text.join("")];
			}
			var string = options.string;
			var regex = options.regex;
			var pattern = string;
			var flags = "";
			var caseInsensitive = options.caseInsensitive;
			if (pattern) {
				if (regex) {
					var parsed = mRegex.parse(pattern);
					if (parsed) {
						pattern = parsed.pattern;
						flags = parsed.flags;
					}
				} else {
					pattern = string.replace(/([\\$\^*\/+?\.\(\)|{}\[\]])/g, "\\$&"); //$NON-NLS-0$
					/*
					* Bug in JS RegEx. In a Turkish locale, dotless i (u0131) capitalizes to I (u0049) and i (u0069) 
					* capitalizes to dot I (u0130). The JS RegEx does not match correctly the Turkish i's in case
					* insensitive mode. The fix is to detect the presence of Turkish i's in the search pattern and 
					* to modify the pattern to search for both upper and lower case.
					*/
					if (caseInsensitive) {
						pattern = pattern.replace(/[iI\u0130\u0131]/g, "[Ii\u0130\u0131]"); //$NON-NLS-0$
					}
				}
			}
			var current = null, skip;
			if (pattern) {
				var reverse = options.reverse;
				var wrap = options.wrap;
				var wholeWord = options.wholeWord;
				var start = options.start || 0;
				var rangeStart = options.rangeStart;
				var rangeEnd = options.rangeEnd;
				var isRange = rangeStart !== null && rangeStart !== undefined && rangeEnd !== null && rangeEnd !== undefined;
				if (flags.indexOf("g") === -1) { flags += "g"; } //$NON-NLS-1$ //$NON-NLS-2$
				if (flags.indexOf("m") === -1) { flags += "m"; } //$NON-NLS-1$ //$NON-NLS-2$
				if (caseInsensitive) {
					if (flags.indexOf("i") === -1) { flags += "i"; } //$NON-NLS-1$ //$NON-NLS-2$
				}
				if (wholeWord) {
					pattern = "\\b" + pattern + "\\b"; //$NON-NLS-1$ //$NON-NLS-2$
				}
				var text = this._text[0], result, lastIndex, offset = 0;
				if (isRange) {
					var s = rangeStart < rangeEnd ? rangeStart : rangeEnd;
					var e = rangeStart < rangeEnd ? rangeEnd : rangeStart;
					text = text.substring(s, e);
					offset = s;
				}
				var re = new RegExp(pattern, flags);
				if (reverse) {
					skip = function() {
						var match = null;
						re.lastIndex = 0;
						while (true) {
							lastIndex = re.lastIndex;
							result = re.exec(text);
							if (lastIndex === re.lastIndex) {
								return null;
							}
							if (result) {
								if (result.index + offset < start) {
									match = {start: result.index + offset, end: re.lastIndex + offset};
								} else {
									if (!wrap || match) {
										break;
									}
									start = text.length + offset;
									match = {start: result.index + offset, end: re.lastIndex + offset};
								}
							} else {
								break;
							}
						}
						if (match) { start = match.start; }
						return match;
					};
				} else {
					re.lastIndex = start - offset;
					skip = function() {
						while (true) {
							lastIndex = re.lastIndex;
							result = re.exec(text);
							if (lastIndex === re.lastIndex) {
								return null;
							}
							if (result) {
								return {start: result.index + offset, end: re.lastIndex + offset};
							}
							if (lastIndex !== 0) {
								if (wrap) {
									continue;
								}
							}
							break;
						}
						return null;
					};
				}
				current = skip();
			}
			return {
				/**
				 * @callback 
				 */
				next: function() {
					var result = current;
					if (result) { current = skip(); }
					return result;					
				},
				/**
				 * @callback 
				 */
				hasNext: function() {
					return current !== null;
				}
			};
		},
		/**
		 * Returns the number of characters in the model.
		 *
		 * @returns {Number} the number of characters in the model.
		 */
		getCharCount: function() {
			var count = 0;
			for (var i = 0; i<this._text.length; i++) {
				count += this._text[i].length;
			}
			return count;
		},
		/**
		 * Returns the text of the line at the given index.
		 * <p>
		 * The valid indices are 0 to line count exclusive.  Returns <code>null</code> 
		 * if the index is out of range. 
		 * </p>
		 *
		 * @param {Number} lineIndex the zero based index of the line.
		 * @param {Boolean} [includeDelimiter=false] whether or not to include the line delimiter. 
		 * @returns {String} the line text or <code>null</code> if out of range.
		 *
		 * @see orion.editor.TextModel#getLineAtOffset
		 */
		getLine: function(lineIndex, includeDelimiter) {
			var lineCount = this.getLineCount();
			if (!(0 <= lineIndex && lineIndex < lineCount)) {
				return null;
			}
			var start = this._lineOffsets[lineIndex];
			if (lineIndex + 1 < lineCount) {
				var text = this.getText(start, this._lineOffsets[lineIndex + 1]);
				if (includeDelimiter) {
					return text;
				}
				var end = text.length, c;
				while (((c = text.charCodeAt(end - 1)) === 10) || (c === 13)) {
					end--;
				}
				return text.substring(0, end);
			} else {
				return this.getText(start); 
			}
		},
		/**
		 * Returns the line index at the given character offset.
		 * <p>
		 * The valid offsets are 0 to char count inclusive. The line index for
		 * char count is <code>line count - 1</code>. Returns <code>-1</code> if
		 * the offset is out of range.
		 * </p>
		 *
		 * @param {Number} offset a character offset.
		 * @returns {Number} the zero based line index or <code>-1</code> if out of range.
		 */
		getLineAtOffset: function(offset) {
			var charCount = this.getCharCount();
			if (!(0 <= offset && offset <= charCount)) {
				return -1;
			}
			var lineCount = this.getLineCount();
			if (offset === charCount) {
				return lineCount - 1; 
			}
			var lineStart, lineEnd;
			var index = this._lastLineIndex;
			if (0 <= index && index < lineCount) {
				lineStart = this._lineOffsets[index];
				lineEnd = index + 1 < lineCount ? this._lineOffsets[index + 1] : charCount;
				if (lineStart <= offset && offset < lineEnd) {
					return index;
				}
			}
			var high = lineCount;
			var low = -1;
			while (high - low > 1) {
				index = Math.floor((high + low) / 2);
				lineStart = this._lineOffsets[index];
				lineEnd = index + 1 < lineCount ? this._lineOffsets[index + 1] : charCount;
				if (offset <= lineStart) {
					high = index;
				} else if (offset < lineEnd) {
					high = index;
					break;
				} else {
					low = index;
				}
			}
			this._lastLineIndex = high;
			return high;
		},
		/**
		 * Returns the number of lines in the model.
		 * <p>
		 * The model always has at least one line.
		 * </p>
		 *
		 * @returns {Number} the number of lines.
		 */
		getLineCount: function() {
			return this._lineOffsets.length;
		},
		/**
		 * Returns the line delimiter that is used by the view
		 * when inserting new lines. New lines entered using key strokes 
		 * and paste operations use this line delimiter.
		 *
		 * @return {String} the line delimiter that is used by the view when inserting new lines.
		 */
		getLineDelimiter: function() {
			return this._lineDelimiter;
		},
		/**
		 * Returns the end character offset for the given line. 
		 * <p>
		 * The end offset is not inclusive. This means that when the line delimiter is included, the 
		 * offset is either the start offset of the next line or char count. When the line delimiter is
		 * not included, the offset is the offset of the line delimiter.
		 * </p>
		 * <p>
		 * The valid indices are 0 to line count exclusive.  Returns <code>-1</code> 
		 * if the index is out of range. 
		 * </p>
		 *
		 * @param {Number} lineIndex the zero based index of the line.
		 * @param {Boolean} [includeDelimiter=false] whether or not to include the line delimiter. 
		 * @return {Number} the line end offset or <code>-1</code> if out of range.
		 *
		 * @see orion.editor.TextModel#getLineStart
		 */
		getLineEnd: function(lineIndex, includeDelimiter) {
			var lineCount = this.getLineCount();
			if (!(0 <= lineIndex && lineIndex < lineCount)) {
				return -1;
			}
			if (lineIndex + 1 < lineCount) {
				var end = this._lineOffsets[lineIndex + 1];
				if (includeDelimiter) {
					return end;
				}
				var text = this.getText(Math.max(this._lineOffsets[lineIndex], end - 2), end);
				var i = text.length, c;
				while (((c = text.charCodeAt(i - 1)) === 10) || (c === 13)) {
					i--;
				}
				return end - (text.length - i);
			} else {
				return this.getCharCount();
			}
		},
		/**
		 * Returns the start character offset for the given line.
		 * <p>
		 * The valid indices are 0 to line count exclusive.  Returns <code>-1</code> 
		 * if the index is out of range. 
		 * </p>
		 *
		 * @param {Number} lineIndex the zero based index of the line.
		 * @return {Number} the line start offset or <code>-1</code> if out of range.
		 *
		 * @see orion.editor.TextModel#getLineEnd
		 */
		getLineStart: function(lineIndex) {
			if (!(0 <= lineIndex && lineIndex < this.getLineCount())) {
				return -1;
			}
			return this._lineOffsets[lineIndex];
		},
		/**
		 * Returns the text for the given range.
		 * <p>
		 * The end offset is not inclusive. This means that character at the end offset
		 * is not included in the returned text.
		 * </p>
		 *
		 * @param {Number} [start=0] the zero based start offset of text range.
		 * @param {Number} [end=char count] the zero based end offset of text range.
		 *
		 * @see orion.editor.TextModel#setText
		 */
		getText: function(start, end) {
			if (start === undefined) { start = 0; }
			if (end === undefined) { end = this.getCharCount(); }
			if (start === end) { return ""; }
			var offset = 0, chunk = 0, length;
			while (chunk<this._text.length) {
				length = this._text[chunk].length; 
				if (start <= offset + length) { break; }
				offset += length;
				chunk++;
			}
			var firstOffset = offset;
			var firstChunk = chunk;
			while (chunk<this._text.length) {
				length = this._text[chunk].length; 
				if (end <= offset + length) { break; }
				offset += length;
				chunk++;
			}
			var lastOffset = offset;
			var lastChunk = chunk;

			// error check for invalid chunks of text
			if (firstChunk >= this._text.length || lastChunk >= this._text.length || firstChunk > lastChunk) {
				return "";
			}
			
			if (firstChunk === lastChunk) {
				return this._text[firstChunk].substring(start - firstOffset, end - lastOffset);
			}
			var beforeText = this._text[firstChunk].substring(start - firstOffset);
			var afterText = this._text[lastChunk].substring(0, end - lastOffset);
			return beforeText + this._text.slice(firstChunk+1, lastChunk).join("") + afterText; 
		},
		/**
		 * Notifies all listeners that the text is about to change.
		 * <p>
		 * This notification is intended to be used only by the view. Application clients should
		 * use {@link orion.editor.TextView#event:onModelChanging}.
		 * </p>
		 * <p>
		 * NOTE: This method is not meant to called directly by application code. It is called internally by the TextModel
		 * as part of the implementation of {@link #setText}. This method is included in the public API for documentation
		 * purposes and to allow integration with other toolkit frameworks.
		 * </p>
		 *
		 * @param {orion.editor.ModelChangingEvent} modelChangingEvent the changing event
		 */
		onChanging: function(modelChangingEvent) {
			setRange(this, modelChangingEvent);
			return this.dispatchEvent(modelChangingEvent);
		},
		/**
		 * Notifies all listeners that the text has changed.
		 * <p>
		 * This notification is intended to be used only by the view. Application clients should
		 * use {@link orion.editor.TextView#event:onModelChanged}.
		 * </p>
		 * <p>
		 * NOTE: This method is not meant to called directly by application code. It is called internally by the TextModel
		 * as part of the implementation of {@link #setText}. This method is included in the public API for documentation
		 * purposes and to allow integration with other toolkit frameworks.
		 * </p>
		 *
		 * @param {orion.editor.ModelChangedEvent} modelChangedEvent the changed event
		 */
		onChanged: function(modelChangedEvent) {
			setRange(this, modelChangedEvent);
			return this.dispatchEvent(modelChangedEvent);
		},
		/**
		 * Sets the line delimiter that is used by the view
		 * when new lines are inserted in the model due to key
		 * strokes and paste operations. The line delimiter of
		 * existing lines are unchanged unless the to <code>all</code>
		 * argument is <code>true</code>.
		 * <p>
		 * If lineDelimiter is "auto", the delimiter is computed to be
		 * the first delimiter found in the current text. If lineDelimiter
		 * is undefined or if there are no delimiters in the current text, the
		 * platform delimiter is used.
		 * </p>
		 *
		 * @param {String} lineDelimiter the line delimiter that is used by the view when inserting new lines.
		 * @param {Boolean} [all=false] whether or not the delimiter of existing lines are changed.
		 */
		setLineDelimiter: function(lineDelimiter, all) {
			if (lineDelimiter === "auto") {
				lineDelimiter = undefined;
				if (this.getLineCount() > 1) {
					lineDelimiter = this.getText(this.getLineEnd(0), this.getLineEnd(0, true));
				}
			}
			this._lineDelimiter = lineDelimiter ? lineDelimiter : util.platformDelimiter;
			if (all) {
				var lineCount = this.getLineCount();
				if (lineCount > 1) {
					var lines = new Array(lineCount);
					for (var i=0; i<lineCount; i++) {
						lines[i] = this.getLine(i);
					}
					this.setText(lines.join(this._lineDelimiter));
				}
			}
		},
		/**
		 * Replaces the text in the given range with the given text.
		 * <p>
		 * The end offset is not inclusive. This means that the character at the 
		 * end offset is not replaced.
		 * </p>
		 * <p>
		 * The text model must notify the listeners before and after the
		 * the text is changed by calling {@link #onChanging} and {@link #onChanged}
		 * respectively. 
		 * </p>
		 *
		 * @param {String} [text=""] the new text.
		 * @param {Number} [start=0] the zero based start offset of text range.
		 * @param {Number} [end=char count] the zero based end offset of text range.
		 *
		 * @see orion.editor.TextModel#getText
		 */
		setText: function(text, start, end) {
			if (text === undefined) { text = ""; }
			if (start === undefined) { start = 0; }
			if (end === undefined) { end = this.getCharCount(); }
			if (start === end && text === "") { return; }
			var startLine = this.getLineAtOffset(start);
			var endLine = this.getLineAtOffset(end);
			var eventStart = start;
			var removedCharCount = end - start;
			var removedLineCount = endLine - startLine;
			var addedCharCount = text.length;
			var addedLineCount = 0;
			var lineCount = this.getLineCount();
			
			var cr = 0, lf = 0, index = 0;
			var newLineOffsets = [];
			while (true) {
				if (cr !== -1 && cr <= index) { cr = text.indexOf("\r", index); } //$NON-NLS-0$
				if (lf !== -1 && lf <= index) { lf = text.indexOf("\n", index); } //$NON-NLS-0$
				if (lf === -1 && cr === -1) { break; }
				if (cr !== -1 && lf !== -1) {
					if (cr + 1 === lf) {
						index = lf + 1;
					} else {
						index = (cr < lf ? cr : lf) + 1;
					}
				} else if (cr !== -1) {
					index = cr + 1;
				} else {
					index = lf + 1;
				}
				newLineOffsets.push(start + index);
				addedLineCount++;
			}
		
			var modelChangingEvent = {
				type: "Changing", //$NON-NLS-0$
				text: text,
				start: eventStart,
				removedCharCount: removedCharCount,
				addedCharCount: addedCharCount,
				removedLineCount: removedLineCount,
				addedLineCount: addedLineCount
			};
			this.onChanging(modelChangingEvent);
			
			var changedText = text;

			//TODO this should be done the loops below to avoid getText()
			if (newLineOffsets.length === 0) {
				var startLineOffset = this.getLineStart(startLine), endLineOffset;
				if (endLine + 1 < lineCount) {
					endLineOffset = this.getLineStart(endLine + 1);
				} else {
					endLineOffset = this.getCharCount();
				}
				if (start !== startLineOffset) {
					text = this.getText(startLineOffset, start) + text;
					start = startLineOffset;
				}
				if (end !== endLineOffset) {
					text = text + this.getText(end, endLineOffset);
					end = endLineOffset;
				}
			}
			
			var changeCount = addedCharCount - removedCharCount;
			for (var j = startLine + removedLineCount + 1; j < lineCount; j++) {
				this._lineOffsets[j] += changeCount;
			}
			
			/*
			* Feature in Chrome.  Chrome exceeds the maximum call stack when calling splice
			* around 62k arguments. The limit seems to be higher on IE (250K) and Firefox (450k).
			* The fix is to break the splice in junks of 50k.
			*/
			var SPLICE_LIMIT = 50000;
			var limit = SPLICE_LIMIT, args;
			if (newLineOffsets.length < limit) {
				args = [startLine + 1, removedLineCount].concat(newLineOffsets);
				Array.prototype.splice.apply(this._lineOffsets, args);
			} else {
				index = startLine + 1;
				this._lineOffsets.splice(index, removedLineCount);
				for (var k = 0; k < newLineOffsets.length; k += limit) {
					args = [index, 0].concat(newLineOffsets.slice(k, Math.min(newLineOffsets.length, k + limit)));
					Array.prototype.splice.apply(this._lineOffsets, args);
					index += limit;
				}
			}
			
			var offset = 0, chunk = 0, length;
			while (chunk<this._text.length) {
				length = this._text[chunk].length; 
				if (start <= offset + length) { break; }
				offset += length;
				chunk++;
			}
			var firstOffset = offset;
			var firstChunk = chunk;
			while (chunk<this._text.length) {
				length = this._text[chunk].length; 
				if (end <= offset + length) { break; }
				offset += length;
				chunk++;
			}
			var lastOffset = offset;
			var lastChunk = chunk;
			var firstText = this._text[firstChunk];
			var lastText = this._text[lastChunk];
			var beforeText = firstText.substring(0, start - firstOffset);
			var afterText = lastText.substring(end - lastOffset);
			var params = [firstChunk, lastChunk - firstChunk + 1];
			if (beforeText) { params.push(beforeText); }
			if (text) { params.push(text); }
			if (afterText) { params.push(afterText); }
			Array.prototype.splice.apply(this._text, params);
			if (this._text.length === 0) { this._text = [""]; }
			
			var modelChangedEvent = {
				type: "Changed", //$NON-NLS-0$
				start: eventStart,
				text: changedText,
				removedCharCount: removedCharCount,
				addedCharCount: addedCharCount,
				removedLineCount: removedLineCount,
				addedLineCount: addedLineCount
			};
			this.onChanged(modelChangedEvent);
		}
	};
	mEventTarget.EventTarget.addMixin(TextModel.prototype);
	
	return {TextModel: TextModel};
});

/*******************************************************************************
 * @license
 * Copyright (c) 2011, 2012 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
/*eslint-env browser, amd*/
define('orion/URITemplate',[],function(){
	
	var OPERATOR = {
		NUL: {first:"", sep:",", named: false, ifemp: "", allow: "U"}, //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
		"+": {first:"", sep:",", named: false, ifemp: "", allow: "U+R"}, //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
		".": {first:".", sep:",", named: false, ifemp: "", allow: "U"}, //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
		"/": {first:"/", sep:"/", named: false, ifemp: "", allow: "U"}, //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
		";": {first:";", sep:";", named: true, ifemp: "", allow: "U"}, //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
		"?": {first:"?", sep:"&", named: true, ifemp: "=", allow: "U"}, //$NON-NLS-4$ //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
		"&": {first:"&", sep:"&", named: true, ifemp: "=", allow: "U"}, //$NON-NLS-4$ //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
		"#": {first:"#", sep:",", named: false, ifemp: "", allow: "U+R"}, //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
		",": {first:"", sep:",", named: false, ifemp: "", allow: "U+R-,"} //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
	};

	var VARSPEC_REGEXP = /^((?:(?:[a-zA-Z0-9_])|(?:%[0-9A-F][0-9A-F]))(?:(?:[a-zA-Z0-9_.])|(?:%[0-9A-F][0-9A-F]))*)(?:(\*)|:([0-9]+))?$/;
	var PCT_ENCODED_G = /%25[0-9A-F][0-9A-F]/g;

	function Literal(text) {
		this._text = text;
	}

	Literal.prototype = {
		expand: function(vars) {
			return encodeURI(this._text);
		}
	};
	
	function decodePercent(str) {
		return str.replace("%25", "%");
	}
	
	function encodeString(value, encoding) {
		if (encoding === "U") { //$NON-NLS-0$
			return encodeURIComponent(value).replace(/[!'()*]/g, function(str) {
				return '%' + str.charCodeAt(0).toString(16).toUpperCase(); //$NON-NLS-0$
			});
		}
		if (encoding === "U+R") { //$NON-NLS-0$
			return encodeURI(value).replace(/%5B/g, '[').replace(/%5D/g, ']').replace(PCT_ENCODED_G, decodePercent); //$NON-NLS-1$ //$NON-NLS-0$
		}
		if (encoding === "U+R-,") { //$NON-NLS-0$
			return encodeURI(value).replace(/%5B/g, '[').replace(/%5D/g, ']').replace(/,/g, '%2C'); //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
		}
		throw new Error("Unknown allowed character set: " + encoding);
	}
	
	function encodeArray(value, encoding, separator) {
		var result = [];
		for (var i=0; i < value.length; i++) {
			if (typeof(value[i]) !== "undefined") { //$NON-NLS-0$
				result.push(encodeString(value[i], encoding));
			}
		}
		return result.join(separator);
	}
	
	function encodeObject(value, encoding, nameValueSeparator, pairSeparator ) {
		var keys = Object.keys(value);
		var result = [];
		for (var i=0; i < keys.length; i++) {
			if (typeof(value[keys[i]]) !== "undefined") { //$NON-NLS-0$
				result.push(encodeString(keys[i], encoding) + nameValueSeparator + encodeString(value[keys[i]], encoding));
			}
		}
		return result.join(pairSeparator);
	}
	
	function parseVarSpecs(text) {
		var result = [];
		var rawSpecs = text.split(","); //$NON-NLS-0$
		for (var i=0; i < rawSpecs.length; i++) {
			var match = rawSpecs[i].match(VARSPEC_REGEXP);
			if (match === null) {
				throw new Error("Bad VarSpec: " + text); //$NON-NLS-0$
			}
			result.push({
				name: match[1], 
				explode: !!match[2], 
				prefix: match[3] ? parseInt(match[3], 10) : -1
			}); 
		}
		return result;
	}
	
	function Expression(text) {
		if (text.length === 0) {
			throw new Error("Invalid Expression: 0 length expression"); //$NON-NLS-0$
		}
		
		this._operator = OPERATOR[text[0]];
		if (this._operator) {
			text = text.substring(1);
		} else {
			this._operator = OPERATOR.NUL;
		}
		
		this._varSpecList = parseVarSpecs(text);
	}
	
	Expression.prototype = {
		expand: function(params) {
			var result = [];
			for (var i=0; i < this._varSpecList.length; i++) {
				var varSpec = this._varSpecList[i];
				var name = varSpec.name;
				var value = params[name];
				var valueType = typeof(value);
				if (valueType !== "undefined" && value !== null) { //$NON-NLS-0$
					var resultText = result.length === 0 ? this._operator.first: this._operator.sep;			
					if (valueType === "string") { //$NON-NLS-0$
						if (this._operator.named) {
							resultText += encodeString(name, "U+R"); //$NON-NLS-0$
							resultText += (value.length === 0) ? this._operator.ifemp : "="; //$NON-NLS-0$
						}
						if (varSpec.prefix !== -1 && varSpec.prefix < value.length) {
							value = value.substring(0, varSpec.prefix);
						}
						
						resultText += encodeString(value, this._operator.allow);
					} else if (Array.isArray(value)) {
						if (value.length === 0) {
							continue; // treated as undefined and skipped
						}
						if (!varSpec.explode) {
							var encodedArray = encodeArray(value, this._operator.allow, ","); //$NON-NLS-0$
							if (this._operator.named) {
								resultText += encodeString(name, "U+R"); //$NON-NLS-0$
								resultText += (encodedArray.length === 0) ? this._operator.ifemp : "="; //$NON-NLS-0$
							}
							resultText += encodedArray;
						} else {
							resultText += encodeArray(value, this._operator.allow, this._operator.sep);
						}				
					} else if (valueType === "object") { //$NON-NLS-0$
						if (Object.keys(value).length === 0) {
							continue; // treated as undefined and skipped
						}
						if (!varSpec.explode) {
							var encodedObject = encodeObject(value, this._operator.allow, ",", ","); //$NON-NLS-1$ //$NON-NLS-0$
							if (this._operator.named) {
								resultText += encodeString(name, "U+R"); //$NON-NLS-0$
								resultText += (encodedObject.length === 0) ? this._operator.ifemp : "="; //$NON-NLS-0$
							}
							resultText += encodedObject; //$NON-NLS-0$
						} else {
							resultText += encodeObject(value, this._operator.allow, "=", this._operator.sep); //$NON-NLS-0$
						}
					} else {
						throw new Error("bad param type: " + name + " : " + valueType); //$NON-NLS-1$ //$NON-NLS-0$
					}
					result.push(resultText);
				}
			}
			return result.join("");
		}
	};

	function parseTemplate(text) {
		var result = [];
		var current = 0;	
		var curlyStartIndex = text.indexOf("{", current); //$NON-NLS-0$
		while (curlyStartIndex !== -1) {
			result.push(new Literal(text.substring(current, curlyStartIndex)));
			var curlyEndIndex = text.indexOf("}", curlyStartIndex + 1); //$NON-NLS-0$
			if (curlyEndIndex === -1) {
				throw new Error("Invalid template: " + text); //$NON-NLS-0$
			}
			result.push(new Expression(text.substring(curlyStartIndex + 1, curlyEndIndex)));
			current = curlyEndIndex + 1;
			curlyStartIndex = text.indexOf("{", current);			 //$NON-NLS-0$
		}
		result.push(new Literal(text.substring(current)));
		return result;
	}

	/**
	 * @name orion.URITemplate
	 * @class A URITemplate describes a range of Uniform Resource Identifiers through variable expansion, and allows for particular URIs to 
	 * be generated by expanding variables to actual values.</p>
	 * <p>Because the syntax and encoding rules of URIs can be complex, URITemplates are recommended over manual construction of URIs through 
	 * string concatenation or other means.</p>
	 * <p>A URITemplate is created by invoking the constructor, passing a <em>template string</em>:</p>
	 * <p><code>new URITemplate(template)</code></p>
	 * <p>The <dfn>template string</dfn> is an expression following a well-defined syntax (see <a href="http://tools.ietf.org/html/rfc6570#section-1.2">here</a>
	 * for an introduction). Most notably, the template may include variables.</p>
	 * <p>Once created, a URITemplate's {@link #expand} method can be invoked to generate a URI. Arguments to {@link #expand} give the values to be 
	 * substituted for the template variables.</p>
	 * @description Creates a new URITemplate.
	 * @param {String} template The template string. Refer to <a href="http://tools.ietf.org/html/rfc6570#section-2">RFC 6570</a> for details
	 * of the template syntax.
	 */
	function URITemplate(template) {
		this._templateComponents = parseTemplate(template);
	}
	
	URITemplate.prototype = /** @lends orion.URITemplate.prototype */ {
		/**
		 * Expands this URITemplate to a URI.
		 * @param {Object} params The parameters to use for expansion. This object is a map of keys (variable names) to values (the variable's
		 * value in the <a href="http://tools.ietf.org/html/rfc6570#section-3.2.1">expansion algorithm</a>).
		 * @returns {String} The resulting URI.
		 */
		expand: function(params) {
			var result = [];
			for (var i = 0; i < this._templateComponents.length; i++) {
				result.push(this._templateComponents[i].expand(params));
			}
			return result.join("");
		}
	};

	return URITemplate;
});
/*******************************************************************************
 * @license
 * Copyright (c) 2011, 2012 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
/*eslint-env browser, amd*/
define('orion/searchUtils',['i18n!orion/nls/messages', 'orion/regex', 'orion/editor/textModel', 'orion/URITemplate'], function(messages, mRegex, mTextModel, URITemplate) {

/**
 * @name orion.searchUtils.SearchParams
 * @class
 * @property {String} fileType
 * @property {String} keyword
 * @property {Boolean} regEx
 * @property {Boolean} nameSearch
 * @property {Boolean} caseSensitive
 */

/**
 * @namespace Search utility functions.
 * @name orion.searchUtils
 */
var searchUtils = {};

searchUtils.ALL_FILE_TYPE = "*.*"; //$NON-NLS-0$

function _generateSearchHelperRegEx(inFileQuery, searchParams, fromStart){
	var prefix = "";
	if(fromStart){
		prefix = "^"; //$NON-NLS-0$
	}
	var searchStr = searchParams.wholeWord ? "\\b" + inFileQuery.searchStr + "\\b" : inFileQuery.searchStr;
	var regexp = mRegex.parse("/" + prefix + searchStr + "/"); //$NON-NLS-1$ //$NON-NLS-0$
	if (regexp) {
		var pattern = regexp.pattern;
		var flags = regexp.flags;
		if(flags.indexOf("i") === -1 && !searchParams.caseSensitive){ //$NON-NLS-0$ 
			//If the regEx flag does not include 'i' then we have to add it by searchParams.caseSensitive
			flags = flags + "i";//$NON-NLS-0$
		}
		inFileQuery.regExp = {pattern: pattern, flags: flags};
		inFileQuery.wildCard = true;
	}
}

searchUtils.getSearchParams = function(searcher, searchStr, advOptions, searchScopeOption){
	if (searcher) {
		var newSearchStr = searchStr, commitSearch = true;
		if(newSearchStr === "*"){ //$NON-NLS-0$
			newSearchStr = "";
		}
		if(newSearchStr === ""){
			commitSearch = advOptions && advOptions.type !== searchUtils.ALL_FILE_TYPE;
		}
		if (commitSearch) {
			var searchParams = searcher.createSearchParams(newSearchStr, false, false, advOptions, searchScopeOption);
			return searchParams;
		}
	} else {
		window.alert(messages["NoSearchAvailableErr"]);
	}
	
	return null;
};

/**
 * Generate a helper query object used for search result renderer.
 * @param {orion.searchUtils.SearchParams} searchParams The search parameters.
 * @param {Boolean} fromStart True if doing file name search, otherwise false.
 * @returns {Object} An object having the properties:<ul>
 * <li><code>{@link orion.searchUtils.SearchParams}</code> <code>params</code> The search parameters.</li>
 * <li><code>{@link Object}</code> <code>inFileQuery</code> The query object for in file search.</li>
 * <li><code>{@link String}</code> <code>displayedSearchTerm</code> The search term display string.</li>
 * </ul>
 * @name orion.searchUtils.generateSearchHelper
 * @function
 */
searchUtils.generateSearchHelper = function(searchParams, fromStart) {
	var searchStr = searchParams.keyword;
	var displayedSearchTerm = searchStr;
	var inFileQuery = {};
	if(searchParams.fileType && searchParams.fileType !== searchUtils.ALL_FILE_TYPE && searchStr === ""){
		displayedSearchTerm = "*." + searchParams.fileType; //$NON-NLS-0$
	}
	if(!searchParams.regEx){
		var hasStar = (searchStr.indexOf("*") > -1); //$NON-NLS-0$
		var hasQMark = (searchStr.indexOf("?") > -1); //$NON-NLS-0$
		if(hasStar){
			searchStr = searchStr.split("*").join(".*"); //$NON-NLS-1$ //$NON-NLS-0$
		}
		if(hasQMark){
			searchStr = searchStr.split("?").join("."); //$NON-NLS-1$ //$NON-NLS-0$
		}
		if(searchParams.wholeWord){
			//escape all meta characters in string literal search except for * and .(when * or ? present)
			searchStr = hasStar || hasQMark ? searchStr.replace(/[-[\]{}()+,\\^$|#\s]/g, "\\$&") : searchStr.replace(/[-[\]{}()+.,\\^$|#\s]/g, "\\$&") ;
		}
		if(!hasStar && !hasQMark && !searchParams.nameSearch && !searchParams.wholeWord){
			inFileQuery.searchStr = searchParams.caseSensitive ? searchStr.split("\\").join("") : searchStr.split("\\").join("").toLowerCase(); //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
			inFileQuery.wildCard = false;
		} else {
			inFileQuery.searchStr = searchParams.caseSensitive ? searchStr : searchStr.toLowerCase();
			_generateSearchHelperRegEx(inFileQuery, searchParams, fromStart);
			inFileQuery.wildCard = true;
		}
	} else {
		inFileQuery.searchStr =searchStr;
		_generateSearchHelperRegEx(inFileQuery, searchParams, fromStart);
	}
	inFileQuery.searchStrLength = inFileQuery.searchStr.length;
	return {params: searchParams, inFileQuery: inFileQuery, displayedSearchTerm: displayedSearchTerm};
};

searchUtils.convertSearchParams = function(searchParams) {
	if(searchParams.rows !== undefined){
		searchParams.rows = parseInt(searchParams.rows, 10);
	}
	if(searchParams.start !== undefined){
		searchParams.start = parseInt(searchParams.start, 10);
	}
	if(typeof searchParams.regEx === "string"){ //$NON-NLS-0$
		searchParams.regEx = (searchParams.regEx.toLowerCase() === "true"); //$NON-NLS-0$
	}
	if(typeof searchParams.caseSensitive === "string"){ //$NON-NLS-0$
		searchParams.caseSensitive = (searchParams.caseSensitive.toLowerCase() === "true"); //$NON-NLS-0$
	}
	if(typeof searchParams.nameSearch === "string"){ //$NON-NLS-0$
		searchParams.nameSearch = (searchParams.nameSearch.toLowerCase() === "true"); //$NON-NLS-0$
	}
	if(searchParams.fileNamePatterns !== undefined){
		searchParams.fileNamePatterns = searchUtils.getFileNamePatternsArray(searchParams.fileNamePatterns);
	}
};

searchUtils.getFileNamePatternsArray = function(patterns) {
	var fileNamePatternArray = undefined;
	
	if (patterns) {
		var fileNamePatterns = patterns.trim();
		
		fileNamePatterns = fileNamePatterns.replace(/^(\s*,\s*)+/g, ""); //get rid of leading commas
		
		fileNamePatterns = fileNamePatterns.replace(/([^\\]),(\s*,\s*)*/g, "$1/"); //replace all unescaped commas with slashes (since slashes aren't legal in file names)
		
		fileNamePatterns = fileNamePatterns.replace(/(\s*\/\s*)/g, "/"); //get rid of spaces before and after delimiter
		fileNamePatterns = fileNamePatterns.replace(/\/\/+/g, "/"); //get rid of empty patterns
		fileNamePatterns = fileNamePatterns.replace(/\/+$/g, ""); //get rid of trailing delimiters
		
		fileNamePatternArray = fileNamePatterns.split("/");
	}
	
	return fileNamePatternArray;
};

searchUtils.copySearchParams = function(searchParams, copyReplace) {
	var result = {};
	for (var prop in searchParams) {
		if(searchParams[prop] !== undefined && searchParams[prop] !== null){
			if(!copyReplace && prop === "replace") { //$NON-NLS-0$
				continue;
			}
			result[prop] = searchParams[prop];
		}
	}
	return result;	
};

searchUtils.generateFindURLBinding = function(searchParams, inFileQuery, lineNumber, replaceStr, paramOnly) {
	var params = {
		find: inFileQuery.searchStr,
		regEx: inFileQuery.wildCard ? true : undefined,
		caseSensitive: searchParams.caseSensitive ? true : undefined,
		wholeWord: searchParams.wholeWord ? true : undefined,
		replaceWith: typeof(replaceStr) === "string" ? replaceStr : undefined, //$NON-NLS-0$
		atLine: typeof(lineNumber) === "number" ? lineNumber : undefined //$NON-NLS-0$
	};
	if(paramOnly){
		return params;
	}
	var binding = new URITemplate("{,params*}").expand({ //$NON-NLS-0$
		params: params
	});
	return "," + binding; //$NON-NLS-0$
};

searchUtils.convertFindURLBinding = function(findParams) {
	if(typeof findParams.regEx === "string"){ //$NON-NLS-0$
		findParams.regEx = (findParams.regEx.toLowerCase() === "true"); //$NON-NLS-0$
	}
	if(typeof findParams.caseSensitive === "string"){ //$NON-NLS-0$
		findParams.caseSensitive = (findParams.caseSensitive.toLowerCase() === "true"); //$NON-NLS-0$
	}
	if(typeof findParams.wholeWord === "string"){ //$NON-NLS-0$
		findParams.wholeWord = (findParams.wholeWord.toLowerCase() === "true"); //$NON-NLS-0$
	}
	if(typeof findParams.atLine === "string"){ //$NON-NLS-0$
		findParams.atLine = parseInt(findParams.atLine, 10);
	}
};

searchUtils.replaceRegEx = function(text, regEx, replacingStr){
	var regexp = new RegExp(regEx.pattern, regEx.flags);
	return text.replace(regexp, replacingStr); 
	
};

searchUtils.replaceStringLiteral = function(text, keyword, replacingStr){
	var regexp = mRegex.parse("/" + keyword + "/gim"); //$NON-NLS-1$ //$NON-NLS-0$
	return searchUtils.replaceRegEx(text,regexp, replacingStr);
};

searchUtils.searchOnelineLiteral =  function(inFileQuery, lineString, onlyOnce, textModel, lineIndex){
	var i,startIndex = 0;
	var found = false;
	var result = [];
	while(true){
		i = lineString.indexOf(inFileQuery.searchStr, startIndex);
		if (i < 0) {
			break;
		} else {
			if(textModel) {
				var start = textModel.getLineStart(lineIndex) + i;
				result.push({startIndex: i, length: inFileQuery.searchStrLength, start: start, end: start + inFileQuery.searchStrLength});
			} else {
				result.push({startIndex: i, length: inFileQuery.searchStrLength});
			}
			found = true;
			if(onlyOnce){
				break;
			}
			startIndex = i + inFileQuery.searchStrLength;
		}
	}
	if(found) {
		return result;
	}
	return null;
	
};

/**
 * Helper for finding regex matches in text contents.
 *
 * @param {String}
 *            text Text to search in.
 * @param {String}
 *            pattern A valid regexp pattern.
 * @param {String}
 *            flags Valid regexp flags. Allowed flags are: <code>"i"</code>, <code>"s"</code>, and any combination thereof.
 * @param {Number}
 *            [startIndex] Index to begin searching from.
 * @return {Object} An object giving the match details, or
 *         <code>null</code> if no match found. The
 *         returned object will have the properties:<br />
 *         <code>{Number} index</code><br />
 *         <code>{Number} length</code>
 * @name orion.searchUtils.findRegExp
 * @function
 */
searchUtils.findRegExp =  function(text, pattern, flags, startIndex) {
	if (!pattern) {
		return null;
	}
	flags = flags || "";
	// 'g' makes exec() iterate all matches, 'm' makes ^$
	// work linewise
	flags += (flags.indexOf("g") === -1 ? "g" : "") + //$NON-NLS-1$ //$NON-NLS-0$
			(flags.indexOf("m") === -1 ? "m" : ""); //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
	var regexp = new RegExp(pattern, flags);
	var result = null;
	result = regexp.exec(text.substring(startIndex));
	return result && {
		startIndex: result.index + startIndex,
		length: result[0].length
	};
};

searchUtils.searchOnelineRegEx =  function(inFileQuery, lineString, onlyOnce, textModel, lineIndex){
	var startIndex = 0;
	var found = false;
	var result = [];
	while(true){
		var regExResult = searchUtils.findRegExp(lineString, inFileQuery.regExp.pattern, inFileQuery.regExp.flags, startIndex);
		if(regExResult){
			if(textModel) {
				var start = textModel.getLineStart(lineIndex) + regExResult.startIndex;
				regExResult.start = start;
				regExResult.end = start + regExResult.length;
			}
			result.push(regExResult);
			found = true;
			if(onlyOnce){
				break;
			}
			startIndex = regExResult.startIndex + regExResult.length;
		} else {
			break;
		}
	}
	if(found) {
		return result;
	}
	return null;
};

searchUtils.generateNewContents = function( updating, oldContents, newContents, fileModelNode, replaceStr, searchStrLength){
	if(fileModelNode && oldContents){
		if(!updating){
			newContents.contents = [];
		}
		for(var i = 0; i < oldContents.length ; i++){
			var lineStringOrigin = oldContents[i];
			var changingLine = false;
			var checked = false;
			var checkedMatches = [];
			var originalMatches;
			var k, startNumber = 0;
			for(var j = 0; j < fileModelNode.children.length; j++){
				var lnumber = fileModelNode.children[j].lineNumber - 1;
				if(lnumber === i){
					startNumber = j;
					for(k = 0; k < fileModelNode.children[j].matches.length; k++ ){
						if(fileModelNode.children[j+k].checked !== false){
							checkedMatches.push(k);
						}
					}
					checked = (checkedMatches.length > 0);
					originalMatches = fileModelNode.children[j].matches; 
					changingLine = true;
					break;
				}
			}
			if(changingLine){
				var newStr;
				if(!checked){
					newStr = lineStringOrigin;
					for(k = 0; k < fileModelNode.children[startNumber].matches.length; k++ ){
						fileModelNode.children[startNumber+k].newMatches = fileModelNode.children[startNumber+k].matches;
					}
				} else{
					var result =  searchUtils.replaceCheckedMatches(lineStringOrigin, replaceStr, originalMatches, checkedMatches, searchStrLength);
					newStr = result.replacedStr;
					for(k = 0; k < fileModelNode.children[startNumber].matches.length; k++ ){
						fileModelNode.children[startNumber+k].newMatches = result.newMatches;
					}
				}
				if(updating){
					newContents.contents[i] = newStr;
				} else {
					newContents.contents.push(newStr);
				}
			} else if(!updating){
				newContents.contents.push(lineStringOrigin);
			}
		}
	}
};

searchUtils.generateMatchContext = function(contextAroundLength, fileContents, lineNumber/*zero based*/){
	var context = [];
	var totalContextLength = contextAroundLength*2 + 1;
	var startFrom, endTo;
	if(fileContents.length <= totalContextLength){
		startFrom = 0;
		endTo = fileContents.length -1;
	} else {
		startFrom = lineNumber - contextAroundLength;
		if(startFrom < 0){
			startFrom = 0;
			endTo = startFrom + totalContextLength - 1;
		} else {
			endTo = lineNumber + contextAroundLength;
			if(endTo > (fileContents.length -1)){
				endTo = fileContents.length -1;
				startFrom = endTo - totalContextLength + 1;
			}
			
		}
	}
	for(var i = startFrom; i <= endTo; i++){
		context.push({context: fileContents[i], current: (i === lineNumber)});
	}
	return context;
};

/**
 * Split file contents into lines. It also handles the mixed line endings with "\n", "\r" and "\r\n".
 *
 * @param {String} text The file contents.
 * @returns {String[]} Split file lines. 
 * @name orion.searchUtils.splitFile
 * @function
 */
searchUtils.splitFile = function(text) {
	var cr = 0, lf = 0, index = 0, start = 0;
	var splitLines = [];
	while (true) {
		if (cr !== -1 && cr <= index) { 
			cr = text.indexOf("\r", index);  //$NON-NLS-0$
		}
		if (lf !== -1 && lf <= index) { 
			lf = text.indexOf("\n", index);  //$NON-NLS-0$
		}
		if (lf === -1 && cr === -1) {
			splitLines.push(text.substring(start));
			break; 
		}
		var offset = 1;
		if (cr !== -1 && lf !== -1) {
			if (cr + 1 === lf) {
				offset = 2;
				index = lf + 1;
			} else {
				index = (cr < lf ? cr : lf) + 1;
			}
		} else if (cr !== -1) {
			index = cr + 1;
		} else {
			index = lf + 1;
		}
		splitLines.push(text.substring(start, index));
		start = index;
	}
	return splitLines;
};

searchUtils.searchWithinFile = function( inFileQuery, fileModelNode, fileContentText, replacing, caseSensitive, noContext, useTextModel){
	var textModel;
	if(noContext || useTextModel) {
		textModel = new mTextModel.TextModel(fileContentText);
	}
	var fileContents = searchUtils.splitFile(fileContentText);
	if(replacing || noContext){
		fileModelNode.contents = fileContents;
	}
	if(fileModelNode){
		fileModelNode.children = [];
		var totalMatches = 0;
		for(var i = 0; i < fileContents.length ; i++){
			var lineStringOrigin = fileContents[i];
			if(lineStringOrigin && lineStringOrigin.length > 0){
				var lineString = caseSensitive ? lineStringOrigin : lineStringOrigin.toLowerCase();
				var result;
				if(inFileQuery.wildCard){
					result = searchUtils.searchOnelineRegEx(inFileQuery, lineString, false, textModel, i);
				} else {
					result = searchUtils.searchOnelineLiteral(inFileQuery, lineString, false, textModel, i);
				}
				if(result){
					var detailNode, lineNumber = i+1;
					if(!replacing){
						if(noContext) {
							detailNode = {lineNumber: lineNumber, matches: result, name: lineStringOrigin};
						} else {
							detailNode = {parent: fileModelNode, context: searchUtils.generateMatchContext(2, fileContents, i), checked: fileModelNode.checked, 
											  type: "detail", matches: result, lineNumber: lineNumber, name: lineStringOrigin, //$NON-NLS-0$ 
											  location: fileModelNode.location}; //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
						}
						fileModelNode.children.push(detailNode);
					} else {
						for(var j = 0; j < result.length; j++){
							var matchNumber = j+1;
							detailNode = {parent: fileModelNode, checked: fileModelNode.checked, type: "detail", matches: result, lineNumber: lineNumber, matchNumber: matchNumber, name: lineStringOrigin, location: fileModelNode.location}; //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
							fileModelNode.children.push(detailNode);
						}
					}
					totalMatches += result.length;
				}
			}
		}
		fileModelNode.totalMatches = totalMatches;
	}
};

searchUtils.replaceCheckedMatches = function(text, replacingStr, originalMatches, checkedMatches, defaultMatchLength){
	var gap = defaultMatchLength;
	var startIndex = 0;
	var replacedStr = "";
	var newMatches = [];
	for(var i = 0; i < originalMatches.length; i++){
		if(startIndex !== originalMatches[i].startIndex){
			replacedStr = replacedStr + text.substring(startIndex, originalMatches[i].startIndex);
		}
		if(originalMatches[i].length){
			gap = originalMatches[i].length;
		}
		var needReplace = false;
		for (var j = 0; j < checkedMatches.length; j++){
			if(checkedMatches[j] === i){
				needReplace = true;
				break;
			}
		}
		if(needReplace){
			newMatches.push({startIndex: replacedStr.length, length: replacingStr.length});
			replacedStr = replacedStr + replacingStr;
		} else {
			newMatches.push({startIndex: replacedStr.length, length: gap});
			replacedStr = replacedStr + text.substring(originalMatches[i].startIndex, originalMatches[i].startIndex + gap);
		}
		startIndex = originalMatches[i].startIndex + gap;
	}
	if(startIndex < text.length){
		replacedStr = replacedStr + text.substring(startIndex);
	}
	return {replacedStr: replacedStr, newMatches: newMatches};
};

searchUtils.fullPathNameByMeta = function(parents){
	var parentIndex = parents.length;
	var fullPath = "";
	//add parents chain top down if needed
	if(parentIndex > 0){
		for(var j = parentIndex - 1; j > -1; j--){
			var separator = (fullPath === "") ? "" : "/"; //$NON-NLS-1$ //$NON-NLS-0$
			fullPath = fullPath + separator + parents[j].Name;
		}
	}
	return fullPath;
};

return searchUtils;
});

/*******************************************************************************
 * @license
 * Copyright (c) 2012 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 * 
 ******************************************************************************/
/*eslint-env browser, amd*/
define('orion/crawler/nls/messages',{
	root:true
});

/*******************************************************************************
 * @license
 * Copyright (c) 2012 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 * 
 ******************************************************************************/
/*eslint-env browser, amd*/
define('orion/crawler/nls/root/messages',{//Default message bundle
		"filesFound": "${0} files found out of ${1}",
		"searchCancelled": "Search cancelled by user",
		"Cancel": "Cancel"
});


/*******************************************************************************
 * @license
 * Copyright (c) 2011, 2017 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
/*eslint-env browser, amd*/
define('orion/contentTypes',["orion/serviceTracker"], function(ServiceTracker) {
	var SERVICE_ID = "orion.core.contentTypeRegistry"; //$NON-NLS-0$
	var EXTENSION_ID = "orion.core.contenttype"; //$NON-NLS-0$
	var OLD_EXTENSION_ID = "orion.file.contenttype"; // backwards compatibility //$NON-NLS-0$

	/**
	 * @name orion.core.ContentType
	 * @class Represents a content type known to Orion.
	 * @property {String} id Unique identifier of this ContentType.
	 * @property {String} name User-readable name of this ContentType.
	 * @property {String} extends Optional; Gives the ID of another ContentType that is this one's parent.
	 * @property {String[]} extension Optional; List of file extensions characterizing this ContentType. Extensions are not case-sensitive.
	 * @property {String[]} filename Optional; List of filenames characterizing this ContentType.
	 */

	function contains(array, item) {
		return array.indexOf(item) !== -1;
	}

	function isImage(contentType) {
		switch (contentType && contentType.id) {
			case "image/jpeg": //$NON-NLS-0$
			case "image/png": //$NON-NLS-0$
			case "image/gif": //$NON-NLS-0$
			case "image/ico": //$NON-NLS-0$
			case "image/tiff": //$NON-NLS-0$
			case "image/svg": //$NON-NLS-0$
				return true;
		}
		return false;
	}
	
	function isBinary(cType) {
		if(!cType) {
			return false;
		}
		return (cType.id === "application/octet-stream" || cType['extends'] === "application/octet-stream"); //$NON-NLS-0$ //$NON-NLS-1$ //$NON-NLS-2$
	}
	
	/**
	 * @name getFilenameContentType
	 * @description Return the best contentType match to the given filename or null if no match. Filename pattern checked first, then extension
	 * @param filename the filename to compare against contentTypes
	 * @param contentTypes the array of possible contentTypes to check
	 * @returns returns ContentType that is the best match or null
	 */
	function getFilenameContentType(/**String*/ filename, contentTypes) {
		if (typeof filename !== "string") { //$NON-NLS-0$
			return null;
		}
		
		var best = null;
		var current;
		
		var extStart = filename.indexOf('.'); //$NON-NLS-0$
		extStart++; // leading period not included in extension
		var extension = filename.substring(extStart).toLowerCase();
		
		// Check the most common cases, exact filename match or full extension match
		for (var i=0; i < contentTypes.length; i++) {
			current = contentTypes[i];
			if (current.filename.indexOf(filename) >= 0){
				best = current;
				break;
			}
			
			if (contains(current.extension, extension)){
				// A filename match is considered better than a perfect extension match
				best = current;
				continue;
			}
			if(typeof current.filenamePattern === 'string') {
				try {
					if(new RegExp(current.filenamePattern, 'i').test(filename)) {
						best = current;
					}
				} catch(err) {}
			}
		}
		
		// Check the less common case where the filename contains periods (foo.bar.a.b check 'bar.a.b' then 'a.b' then 'b')
		if (!best){
			extStart = extension.indexOf('.'); //$NON-NLS-0$
			while (!best && extStart >= 0){
				extStart++; // leading period not included in extension
				extension = extension.substring(extStart);
				for (i=0; i < contentTypes.length; i++) {
					current = contentTypes[i];
					if (contains(current.extension, extension)){
						best = current;
						break;
					}
				}
				extStart = extension.indexOf('.'); //$NON-NLS-0$
			}
		}
		
		return best;		
	}

	function array(obj) {
		if (obj === null || typeof obj === "undefined") { return []; } //$NON-NLS-0$
			return (Array.isArray(obj)) ? obj : [obj];
		}

	function arrayLowerCase(obj) {
		return array(obj).map(function(str) { return String.prototype.toLowerCase.call(str); });
	}

	function process(contentTypeData) {
		return {
			id: contentTypeData.id,
			name: contentTypeData.name,
			image: contentTypeData.image,
			imageClass: contentTypeData.imageClass,
			"extends": contentTypeData["extends"], //$NON-NLS-1$ //$NON-NLS-0$
			extension: arrayLowerCase(contentTypeData.extension),
			filename: array(contentTypeData.filename),
			filenamePattern: contentTypeData.filenamePattern
		};
	}
	
	function add2Map(map, contentTypeDatas) {
		contentTypeDatas.map(process).forEach(function(contentType) {
			if (!Object.prototype.hasOwnProperty.call(map, contentType.id)) {
				map[contentType.id] = contentType;
			}
		});
	}
	
	function deleteFromMap(map, contentTypeDatas) {
		contentTypeDatas.map(process).forEach(function(contentType) {
			if (Object.prototype.hasOwnProperty.call(map, contentType.id)) {
				delete map[contentType.id];
			}
		});
	}
	
	function add2TypeData(serviceRef, contentTypeDatas) {
		var types = array(serviceRef.getProperty("contentTypes")); //$NON-NLS-0$
		for (var j=0; j < types.length; j++) {
			contentTypeDatas.push(types[j]);
		}
	}

	function buildMap(contentTypeDatas) {
		var map = Object.create(null);
		add2Map(map, contentTypeDatas);
		return map;
	}

	function buildMapFromServiceRegistry(serviceRegistry) {
		var serviceReferences = serviceRegistry.getServiceReferences(EXTENSION_ID).concat(
				serviceRegistry.getServiceReferences(OLD_EXTENSION_ID));
		var contentTypeDatas = [];
		for (var i=0; i < serviceReferences.length; i++) {
			var serviceRef = serviceReferences[i];
			add2TypeData(serviceRef, contentTypeDatas);
		}
		return buildMap(contentTypeDatas);
	}

	/**
	 * @name orion.core.ContentTypeRegistry
	 * @class A service for querying {@link orion.core.ContentType}s.
	 * @description A registry that provides information about {@link orion.core.ContentType}s.
	 *
	 * <p>If a {@link orion.serviceregistry.ServiceRegistry} is available, clients should request the service with
	 * objectClass <code>"orion.core.contentTypeRegistry"</code> from the registry rather than instantiate this 
	 * class directly. This constructor is intended for use only by page initialization code.</p>
	 *
	 * @param {orion.serviceregistry.ServiceRegistry|orion.core.ContentType[]} dataSource The service registry
	 * to use for looking up available content types and for registering this ContentTypeRegistry.
	 * 
	 * <p>Alternatively, an array of ContentType data may be passed instead, which allows clients to use this
	 * ContentTypeRegistry without a service registry.</p>
	 */
	function ContentTypeRegistry(dataSource) {
		if (dataSource && dataSource.registerService) {
			this.serviceRegistry = dataSource;
			var tracker = new ServiceTracker(this.serviceRegistry, "orion.core.contenttype"); //$NON-NLS-0$
			var _self = this;
			tracker.onServiceAdded = function(serviceRef) {
				var contentTypeDatas = [];
				add2TypeData(serviceRef, contentTypeDatas);
				add2Map(_self.map, contentTypeDatas);
			};
			tracker.removedService = function(serviceRef) {
				var contentTypeDatas = [];
				add2TypeData(serviceRef, contentTypeDatas);
				deleteFromMap(_self.map, contentTypeDatas);
			};
			tracker.open(false);
			this.map = buildMapFromServiceRegistry(dataSource);
			dataSource.registerService(SERVICE_ID, this);
		} else if (Array.isArray(dataSource)) {
			this.serviceRegistry = null;
			this.map = buildMap(dataSource);
		} else {
			throw new Error("Invalid parameter"); //$NON-NLS-0$
		}
	}
	ContentTypeRegistry.prototype = /** @lends orion.core.ContentTypeRegistry.prototype */ {
		/**
		 * Gets all the ContentTypes in the registry.
		 * @returns {orion.core.ContentType[]} An array of all registered ContentTypes.
		 */
		getContentTypes: function() {
			var map = this.getContentTypesMap();
			var types = [];
			for (var type in map) {
				if (Object.prototype.hasOwnProperty.call(map, type)) {
					types.push(map[type]);
				}
			}
			return types;
		},
		/**
		 * Gets a map of all ContentTypes.
		 * @return {Object} A map whose keys are ContentType IDs and values are the {@link orion.core.ContentType} having that ID.
		 */
		getContentTypesMap: function() {
			return this.map;
		},
		/**
		 * Looks up the ContentType for a file or search result, given the metadata.
		 * @param {Object} fileMetadata Metadata for a file or search result.
		 * @returns {orion.core.ContentType} The ContentType for the file, or <code>null</code> if none could be found.
		 */
		getFileContentType: function(fileMetadata) {
			return getFilenameContentType(fileMetadata.Name, this.getContentTypes());
		},
		/**
		 * Looks up the ContentType, given a filename.
		 * @param {String} filename The filename.
		 * @returns {orion.core.ContentType} The ContentType for the file, or <code>null</code> if none could be found.
		 */
		getFilenameContentType: function(filename) {
			return getFilenameContentType(filename, this.getContentTypes());
		},
		/**
		 * Gets a ContentType by ID.
		 * @param {String} id The ContentType ID.
		 * @returns {orion.core.ContentType} The ContentType having the given ID, or <code>null</code>.
		 */
		getContentType: function(id) {
			return this.map[id] || null;
		},
		/**
		 * Determines whether a ContentType is an extension of another.
		 * @param {orion.core.ContentType|String} contentTypeA ContentType or ContentType ID.
		 * @param {orion.core.ContentType|String} contentTypeB ContentType or ContentType ID.
		 * @returns {Boolean} Returns <code>true</code> if <code>contentTypeA</code> equals <code>contentTypeB</code>,
		 *  or <code>contentTypeA</code> descends from <code>contentTypeB</code>.
		 */
		isExtensionOf: function(contentTypeA, contentTypeB) {
			contentTypeA = (typeof contentTypeA === "string") ? this.getContentType(contentTypeA) : contentTypeA; //$NON-NLS-0$
			contentTypeB = (typeof contentTypeB === "string") ? this.getContentType(contentTypeB) : contentTypeB; //$NON-NLS-0$
			if (!contentTypeA || !contentTypeB) { return false; }
			if (contentTypeA.id === contentTypeB.id) { return true; }
			else {
				var parent = contentTypeA, seen = {};
				while (parent && (parent = this.getContentType(parent['extends']))) { //$NON-NLS-0$
					if (parent.id === contentTypeB.id) { return true; }
					if (seen[parent.id]) { throw new Error("Cycle: " + parent.id); } //$NON-NLS-0$
					seen[parent.id] = true;
				}
			}
			return false;
		},
		/**
		 * Similar to {@link #isExtensionOf}, but works on an array of contentTypes.
		 * @param {orion.core.ContentType|String} contentType ContentType or ContentType ID.
		 * @param {orion.core.ContentType[]|String[]} contentTypes Array of ContentTypes or ContentType IDs.
		 * @returns {Boolean} <code>true</code> if <code>contentType</code> equals or descends from any of the
		 * ContentTypes in <code>contentTypes</code>.
		 */
		isSomeExtensionOf: function(contentType, contentTypes) {
			for (var i=0; i < contentTypes.length; i++) {
				if (this.isExtensionOf(contentType, contentTypes[i])) {
					return true;
				}
			}
			return false;
		}
	};
	return {
		ContentTypeRegistry: ContentTypeRegistry,
		isImage: isImage,
		isBinary: isBinary,
		getFilenameContentType: getFilenameContentType
	};
});
/*******************************************************************************
 * @license
 * Copyright (c) 2009, 2016 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 * 
 * Contributors: IBM Corporation - initial API and implementation
 ******************************************************************************/

/*eslint-env browser, amd*/
define('orion/crawler/searchCrawler',['i18n!orion/crawler/nls/messages', 'orion/i18nUtil', 'orion/searchUtils', 'orion/contentTypes', 'orion/uiUtils', 'orion/Deferred'], 
		function(messages, i18nUtil, mSearchUtils, mContentTypes, mUiUtils, Deferred) {
	
	var DEBUG = false;
	var _folderFilter = [".git", "node_modules", ".cvs"];
	/**
	 * SearchCrawler is an alternative when a file service does not provide the search API.
	 * It assumes that the file client at least provides the fetchChildren and read APIs.
	 * It basically visits all the children recursively under a given directory location and search on a given keyword, either literal or wild card.
	 * @param {serviceRegistry} serviceRegistry The service registry.
	 * @param {fileClient} fileClient The file client that provides fetchChildren and read APIs.
	 * @param {Object} searchParams The search parameters. 
	 * @param {Object} options Not used yet. For future use.
	 * @name orion.search.SearchCrawler
	 */
	function SearchCrawler(	serviceRegistry, fileClient, searchParams, options) {
		this.registry= serviceRegistry;
		this.fileClient = fileClient; 
		this.fileLocations = [];
		this.fileSkeleton = [];
		this._hitCounter = 0;
		this._totalCounter = 0;
		this._searchOnName = options && options.searchOnName;
		this._buildSkeletonOnly = options && options.buildSkeletonOnly;
		this._fetchChildrenCallBack = options && options.fetchChildrenCallBack;
		this._searchParams = searchParams;
		this.searchHelper = (this._searchOnName || this._buildSkeletonOnly || !this._searchParams) ? null: mSearchUtils.generateSearchHelper(searchParams);
		this._location = searchParams ? searchParams.resource : options && options.location;
		this._childrenLocation = options && options.childrenLocation ? options.childrenLocation : this._location;   
		this._reportOnCancel = options && options.reportOnCancel;
		this._visitSingleFile = options && options.visitSingleFile;
		if(!this._visitSingleFile) {
			this._visitSingleFile = this._searchSingleFile;
		}
		this._cancelMessage = options && options.cancelMessage;
		if(!this._cancelMessage) {
			this._cancelMessage = messages["searchCancelled"];
		}
		this._cancelled = false;
		this._statusService = this.registry.getService("orion.page.message"); //$NON-NLS-0$
		this._progressService = this.registry.getService("orion.page.progress"); //$NON-NLS-0$
		if(this._statusService) {
			this._statusService.setCancelFunction(function() {this._cancelFileVisit();}.bind(this));
		}
	}
	
	/**
	 * Do search based on this.searchHelper.
	 * @param {Function} onComplete The callback function on search complete. The array of hit file locations are passed to the callback.
	 */
	SearchCrawler.prototype.search = function(onComplete){
		this.contentTypeService = this.registry.getService("orion.core.contentTypeRegistry"); //$NON-NLS-0$
		this._onSearchComplete = onComplete;
		this._cancelled = false;
		this._deferredArray = [];
		var result;
		return this.contentTypeService.getContentTypes().then(function(ct) {
			this.contentTypesCache = ct;
			var crawler = this;
			return this._visitRecursively(this._childrenLocation).then(function(){
				//We only report the result on the completion in two cases: 1.If there is no cancellation 2.If the option reportResultOnCancel is true
				if(!crawler._cancelled || crawler._reportOnCancel){//If it is in simulating mode we need to report the result anyway
					result = crawler._reportResult();
				} 
				//Normally if a cancellation happens it goes to error handler. But in corner cases that deferred.resolve is faster than deferred.cancel we need to capture the case
				if(crawler._cancelled) {
					crawler._HandleStatus({name: "Cancel"}); //$NON-NLS-0$
				}
				return new Deferred().resolve(result);
			}.bind(crawler),
			function(error){
				result = crawler._reportResult();
				crawler._HandleStatus(error); 
				return new Deferred().resolve(result);
			}.bind(crawler));
		}.bind(this));
	};
	
	/**
	 * Search file name on the query string from the file skeleton.
	 * @param {String} queryStr The query string. This is temporary for now. The format is "?sort=Path asc&rows=40&start=0&q=keyword+Location:/file/e/bundles/\*"
	 * @param {Function} onComplete The callback function on search complete. The array of hit file locations are passed to the callback.
	 */
	SearchCrawler.prototype.searchName = function(searchParams){
		if(searchParams){
			this._searchParams = searchParams;
			this.searchHelper = mSearchUtils.generateSearchHelper(searchParams, true);
		}
		var results = [];
		this._cancelled = false;
		this._deferredArray = [];
		this._sort(this.fileSkeleton);
		if(this.fileSkeleton.length > 0){
			for (var i = 0; i < this.fileSkeleton.length ; i++){
				var lineString = this.fileSkeleton[i].Name.toLowerCase();
				var result;
				if(this.searchHelper.inFileQuery.wildCard){
					result = mSearchUtils.searchOnelineRegEx(this.searchHelper.inFileQuery, lineString, true);
				} else {
					result = mSearchUtils.searchOnelineLiteral(this.searchHelper.inFileQuery, lineString, true);
				}
				if(result){
					results.push(this.fileSkeleton[i]);
					if(results.length >= this.searchHelper.params.rows){
						break;
					}
				}
			}
			var response = {numFound: results.length, docs: results };
			return new Deferred().resolve({response: response});
		} else {
			return new Deferred().resolve({response: {numFound: 0, docs: []}});
		}
	};
	
	/**
	 * Do search based on this.searchHelper.
	 * @param {Function} onComplete The callback function on search complete. The array of hit file locations are passed to the callback.
	 */
	SearchCrawler.prototype.buildSkeleton = function(onBegin, onComplete){
		this._buildingSkeleton = true;
		this.contentTypeService = this.registry.getService("orion.core.contentTypeRegistry"); //$NON-NLS-0$
		this._cancelled = false;
		this._deferredArray = [];
		var that = this;
		onBegin();
		this.contentTypeService.getContentTypes().then(function(ct) {
			that.contentTypesCache = ct;
			that._visitRecursively(that._childrenLocation).then(function(){ //$NON-NLS-0$
					that._buildingSkeleton = false;
					onComplete();
			});
		});
	};
	
	SearchCrawler.prototype.incrementalReport = function(fileObj, doSort){
		if(this._cancelled){
			return;
		}
		fileObj.LastModified = fileObj.LocalTimeStamp;
		this.fileLocations.push(fileObj);
		this._hitCounter++;
		if(doSort) {
			this._sort(this.fileLocations);
		}
		var response = {numFound: this.fileLocations.length, docs: this.fileLocations };
		this._onSearchComplete({response: response}, true);
		if(this._statusService) {
			this._statusService.setProgressResult({Message: i18nUtil.formatMessage(messages["filesFound"], this._hitCounter, this._totalCounter)}, messages["Cancel"]);
		}
	};
	
	SearchCrawler.prototype.addTotalCounter = function(number){
		if(!number) {
			number = 1;
		}
		this._totalCounter = this._totalCounter + number;
	};
	
	SearchCrawler.prototype.isCancelled = function(){
		return this._cancelled;
	};
	
	/**
	 * @name SearchCrawler.prototype._contains
	 * @description Checks to see if the given string item is in the given array of strings - ignoring case
	 * @function
	 * @private
	 * @param {Array.<String>} array The array to check
	 * @param {String} item The item to check for
	 * @returns {Boolean} Returns if the string is found in the array, ignoring case
	 */
	SearchCrawler.prototype._contains = function(array, item){
		if(Array.isArray(array) && typeof item === 'string') {
			var val = item.toLocaleLowerCase();
			return array.some(function(elt) {
				return elt === val;
			});
		}
		return false;
	};
	
	SearchCrawler.prototype._sort = function(fileArray){
		fileArray.sort(function(a, b) {
			var n1, n2;
			if(this._searchParams && this._searchParams.sort === "Path asc"){ //$NON-NLS-0$
				//Folder equals to Location's substring after tailing out the file name
				//We can not purely sort on Location because "Location" includes the file name at the tail.
				//E.g. "DDD/f1_2_1.css" will be lined up after "DDD/AAA/f1_2_2.html" if we do so.
				var location1 = a.Location && a.Location.toLowerCase();
				n1 = mUiUtils.path2FolderName(location1, true);
				var location2 = b.Location && b.Location.toLowerCase();
				n2 = mUiUtils.path2FolderName(location2, true);
				if (n1 < n2) { return -1; }
				if (n1 > n2) { return 1; }
				//If the same folder appears to two files, then we sort on file name
				return this._sortOnNameSingle(a, b);
			}
			return this._sortOnNameSingle(a, b);
		}.bind(this)); 
	};
		
	SearchCrawler.prototype._HandleStatus = function(error){
		if(this._statusService && error.name === "Cancel") { //$NON-NLS-0$
			if(DEBUG) {
				console.log("Crawling search cancelled. Deferred array length : " + this._deferredArray.length); //$NON-NLS-0$
			}
			this._statusService.setProgressResult({Message: this._cancelMessage, Severity: "Warning"}); //$NON-NLS-0$
		}
	};
		
	SearchCrawler.prototype._reportResult = function(){
		this._sort(this.fileLocations);
		var response = {numFound: this.fileLocations.length, docs: this.fileLocations };
		var result = {response: response};
		this._onSearchComplete(result);
		return result;
	};
		
	SearchCrawler.prototype._sortOnNameSingle = function(a, b){
		var	n1 = a.Name && a.Name.toLowerCase();
		var	n2 = b.Name && b.Name.toLowerCase();
		if (n1 < n2) { return -1; }
		if (n1 > n2) { return 1; }
		return 0;
	};
	
	SearchCrawler.prototype._fileNameMatches = function(fileName){
		var matches = true;
		if(this.searchHelper && this.searchHelper.params.fileNamePatterns){
			matches = this.searchHelper.params.fileNamePatterns.some(function(pattern){
				var regExpPattern = "^" + pattern.replace(/([*?])/g, ".$1") + "$"; // add line start, line end, and convert user input * and ? to .* and .? //$NON-NLS-0$
				return fileName.match(regExpPattern);
			});
		}
		return matches;
	};
	
	SearchCrawler.prototype._visitRecursively = function(directoryLocation){
		var results = [];
		var _this = this;
		if(this._fetchChildrenCallBack){
			this._fetchChildrenCallBack(directoryLocation);
		}
		return (_this._progressService ? this._progressService.progress(_this.fileClient.fetchChildren(directoryLocation), "Crawling search for children of " + directoryLocation) : _this.fileClient.fetchChildren(directoryLocation)).then(function(children) { //$NON-NLS-0$
			for (var i = 0; i < children.length ; i++){
				if(children[i].Directory !== undefined && children[i].Directory === false){
					if(_this._searchOnName){
						results.push(_this._buildSingleSkeleton(children[i]));
					} else if(_this._buildSkeletonOnly){
						results.push(_this._buildSingleSkeleton(children[i]));
					}else if(!_this._cancelled) {
						var contentType = mContentTypes.getFilenameContentType(children[i].Name, _this.contentTypesCache);
						var isBinary = (mContentTypes.isImage(contentType) || mContentTypes.isBinary(contentType));
						if(!isBinary && _this._fileNameMatches(children[i].Name)){
							var fileDeferred = _this._visitSingleFile(_this, children[i], contentType);
							results.push(fileDeferred);
							_this._deferredArray.push(fileDeferred);
						}
					}
				} else if (children[i].Location) {
					if(_this._cancelled) {
						break;
					} else if(_this._contains(_folderFilter, children[i].Name)) {
						continue;
					} else {
						var folderDeferred = _this._visitRecursively(children[i].ChildrenLocation);
						results.push(folderDeferred);
						_this._deferredArray.push(folderDeferred);
					}
				}
			}
			return Deferred.all(results);
		});
	};

	SearchCrawler.prototype._hitOnceWithinFile = function( fileContentText){
		var lineString = this._searchParams.caseSensitive ? fileContentText : fileContentText.toLowerCase();
		var result;
		if(this.searchHelper.inFileQuery.wildCard){
			result = mSearchUtils.searchOnelineRegEx(this.searchHelper.inFileQuery, lineString, true);
		} else {
			result = mSearchUtils.searchOnelineLiteral(this.searchHelper.inFileQuery, lineString, true);
		}
		return result;
	};

	SearchCrawler.prototype._cancelFileVisit = function(){
		this._cancelled = true;
		if(this._cancelled) {
			this._deferredArray.forEach(function(result) {
				result.cancel();
			});
		}
	};
	
	SearchCrawler.prototype._searchSingleFile = function(crawer, fileObj, contentType){
		this.addTotalCounter();
		var self = this;
		if(this._cancelled){
			return;
		}
		if(this.searchHelper.params.keyword === ""){
			this.incrementalReport(fileObj, true);
		} else {
			return (self._progressService ? self._progressService.progress(self.fileClient.read(fileObj.Location), "Reading file " + fileObj.Location) : self.fileClient.read(fileObj.Location)).then(function(jsonData) { //$NON-NLS-0$
					if(self._hitOnceWithinFile(jsonData)){
						self.incrementalReport(fileObj, true);
					}
				},
				function(error) {
					if(error && error.message && error.message.toLowerCase() !== "cancel") { //$NON-NLS-0$
						console.error("Error loading file content: " + error.message); //$NON-NLS-0$
					}
				}
			);
		}
	};
	
	SearchCrawler.prototype._buildSingleSkeleton = function(fileObj){
		this.addTotalCounter();
		this.fileSkeleton.push(fileObj);
		var df = new Deferred();
		df.resolve(this._totalCounter);
		return df;
	};
	
	SearchCrawler.prototype.constructor = SearchCrawler;
	
	//return module exports
	return {
		SearchCrawler: SearchCrawler
	};
});
/*******************************************************************************
 * @license
 * Copyright (c) 2010, 2015 IBM Corporation and others 
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 * 
 * Contributors:
 * IBM Corporation - initial API and implementation
 *******************************************************************************/
 
/*eslint-env browser, amd*/
define('orion/searchClient',[
	'i18n!orion/search/nls/messages', 
	'orion/webui/littlelib', 
	'orion/i18nUtil', 
	'orion/searchUtils', 
	'orion/crawler/searchCrawler', 
	'orion/Deferred'
], function(messages, lib, i18nUtil, mSearchUtils, mSearchCrawler, Deferred){

	/**
	 * Creates a new search client.
	 * @param {Object} options The options object
	 * @param {orion.serviceregistry.ServiceRegistry} options.serviceRegistry The service registry
	 * @name orion.searchClient.Searcher
	 * @class Provides API for searching the workspace.
	 */
	function Searcher(options) {
		this._registry= options.serviceRegistry;
		this._commandService = options.commandService;
		this._fileClient = options.fileService;
		//TODO clean up the search client API. Make any helper private
		this._registry.registerService("orion.core.search.client", this); //$NON-NLS-1$
	}
	Searcher.prototype = /**@lends orion.searchClient.Searcher.prototype*/ {
		getFileService: function(){
			return this.getFileClient();
		},
		_getNoneRootMeta: function(meta) {
			if(meta) {
				if(meta.Directory === undefined && meta.Location) {// Nodejs server does not return Directory property on a non root folder from a file's parent chain.
					return meta;
				}
				if(meta.Directory && meta.Location && meta.Parents) {
					return meta;
				}
			}
			return null;
		},
		/**
		 * Used to update "selectd" and "project" search scope based on the file or folder selected.
		 */
		setLocationByMetaData: function(meta, useParentLocation){
			var locationName = "";
			var noneRootMeta = null;
			this._setLocationbyURL(meta);
			this._searchRootLocation = meta.WorkspaceLocation || this._fileClient.fileServiceRootURL(meta.Location);
			if(useParentLocation && meta && meta.Parents && meta.Parents.length > 0){
				if(useParentLocation.index === "last"){
					noneRootMeta = meta.Parents[meta.Parents.length-1];
				} else {
					noneRootMeta = meta.Parents[0];
				}
			} else {
				noneRootMeta = this._getNoneRootMeta(meta);
			} 
			if(noneRootMeta){
				this.setLocationbyURL(noneRootMeta.Location);
				locationName = noneRootMeta.Name;
				this._childrenLocation = noneRootMeta.ChildrenLocation;
			} else if(meta){
				this.setLocationbyURL(this._searchRootLocation);
				locationName = this._fileClient.fileServiceName(meta.Location);
				this._childrenLocation = meta.ChildrenLocation;
			}
			var searchInputDom = lib.node("search"); //$NON-NLS-0$
			if(!locationName){
				locationName = "";
			}
			this._searchLocationName = locationName;
			if(searchInputDom && searchInputDom.placeholder){
				searchInputDom.value = "";
				var placeHolder = i18nUtil.formatMessage(messages["Search ${0}"], locationName);
				
				if(placeHolder.length > 30){
					searchInputDom.placeholder = placeHolder.substring(0, 27) + "..."; //$NON-NLS-0$
				} else {
					searchInputDom.placeholder = i18nUtil.formatMessage(messages["Search ${0}"], locationName);
				}
			}
			if(searchInputDom && searchInputDom.title){
				searchInputDom.title = messages["TypeKeyOrWildCard"] + locationName;
			}
		},
		setLocationbyURL: function(locationURL){
			this._searchLocation = locationURL;			
		},
		_calculateProjectScope : function (data) {
		  //Similar mechanism to the setLocationByMetaData method in searchClient.js with meta = data.items[0]
		  //and useParentLocation = {index: "last"} to retrieve project scope info.
		  var searchLoc = null;
		  if(data.items[0] && data.items[0].Parents && data.items[0].Parents.length){
		    searchLoc = data.items[0].Parents[data.items[0].Parents.length - 1];
		  } else if(data.items[0]) {
		    searchLoc = data.items[0];
		  } else {
		  	searchLoc = data.items;
		  }
		  return searchLoc;
		},
		/**
		 * Used to update "other" search scope, this location info comes directly from InlineSearchPane.js
		 */
		setLocationOther: function(otherLocation){
			this._searchLocation_other = otherLocation;
		},
		_handleSearchscopeLocation: function(searchTarget){
			// If the search target's Location is /workspace/orionode, change it to fileSearviceRootUrl(), which in most cases will give you /file
			return searchTarget.Location !== "/workspace/orionode" ? searchTarget.Location : this._fileClient.fileServiceRootURL();
		},
		_setLocationbyURL: function(meta){
			this._searchLocation_selected = typeof meta ==="string" ? meta : meta.Directory ? meta : meta.Parents[0];
			this._searchLocation_project = this._calculateProjectScope({items: [meta]});
			if(this._displaycallBack){
				if(this._searchScopeOption === "selected"){
					this._displaycallBack([this._handleSearchscopeLocation(this._searchLocation_selected)]);
				}else if(this._searchScopeOption === "project"){
					this._displaycallBack([this._handleSearchscopeLocation(this._searchLocation_project)]);
				}
			}
		},
		getSearchLocation: function(searchScope){
			switch(searchScope){
				case "selected":
					if(this._searchLocation_selected){
						return this._handleSearchscopeLocation(this._searchLocation_selected);
					}
					break;
				case "project":
					if(this._searchLocation_project){
						return this._handleSearchscopeLocation(this._searchLocation_project);
					}
					break;
				case "workspace":
					return this.getSearchRootLocation();
				case "other":
					if(this._searchLocation_other){
						return this._searchLocation_other;
					}
					break;
			}
			if(this._searchLocation){
				return this._searchLocation;
			}
			return this._fileClient.fileServiceRootURL();
		},
		getSearchLocationName: function(){
			return this._searchLocationName;
		},
		getSearchRootLocation: function(){
			return this._searchRootLocation || this._fileClient.fileServiceRootURL();
		},
		getChildrenLocation: function(){
			return this._childrenLocation || this.getSearchRootLocation();
		},
		addDisplaycallback: function(displayCallback, searchScopeOption){
			this._displaycallBack = displayCallback;
			this._searchScopeOption = searchScopeOption;
		},
		
		/**
		 * @name getFileClient
		 * @description Get the file client;
		 * @function
		 * @returns {orion.FileClient} returns a file client
		 */
		getFileClient: function() {
			return this._fileClient ? this._fileClient : this._registry.getService("orion.core.file.client"); //$NON-NLS-1$
		},
		/**
		 * Runs a search and displays the results under the given DOM node.
		 * @public
		 * @param {Object} searchParams The search parameters.
		 * @param {Function(JSONObject)} Callback function that receives the results of the query.
		 */
		search: function(searchParams, generateMatches, generateMeta) {
			try {
				return this.getFileClient().search(searchParams).then(function(jsonData) {
					var searchResult = this.convert(jsonData, searchParams);
					return this._generateMatches(searchParams, searchResult, generateMatches).then(function() {
						return this._generateMeta(searchResult, generateMeta).then(function() {
							return searchResult;
						});
					}.bind(this));
				}.bind(this));
			}
			catch(err){
				var error = err.message || err;
				if(typeof error === "string" && error.toLowerCase().indexOf("search") > -1){ //$NON-NLS-1$ //$NON-NLS-0$
					if(!this._crawler) {
						this._crawler = this._createCrawler(searchParams);
					}
					if(searchParams.nameSearch) {
						return this._crawler.searchName(searchParams).then(function(jsonData) {
							return this.convert(jsonData, searchParams);
						}.bind(this));
					}
					var result;
					return result = this._crawler.search(function() {
						result.progress(arguments[0], arguments[1]);
					}).then(function(jsonData) {
						return this.convert(jsonData, searchParams);
					}.bind(this));
				}
				throw error;
			}
		},
		_generateSingle: function(sResult, searchHelper) {
			return this.getFileClient().read(sResult.location).then(function(jsonData) {
				mSearchUtils.searchWithinFile(searchHelper.inFileQuery, sResult, jsonData, false, searchHelper.params.caseSensitive, true);
				return sResult;
			}.bind(this),
			function(error) {
				var statusService = this._registry.getService("orion.page.message"); //$NON-NLS-1$
				if (statusService) {
					statusService.setProgressResult({Message: error.message, Severity: "Error"}); //$NON-NLS-1$
				}
			}.bind(this));
		},
		_generateMatches: function(searchParams, searchResult, generateMatches) {
			if(!generateMatches || searchResult.length === 0) {
				return new Deferred().resolve(searchResult);
			}
			var searchHelper = mSearchUtils.generateSearchHelper(searchParams);
			var promises = [];
			searchResult.forEach(function(sResult) {
				promises.push(this._generateSingle(sResult, searchHelper));
			}.bind(this)); 
			return Deferred.all(promises, function(error) { return {_error: error}; });
		},
		_generateSingleMeta: function(sResult) {
			return this.getFileClient().read(sResult.location, true).then(function(jsonData) {
				sResult.metadata = jsonData;
				return sResult;
			}.bind(this), function(error) {
				var statusService = this._registry.getService("orion.page.message"); //$NON-NLS-1$
				if (statusService) {
					statusService.setProgressResult({Message: error.message, Severity: "Error"}); //$NON-NLS-1$
				}
			}.bind(this));
		},
		_generateMeta: function(searchResult, generateMeta) {
			if(!generateMeta || searchResult.length === 0) {
				return new Deferred().resolve(searchResult);
			}
			var promises = [];
			searchResult.forEach(function(sResult) {
				promises.push(this._generateSingleMeta(sResult));
			}.bind(this)); 
			return Deferred.all(promises, function(error) { return {_error: error}; });
		},
		convert: function(jsonData, searchParams) {
			var converted = [];
			var rootURL = this._fileClient.fileServiceRootURL(searchParams.resource);
			if (jsonData.response.numFound > 0) {
				for (var i=0; i < jsonData.response.docs.length; i++) {
					var hit = jsonData.response.docs[i];
					if (!hit.Directory) {
						var loc = hit.Location;
						var path = hit.Path;
						if (!path) {
							path = loc.substring(rootURL ? rootURL.length : 0); //remove file service root from path
						}
						converted.push({location: loc, path: path, name: hit.Name, workspace: this._searchRootLocation});
					}
				}
			}
			return converted;
		},
		_createCrawler: function(searchParams, options) {
			this._crawler = new mSearchCrawler.SearchCrawler(this._registry, this.getFileClient(), searchParams, options);
			return this._crawler;
		},
		
		/**
		 * Returns a query object for search. The return value has the propertyies of resource and parameters.
		 * @param {String} keyword The text to search for, or null when searching purely on file name
		 * @param {Boolean} [nameSearch] The name of a file to search for
		 * @param {Boolean} [useRoot] If true, do not use the location property of the searcher. Use the root url of the file system instead.
		 */
		createSearchParams: function(keyword, nameSearch, useRoot, advancedOptions, searchScope)  {
			var searchOn = useRoot ? this.getSearchRootLocation(): this.getSearchLocation(searchScope);
			if (nameSearch) {
				//assume implicit trailing wildcard if there isn't one already
				//var wildcard= (/\*$/.test(keyword) ? "" : "*"); //$NON-NLS-0$
				return {
					resource: searchOn,
					sort: "NameLower asc", //$NON-NLS-0$
					rows: 100,
					start: 0,
					nameSearch: true,
					keyword: keyword,
					exclude: (advancedOptions && advancedOptions.exclude) ? advancedOptions.exclude : undefined,
				};
			}
			return {
				resource: searchOn,
				sort: advancedOptions && advancedOptions.sort ? advancedOptions.sort : "Path asc", //$NON-NLS-0$
				rows: advancedOptions && advancedOptions.rows ? advancedOptions.rows : 40,
				start: 0,
				caseSensitive: advancedOptions ? advancedOptions.caseSensitive : undefined,
				wholeWord: advancedOptions ? advancedOptions.wholeWord : undefined,
				regEx: advancedOptions ? advancedOptions.regEx : undefined,
				fileType: advancedOptions ? advancedOptions.fileType : undefined,
				fileNamePatterns: (advancedOptions && advancedOptions.fileNamePatterns) ? advancedOptions.fileNamePatterns : undefined,
				exclude: (advancedOptions && advancedOptions.exclude) ? advancedOptions.exclude : undefined,
				keyword: keyword,
				replace: advancedOptions ? advancedOptions.replace : undefined,
				searchScope: searchScope
			};
		}
	};

	Searcher.prototype.constructor = Searcher;
	//return module exports
	return {Searcher:Searcher};
});
/*******************************************************************************
 * @license
 * Copyright (c) 2012 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 * 
 ******************************************************************************/
/*eslint-env browser, amd*/
define('orion/widgets/nls/messages',{
	root:true
});

/*******************************************************************************
 * @license
 * Copyright (c) 2012 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 * 
 ******************************************************************************/
/*eslint-env browser, amd*/
define('orion/widgets/nls/root/messages',{//Default message bundle
	"Choose a Folder": "Choose a Folder",
	"OK": "OK",
	"Profile": "Profile",
	"Sign out": "Sign out",
	"N/A": "N/A",
	"logged in since ": "logged in since ",
	"Sign in": "Sign in",
	"Authentication required!": "Authentication required!",
	"Name:": "Name:",
	"Plug-ins": "Plug-ins",
	"Properties": "Properties",
	"Services": "Services",
	"SFTP Transfer": "SFTP Transfer",
	"Remote host:": "Remote host:",
	"Port:": "SFTP Port:",
	"Remote path:": "Remote path:",
	"User name:": "User name:",
	"Password:": "Password:",
	"Start Transfer": "Start Transfer",
	"Location:": "Location:",
	"orion.sftpConnections": "orion.sftpConnections",
	"Drag a file here": "Drag a file here",
	"unzip zips": "Unzip *.zip files",
	"or if you prefer": "(or upload a file using the buttons below)",
	"Upload" : "Upload",
	"Browse...": "Browse...",
	"Import a file or zip": "Import a file or zip",
	"MissingSearchRenderer": "Missing required argument: searchRenderer",
	"FindFileNamed": "Find File in ${0}",
	"FindFileGlobal": "Find File in any Project",
	"Search": "Search",
	"Folders": "Folders",
	"FileName FolderName": "FileName FolderName(Optional)",
	"Searching...": "Searching...",
	"SearchOccurences": "Searching for occurrences of: \"${0}\"",
	"name": "name",
	"test": "test",
	"Type the name of a file to open (? = any character, * = any string):": "Type the name of a file to open (? = any character, * = any string):",
	"Sign Out": "Sign Out",
	"Sign In": "Sign In",
	"Help": "Help",
	"Report a Bug": "Report a Bug",
	"Keyboard Shortcuts": "Keyboard Shortcuts",
	"Clear Local Storage": "Clear Local Storage",
	"About": "About",
	"Check for Updates": "Check for Updates",
	"Download": "Download",
	"Open": "Open",
	"Close": "Close",
	"Version: ": "Version: ",
	"Build ID: ": "Build ID: ",
	"Update Channel: ": "Update Channel: ",
	"Stable": "Stable",
	"Alpha" : "Alpha",
	"Update available. Download now?" : "Update available. Download now?",
	"No updates available." : "No updates available.",
	"Error occurred while checking for updates.": "Error occurred while checking for updates.",
	"Update is downloading in the background." : "Update is downloading in the background.",
	"Settings": "Settings",
	"userSettings": "User Profile",
	"View profile of ": "View profile of ",
	"Profiles": "Profiles",
	"Information Needed": "Information Needed",
	"Cancel": "Cancel",
	"If the same file exists in both the source and destination:" : "If the same file exists in both the source and destination:",
	"Cancel the transfer" : "Cancel the transfer",
	"Always overwrite destination" : "Always overwrite destination",
	"Overwrite if source is newer" : "Overwrite if source is newer",
	"New" : "New",
	"Building file skeleton..." : "Building file skeleton...",
	"Add" : "Add",
	"Upload..." : "Upload...",
	"AvailableCmdsType": "For a list of available commands type '${0}'.",
	"Main Pages": "Main Pages",
	"Related Links": "Related Links",
	"Yes": "Yes",
	"No": "No",
	"DeleteSearchTrmMsg": "Click or use delete key to delete the search term",
	"Application": "Application",
	"selectLaunchConfig": "Create new launch configuration",
	"launchConfiguration": "Launch configuration:",
	"launchConfigurations": "Launch configurations",
	"createNew": "Create New",
	"Running": "Running",
	"checkingStateMessage": "Checking status of ${0}",
	"checkingStateShortMessage": "checking status",
	"Status": "Status",
	"appInfoStopped": "stopped",
	"appInfoRunning": "running",
	"appInfoUnknown": "unknown",
	"appInfoError": "error",
	"displayNameSeparator": " on ",
	"openApp": "Open App",
	"openAppTooltip": "Open the Deployed App",
	"openLogs": "Logs",
	"openLogsTooltip": "Open the Deploy Log",
	"redeployConfirmationDialogTitle": "Stop and Redeploy?",
	"redeployConfirmationDialogMessage": "Your application ${0} will be re-deployed.",
	"redeployConfirmationDialogCheckboxMessage": "Don't ask me again.",
	"createNewTooltip": "Create a new launch configuration",
	"back": "< Back",
	"next": "Next >",
	"Downloading": "Downloading new version",
	"Checking for Update": "Checking for Update"
});


/*******************************************************************************
 * @license
 * Copyright (c) 2012 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 * 
 ******************************************************************************/
/*eslint-env browser, amd*/
define('orion/edit/nls/messages',["module"],function(module){
    var config = module.config();
    return config && config.root ? config : {root:true};
});

/*******************************************************************************
 * @license
 * Copyright (c) 2012, 2017 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 * 
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *     Casey Flynn - Google Inc.
 ******************************************************************************/
/*eslint-env browser, amd*/
define('orion/edit/nls/root/messages',{
	"Editor": "Editor",
	"switchEditor": "Switch Editor",
	"Fetching": "Fetching: ${0}",
	"confirmUnsavedChanges": "This file contains unsaved changes.  If you navigate away, will lose them.  \n\nDo you want to save your changes?",
	"searchFiles": "Quick Search in ${0}",
	"searchTerm": "Enter search term:",
	"unsavedChanges": "There are unsaved changes in current file, you can't navigate away without saving it.",
	"unsavedAutoSaveChanges": "Please stay on the page until Auto Save is complete.",
	"Save": "Save",
	"Saved": "Saved",
	"Blame": "Blame",
	"BlameTooltip":"Show blame annotations",
	"Diff": "Diff",
	"DiffTooltip":"Show diff annotations",
	"saveOutOfSync": "Resource is out of sync with the server. Do you want to save it anyway?",
	"loadOutOfSync": "Resource is out of sync with the server. Do you want to load it anyway? This will overwrite your local changes.",
	"ReadingMetadata": "Reading metadata of ${0}",
	"ReadingMetadataError": "Cannot get metadata of ${0}",
	"Reading": "Reading ${0}",
	"ReloadWith": "Reload With",
	"Convert Line Delimiters": "Convert Line Delimiters",
	"Windows (CR/LF)": "Windows (CR/LF)",
	"Unix (LF)": "Unix (LF)",
	"ConversionCompleteCRLF": "Line delimiters have been converted to CR/LF",
	"ConversionCompleteLF": "Line delimiters have been converted to LF",
	"readonly": "Read Only.",
	"saveFile": "Save this file",
	"toggleZoomRuler": "Toggle Zoom Ruler",
	"gotoLine": "Go to Line...",
	"gotoLineTooltip": "Go to specified line number",
	"gotoLinePrompt": "Go to line:",
	"Undo": "Undo",
	"Redo": "Redo",
	"Cut": "Cut",
	"Copy": "Copy",
	"Paste": "Paste",
	"Find": "Find...",
	"noResponse": "No response from server. Check your internet connection and try again.",
	"noResponseTimeout": "No response from server (timed out after ${0} seconds). Check your internet connection and try again.",
	"savingFile": "Saving file ${0}",
	"running": "Running ${0}",
	"Saving..." : "Saving...",
	"View": "View",
	"SplitSinglePage": "Single Page",
	"SplitVertical": "Split Vertical",
	"SplitHorizontal": "Split Horizontal",
	"SplitPipInPip": "Picture in Picture",
	"SplitModeTooltip": "Change split editor mode",
	"AllTabsDropDown": "Open Tabs (Ctrl + Shift + E)",
	"AllTabsDropDownMac": "Open Tabs (Cmd + Shift + E)",
	"SidePanel": "Side Panel",
	"SidePanelTooltip": "Choose what to show in the side panel.",
	"Slideout": "Slideout",
	"Actions": "Actions",
	"Navigator": "Navigator",
	"FolderNavigator": "Folder Navigator",
	"ProjectNavigator": "Project Navigator",
	"Project": "Project",
	"New": "New",
	"File": "File",
	"Edit": "Edit",
	"Tools": "Tools",
	"Add": "Add",
	"noActions": "There are no actions for the current selection.",
	"NoFile": "Use the ${0} to create new files and folders. Click a file to start coding, or go to the Git page to bring in existing code.",
	"LocalEditorSettings": "Local Editor Settings",
	"EditorSettings": "Editor Settings",
	"NoProject": "${0} is not a project. To convert it to a project use ${1}.",
	"NoProjects": "There are no projects in your workspace. Use the ${0} menu to create projects.",
	"Disconnected": "${0} (disconnected)",
	"ChooseFS": "Choose Filesystem",
	"ChooseFSTooltip": "Choose the filesystem you want to view.",
	"FSTitle": "${0} (${1})",
	"EnterCondition": "Please enter a condition:",
	"Deploy": "Deploy",
	"Deploy As": "Deploy As",
	"Import": "Import",
	"Export": "Export",
	"OpenWith": "Open With",
	"OpenRelated": "Open Related",
	"OpenFolder": "Open Folder",
	"SwitchWorkspace": "Switch To",
	"SwitchWorkspaceTip": "Switch workspaces",
	"OpenRecent": "Open Recent",
	"OpenFolderTip": "Change the root folder",
	"Dependency": "Dependency",
	"UnnamedCommand": "Unnamed",
	"Search": "Search...",
	"Show Debug": "Debug...",
	"ProjectInfo": "Project Information",
	"Name": "Name",
	"Description": "Description",
	"Site": "Site",
	'projectsSectionTitle': 'Projects',
	'listingProjects': 'Listing projects...',
	'gettingWorkspaceInfo': 'Getting workspace information...',
	"showProblems": "Show Problems...",
	"showTooltip": "Show Tooltip",
	"showTooltipTooltip": "Shows the tooltip based on the caret position",
	"showLineTooltip": "Show Line Tooltip",
	"showLineTooltipTooltip": "Shows the tooltip based on the current line",
	"emptyDeploymentInfoMessage": "Use the Launch Configurations dropdown to deploy this project",
	"Orion": "Orion",
	"OK": "Ok",
	"Format" : "Format Code",
	"FormatTooltip":"Format editor contents",
	"fileContents":"${0} contents",
	"fileContentsSplit":"${0} contents split",
	"References" : "References",
	"ReferencesTooltip":"Find references in project",
	"FindReferences": "Finding references",
	"OpenDeclaration": "Open Declaration",
	"OpenDeclarationTooltip": "Open the declaration for the current selection",
	"FindDeclaration": "Finding declaration",
	"Cancel":"Cancel",
	"Yes":"Yes",
	"No":"No",
	"selectNextTab": "Select Next Editor Tab",
	"selectPreviousTab": "Select Previous Editor Tab",
	"showTabDropdown": "Display Open Editor Tabs",
	"Collaborate": "Collaborate",
	"CollaborateToolTip": "Start a Collaboration session on the current file",
	"closeOthers":"Close Other Tabs",
	"closeTotheRight":"Close Tabs To The Right",
	"keepOpen":"Keep Open",
	"closeSelf":"Close"
});



define('text!orion/banner/CommandSlideout.html',[],function () { return '<div id="slideContainer" class="slideParameters slideContainer">\n\t<span id="pageCommandParameters" class="layoutLeft parameters"></span>\n\t<span id="pageCommandDismiss" class="layoutRight parametersDismiss"></span>\n</div>';});

/*******************************************************************************
 * @license
 * Copyright (c) 2011, 2019 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
/*eslint-env browser, amd*/

define('orion/commonHTMLFragments',['orion/webui/littlelib', 'text!orion/banner/CommandSlideout.html'], 
        function(lib, CommandSlideoutTemplate){
        
	/**
	 * This module contains dynamic HTML fragments that depend on client information.
	 * @name orion.commonHTMLFragments
	 */

	function slideoutHTMLFragment(idPrefix) { 
		var tempDiv = document.createElement("div"); //$NON-NLS-0$
		lib.setSafeInnerHTML(tempDiv, CommandSlideoutTemplate);
		
		// replacing generic id's with prefixed id's
		var node = lib.$("#slideContainer", tempDiv); //$NON-NLS-0$
		node.id = idPrefix + node.id;
		node = lib.$("#pageCommandParameters", tempDiv); //$NON-NLS-0$
		node.id = idPrefix + node.id;
		node = lib.$("#pageCommandDismiss", tempDiv); //$NON-NLS-0$
		node.id = idPrefix + node.id;
		return tempDiv.innerHTML;
	}
		
	//return the module exports
	return {
		slideoutHTMLFragment: slideoutHTMLFragment
	};
});

/*******************************************************************************
 * @license
 * Copyright (c) 2011, 2019 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
/*eslint-env browser, amd*/

define('orion/parameterCollectors',['i18n!orion/nls/messages', 'orion/webui/littlelib', 'orion/bidiUtils', 'orion/bidiFormat', 'orion/webui/tooltip'], 
        function(messages, lib, bidiUtils, bidiFormat, mTooltip) {

	
	/**
	 * Constructs a new command parameter collector.
	 * @name orion.parametercollectors.CommandParameterCollector
	 * @class <code>CommandParameterCollector</code> can collect parameters in a way that is integrated with the common 
	 * header elements of pages or sections.
	 * @param {Function} getElementsFunction
	 * @param {Function} toolbarLayoutFunction
	 * @extends orion.commandregistry.ParameterCollector
	 * @borrows orion.commandregistry.ParameterCollector#close as #close
	 * @borrows orion.commandregistry.ParameterCollector#collectParameters as #collectParameters
	 * @borrows orion.commandregistry.ParameterCollector#getFillFunction as #getFillFunction
	 * @borrows orion.commandregistry.ParameterCollector#open as #open
	 */	
	function CommandParameterCollector (getElementsFunction, toolbarLayoutFunction) {
		this._activeContainer = null;
		this._getElementsFunction = getElementsFunction;
		this._toolbarLayoutFunction = toolbarLayoutFunction;
	}
	
	CommandParameterCollector.prototype = /** @lends orion.parametercollectors.CommandParameterCollector.prototype */ {
	
		close: function () {
			if (this._activeElements) {
				lib.returnFocus(this._activeElements.slideContainer, this._oldFocusNode, function() {
					if (this._activeElements.parameterArea) {
						lib.empty(this._activeElements.parameterArea);
					}
					if (this._activeElements.slideContainer) {
						this._activeElements.slideContainer.classList.remove("slideContainerActive"); //$NON-NLS-0$
					}
					if (this._activeElements.dismissArea) {
						 lib.empty(this._activeElements.dismissArea);
					}
					if (this._activeElements.commandNode) {
						this._activeElements.commandNode.classList.remove("activeCommand"); //$NON-NLS-0$
					}
					if (this._activeElements.closeTooltip) {
			            this._activeElements.closeTooltip.destroy();
			            this._activeElements.closeTooltip = null;
			        }
					this._toolbarLayoutFunction(this._activeElements);
					if (this._activeElements.onClose) {
						this._activeElements.onClose();
					}
					if (this._oldFocusNode) {
						this._oldFocusNode = null;
					}
				}.bind(this));
			}
			this._activeElements = null;
		},
		
		open: function(commandNode, fillFunction, onClose, name) {
			if (typeof commandNode === "string") { //$NON-NLS-0$
				commandNode = lib.node(commandNode);
			}
			if (this._activeElements && this._activeElements.slideContainer && this._activeElements.commandNode === commandNode) {
				// already open.  Just return focus where it needs to be.
				if (this._activeElements.focusNode) {
					this._activeElements.focusNode.focus();
				}
				return true;
			}
			this.close();
			this._activeElements = null;
			// determine the closest parameter container to the command.
			this._activeElements = this._getElementsFunction(commandNode);
			if (this._activeElements && this._activeElements.parameterArea && this._activeElements.slideContainer) {
				this._activeElements.onClose = onClose;
				var focusNode = fillFunction(this._activeElements.parameterArea, this._activeElements.dismissArea, this._activeElements.slideContainer);
				if (!focusNode) {
					// no parameters were generated.  
					return false;
				}
				this._activeElements.focusNode = focusNode;
				var self = this;
				var close = lib.$$array("#closebox", this._activeElements.dismissArea || this._activeElements.parameterArea); //$NON-NLS-0$
				if (close.length === 0) {
					// add the close button if the fill function did not.
					var dismiss = this._activeElements.dismissArea || this._activeElements.parameterArea;
					close = document.createElement("button"); //$NON-NLS-0$
					close.id = "closebox"; //$NON-NLS-0$
					close.className ="imageSprite core-sprite-close dismissButton"; //$NON-NLS-0$
					lib.setSafeAttribute(close, "aria-label", messages['Close']);
					this._activeElements.closeTooltip = new mTooltip.Tooltip({
							node: close,
							text: messages['Close'],
							position: ["right", "below", "above", "left"] //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
					});
					dismiss.appendChild(close);
					close.addEventListener("click", function(event) { //$NON-NLS-0$
						self.close();
					}, false);
				}
				// ESC closes slideout if it has focus
				this._activeElements.slideContainer.tabIndex = -1;
				this._activeElements.slideContainer.style.outline = "none";
				
				// all parameters have been generated.  Activate the area.
				lib.setSafeAttribute(this._activeElements.slideContainer, "role", "dialog");
				if (name) {
					lib.setSafeAttribute(this._activeElements.slideContainer, "aria-label", name);
				}
				this._activeElements.slideContainer.classList.add("slideContainerActive"); //$NON-NLS-0$
				this._toolbarLayoutFunction(this._activeElements);

				if (focusNode) {
					this._oldFocusNode = window.document.activeElement;
					var slideContainer = this._activeElements.slideContainer;
					window.setTimeout(function() {
						focusNode.focus();
						if (focusNode.select) {
							focusNode.select();
						}
						lib.trapTabs(slideContainer);
					}, 0);
				}
				if (this._activeElements.commandNode) {
					this._activeElements.commandNode.classList.add("activeCommand"); //$NON-NLS-0$
				}
				return true;
			}
			return false;
		},
		
		_collectAndCall: function(commandInvocation, parent) {
			var validate = function(name, value, node) {
				if (commandInvocation.parameters.validate(name, value)) {
					commandInvocation.parameters.setValue(name, value);
					return true;
				}
				node.classList.add("parameterInvalid");
				return false;
			};
			
			var isValid = function(field) { //$NON-NLS-0$
				if (field.type === "checkbox") { //$NON-NLS-0$
					if (!validate(field.parameterName, field.checked, field)) {
						return true;
					}
				} else if (field.type === "url" && field.nodeName === "DIV") { //$NON-NLS-0$
					if (!validate(field.parameterName, field.textContent.trim(), field)) {
						return true;
					}
				} else if (field.type !== "button") { //$NON-NLS-0$
					if (!validate(field.parameterName, field.value.trim(), field)) {
						return true;
					}
				} else if (field.type !== "textarea") { //$NON-NLS-0$
					if (!validate(field.parameterName, field.value.trim(), field)) {
						return true;
					}
				}
				return false;
			};

			if (lib.$$array("input", parent).some(isValid)) {  //$NON-NLS-0$
				return false;
			}
			
			if (lib.$$array("textArea", parent).some(isValid)) {  //$NON-NLS-0$
				return false;
			}
			
			if (lib.$$array("div[contenteditable=true]", parent).some(isValid)) {  //$NON-NLS-0$
				return false;
			}
			
			var getParameterElement = commandInvocation.parameters.getParameterElement;
			if (getParameterElement) {
				if (commandInvocation.parameters.some(function(param) {
					var field = getParameterElement(param, parent);
					if (field) {
						return isValid(field);
					}
					return false;
				})) {
					return false;
				}
			}
			if (commandInvocation.command.callback) {
				commandInvocation.command.callback.call(commandInvocation.handler, commandInvocation);
			}
			return true;
		},
		
		collectParameters: function(commandInvocation, cancelCallback, name) {
			if (commandInvocation.parameters) {
				if (commandInvocation.domNode) {
					commandInvocation.domNode.classList.add("commandMarker"); //$NON-NLS-0$
				}
				return this.open(commandInvocation.domNode || commandInvocation.domParent, this.getFillFunction(commandInvocation,null,cancelCallback), null, name);
			}
			return false;
		},
		
		getFillFunction: function(commandInvocation, closeFunction, cancelFunction) {
			var self = this;
			return function(parameterArea, dismissArea, containerArea) {
				var first = null;
				var localClose = function() {
					if (closeFunction) {
						closeFunction();
					}
					self.close();
				};
				var keyHandler = function(event) {
					event.target.classList.remove("parameterInvalid");  //$NON-NLS-0$
					if (event.keyCode === lib.KEY.ENTER && event.target.tagName !== "TEXTAREA") {  //$NON-NLS-0$
							self._collectAndCall(commandInvocation, parameterArea);
							localClose();
							lib.stop(event);
					}
					if (event.keyCode === lib.KEY.ESCAPE) {
						if (typeof(cancelFunction) === 'function') cancelFunction();
						localClose();
						lib.stop(event);
					}
				};
				
				if (containerArea) {
					containerArea.addEventListener("keydown", function(event) { //$NON-NLS-0$
						if (event.keyCode === lib.KEY.ESCAPE) {
							if (typeof(cancelFunction) === 'function') cancelFunction(); //$NON-NLS-0$
							localClose();
							lib.stop(event);
						}
					}, false);
				}

				var makeButton = function(text, parent) {
					var button = document.createElement("button"); //$NON-NLS-0$
					parent.appendChild(button);
					if (text) {
						button.appendChild(document.createTextNode(text)); //$NON-NLS-0$
					}
					button.classList.add("dismissButton"); //$NON-NLS-0$
					return button;
				};

				var parameters = commandInvocation.parameters;
				
				if (parameters.message) {
					var label = document.createElement("div"); //$NON-NLS-0$
					label.classList.add("parameterMessage"); //$NON-NLS-0$
					label.textContent = typeof parameters.message === "function" ? parameters.message(commandInvocation) : parameters.message;
					parameterArea.appendChild(label);
				}
				
				parameters.forEach(function(parm) {
					var field = parameters.getParameterElement ? parameters.getParameterElement(parm, parameterArea) : null;
					var label = null;
					if (!field && parm.label) {
						label = document.createElement("label"); //$NON-NLS-0$
						label.classList.add("parameterInput"); //$NON-NLS-0$
						lib.setSafeAttribute(label, "for", parm.name + "parameterCollector");
						if (parm.type !== "boolean") {
							label.textContent = parm.label;
						}
						parameterArea.appendChild(label);
					} 
					var type = parm.type;
					var id = parm.name + "parameterCollector"; //$NON-NLS-0$
					var parent = label || parameterArea;
					if (type === "text" && typeof(parm.lines) === "number" && parm.lines > 1) { //$NON-NLS-1$ //$NON-NLS-0$
						if (!field) {
							field = document.createElement("textarea"); //$NON-NLS-0$
							field.rows = parm.lines;
							field.type = "textarea"; //$NON-NLS-0$
							field.id = id;							
							parent.appendChild(field);
						}
						bidiUtils.initInputField(field);
					} else if (parm.type === "boolean") { //$NON-NLS-0$
						if (!field) {
							field = document.createElement("input"); //$NON-NLS-0$
							field.type = "checkbox"; //$NON-NLS-0$
							field.id = id;
							
							parent.appendChild(field);
						}
						if (parm.value) {
							field.checked = true;
						}
					} else if (parm.type === "button") { //$NON-NLS-0$
						if (!field) {
							field = makeButton(parm.value || "", parent);
							field.id = id;
						} else {
							if (parm.value) {
								field.value = parm.value;
							}
						}
					} else {
						var isSTT = (bidiUtils.isBidiEnabled() && parm.type === "url"); //$NON-NLS-0$
						if (!field) {
							field = (!isSTT ? document.createElement("input") : document.createElement("div")); //$NON-NLS-0$
							field.type = parm.type;
							field.id = id;
							if (isSTT) {
								field.contentEditable = true;							
							}
							parent.appendChild(field);
						}
						if (parm.value) {
							if (!isSTT) {
								field.value = parm.value;
							} else {
								lib.setSafeInnerHTML(field, bidiFormat.getHtml(parm.value, "url", {}, false, "en"));							
							}
						}					
						(!isSTT ? bidiUtils.initInputField(field) : bidiFormat.attach(field, "url", {}, false, "en"));
					}
					if (label && parm.type === "boolean") {
						// label text goes after checkbox
						label.appendChild(document.createTextNode(parm.label));
					}
					field.classList.add("parameterInput"); //$NON-NLS-0$
					// for fun
					lib.setSafeAttribute(field, "speech", "speech");
					lib.setSafeAttribute(field, "x-webkit-speech", "x-webkit-speech");
					field.parameterName = parm.name;
					if (!first) {
						first = field;
					}
					
					// for more fun
					if(parm.eventListeners.length > 0){
						parm.eventListeners.forEach(function(listener){
							field.addEventListener(listener.event, function(evt){
								return listener.handler(evt, commandInvocation);
							}, listener.capture);
						});
					}
					
					field.addEventListener("keydown", keyHandler, false); //$NON-NLS-0$
				});
				var parentDismiss = dismissArea;
				if (!parentDismiss) {
					parentDismiss = document.createElement("span"); //$NON-NLS-0$
					parentDismiss.classList.add("layoutRight"); //$NON-NLS-0$
					parentDismiss.classList.add("parametersDismiss"); //$NON-NLS-0$
					parameterArea.appendChild(parentDismiss);
				}
				var finish = function (collector) {
					if (collector._collectAndCall(commandInvocation, parameterArea)) {
						localClose();
					}
				};
				
				if (commandInvocation.parameters.hasOptionalParameters()) {
					commandInvocation.parameters.optionsRequested = false;
					
					var options = makeButton(messages["More"], parentDismiss); //$NON-NLS-0$
					options.addEventListener("click", function() { //$NON-NLS-0$
						commandInvocation.parameters.optionsRequested = true;
						finish(self);
					}, false);
				}
				// OK and cancel buttons
				var ok = makeButton(parameters.getSubmitName ? parameters.getSubmitName(commandInvocation) : messages["Submit"], parentDismiss);
					ok.addEventListener("click", function() { //$NON-NLS-0$
					finish(self);
				}, false);
				ok.addEventListener("keydown", keyHandler);
				
				var name = parameters.getCancelName ? parameters.getCancelName(commandInvocation) : null;
				var close = makeButton(name, parentDismiss);
				close.id = "closebox"; //$NON-NLS-0$
				if (!name) {				
					close.classList.add("imageSprite"); //$NON-NLS-0$
					close.classList.add("core-sprite-close"); //$NON-NLS-0$
					lib.setSafeAttribute(close, "aria-label", messages['Close']);
					self._activeElements.closeTooltip = new mTooltip.Tooltip({
							node: close,
							text: messages['Close'],
							position: ["right", "below", "above", "left"] //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
					});
				}
				close.addEventListener("click", function(event) { //$NON-NLS-0$
					localClose();
					if (typeof(cancelFunction) === 'function') cancelFunction();
				}, false);
				close.addEventListener("keydown", keyHandler);
				return first;
			};
		 }
	};
	CommandParameterCollector.prototype.constructor = CommandParameterCollector;
	
	//return the module exports
	return {
		CommandParameterCollector: CommandParameterCollector
	};
});

/*******************************************************************************
 * @license
 * Copyright (c) 2012, 2014 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 * 
 ******************************************************************************/
/*eslint-env browser, amd*/
/*global URL*/
define('orion/PageLinks',[
	"require",
	"orion/Deferred",
	"orion/PageUtil",
	"orion/URITemplate",
	"orion/i18nUtil",
	"orion/objects",
	"orion/URL-shim"
], function(require, Deferred, PageUtil, URITemplate, i18nUtil, objects) {

	/**
	 * Returns the value of the <code>{OrionHome}</code> variable.
	 * @memberOf orion.PageLinks
	 * @function
	 * @returns {String} The value of the <code>{OrionHome}</code> variable.
	 */
	function getOrionHome() {
		if(!require.toUrl){
			return new URL("/", self.location.href).href.slice(0, -1);
		} else {
			// The idea here is to find the path of `orion/*` modules from the loader, and go up one folder to
			// the servlet context path. Finally, return a complete URL, slicing off the trailing `/`.
			// RequireJS 2.1.15:
			var orionSrcURL = new URL(require.toUrl("orion/"), self.location.href); //$NON-NLS-0$
			return new URL("../", orionSrcURL).href.slice(0, -1); //$NON-NLS-0$
		}
	}

	/**
	 * Reads metadata from an <code>orion.page.xxxxx</code> service extension.
	 * @memberOf orion.PageLinks
	 * @function
	 * @param {orion.ServiceRegistry} serviceRegistry The service registry.
	 * @param {String} [serviceName="orion.page.link"] Service name to read extensions from.
	 * @return {orion.Promise} A promise that resolves to an {@link orion.PageLinks.PageLinksInfo} object.
	 */
	function getPageLinksInfo(serviceRegistry, serviceName) {
		return _readPageLinksMetadata(serviceRegistry, serviceName).then(function(metadata) {
			return new PageLinksInfo(metadata);
		});
	}

	function _getPropertiesMap(serviceRef) {
		var props = {};
		serviceRef.getPropertyKeys().forEach(function(key) {
			if (key !== "objectClass" && key !== "service.names" && key !== "service.id" && key !== "__plugin__") //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
				props[key] = serviceRef.getProperty(key);
		});
		return props;
	}

	function _readPageLinksMetadata(serviceRegistry, serviceName) {
		serviceName = serviceName || "orion.page.link"; //$NON-NLS-0$

		// Read page links.
		// https://wiki.eclipse.org/Orion/Documentation/Developer_Guide/Plugging_into_Orion_pages
		var navLinks= serviceRegistry.getServiceReferences(serviceName);
		var params = PageUtil.matchResourceParameters(window.location.href);
		// TODO: should not be necessary, see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=373450
		var orionHome = getOrionHome();
		var locationObject = {OrionHome: orionHome, Location: params.resource};
		var navLinkInfos = [];
		navLinks.forEach(function(navLink) {
			var info = _getPropertiesMap(navLink);
			if (!info.uriTemplate || (!info.nls && !info.name)) {
				return; // missing data, skip
			}

			var uriTemplate = new URITemplate(info.uriTemplate);
			var expandedHref = uriTemplate.expand(locationObject);
			expandedHref = PageUtil.validateURLScheme(expandedHref);
			info.href = expandedHref;

			info.textContent = info.name || info.nameKey;
			navLinkInfos.push(new Deferred().resolve(info));
		});
		return Deferred.all(navLinkInfos);
	}

	// Categories apply to all orion.page.link* serviceNames, so cache them.
	var _cachedCategories;
	/**
	 * Reads info about page link categories.
	 * @returns {orion.Promise} Resolving to {@link orion.PageLinks.CategoriesInfo}
	 */
	function getCategoriesInfo(serviceRegistry) {
		// Read categories.
		var categoryInfos;
		if (!_cachedCategories) {
			categoryInfos = [];
			var navLinkCategories = serviceRegistry.getServiceReferences("orion.page.link.category"); //$NON-NLS-0$
			navLinkCategories.forEach(function(serviceRef) {
				var info = _getPropertiesMap(serviceRef);
				if (!info.id || (!info.name && !info.nameKey)) {
					return;
				}
				info.service = serviceRegistry.getService(serviceRef);
				info.textContent = info.name;
				categoryInfos.push(new Deferred().resolve(info));				
			});
			return Deferred.all(categoryInfos).then(function(infos) {
				_cachedCategories = new CategoriesInfo(infos);
				return _cachedCategories;
			});
		}
		return new Deferred().resolve(_cachedCategories);
	}

	function CategoriesInfo(categoriesArray) {
		var categories = this.categories = Object.create(null); // Maps category id {String} to category {Object}

		categoriesArray.forEach(function(category) {
			categories[category.id] = category;
		});
	}
	objects.mixin(CategoriesInfo.prototype, /** @lends orion.CategoriesInfo.CategoriesInfo.prototype */ {
		/**
		 * Returns the category IDs.
		 * @returns {String[]} The category IDs.
		 */
		getCategoryIDs: function() {
			return Object.keys(this.categories);
		},
		/**
		 * Returns the data for a given category.
		 * @param {String} id The category ID.
		 * @returns {Object} The category data.
		 */
		getCategory: function(id) {
			return this.categories[id] || null;
		}
	});

	/**
	 * @name orion.PageLinks.PageLinksInfo
	 * @class
	 * @description Provides access to info about page links read from an extension point.
	 */
	function PageLinksInfo(allPageLinks) {
		this.allPageLinks = allPageLinks;
		this.allPageLinks.sort(_comparePageLinks);
	}
	objects.mixin(PageLinksInfo.prototype, /** @lends orion.PageLinks.PageLinksInfo.prototype */ {
		/**
		 * Builds DOM elements for links
		 * @returns {Element[]} The links.
		 */
		createLinkElements: function() {
			return this.allPageLinks.map(function(info) {
				return _createLink(info.href, "_self", info.textContent); //$NON-NLS-0$
			});
		},
		/**
		 * @returns {Object[]} The links.
		 */
		getAllLinks: function() {
			return this.allPageLinks;
		}
	});

	function _comparePageLinks(a, b) {
		var n1 = a.textContent && a.textContent.toLowerCase();
		var n2 = b.textContent && b.textContent.toLowerCase();
		if (n1 < n2) { return -1; }
		if (n1 > n2) { return 1; }
		return 0;
	}

	function _createLink(href, target, textContent) {
		var a = document.createElement("a");
		a.href = href;
		a.target = target;
		a.classList.add("targetSelector");
		a.textContent = textContent;
		return a;
	}

	/**
	 * @name orion.PageLinks
	 * @class Utilities for reading <code>orion.page.link</code> services.
	 * @description Utilities for reading <code>orion.page.link</code> services.
	 */
	return {
		getCategoriesInfo: getCategoriesInfo,
		getPageLinksInfo: getPageLinksInfo,
		getOrionHome: getOrionHome
	};
});

/*******************************************************************************
 * @license
 * Copyright (c) 2011,2012 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
/*eslint-env browser, amd*/
define('orion/extensionCommands',["orion/Deferred", "orion/commands", 	'orion/PageUtil', "orion/contentTypes", "orion/URITemplate", "orion/i18nUtil", "orion/PageLinks", "i18n!orion/edit/nls/messages", "orion/util", "orion/URL-shim"],
	function(Deferred, mCommands, PageUtil, mContentTypes, URITemplate, i18nUtil, PageLinks, messages, util){

	/**
	 * Utility methods
	 * @class This class contains static utility methods for creating and managing commands from extension points
	 * related to file management.
	 * @name orion.extensionCommands
	 */
	var extensionCommandUtils  = {};
	
	// TODO working around https://bugs.eclipse.org/bugs/show_bug.cgi?id=373450
	var orionHome = PageLinks.getOrionHome();
	
	extensionCommandUtils._cloneItemWithoutChildren = function clone(item){
	    if (item === null || typeof(item) !== 'object') { //$NON-NLS-0$
	        return item;
	      }
	
	    var temp = item.constructor(); // changed
	
	    for(var key in item){
			if(key!=="children" && key!=="Children" && key!=="parent" && key!=="Project") { //$NON-NLS-1$ //$NON-NLS-0$
				temp[key] = clone(item[key]);
			}
	    }
	    return temp;
	};
	
	/*
	 * Helper function which returns an object containing all of the specified 
	 * serviceReference's properties.
	 * @name _getServiceProperties
	 * @param {orion.serviceregistry.ServiceReference} serviceReference
	 * @returns {Object} All the properties of the given <code>serviceReference</code>.
	 */
	function _getServiceProperties(serviceReference){
		var info = {};
		var propertyNames = serviceReference.getPropertyKeys();
		propertyNames.forEach(function(propertyName) {
			info[propertyName] = serviceReference.getProperty(propertyName);
		});
		return info;
	}
	
	/**
	 * Reads <code>"orion.navigate.openWith"</code> service contributions and returns corresponding <code>orion.navigate.command<code> extensions.
	 * @name orion.extensionCommands._getOpenWithNavCommandExtensions
	 * @function
	 * @returns {Object[]} The nav command extensions.
	 */
	extensionCommandUtils._getOpenWithNavCommandExtensions = function(serviceRegistry, contentTypes) {
		function getEditors() {
			var serviceReferences = serviceRegistry.getServiceReferences("orion.edit.editor"); //$NON-NLS-0$
			var editors = [];
			for (var i=0; i < serviceReferences.length; i++) {
				var serviceRef = serviceReferences[i], id = serviceRef.getProperty("id"); //$NON-NLS-0$
				editors.push({
					id: id,
					"default": serviceRef.getProperty("default") || false, //$NON-NLS-1$ //$NON-NLS-0$
					name: serviceRef.getProperty("name"), //$NON-NLS-0$
					nameKey: serviceRef.getProperty("nameKey"), //$NON-NLS-0$
					nls: serviceRef.getProperty("nls"), //$NON-NLS-0$
					uriTemplate: serviceRef.getProperty("orionTemplate") || serviceRef.getProperty("uriTemplate"), //$NON-NLS-1$ //$NON-NLS-0$
					validationProperties: serviceRef.getProperty("validationProperties") || [] //$NON-NLS-0$
				});
			}
			return editors;
		}

		function getEditorOpenWith(serviceRegistry, editor) {
			var openWithReferences = serviceRegistry.getServiceReferences("orion.navigate.openWith"); //$NON-NLS-0$
			var types = [];
			var excludedTypes = [];
			for (var i=0; i < openWithReferences.length; i++) {
				var ref = openWithReferences[i];
				if (ref.getProperty("editor") === editor.id) { //$NON-NLS-0$
					var ct = ref.getProperty("contentType"); //$NON-NLS-0$
					if (ct instanceof Array) {
						types = types.concat(ct);
					} else { //$NON-NLS-0$
						types.push(ct || "*/*");
					}
					
					var excludes = ref.getProperty("excludedContentTypes"); //$NON-NLS-0$
					if (excludes instanceof Array) {
						excludedTypes = excludedTypes.concat(excludes);
					} else if ((excludes !== null) && (typeof excludes !== "undefined")) { //$NON-NLS-0$
						excludedTypes.push(excludes);
					}
				}
			}
			if (0 === types.length) {
				types = null;
			}
			if (0 === excludedTypes.length) {
				excludedTypes = null;
			}
			return {contentTypes: types, excludedContentTypes: excludedTypes};
		}
		
		var editors = getEditors();
		var fileCommands = [];
		var genericEditorOpen;
		var orionEditorId = "orion.editor";

		for (var i=0; i < editors.length; i++) {
			var editor = editors[i];
			var editorContentTypeInfo = getEditorOpenWith(serviceRegistry, editor);
			var editorContentTypes = editorContentTypeInfo.contentTypes;
			var excludedContentTypes = editorContentTypeInfo.excludedContentTypes;
			var properties = {
				name: editor.name || editor.id,
				nameKey: editor.nameKey,
				id: "eclipse.openWithCommand." + editor.id, //$NON-NLS-0$
				contentType: editorContentTypes,
				excludedContentTypes: excludedContentTypes,
				uriTemplate: editor.uriTemplate,
				nls: editor.nls,
				forceSingleItem: true,
				isEditor: (editor["default"] ? "default": "editor"), // Distinguishes from a normal fileCommand //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
				validationProperties: editor.validationProperties
			};
			var command = {properties: properties, service: {}};
			if (editor.id === orionEditorId) {
				genericEditorOpen = command;
			} else {
				fileCommands.push(command);
			}
		}
		if (genericEditorOpen) {
			fileCommands.push(genericEditorOpen);
		}
		return fileCommands;
	};
	
	/**
	 * Create a validator for a given set of service properties.  The validator should be able to 
	 * validate a given item using the "contentType" and "validationProperties" service properties.
	 * @name orion.extensionCommands._makeValidator
	 * @function
	 */
	extensionCommandUtils._makeValidator = function(info, serviceRegistry, contentTypes, validationItemConverter) {
		function checkItem(item, key, match, validationProperty, validator) {
			var valid = false;
			var value;
			// Match missing property
			if (key.charAt(0) === "!") { //$NON-NLS-0$
				return (typeof item[key.substring(1)] === "undefined"); //$NON-NLS-0$
			}
			// item has the specified property
			if (typeof(item[key]) !== "undefined") { //$NON-NLS-0$
				if (typeof(match) === "undefined") {  //$NON-NLS-0$ // value doesn't matter, just the presence of the property is enough				if (!match) {  // value doesn't matter, just the presence of the property is enough
					value = item[key];
					valid = true;
				} else if (typeof(match) === 'string') {  // the value is a regular expression that should match some string //$NON-NLS-0$
					if (!typeof(item[key] === 'string')) { //$NON-NLS-0$
						// can't pattern match on a non-string
						return false;
					}
					if (validationProperty.variableName) {
						var patternMatch = new RegExp(match).exec(item[key]);
						if (patternMatch) {
							var firstMatch = patternMatch[0];
							if (validationProperty.variableMatchPosition === "before") { //$NON-NLS-0$
								value = item[key].substring(0, patternMatch.index);
							} else if (validationProperty.variableMatchPosition === "after") { //$NON-NLS-0$
								value = item[key].substring(patternMatch.index + firstMatch.length);
							} else if (validationProperty.variableMatchPosition === "only") { //$NON-NLS-0$
								value = firstMatch;
							} else {  // "all"
								value = item[key];
							}
							valid = true;
						}
					} else {
						return new RegExp(match).test(item[key]);
					}
				} else {
					if (item[key] === match) {
						value = item[key];
						valid = true;
					}
				}
				// now store any variable values and look for replacements
				var variableName = validationProperty.variableName, replacements = validationProperty.replacements;
				if (valid && variableName) {
					// store the variable values in the validator, keyed by variable name.  Also remember which item this value applies to.
					validator[variableName] = value;
					validator.itemCached = item;
					if (replacements) {
						if (typeof value !== "string") {
							window.console.log("Cannot replace " + variableName + ", value is not a string: " + value);
							return valid;
						}
						for (var i=0; i<replacements.length; i++) {
							var invalid = false;
							if (replacements[i].pattern) {
								var from = replacements[i].pattern;
								var to = replacements[i].replacement || "";
								validator[variableName] = validator[variableName].replace(new RegExp(from), to).replace(new RegExp(from), to);
							} else {
								invalid = true;
							}
							if (invalid) {
								window.console.log("Invalid replacements specified in validation property.  " + replacements[i]); //$NON-NLS-0$
							}
						}
					}
				}
				return valid;
			}
			return false;
		}

		/**
		 * @param {Object|Array} item
		 * @param {String} propertyName
		 * @param {Object} validationProperty
		 * @param {Validator} validator
		 */
		function matchSinglePattern(item, propertyName, validationProperty, validator){
			var value = validationProperty.match;
			var key, keyLastSegments, pos1, pos2;
			// Initial processing to handle array indices
			if ((pos1 = propertyName.indexOf("[")) >= 0) { //$NON-NLS-0$
				if((pos2 = propertyName.indexOf("]")) < 0){ //$NON-NLS-0$
					return false;
				}
				// The [] is used to drill into a numeric property of an array
				var fieldName = propertyName.substring(0, pos1), array, arrayIndex;
				if(!(array = item[fieldName]) || !Array.isArray(array)){
					return false;
				}
				key = propertyName.substring(pos1 + 1, pos2);
				arrayIndex = parseInt(key, 10);
				if (isNaN(arrayIndex))
					return false;

				// Index may be < 0 in which case it counts backwards from object.length
				if (arrayIndex < 0)
					arrayIndex += array.length;

				// Just rewrite the [] expression into a nested property access and fall down to the ":" case
				keyLastSegments = propertyName.substring(pos2 + 1);
				propertyName = fieldName + ":" + String(arrayIndex) + keyLastSegments;
			}

			if (propertyName.indexOf("|") >= 0) { //$NON-NLS-0$
				// the pipe means that any one of the piped properties can match
				key = propertyName.substring(0, propertyName.indexOf("|")); //$NON-NLS-0$
				keyLastSegments = propertyName.substring(propertyName.indexOf("|")+1); //$NON-NLS-0$
				// if key matches, we can stop.  No match is not a failure, look in the next segments.
				if (matchSinglePattern(item, key, validationProperty, validator)) {
					return true;
				} else {
					return matchSinglePattern(item, keyLastSegments, validationProperty, validator);
				}
			} else if (propertyName.indexOf(":") >= 0) { //$NON-NLS-0$
				// the colon is used to drill into a property
				key = propertyName.substring(0, propertyName.indexOf(":")); //$NON-NLS-0$
				keyLastSegments = propertyName.substring(propertyName.indexOf(":")+1); //$NON-NLS-0$
				// must have key and then check the next value
				if (item[key]) {
					return matchSinglePattern(item[key], keyLastSegments, validationProperty, validator);
				} else {
					return false;
				}
			} else {
				// we are checking a single property
				return checkItem(item, propertyName, value, validationProperty, validator);
			}
		}
		
		function validateSingleItem(item, contentTypes, validator){
			// first validation properties
			if (validator.info.validationProperties) {
				for (var i=0; i<validator.info.validationProperties.length; i++) {
					var validationProperty = validator.info.validationProperties[i];
					if (typeof(validationProperty.source) !== "undefined") { //$NON-NLS-0$
						var matchFound = matchSinglePattern(item, validationProperty.source, validationProperty, validator);
						if (!matchFound){
							return false;
						} 
					} else {
						window.console.log("Invalid validationProperties in " + info.id + ".  No source property specified."); //$NON-NLS-1$ //$NON-NLS-0$
						return false;
					}
				}
			}
			
			// Check content type validation
			if (!validator.info.contentType && !validator.info.excludedContentTypes){
				// Validation doesn't care about content type
				return true;
			}
			
			// Directories don't match any content types except */*
			if (item.Directory) {
				// */* is a special case used by openWithCommand that applies to directories (Bug 445677)
				if (validator.info.contentType && validator.info.contentType.indexOf('*/*') >= 0){
					return true;
				}
				return false;
			}
			
			var showCommand = true;
			var contentType = contentTypes ? mContentTypes.getFilenameContentType(item.Name || item.Location, contentTypes) : null;
			contentType = contentType || {
				id:"application/octet-stream"
			};
			if (validator.info.excludedContentTypes && contentTypes) {
				showCommand = validator.info.excludedContentTypes.every(function(excludedContentType){
					var filter = excludedContentType.replace(/([*?])/g, ".$1");	//$NON-NLS-0$ //convert user input * and ? to .* and .?
					if (-1 !== contentType.id.search(filter)) {
						// found a match, return false thereby hiding this command
						return false;
					}
					return true;
				});
			}
			
			if (showCommand && validator.info.contentType && contentTypes) {
				// the presence of validator.info.contentType means that we only 
				// want to show the command if the contentType matches
				showCommand = validator.info.contentType.some(function(includedContentType){
					var filter = includedContentType.replace(/([*?])/g, ".$1");	//$NON-NLS-0$ //convert user input * and ? to .* and .?
					if (-1 !== contentType.id.search(filter)) {
						// found a match, return true
						return true;
					}
					return false;
				});
			}			
			return showCommand;
		}
	
		var validator = {info: info};
		validator.validationFunction =  function(items){
			if (typeof validationItemConverter === "function") { //$NON-NLS-0$
				items = validationItemConverter.call(this, items);
			}
			if (items) {
				if (Array.isArray(items)){
					if ((this.info.forceSingleItem || this.info.uriTemplate) && items.length !== 1) {
						return false;
					}
					if (items.length < 1){
						return false;
					}
				} else {
					items = [items];
				}
				
				for (var i=0; i<items.length; i++){
					if(!validateSingleItem(items[i], contentTypes, this)){
						return false;
					}
				}
				return true;
			}
			return false;
		};
		validator.generatesURI = function() {
			return !!this.info.uriTemplate;
		};
		
		validator.getURI = function(item) {
			if (this.info.uriTemplate) {
				var variableExpansions = {};
				// we need the properties of the item
				for (var property in item){
					if(Object.prototype.hasOwnProperty.call(item, property)){
						variableExpansions[property] = item[property];
					}
				}
				// now we need the variable expansions collected during validation.  
				if (this.info.validationProperties) {
					for (var i=0; i<this.info.validationProperties.length; i++) {
						var validationProperty = this.info.validationProperties[i];
						if (validationProperty.source && validationProperty.variableName) {
							// we may have just validated this item.  If so, we don't need to recompute the variable value.
							var alreadyCached = this.itemCached === item && this[validationProperty.variableName];
							if (!alreadyCached) {
								matchSinglePattern(item, validationProperty.source, validationProperty, this);
							}
							if (!item[validationProperty.variableName]) {
								variableExpansions[validationProperty.variableName] = this[validationProperty.variableName];
							} else {
								window.console.log("Variable name " + validationProperty.variableName + " in the extension " + this.info.id + " conflicts with an existing property in the item metadata."); //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
							}
						}
					}
				}
				// special properties.  Should already be in metadata.  See bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=373450
				variableExpansions.OrionHome = orionHome;
				var uriTemplate = new URITemplate(this.info.uriTemplate);
				return uriTemplate.expand(variableExpansions);
			} 
			return null;
		};
		return validator;
	};
	
	/**
	 * Helper function which returns the id from an info object.
	 */
	function getIdFromInfo(info) {
		return info.id || info.name;
	}

	var DEFAULT_NAME = messages["UnnamedCommand"]; //$NON-NLS-0$
	var DEFAULT_TOOLTIP = ""; //$NON-NLS-0$
	// Turns an info object containing the service properties and the service (or reference) into Command options.
	extensionCommandUtils._createCommandOptions = function(/**Object*/ info, /**Service*/ serviceOrReference, serviceRegistry, contentTypesMap, /**boolean*/ createNavigateCommandCallback, /**optional function**/ validationItemConverter) {
		
		var deferred = new Deferred();
		
		function enhanceCommandOptions(commandOptions, deferred){
			var validator = extensionCommandUtils._makeValidator(info, serviceRegistry, contentTypesMap, validationItemConverter);
			commandOptions.visibleWhen = validator.validationFunction.bind(validator);
			
			if (createNavigateCommandCallback) {
				if (validator.generatesURI.bind(validator)()) {
					commandOptions.hrefCallback = function(data){
						var item = Array.isArray(data.items) ? data.items[0] : data.items;
						var href = validator.getURI.bind(validator)(item);
						// Preserve the query params of the current location to keep context
						var url = new URL(href);
						if (!url.search) {
							url.search = window.location.search;
						}
						href = url.href;
						if (data.command && data.command.isEditor) {
							data.domNode.addEventListener("click", function(evt) {
								if(item.Location) {
									var resourceParam = PageUtil.matchResourceParameters();
									if(resourceParam.resource !== item.Location) {
										data.domNode.target = "_blank";
										return;
									}
									var cmdHrefParam = PageUtil.matchResourceParameters(href);
									if(cmdHrefParam && cmdHrefParam.editor === resourceParam.editor) {
										data.domNode.target = "_blank";
										return;
									}
								}
								data.domNode.target = "";
							});
						}
						return href;
					};
					if(util.isElectron && info.uriTemplate){
						commandOptions.hrefTarget = "_blank";
					}
				} else {
					var inf = info;
					commandOptions.callback = function(data){
						var shallowItemsClone;
						if (inf.forceSingleItem) {
							var item = Array.isArray(data.items) ? data.items[0] : data.items;
							shallowItemsClone = extensionCommandUtils._cloneItemWithoutChildren(item);
						} else {
							if (Array.isArray(data.items)) {
								shallowItemsClone = [];
								for (var j = 0; j<data.items.length; j++) {
									shallowItemsClone.push(extensionCommandUtils._cloneItemWithoutChildren(data.items[j]));
								}
							} else {
								shallowItemsClone = extensionCommandUtils._cloneItemWithoutChildren(data.items);
							}
						}
						if(serviceRegistry){
							var progress = serviceRegistry.getService("orion.page.progress");
						}
						if(serviceOrReference.run) {
							if(progress){
								progress.progress(serviceOrReference.run(shallowItemsClone), "Running command: " + commandOptions.name);
							}else {
								serviceOrReference.run(shallowItemsClone);
							}
						} else if (serviceRegistry) {
							if(progress){
								progress.progress(serviceRegistry.getService(serviceOrReference).run(shallowItemsClone), "Running command: " + commandOptions.name);
							} else {
								serviceRegistry.getService(serviceOrReference).run(shallowItemsClone);
							}
						}
					};
				}  // otherwise the caller will make an appropriate callback for the extension
			}
			deferred.resolve(commandOptions);
		}
		
		var commandOptions = {
			name: info.name || info.nameKey || DEFAULT_NAME,
			image: info.image,
			id: getIdFromInfo(info),
			tooltip: info.tooltip || info.tooltipKey || DEFAULT_TOOLTIP,
			isEditor: info.isEditor,
			showGlobally: info.showGlobally
		};
		
		// Quickfixes for annotations are handled via commands, this option enable quickfixes to apply to all annotations
		if (info.fixAllEnabled){
			commandOptions.fixAllEnabled = true;
		}
		enhanceCommandOptions(commandOptions, deferred);
		return deferred;
	};

	/**
	 * Gets the "open with" command in the given <code>commandRegistry</code> for a given item. If {@link #createFileCommands}, has not been called,
	 * this returns <code>null</code>.
	 * @name orion.extensionCommands.getOpenWithCommand
	 * @function
	 * @param {orion.commandregistry.CommandRegistry} commandRegistry The command registry to consult.
	 * @param {Object} item The item to open.
	 * @param {orion.commands.Command[]} The optional list of commands to search for the appropriate command. If it is not provided, 
	 * 		orion.extensionCommands.getOpenWithCommands() is used.
	 */
	extensionCommandUtils.getOpenWithCommand = function(commandRegistry, item, commands) {
		var openWithCommand;
		var openWithCommands = commands || extensionCommandUtils.getOpenWithCommands(commandRegistry);
		for (var i=0; i < openWithCommands.length; i++) {
			if (openWithCommands[i].visibleWhen(item)) {
				var isDefault = openWithCommands[i].isEditor === "default"; //$NON-NLS-0$
				if (!openWithCommand || isDefault) {
					openWithCommand = openWithCommands[i];
					if (isDefault) {
						break;
					}
				}
			}
		}
		return openWithCommand;
	};

	/**
	 * Gets any "open with" commands in the given <code>commandRegistry</code>. If {@link #createFileCommands}, has not been called,
	 * this returns an empty array.
	 * @name orion.extensionCommands.getOpenWithCommands
	 * @function
	 * @param {orion.commandregistry.CommandRegistry} commandRegistry The command registry to consult.
	 * @returns {orion.commands.Command[]} All the "open with" commands added to the given <code>commandRegistry</code>.
	 */
	extensionCommandUtils.getOpenWithCommands = function(commandRegistry) {
		var openWithCommands = [];
		for (var commandId in commandRegistry._commandList) {
			var command = commandRegistry._commandList[commandId];
			if (command.isEditor) {
				openWithCommands.push(command);
			}
		}
		return openWithCommands;
	};
	
	var contentTypesCache;

	/**
	 * Collects file commands from extensions, turns them into {@link orion.commands.Command}s, and adds the commands with the given <code>commandRegistry</code>.
	 * @name orion.extensionCommands.createAndPlaceFileCommandsExtension
	 * @function
	 * @param {orion.serviceregistry.ServiceRegistry} serviceRegistry
	 * @param {orion.commandregistry.CommandRegistry} commandRegistry
	 * @param {String} toolbarId
	 * @param {Number} position
	 * @param {String} commandGroup
	 * @param {Boolean} isNavigator
	 * @param {Function} visibleWhen
	 * @returns {orion.Promise}
	 */
	extensionCommandUtils.createAndPlaceFileCommandsExtension = function(serviceRegistry, commandRegistry, toolbarId, position, commandGroup, isNavigator) {
		var navCommands = (isNavigator ? "all" : undefined); //$NON-NLS-0$
		var openWithCommands = !!isNavigator;
		return extensionCommandUtils.createFileCommands(serviceRegistry, null, navCommands, openWithCommands, commandRegistry).then(function(fileCommands) {
			if (commandGroup && (0 < fileCommands.length)) {
				commandRegistry.addCommandGroup(toolbarId, "eclipse.openWith", 1000, messages["OpenWith"], commandGroup, null, null, null, "dropdownSelection"); ///$NON-NLS-1$ //$NON-NLS-0$
				commandRegistry.addCommandGroup(toolbarId, "eclipse.fileCommandExtensions", 1000, messages["OpenRelated"], commandGroup); //$NON-NLS-0$
			}
			fileCommands.forEach(function(command) {
				var group = null;	
				if (commandGroup) {
					if (command.isEditor) {
						group = commandGroup + "/eclipse.openWith"; //$NON-NLS-0$
					} else {
						group = commandGroup + "/eclipse.fileCommandExtensions"; //$NON-NLS-0$
					}
				}
				
				commandRegistry.registerCommandContribution(toolbarId, command.id, position, group); //$NON-NLS-0$
			});
			return {};
		});
	};
		
	/**
	 * Reads file commands from extensions (<code>"orion.navigate.command"</code> and <code>"orion.navigate.openWith"</code>), and converts them into
	 * instances of {@link orion.commands.Command}.
	 * @name orion.extensionCommands.createFileCommands
	 * @function
	 * @param {orion.serviceregistry.ServiceRegistry} serviceRegistry
	 * @param {orion.core.ContentTypeRegistry} [contentTypeRegistry] If not provided, will be obtained from the serviceRegistry.
	 * @param {String} [includeNavCommands="global"] What kinds of <code>orion.navigate.command</code> contributions to include in the list of returned file commands.
	 * Allowed values are:
	 * <dl>
	 * <dt><code>"all"</code></dt> <dd>Include all nav commands.</dd>
	 * <dt><code>"global"</code></dt> <dd>Include only nav commands having the <code>forceSingleItem</code> and <code>showGlobally</code> flags.</dd>
	 * <dt><code>"none"</code></dt> <dd>Include no nav commands.</dd>
	 * </dl>
	 * @param {Boolean} [includeOpenWithCommands=true] Whether to include commands derived from <code>orion.navigate.openWith</code> in the list of returned file commands.
	 * @param {orion.commandregistry.CommandRegistry} commandRegistry
	 * @returns {orion.Promise} A promise resolving to an {@link orion.commands.Command[]} giving an array of file commands.
	 */
	extensionCommandUtils.createFileCommands = function(serviceRegistry, contentTypeRegistry, includeFileCommands, includeOpenWithCommands, commandRegistry) {
		includeFileCommands = (includeFileCommands === undefined) ? "global" : includeFileCommands;
		includeOpenWithCommands = (includeOpenWithCommands === undefined) ? true : includeOpenWithCommands;

		// Note that the shape of the "orion.navigate.command" extension is not in any shape or form that could be considered final.
		// We've included it to enable experimentation. Please provide feedback on IRC or bugzilla.
		//
		// The shape of the contributed commands is (for now):
		// info - information about the command (object).
		//		required attribute: name - the name of the command
		//		required attribute: id - the id of the command
		//		optional attribute: tooltip - the tooltip to use for the command
		//      optional attribute: image - a URL to an image for the command
		//      optional attribute: uriTemplate - a URI template that can be expanded to generate a URI appropriate for the item.
		//      optional attribute: forceSingleItem - if true, then the service is only invoked when a single item is selected
		//			and the item parameter to the run method is guaranteed to be a single item vs. an array.  When this is not true, 
		//			the item parameter to the run method may be an array of items.
		//      optional attribute: contentType - an array of content types for which this command is valid
		//      optional attribute: validationProperties - an array of validation properties used to read the resource
		//          metadata to determine whether the command is valid for the given resource.  Regular expression patterns are
		//          supported as values in addition to specific values.
		//          For example the validation property
		//				[{source: "Git"}, {source: "Directory", match:"true"}]
		//              specifies that the property "Git" must be present, and that the property "Directory" must be true.
		// run - the implementation of the command (function).
		//        arguments passed to run: (itemOrItems)
		//          itemOrItems (object or array) - an array of items to which the item applies, or a single item if the info.forceSingleItem is true
		//        the run function is assumed to perform all necessary action and the return is not used.
		var fileCommands = [];
		
		if (!extensionCommandUtils._cachedFileCommands) {
			extensionCommandUtils._createCachedFileCommands(serviceRegistry);
		}
		
		//we have already created the file commands, only select applicable ones based on function parameters	
		if (includeFileCommands === "all" || includeFileCommands === "global") { //$NON-NLS-1$ //$NON-NLS-0$
			extensionCommandUtils._cachedFileCommands.forEach(function(fileCommand) {
				var properties = fileCommand.properties;
				// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=402447
				if ((includeFileCommands === "all") || (properties.forceSingleItem && properties.showGlobally)) { //$NON-NLS-0$
					fileCommands.push(fileCommand);
				}
			});
		}
				
		function getContentTypes() {
			var contentTypes = serviceRegistry.getService("orion.core.contentTypeRegistry") || contentTypeRegistry;
			return contentTypesCache || Deferred.when(contentTypes.getContentTypes(), function(ct) { //$NON-NLS-0$
				contentTypesCache = ct;
				return contentTypesCache;
			});
		}
				
		return Deferred.when(getContentTypes(), function() {
			// If we are processing commands for the navigator, also include the open with command.  If we are not in the navigator, we only want the
			// commands we processed before.
			// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=402447
			if (includeOpenWithCommands) {
				if (!extensionCommandUtils._cachedOpenWithExtensions) {
					extensionCommandUtils._cachedOpenWithExtensions = extensionCommandUtils._getOpenWithNavCommandExtensions(serviceRegistry, contentTypesCache);
				}
				//add _cachedOpenWithExtensions to fileCommands
				fileCommands = fileCommands.concat(extensionCommandUtils._cachedOpenWithExtensions);
				commandRegistry._addedOpenWithCommands = includeOpenWithCommands;
			}
						
			var commandDeferreds = fileCommands.map(function(fileCommand) {
				var commandInfo = fileCommand.properties;
				var service = fileCommand.service;
				var cachedCommand = commandRegistry.findCommand(getIdFromInfo(commandInfo));
				if (cachedCommand) {
					return new Deferred().resolve(cachedCommand);
				} else {
					return extensionCommandUtils._createCommandOptions(commandInfo, service, serviceRegistry, contentTypesCache, true).then(function(commandOptions) {
						var command = new mCommands.Command(commandOptions);
						commandRegistry.addCommand(command);
						return command;
					});
				}
			});
			return Deferred.all(commandDeferreds, function(error) {
				return {_error: error};
			}).then(function(errorOrResultArray) {
				return errorOrResultArray;
			});
		});
	};

	extensionCommandUtils._createCachedFileCommands = function(serviceRegistry) {
		var commandsReferences = serviceRegistry.getServiceReferences("orion.navigate.command"); //$NON-NLS-0$
		extensionCommandUtils._cachedFileCommands = [];

		for (var i=0; i<commandsReferences.length; i++) {
			// Exclude any navigation commands themselves, since we are the navigator.
			var id = commandsReferences[i].getProperty("id"); //$NON-NLS-0$
			if (id !== "orion.navigateFromMetadata") { //$NON-NLS-0$
				var service = serviceRegistry.getService(commandsReferences[i]);
				var properties = _getServiceProperties(commandsReferences[i]);
				extensionCommandUtils._cachedFileCommands.push({properties: properties, service: service});
			}
		}
	};
	
	/**
	 * Reads the cached non-openWith file commands from extensions, and 
	 * returns an array containing their ids. If the cached commands haven't
	 * been created an exception will be thrown.
	 * 
	 * @name orion.extensionCommands.getFileCommandIds
	 * @function
	 * @returns {Array} An array containing the {String} ids of the cached non-openWith file commands
	 */
	extensionCommandUtils.getFileCommandIds = function() {
		var ids = [];
		if (!extensionCommandUtils._cachedFileCommands) {
			throw "extensionCommandUtils._cachedFileCommands is not initialized"; //$NON-NLS-0$
		} else if (extensionCommandUtils._cachedFileCommands.length) {
			ids = extensionCommandUtils._cachedFileCommands.map(function(command){
				return command.properties.id;
			});
		}
		return ids;
	};
	
	/**
	 * Reads <code>"orion.navigate.openWith"</code> extensions, and converts them into instances of {@link orion.commands.Command}.
	 * @name orion.extensionCommands.createOpenWithCommands
	 * @function
	 * @param {orion.serviceregistry.ServiceRegistry} serviceRegistry
	 * @param {orion.commandregistry.CommandRegistry} [commandRegistry]
	 * @param {orion.core.ContentTypeRegistry} [contentTypeRegistry] If not provided, will be obtained from the serviceRegistry.
	 * @returns {orion.Promise} A promise resolving to an {@link orion.commands.Command[]} giving an array of file commands.
	 */
	extensionCommandUtils.createOpenWithCommands = function(serviceRegistry, contentTypeService, commandRegistry) {
		if (commandRegistry && commandRegistry._addedOpenWithCommands) {
			// already processed by #createAndPlaceFileCommandsExtension
			return new Deferred().resolve(extensionCommandUtils.getOpenWithCommands(commandRegistry));
		}
		return extensionCommandUtils.createFileCommands(serviceRegistry, contentTypeService, "none", true, commandRegistry);
	};

	return extensionCommandUtils;
});

/*******************************************************************************
 * @license
 * Copyright (c) 2012, 2019 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made
 * available under the terms of the Eclipse Public License v1.0
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html).
 *
 * Contributors: IBM Corporation - initial API and implementation
 ******************************************************************************/
/*eslint-env browser, amd*/
define('orion/webui/splitter',[
	'orion/EventTarget',
	'orion/util',
	'orion/metrics',
	'orion/webui/littlelib'
], function(EventTarget, util, metrics, lib) {

	var ORIENTATION_HORIZONTAL = 1;
	var ORIENTATION_VERTICAL = 2;

	/**
	 * @name orion.webui.Splitter
	 * @class A splitter manages the layout of two panels, a side panel and a main panel.
	 * @description Constructs a new Splitter with the given options.  A splitter manages the layout
	 * of two panels, a side panel and a main panel.  An optional toggle button can open or close the
	 * side panel.
	 *
	 * <p>The relative proportions of the side and main panels are determined by the initial style of
	 * the splitter bar in the document. The panels will pin themselves to the splitter by default.
	 * Once the user moves the splitter, the positions are remembered. If the splitter is *not* proportional
	 * but *is* vertical then its position is stored separately from its horizontal position.</p>
	 * 
	 * <p>The splitter defines the CSS to position the nodes it's splitting based on which of the nodes
	 * 'collapses' when it's 'closed'. If the left (leading) node collapses then everything is defined relative
	 * to the left; if the trailing node collapses (closeReversely=true) then everything is relative to the right.
	 * In either case the CSS is defined so that the non-collapsing node gets the extra space if the browser grows.
	 *
	 * <p>By default, a splitter is open. The client can create a closed splitter by setting a 
	 * <code>data-initial-state</code> attribute with value <code>"closed"</code> on the 
	 * splitter's <code>node</code> element. Note that the user can drag a splitter 'closed' or 'open'
	 * and the correct state is maintained (i.e. if it were open and we dragged it all the way to its closed
	 * position then hitting the thumb would open it and vice versa.</p>
	 *
	 * @param {Object} options The options object which must specify the split dom node
	 * @param {Element} options.node The node for the splitter presentation.  Required.
	 * @param {Element} options.sidePanel The node for the side (toggling) panel.  Required.
	 * @param {Element} options.mainPanel The node for the main panel.  Required.
	 * @param {Boolean} [options.toggle=false] Specifies that the side node should be able to toggle.
	 * @param {Boolean} [options.vertical=false] Specifies that the nodes are stacked vertically rather than horizontal.
	 * @param {Boolean} [options.closeReversely=false] Specifies that the splitter moves to right when nodes are stacked horizontally, or to bottom when nodes are stacked vertically.
	 * @param {Boolean} [options.proportional=false] Specifies that the splitter is proportional so that growing the browser allocates space to both nodes.
	 *
	 * @borrows orion.editor.EventTarget#addEventListener as #addEventListener
	 * @borrows orion.editor.EventTarget#removeEventListener as #removeEventListener
	 * @borrows orion.editor.EventTarget#dispatchEvent as #dispatchEvent
	 */
	function Splitter(options) {
		EventTarget.attach(this);
		this._init(options);
	}
	Splitter.prototype = /** @lends orion.webui.Splitter.prototype */ {

		_init: function(options) {
			this.$splitter = lib.node(options.node);
			if (!this.$splitter) { throw "no dom node for splitter found"; } //$NON-NLS-0$
			this.$leading = lib.node(options.sidePanel);
			if (!this.$leading) { throw "no dom node for side panel found"; } //$NON-NLS-0$
			this.$trailing = lib.node(options.mainPanel);
			if (!this.$trailing) { throw "no dom node for main panel found"; } //$NON-NLS-0$

			this._tracking = false;
			this._animationDelay = 501;  // longer than CSS transitions in layout.css
			this._collapseTrailing = options.closeReversely || false;
			this._proportional = options.proportional || false;

			this._prefix = "/orion/splitter/" + (this.$splitter.id || document.body.id || "");  //$NON-NLS-0$
			
			if (options.toggle) {
				this._thumb = document.createElement("div"); //$NON-NLS-0$
				this.$splitter.appendChild(this._thumb);
				this._thumb.classList.add("splitThumb"); //$NON-NLS-0$
				if (this._vertical) {
					this._thumb.classList.add(this._collapseTrailing ? "splitVerticalThumbDownLayout" : "splitVerticalThumbUpLayout"); //$NON-NLS-1$ //$NON-NLS-0$
				} else {
					if (document.dir == "rtl") { /* BDL */
						this._thumb.classList.add(this._collapseTrailing ? "splitThumbLeftLayout" : "splitThumbRightLayout"); //$NON-NLS-1$ //$NON-NLS-0$
					}
					else {
						this._thumb.classList.add(this._collapseTrailing ? "splitThumbRightLayout" : "splitThumbLeftLayout"); //$NON-NLS-1$ //$NON-NLS-0$
					}
				}
			}

			this.$splitter.classList.add("split"); //$NON-NLS-0$
			lib.setSafeAttribute(this.$splitter, "role", "separator");
			
			// Initialize for the current orientation / collapse direction
			var orientationStr = util.readSetting(this._prefix+"/orientation"); //$NON-NLS-0$
			if (orientationStr) {
				var orientation = orientationStr === "vertical" ? ORIENTATION_VERTICAL : ORIENTATION_HORIZONTAL; //$NON-NLS-0$
			} else {
				orientation = options.vertical ? ORIENTATION_VERTICAL : ORIENTATION_HORIZONTAL;
			}
			this.setOrientation(orientation);
			
			// aria defines orientation as attribute of splitter itself (i.e. opposite of direction of movement)
			lib.setSafeAttribute(this.$splitter, "aria-orientation", orientation === ORIENTATION_VERTICAL ? "horizontal" : "vertical");
			
			if (util.isIOS || util.isAndroid) {
				this.$splitter.addEventListener("touchstart", this._touchStart.bind(this), false); //$NON-NLS-0$
				if (this._thumb) {
					this._thumb.addEventListener("touchstart", this._touchStart.bind(this), false); //$NON-NLS-0$
				}
				this.$splitter.addEventListener("touchmove", this._touchMove.bind(this), false); //$NON-NLS-0$
				this.$splitter.addEventListener("touchend", this._touchEnd.bind(this), false); //$NON-NLS-0$
			} else {
				this.$splitter.addEventListener("mousedown", this._mouseDown.bind(this), false); //$NON-NLS-0$
				window.addEventListener("mouseup", this._mouseUp.bind(this), false); //$NON-NLS-0$
				
				// Keyboard support
				this.$splitter.addEventListener("keydown", this._keyDown.bind(this), false); //$NON-NLS-0$
				this.$splitter.addEventListener("focus", this._focusGained.bind(this), false); //$NON-NLS-0$
				this.$splitter.addEventListener("blur", this._focusLost.bind(this), false); //$NON-NLS-0$
			}
			window.addEventListener("resize", this._resize.bind(this), false);  //$NON-NLS-0$
		},
		isClosed: function() {
			return this._closed;
		},
		getOrientation: function() {
			return this._vertical ? ORIENTATION_VERTICAL : ORIENTATION_HORIZONTAL;
		},		
		setOrientation: function(value, force) {
			var vertical = value === ORIENTATION_VERTICAL;
			if (vertical === this._vertical && !force) {
				return;
			}

			this._vertical = vertical;

			// Store the orientation
			var orientationStr = this._vertical ? "vertical" : "horizontal"; //$NON-NLS-1$ //$NON-NLS-0$
			util.saveSetting(this._prefix+"/orientation", orientationStr); //$NON-NLS-0$

			// Set up the CSS styling
			this.$splitter.style.position = "absolute"; //$NON-NLS-0$
			this.$trailing.style.position = "absolute"; //$NON-NLS-0$
			this.$leading.style.position = "absolute"; //$NON-NLS-0$

			// We need a different storage area for the vertical value in non-proportional layouts
			this._offsetStorageLabel = "/offset"; //$NON-NLS-0$
			if (this._vertical && !this._proportional) {
				this._offsetStorageLabel = "/offsetY"; //$NON-NLS-0$
			}
			
			if (this._vertical) {
				this.$splitter.classList.remove("splitLayout"); //$NON-NLS-0$
				this.$splitter.classList.add("splitVerticalLayout"); //$NON-NLS-0$
				
				// Set up for vertical calculations
				this._topLeft = "top"; //$NON-NLS-0$
				this._bottomRight = "bottom"; //$NON-NLS-0$
				this._widthHeight = "height"; //$NON-NLS-0$
			} else {
				this.$splitter.classList.remove("splitVerticalLayout"); //$NON-NLS-0$
				this.$splitter.classList.add("splitLayout"); //$NON-NLS-0$

				// Set up for vertical calculations
				this._topLeft = "left"; //$NON-NLS-0$
				this._bottomRight = "right"; //$NON-NLS-0$
				this._widthHeight = "width"; //$NON-NLS-0$
			}

			// Grab the initial position *before* hacking on the layout
			this._initializeFromStoredSettings();
			
			// Set up the style constants we need
			this._setStyleConstants();
			
			// 'Constants' (i.e. things we don't set to adjust for the offset)
			if (!this._collapseTrailing) {
				if (document.dir == "rtl") { /* BDL */
					this.$splitter.style[this._topLeft] = "auto"; //$NON-NLS-0$
					this.$leading.style[this._topLeft] = "auto"; //$NON-NLS-0$
					this.$leading.style[this._bottomRight] = "0px"; //$NON-NLS-0$
					this.$trailing.style[this._topLeft] = "0px"; //$NON-NLS-0$					
				}
				else {
					this.$splitter.style[this._bottomRight] = "auto"; //$NON-NLS-0$
					this.$leading.style[this._topLeft] = "0px"; //$NON-NLS-0$
					this.$leading.style[this._bottomRight] = "auto"; //$NON-NLS-0$					
				}

				this.$trailing.style[this._widthHeight] = "auto"; //$NON-NLS-0$
				this.$trailing.style[this._bottomRight] = "0px"; //$NON-NLS-0$
			} else {
				this.$splitter.style[this._topLeft] = "auto"; //$NON-NLS-0$
				
				this.$leading.style[this._topLeft] = "0px"; //$NON-NLS-0$
				this.$leading.style[this._widthHeight] = "auto"; //$NON-NLS-0$
				
				this.$trailing.style[this._topLeft] = "auto"; //$NON-NLS-0$
				this.$trailing.style[this._bottomRight] = "0px"; //$NON-NLS-0$
			}

			if (this._thumb) {
				var classList = this._thumb.classList;
				if (this._vertical) {
					classList.remove(this._collapseTrailing ? "splitThumbRightLayout" : "splitThumbLeftLayout"); //$NON-NLS-1$ //$NON-NLS-0$
					classList.add(this._collapseTrailing ? "splitVerticalThumbDownLayout" : "splitVerticalThumbUpLayout"); //$NON-NLS-1$ //$NON-NLS-0$
				} else {
					classList.remove(this._collapseTrailing ? "splitVerticalThumbDownLayout" : "splitVerticalThumbUpLayout"); //$NON-NLS-1$ //$NON-NLS-0$
					if (document.dir == "rtl") { /* BDL */
						classList.add(this._collapseTrailing ? "splitThumbLeftLayout" : "splitThumbRightLayout"); //$NON-NLS-1$ //$NON-NLS-0$
					}
					else {
						classList.add(this._collapseTrailing ? "splitThumbRightLayout" : "splitThumbLeftLayout"); //$NON-NLS-1$ //$NON-NLS-0$
					}
				}
			}

			if (this._closed) {
				this._closed = false;        // _thumbDown will toggle it, so turn it off and then call _thumbDown.
				this._thumbDown(true, true); // do not animate. do not persist the initial state
			} else {
				this._adjustToOffset();
			}
			
			this._resize();
			
			// Finally, ensure that everything is visible
			this.$splitter.style.visibility = "visible"; //$NON-NLS-0$
			this.$trailing.style.display = "block"; //$NON-NLS-0$
			this.$leading.style.display = "block"; //$NON-NLS-0$
		},
		resize: function() {
			this._resize();
		},

		_setStyleConstants: function() {
			if (this._vertical) {
				this.$splitter.style.left = ""; //$NON-NLS-0$
				this.$splitter.style.right = ""; //$NON-NLS-0$
				
				// We own the width / height of both panes
				this.$leading.style.left = "auto"; //$NON-NLS-0$
				this.$leading.style.right = "auto"; //$NON-NLS-0$
				this.$leading.style.width = "100%"; //$NON-NLS-0$
				this.$trailing.style.left = "auto"; //$NON-NLS-0$
				this.$trailing.style.right = "auto"; //$NON-NLS-0$
				this.$trailing.style.width = "100%"; //$NON-NLS-0$
			} else {
				this.$splitter.style.top = ""; //$NON-NLS-0$
				this.$splitter.style.bottom = ""; //$NON-NLS-0$
				
				// We own the width / height of both panes
				this.$leading.style.top = "auto"; //$NON-NLS-0$
				this.$leading.style.bottom = "auto"; //$NON-NLS-0$
				this.$leading.style.height = "100%"; //$NON-NLS-0$
				this.$trailing.style.top = "auto"; //$NON-NLS-0$
				this.$trailing.style.bottom = "auto"; //$NON-NLS-0$
				this.$trailing.style.height = "100%"; //$NON-NLS-0$
			}
		},
		
		/**
		 * Toggle the open/closed state of the side panel.
		 */
		toggleSidePanel: function() {
			this._thumbDown();
		},

		/**
		 * Close the side panel.  This function has no effect if the side panel is already closed.
		 */
		openSidePanel: function() {
			if (!this._closed) {
				this._thumbDown();
			}
		},
		/**
		 * Adds an event listener for resizing the main and side panels.
		 * @param {Function} listener The function called when a resize occurs.  The DOM node that has
		 * been resized is passed as an argument.
		 *
		 * @deprecated use addEventListener instead
		 */
		addResizeListener: function(listener) {
			this.addEventListener("resize", function(event) { //$NON-NLS-0$
				listener(event.node);
			});
		},

		/*
		 * We use local storage vs. prefs because we don't presume the user wants the same window positioning across browsers and devices.
		 */
		_initializeFromStoredSettings: function() {
			var closedState = util.readSetting(this._prefix+"/toggleState"); //$NON-NLS-0$
			if (typeof closedState === "string") { //$NON-NLS-0$
				this._closed = closedState === "closed"; //$NON-NLS-0$
			} else {
				this._closed = this._closeByDefault;
			}
			
			// Set the initial value for the splitter's width/height
			this._adjustSplitterSize();

			var pos = util.readSetting(this._prefix+this._offsetStorageLabel);
			if (pos) {
				this._offset = parseInt(pos, 10);
				if (this._proportional) {
					this._offset = Math.max(0, Math.min(100 - this._splitterSize, this._offset));
				}
			} else {
				// Use the current splitter location
				var rect = lib.bounds(this.$splitter);
				this._offset = this._adjustOffset(rect[this._topLeft]);
			}
		},

		_adjustSplitterSize: function() {
			// Size in pixels
			var rect = lib.bounds(this.$splitter);
			this._splitterSize = rect[this._widthHeight];
			
			// Make proportional if necessary
			if (this._proportional) {
				var pRect = lib.bounds(this.$splitter.parentNode);
				this._splitterSize = this._splitterSize / (pRect[this._widthHeight] / 100);
			}			
		},
		
		/*
		 * Takes a value that represents the desired left / top position for the
		 * splitter and adjusts based on which side collapses. It then turns the value into
		 * a ratio if the splitter is proportional.
		 */
		_adjustOffset: function(newOffset) {
			var parentRect = lib.bounds(this.$splitter.parentNode);
			if (this._collapseTrailing) {
				var adjustment = newOffset + this._splitterSize;
				newOffset = parentRect[this._widthHeight] - (adjustment - parentRect[this._topLeft]);
			} else {
				if (document.dir == "rtl") { /* BDL */
					var adjustment = newOffset + this._splitterSize;
					newOffset = parentRect[this._widthHeight] - (adjustment - parentRect[this._topLeft]);
				}
				else {
					newOffset = newOffset - parentRect[this._topLeft];
				}
			}
			
			if (this._proportional) {
				newOffset = newOffset / (parentRect[this._widthHeight] / 100);
			}
			
			return newOffset;
		},

		_calcSplitterPercentage: function() {
			var lRect = lib.bounds(this.$leading);
			var tRect = lib.bounds(this.$trailing);
			
			if (this._vertical) {
				var height = lRect.height + tRect.height;
				return height === 0 ? -1 : lRect.height / height;
			}
			var width = lRect.width + tRect.width;
			return width === 0 ? -1 : lRect.width / width;
		},
		
		_adjustToOffset: function() {
			if (this._offset < 0) {
				this._offset = 0;
			}
			
			var suffix = this._proportional ? "%" : "px"; //$NON-NLS-1$ //$NON-NLS-0$
			
			if (!this._collapseTrailing) {
				if (document.dir == "rtl") { /* BDL */
					this.$splitter.style[this._bottomRight] = this._offset + suffix;
					this.$leading.style[this._widthHeight] = this._offset + suffix;
					this.$trailing.style[this._bottomRight] = (this._offset + this._splitterSize) + suffix;
				}
				else
				{
					this.$splitter.style[this._topLeft] = this._offset + suffix;
					this.$leading.style[this._widthHeight] = this._offset + suffix;
					this.$trailing.style[this._topLeft] = (this._offset + this._splitterSize) + suffix;
				}
				
				// Hide the DIV if it's zero sized
				this.$leading.style.visibility = this._offset === 0 ? "hidden" : "visible"; //$NON-NLS-1$ //$NON-NLS-2$
			} else {
				this.$splitter.style[this._bottomRight] = this._offset + suffix;
				this.$leading.style[this._bottomRight] = (this._offset + this._splitterSize) + suffix;
				this.$trailing.style[this._widthHeight] = this._offset + suffix;
				
				// Hide the DIV if it's zero sized
				this.$trailing.style.visibility = this._offset === 0 ? "hidden" : "visible"; //$NON-NLS-1$ //$NON-NLS-2$
			}
			
			var pct = this._calcSplitterPercentage();
			if (pct === -1) {
				var parentRect = lib.bounds(this.$splitter.parentNode);
				pct = this._offset / parentRect[this._widthHeight];
			}
			lib.setSafeAttribute(this.$splitter, "aria-valuenow", Math.round(pct*100));
		},

		_resize: function() {
			if (this.$splitter.style.display === "none") return; //$NON-NLS-0$
			
			if (this._proportional) {
				this._adjustSplitterSize();
				this._adjustToOffset();
			}
			
			this._notifyResizeListeners(this.$trailing);
			this._notifyResizeListeners(this.$leading);
		},

		_notifyResizeListeners: function(node) {
			this.dispatchEvent({type: "resize", node: node}); //$NON-NLS-0$
		},

		_notifyToggleListeners: function() {
			this.dispatchEvent({type: "toggle", closed: this._closed}); //$NON-NLS-0$
		},

		_thumbDown: function(noAnimation, noUpdateStorage) {
			if (!noAnimation) {
				this._addAnimation();
			}

			if (this._closed) {
				var pos = util.readSetting(this._prefix+this._offsetStorageLabel);
				this._offset = pos ? parseInt(pos, 10) : 350;
				this._closed = false;
			} else {
				util.saveSetting(this._prefix+this._offsetStorageLabel, this._offset);
				this._offset = 0;
				this._closed = true;
			}

			this._adjustToOffset();

			if (!noAnimation) {
				this._removeAnimation();
			}
			if (!noUpdateStorage) {
				util.saveSetting(this._prefix+"/toggleState", this._closed ? "closed" : null);  //$NON-NLS-1$  //$NON-NLS-0$
				metrics.logEvent("preferenceChange", "splitterClosed", this._prefix, this._closed ? 0 : 1);
			}
		},

		_removeAnimation: function() {
			// in a timeout to ensure the animations are complete.
			var self = this;
			window.setTimeout(function() {
				self.$leading.classList.remove("generalAnimation"); //$NON-NLS-0$
				self.$trailing.classList.remove("generalAnimation"); //$NON-NLS-0$
				self.$splitter.classList.remove("generalAnimation"); //$NON-NLS-0$
				
				self._resize();
			}, this._animationDelay);
		},

		_addAnimation: function() {
			this.$leading.classList.add("generalAnimation"); //$NON-NLS-0$
			this.$trailing.classList.add("generalAnimation"); //$NON-NLS-0$
			this.$splitter.classList.add("generalAnimation"); //$NON-NLS-0$
		},
		
		_down: function() {
			this.$splitter.classList.add("splitTracking"); //$NON-NLS-0$
			this.$trailing.classList.add("panelTracking"); //$NON-NLS-0$
			this.$leading.classList.add("panelTracking"); //$NON-NLS-0$
		},
		
		_move: function(clientX, clientY) {
			var pos = this._vertical ? clientY : clientX;
			
			// Try to center the cursor on the new splitter pos
			var rect = lib.bounds(this.$splitter);
			var offset = rect[this._widthHeight] / 2;
			if (this._collapseTrailing) {
				this._offset = this._adjustOffset(pos + offset);
			} else {
				this._offset = this._adjustOffset(pos - offset);
			}
			
			this._adjustToOffset();	
			
			this._notifyResizeListeners(this.$trailing);
			this._notifyResizeListeners(this.$leading);
		},
		
		_up: function() {
			this.$splitter.classList.remove("splitTracking"); //$NON-NLS-0$
			this.$trailing.classList.remove("panelTracking"); //$NON-NLS-0$
			this.$leading.classList.remove("panelTracking"); //$NON-NLS-0$

			var curState = this._closed;
			
			// if the user dragged the splitter closed or open capture this
			if (this._offset > 0) {
				// Store the current position
				util.saveSetting(this._prefix+this._offsetStorageLabel, this._offset);
				this._closed = false;
			} else {
				this._closed = true;
			}
			
			// Update the state if necessary
			if (curState !== this._closed) {
				util.saveSetting(this._prefix+"/toggleState", this._closed ? "closed" : null);  //$NON-NLS-1$  //$NON-NLS-0$
				metrics.logEvent("preferenceChange", "splitterClosed", this._prefix, this._closed ? 0 : 1);
			}
		},

		_mouseDown: function(event) {
			if (event.target === this._thumb) {
				lib.stop(event);
				return this._thumbDown();
			}
			if (this._tracking) {
				return;
			}
			this._down(event);
			this._tracking = this._mouseMove.bind(this);
			window.addEventListener("mousemove", this._tracking); //$NON-NLS-0$
			lib.setFramesEnabled(false);
			lib.stop(event);
		},

		_mouseMove: function(event) {
			if (this._tracking) {
				this._move(event.clientX, event.clientY);
				
				this._resize();
			}
		},

		_mouseUp: function(event) {
			if (this._tracking) {
				lib.setFramesEnabled(true);
				window.removeEventListener("mousemove", this._tracking); //$NON-NLS-0$
				this._tracking = null;
				this._up();
				lib.stop(event);
			}
		},

		_keyDown: function(evt) {
			var rect = lib.bounds(this.$splitter);

			if (evt.keyCode === lib.KEY.UP && this._vertical) {
				this._move(rect.left, rect.top - 25);
			} else if (evt.keyCode === lib.KEY.DOWN && this._vertical) {
				this._move(rect.left, rect.top + 25);
			} else if (evt.keyCode === lib.KEY.LEFT && !this._vertical) {
				this._move(rect.left - 25, rect.top);
			} else if (evt.keyCode === lib.KEY.RIGHT && !this._vertical) {
				this._move(rect.left + 25, rect.top);
			} else if (evt.keyCode === lib.KEY.ENTER) {
				if (this._thumb) {
					this._thumbDown();
				}
			} else if (evt.keyCode === lib.KEY.ESCAPE) {
				if (!lib.returnFocus(this.$splitter, this._previousActiveElement)) {
					// put the focus on the 'primary' pane if previous active element is not available
					var primaryPane = this._thumb && !this._collapseTrailing ? this.$trailing : this.$leading;
					var toFocus = lib.firstTabbable(primaryPane);
					if (toFocus) {
						toFocus.focus();
					}
				}
			}
		},

		_focusLost: function(evt) {
			// Ensure that the splitter can't get focus
			this.$splitter.tabIndex = "-1";
		},

		_focusGained: function(evt) {
			this._previousActiveElement = evt.relatedTarget;
		},
		
		_touchStart: function(event) {
			var touches = event.touches;
			if (touches.length === 1) {
				lib.stop(event);
				if (event.target === this._thumb) {
					return this._thumbDown();
				}
				this._down(event);
				this._touching = true;
			}
		},
		
		_touchMove: function(event) {
			if (this._touching) {
				var touches = event.touches;
				if (touches.length === 1) {
					var touch = touches[0];
					this._move(touch.clientX, touch.clientY);
				}
			}
		},
		
		_touchEnd: function(event) {
			var touches = event.touches;
			if (touches.length === 0) {
				this._touching = false;
				this._up();
			}
		}
	};
	Splitter.prototype.constructor = Splitter;
	//return the module exports
	return {
		Splitter: Splitter,
		ORIENTATION_HORIZONTAL: ORIENTATION_HORIZONTAL,
		ORIENTATION_VERTICAL: ORIENTATION_VERTICAL
	};
});

/*******************************************************************************
 * @license
 * Copyright (c) 2013, 2019 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
/*eslint-env browser, amd*/
define('orion/keyAssist',[
	'i18n!orion/nls/messages',
	'orion/webui/littlelib',
	'orion/keyBinding',
	'orion/commands',
	'orion/metrics',
	'orion/uiUtils',
	'orion/util'
], function (messages, lib, keyBinding, mCommands, metrics, UIUtil, util) {

	function KeyAssistPanel(options) {
		this.commandRegistry = options.commandRegistry;
		this.create();
		this._filterString = "";
		this._providers = [];
	}
	KeyAssistPanel.prototype = {
		addProvider: function(provider) {
			if (this._providers.indexOf(provider) === -1) {
				this._providers.push(provider);
			}
		},
		create: function () {
			var keyAssistDiv = this._keyAssistDiv = document.createElement("div"); //$NON-NLS-1$
			keyAssistDiv.id = "keyAssist"; //$NON-NLS-1$
			keyAssistDiv.style.display = "none"; //$NON-NLS-1$
			keyAssistDiv.classList.add("keyAssistFloat"); //$NON-NLS-1$
			lib.setSafeAttribute(keyAssistDiv, "role", "dialog");
			lib.setSafeAttribute(keyAssistDiv, "aria-modal", "true");
			lib.setSafeAttribute(keyAssistDiv, "aria-label", messages["Key Bindings"]);

			var keyAssistInput = this._keyAssistInput = document.createElement("input"); //$NON-NLS-1$
			keyAssistInput.classList.add("keyAssistInput"); //$NON-NLS-1$
			keyAssistInput.type = "text"; //$NON-NLS-1$
			lib.setSafeAttribute(keyAssistInput, "aria-label", messages["Filter bindings:"]);
			keyAssistInput.placeholder = messages["Filter bindings"]; //$NON-NLS-1$
			lib.setSafeAttribute(keyAssistInput, "role", "combobox");
			lib.setSafeAttribute(keyAssistInput, "aria-haspopup", "grid");
			lib.setSafeAttribute(keyAssistInput, "aria-expanded", "true");
			lib.setSafeAttribute(keyAssistInput, "aria-autocomplete", "list");
			lib.setSafeAttribute(keyAssistInput, "aria-controls", "keyAssistList");
			keyAssistDiv.appendChild(keyAssistInput);

			var keyAssistContents = this._keyAssistContents = document.createElement("div"); //$NON-NLS-1$
			keyAssistContents.classList.add("keyAssistContents"); //$NON-NLS-1$
			if (util.isIOS || util.isAndroid) {
				keyAssistContents.style.overflowY = "auto"; //$NON-NLS-1$
			}
			keyAssistDiv.appendChild(keyAssistContents);
			var keyAssistTable = this._keyAssistTable = document.createElement('table'); //$NON-NLS-1$
			lib.setSafeAttribute(keyAssistTable, "role", "grid");
			lib.setSafeAttribute(keyAssistTable, "aria-label", messages["Bindings"]);
			keyAssistTable.id = "keyAssistList"; //$NON-NLS-1$
			keyAssistTable.classList.add("keyAssistList"); //$NON-NLS-1$
			keyAssistContents.appendChild(keyAssistTable);
			document.body.appendChild(keyAssistDiv);
			
			keyAssistInput.addEventListener("keydown", function (e) { //$NON-NLS-1$
				this._keyDown(e);
			}.bind(this));
			keyAssistTable.addEventListener("keydown", function (e) { //$NON-NLS-1$
				this._keyDown(e);
			}.bind(this));
			keyAssistTable.addEventListener("focus", function (e) { //$NON-NLS-1$
				this.selectRow(this._selectedIndex !== -1 ? this._selectedIndex : 0);
			}.bind(this));
			keyAssistInput.addEventListener("input", function (e) { //$NON-NLS-1$
				this.filterChanged();
			}.bind(this));
			keyAssistContents.addEventListener(util.isFirefox ? "DOMMouseScroll" : "mousewheel", function (e) { //$NON-NLS-2$ //$NON-NLS-1$
				this._scrollWheel(e);
			}.bind(this));
			keyAssistDiv.addEventListener("keydown", function (e) { //$NON-NLS-1$
				if (e.keyCode === lib.KEY.ESCAPE) {
					this.hide();
				}
			}.bind(this));
			lib.addAutoDismiss([keyAssistDiv], function () {
				this.hide();
			}.bind(this));
			
			if (this.commandRegistry) {
				this.commandRegistry.addEventListener("bindingChanged", function(args) {
					this.handleBindingChange(args);
				}.bind(this));
			}
		},
		handleBindingChange: function(args) {
			if (!this.isVisible()) {
				return;
			}
			
			var rows = this._keyAssistTable.querySelectorAll(".keyAssistItem"), row; //$NON-NLS-1$
			for (var i=0; i<rows.length; i++) {
				var row = rows[i];
				if (row.cmdID !== args.id)
					continue;
					
				// ensure we're finding the correct row
				if (JSON.stringify(args.prevBinding) === JSON.stringify(row.curBinding)) {
					// Update the binding showm in the table
					var bindingStr = args.newBinding ? UIUtil.getUserKeyString(args.newBinding) : "---"; //$NON-NLS-1$
					row.childNodes[1].firstChild.textContent = bindingStr;
					row.curBinding = args.newBinding;							
				}
			}
		},
		createContents: function () {
			var table = this._keyAssistTable;
			lib.empty(table);
			this._selectedIndex = -1;
			this._selectedRow = null;
			this._keyAssistContents.scrollTop = 0;
			this._idCount = 0;
			lib.setSafeAttribute(this._keyAssistInput, "aria-activedescendant", "");
			for (var i=0; i<this._providers.length; i++) {
				this._providers[i].showKeyBindings(this);
			}
			this.createHeader(messages["Global"], "GlobalScope"); //$NON-NLS-0$
			this.commandRegistry.showKeyBindings(this);
		},
		createItem: function (binding, name, cmdID, execute) {
			var bindingString = binding ? UIUtil.getUserKeyString(binding) : messages["NoBinding"];
			if (this._filterString) {
				var s = this._filterString.toLowerCase(),
					insensitive;
				if (s !== this._filterString) {
					s = this._filterString;
					insensitive = function (str) {
						return str;
					};
				} else {
					insensitive = function (str) {
						return str.toLowerCase();
					};
				}
				if (insensitive(name).indexOf(s) === -1 && insensitive(bindingString).indexOf(s) === -1 && insensitive(this._lastHeader).indexOf(s) === -1) {
					return;
				}
			}
			var row = this._keyAssistTable.insertRow(-1);
			row.id = "keyAssist-keyBinding-" + this._idCount++; //$NON-NLS-1$
			lib.setSafeAttribute(row, "role", "row");
			row.cmdID = cmdID;
			row._execute = execute;
			row.curBinding = binding;
			row.classList.add("keyAssistItem"); //$NON-NLS-1$
			row.addEventListener("click", function (e) { //$NON-NLS-1$
				this._selectedRow = row;
				this.execute();
				e.preventDefault();
			}.bind(this));
			
			var column = row.insertCell(-1);
			column.classList.add("keyAssistName"); //$NON-NLS-1$
			column.headers = this._lastHeaderID; //$NON-NLS-0$
			lib.setSafeAttribute(column, "role", "gridcell");
			column.appendChild(document.createTextNode(name));
			
			column = row.insertCell(-1);
			column.classList.add("keyAssistAccel"); //$NON-NLS-1$
			column.headers = this._lastHeaderID; //$NON-NLS-0$
			lib.setSafeAttribute(column, "role", "gridcell");
			var bindingSpan = document.createElement("span"); //$NON-NLS-1$
			bindingSpan.textContent = bindingString;
			column.appendChild(bindingSpan);
			
			column = row.insertCell(-1);
			column.classList.add("keyAssistActions"); //$NON-NLS-1$
			column.headers = this._lastHeaderID; //$NON-NLS-0$
			var eb = document.createElement("button"); //$NON-NLS-1$
			eb.tabIndex = -1;
			eb.classList.add("keyAssistEditButton"); //$NON-NLS-1$
			eb.classList.add("orionButton"); //$NON-NLS-1$
			eb.classList.add("commandImage"); //$NON-NLS-1$
			var span = document.createElement("span"); //$NON-NLS-0$
			span.classList.add("core-sprite-edit"); //$NON-NLS-1$
			eb.appendChild(span);
			lib.setSafeAttribute(eb, "aria-label", messages["Edit"]);
			//eb.textContent = "E"; //$NON-NLS-1$
			eb.addEventListener("click", function(evt) {
				lib.stop(evt);
				this.editBinding(row);
			}.bind(this));
			column.appendChild(eb);
		},
		editBinding: function(row) {
			var formatKBEdit = function(e) {
				this._keyCode = e.keyCode;
				this._altDown = e.altKey;
				this._ctrlDown = util.isMac ? e.metaKey : e.ctrlKey;
				this._shiftDown = e.shiftKey;
				this._commandDown = util.isMac ? e.ctrlKey : e.metaKey;
				
				var testBinding = new keyBinding.KeyStroke(this._keyCode, this._ctrlDown, this._shiftDown, this._altDown, this._commandDown);
				var bindingString = UIUtil.getUserKeyString(testBinding);
				this.keyAssistKBEdit.value = bindingString;
			}.bind(this);

			var clear = function() {
				this.keyAssistKBEdit.value = "";
				this.bindingField.removeChild(this.keyAssistKBEdit);
				this.bindingField.firstChild.style.display = "block"; //$NON-NLS-1$
				
				// Delete transient state vars
				delete this.keyAssistKBEdit;
				delete this.bindingField;
				delete this._keyCode;
				
				this._editingABinding = false;
			}.bind(this);
			
			// Clear any existing binding edit
			if (this._editingABinding) {
				clear();
			}
			
			// Move the focus to this row
			var rows = this._keyAssistTable.querySelectorAll(".keyAssistItem"); //$NON-NLS-1$
			for(var i = 0; i < rows.length; i++) {
				if (rows[i] === row) {
					this.selectRow(i, rows);
					break;
				}
			}
			
			// Create the edit control
			var keyAssistKBEdit = this.keyAssistKBEdit = document.createElement("input"); //$NON-NLS-1$
			keyAssistKBEdit.id = "keyAssistInput"; //$NON-NLS-1$
			keyAssistKBEdit.type = "text"; //$NON-NLS-1$
			keyAssistKBEdit.placeholder = messages["BindingPrompt"];
			keyAssistKBEdit.classList.add("keyAssistBindingInput"); //$NON-NLS-1$

			keyAssistKBEdit.addEventListener("click", function(e) {
				e.stopPropagation();
			}.bind(this));
			keyAssistKBEdit.addEventListener("keydown", function (e) { //$NON-NLS-1$
				// Skip modifiers...
				if (e.keyCode === lib.KEY.ALT || e.keyCode === lib.KEY.SHIFT || e.keyCode === lib.KEY.CONTROL || e.keyCode === lib.KEY.COMMAND) {
					// Intentional NO-OP
				}
				else if (e.keyCode === lib.KEY.ENTER) {
					if (this._keyCode) {
						// Ensure there's a keyCode
						if (this._keyCode) {
							// remember the override
							var newBinding = new keyBinding.KeyStroke(this._keyCode, this._ctrlDown, this._shiftDown, this._altDown, this._commandDown);
							this.commandRegistry.createBindingOverride(row.cmdID, newBinding, row.curBinding);
							metrics.logEvent("KeyBinding", "Changed", row.cmdID, JSON.stringify(newBinding)); //$NON-NLS-1$ //$NON-NLS-2$
								
							clear();
							this._keyAssistTable.focus();
						}
						
					}
				} else if (e.keyCode === lib.KEY.ESCAPE) {
					clear();
					this._keyAssistInput.focus();
				} else {
					formatKBEdit(e);
				}
				lib.stop(e);
			}.bind(this));
			
			var bindingField = this.bindingField = row.childNodes[1];
			bindingField.firstChild.style.display = "none"; //$NON-NLS-1$

			// Make the edit control the correct width to avoid resizing the panel
			var pl = lib.pixelValueOf(bindingField, "padding-left"); //$NON-NLS-1$
			var pr = lib.pixelValueOf(bindingField, "padding-right"); //$NON-NLS-1$
			var bl = lib.pixelValueOf(bindingField, "border-left"); //$NON-NLS-1$
			var br = lib.pixelValueOf(bindingField, "border-right"); //$NON-NLS-1$
			var rect = lib.bounds(bindingField);
			var calculatedWidth = rect.width - (pl + pr + bl + br);
			
			// Ensure there's enough space to show the new binding
			calculatedWidth = calculatedWidth < 135 ? 135 : calculatedWidth;
			
			keyAssistKBEdit.style.width = calculatedWidth + "px"; //$NON-NLS-1$
			bindingField.appendChild(keyAssistKBEdit);
			keyAssistKBEdit.focus();
			this._editingABinding = true;
		},
		createHeader: function (name, id) {
			this._lastHeader = name;
			this._lastHeaderID = id;
			var rowgroup = document.createElement("tbody");
			this._keyAssistTable.appendChild(rowgroup);
			var row = rowgroup.insertRow(-1);
			row.classList.add("keyAssistSection"); //$NON-NLS-0$
			var column = document.createElement('th'); //$NON-NLS-0$
			column.id = id;
			column.colSpan = 3;
			column.scope = "rowgroup"; //$NON-NLS-0$
			var heading = document.createElement("h2"); //$NON-NLS-0$
			lib.setSafeAttribute(heading, "role", "presentation");
			heading.appendChild(document.createTextNode(name));
			column.appendChild(heading);
			row.appendChild(column);
		},
		execute: function () {
			window.setTimeout(function () {
				this.hide();
				var row = this._selectedRow;
				this._selectedRow = null;
				if (row && row._execute) {
					row._execute();
				}
			}.bind(this), 0);
		},
		filterChanged: function () {
			if (this._timeout) {
				window.clearTimeout(this._timeout);
			}
			this._timeout = window.setTimeout(function () {
				this._timeout = null;
				var value = this._keyAssistInput.value;
				if (this._filterString !== value) {
					this._filterString = value;
					this.createContents();
				}
			}.bind(this), 100);
		},
		hide: function () {
			if (!this.isVisible()) {
				return;
			}
			var keyAssistDiv = this._keyAssistDiv;
			lib.returnFocus(keyAssistDiv, this._previousActiveElement, function() {
				keyAssistDiv.style.display = "none"; //$NON-NLS-1$
			});
			this._previousActiveElement = null;
		},
		isVisible: function () {
			return this._keyAssistDiv.style.display === "block"; //$NON-NLS-1$
		},
		removeProvider: function(provider) {
			var index = this._providers.indexOf(provider);
			if (index !== -1) {
				this._providers.splice(index, 1);
			}
		},
		select: function (forward) {
			var rows = this._keyAssistTable.querySelectorAll(".keyAssistItem"), row; //$NON-NLS-1$
			if (rows.length === 0) {
				this._selectedIndex = -1;
				return;
			}
			var selectedIndex = this._selectedIndex;
			selectedIndex += forward ? 1 : -1;
			selectedIndex %= rows.length;
			if (selectedIndex < 0) {
				selectedIndex = rows.length - 1;
			}
			
			// Select the row (if any)
			this.selectRow(selectedIndex, rows);
		},
		selectRow: function(index, rows) {
			var row, editButton;
			if (!rows) {
				rows = this._keyAssistTable.querySelectorAll(".keyAssistItem");
			}
			if (this._selectedIndex !== -1) {
				row = rows[this._selectedIndex];
				row.classList.remove("selected"); //$NON-NLS-1$
				lib.setSafeAttribute(row, "aria-selected", "false");
				editButton = row.querySelector(".keyAssistEditButton");
				if (editButton) {
					editButton.classList.remove("keyAssistEditButtonVisible"); //$NON-NLS-1$
					editButton.tabIndex = -1;
				}
				this._selectedRow = null;
			}
			
			if (index >= 0 && index < rows.length) {
				this._selectedIndex = index;
				this._selectedRow = rows[this._selectedIndex];
				row = this._selectedRow;
				row.classList.add("selected"); //$NON-NLS-1$
				lib.setSafeAttribute(row, "aria-selected", "true");
				editButton = row.querySelector(".keyAssistEditButton");
				if (editButton) {
					editButton.classList.add("keyAssistEditButtonVisible"); //$NON-NLS-1$
					editButton.tabIndex = 0;
				}
				lib.setSafeAttribute(this._keyAssistInput, "aria-activedescendant", row.id);
				this._keyAssistTable.focus();
				var rowRect = row.getBoundingClientRect();
				var parent = this._keyAssistContents;
				var rect = parent.getBoundingClientRect();
				if (row.offsetTop < parent.scrollTop) {
					if (this._selectedIndex === 0) {
						parent.scrollTop = 0;
					} else {
						row.scrollIntoView(true);
					}
				} else if (rowRect.bottom > rect.bottom) {
					row.scrollIntoView(false);
				}
			}
		},
		show: function () {
			if (this.isVisible()) {
				return;
			}
			lib.trapTabs(this._keyAssistDiv);
			this._previousActiveElement = document.activeElement;
			this._filterString = "";
			this.createContents();
			this._keyAssistContents.style.height = Math.floor(this._keyAssistDiv.parentNode.clientHeight * 0.75) + "px"; //$NON-NLS-1$
			this._keyAssistDiv.style.display = "block"; //$NON-NLS-1$
			this._keyAssistInput.value = this._filterString;
			this._keyAssistInput.focus();
			
			metrics.logEvent("KeyBinding", "Panel", "Opened"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
		},
		_keyDown: function (e) {
			if (e.keyCode === lib.KEY.DOWN) {
				this.select(true);
			} else if (e.keyCode === lib.KEY.UP) {
				this.select(false);
			} else if (e.keyCode === lib.KEY.ENTER) {
				this.execute();
			} else if (e.keyCode === lib.KEY.SPACE && this._selectedRow) {
				if (!this._editingABinding) {
					this.editBinding(this._selectedRow);
				}
			} else {
				return;
			}
			e.preventDefault();
		},
		_scrollWheel: function (e) {
			var pixelY = 0;
			if (util.isIE || util.isOpera) {
				pixelY = -e.wheelDelta;
			} else if (util.isFirefox) {
				pixelY = e.detail * 40;
			} else {
				pixelY = -e.wheelDeltaY;
			}
			var parent = this._keyAssistContents;
			var scrollTop = parent.scrollTop;
			parent.scrollTop += pixelY;
			if (scrollTop !== parent.scrollTop) {
				if (e.preventDefault) {
					e.preventDefault();
				}
				return false;
			}
		}
	};

	function createCommand(keyAssist, scopeId, commandRegistry) {
		var keyAssistCommand = new mCommands.Command({
			name: messages["Show Keys"],
			tooltip: messages["ShowAllKeyBindings"],
			id: "orion.keyAssist", //$NON-NLS-0$
			callback: function () {
				if (keyAssist.isVisible()) {
					keyAssist.hide();
				} else {
					keyAssist.show();
				}
				return true;
			}
		});
		commandRegistry.addCommand(keyAssistCommand);
		commandRegistry.registerCommandContribution(scopeId, "orion.keyAssist", 100, null, true, new keyBinding.KeyBinding(191, false, true, !util.isMac, util.isMac)); //$NON-NLS-1$ //$NON-NLS-0$
		
		return keyAssistCommand;
	}
	return {
		KeyAssistPanel: KeyAssistPanel,
		createCommand: createCommand
	};
});
/*******************************************************************************
 * @license
 * Copyright (c) 2012, 2017 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made
 * available under the terms of the Eclipse Public License v1.0
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html).
 *
 * Contributors:  IBM Corporation - initial API and implementation
 *                Casey Flynn - Google Inc
 ******************************************************************************/
/*eslint-env browser, amd*/

define('orion/widgets/themes/ThemePreferences',['orion/Deferred'], function(Deferred) {

	function ThemePreferences(preferences, themeData) {
		this._preferences = preferences;
		this._themeData = themeData;
		var themeInfo = themeData.getThemeStorageInfo();
		var that = this;
		preferences.addEventListener("changed", function (e) {
			if (e.namespace === themeInfo.storage) {
				that.apply();
			}
		});
	}

	ThemePreferences.prototype = /** @lends orion.editor.ThemePreferences.prototype */ {
		_initialize: function(themeInfo, themeData, themeVersion, prefs) {
			var d = new Deferred();
			var styles, selected;
			var versionKey = themeInfo.styleset + "Version"; //$NON-NLS-0$
			var prefsVer = prefs[versionKey];
			var currentVer = 0;
			this._themeVersion = themeVersion;
			try {
				prefsVer = parseFloat(prefsVer);
				currentVer = parseFloat(themeVersion);
			} catch (e) {
			}
			
			if (prefsVer === currentVer || prefsVer > currentVer) {
				// Version matches (or ThemeData hasn't provided an expected version). Trust prefs
				styles = prefs[themeInfo.styleset];
				selected = prefs['selected']; //$NON-NLS-0$
				if (selected) {
					selected = this._parse(selected);
				}
				this._themeVersion = prefsVer;
			} else {
				// Stale theme prefs. Overwrite everything
				styles = null;
				selected = null;
			}

			if (!styles){
				themeData.getStyles().then(function(styles) {
					prefs[themeInfo.styleset] = styles;
					prefs[versionKey] = themeVersion;
					prefs['selected'] = {};
					d.resolve(styles);
				});
			} else {
				if (!selected || selected[themeInfo.selectedKey] === undefined) {
					selected = selected || {};
					prefs['selected'] = selected; //$NON-NLS-0$
				}
				// prefs have now been updated
				prefs[versionKey] = this._themeVersion;
				d.resolve(true);
			}
			return d;
		},
		_convertThemeStylesToHierarchicalFormat: function(styles) {
			return {
				name: styles.name,
				className: styles.name,
				styles: {
					/* top-level properties */
					backgroundColor: styles.background,
					color: styles.text,
					fontFamily: styles.fontFamily,
					fontSize: styles.fontSize,

					/* from textview.css */
					textviewRightRuler: {
						borderLeft: "1px solid " + styles.annotationRuler //$NON-NLS-0$
					},
					textviewLeftRuler: {
						borderRight: "1px solid " + styles.annotationRuler //$NON-NLS-0$
					},

					split: {
						background: styles.background
					},

					/* from rulers.css */
					ruler: {
						backgroundColor: styles.annotationRuler,
						overview: {
							backgroundColor: styles.overviewRuler
						}
					},
					rulerLines: {
						even: {
							color: styles.lineNumberEven
						},
						odd: {
							color: styles.lineNumberOdd
						}
					},

					/* from annotations.css */
					annotationLine: {
						currentLine: {
							backgroundColor: styles.currentLine
						}
					},

					/* from textstyler.css */
					comment: {
						color: styles.comment
					},
					constant: {
						color: "blue" //$NON-NLS-0$
					},
					entity: {
						name: {
							color: "#7D7755", //$NON-NLS-0$
							"function": { //$NON-NLS-0$
								fontWeight: "bold", //$NON-NLS-0$
								color: "#007b78" //$NON-NLS-0$
							}
						},
						other: {
							"attribute-name": { //$NON-NLS-0$
								color: styles.attribute
							}
						}
					},
					keyword: {
						control: {
							color: styles.keyword,
							fontWeight: "bold" //$NON-NLS-0$
						},
						operator: {
							color: styles.keyword,
							fontWeight: "bold" //$NON-NLS-0$
						},
						other: {
							documentation: {
								color: "#37739f" //$NON-NLS-0$
							}
						}
					},
					markup: {
						bold: {
							fontWeight: "bold" //$NON-NLS-0$
						},
						heading: {
							color: "blue" //$NON-NLS-0$
						},
						italic: {
							fontStyle: "italic" //$NON-NLS-0$
						},
						list: {
							color: "#c04600" //$NON-NLS-0$
						},
						other: {
							separator: {
								color: "#00008F" //$NON-NLS-0$
							},
							strikethrough: {
								textDecoration: "line-through" //$NON-NLS-0$
							},
							table: {
								color: "#157B07" //$NON-NLS-0$
							}
						},
						quote: {
							color: "#314dce" //$NON-NLS-0$
						},
						raw: {
							fontFamily: "monospace" //$NON-NLS-0$
						},
						underline: {
							link: {
								textDecoration: "underline" //$NON-NLS-0$
							}
						}
					},
					meta: {
						documentation: {
							annotation: {
								color: "#37739f" //$NON-NLS-0$
							},
							tag: {
								color: "#7F7F9F" //$NON-NLS-0$
							}
						},
						tag: {
							color: styles.tag
						}
					},
					string: {
						color: styles.string
					},
					support: {
						type: {
							propertyName: {
								color: "#7F0055" //$NON-NLS-0$
							}
						}
					},
					variable: {
						language: {
							color: "#7F0055", //$NON-NLS-0$
							fontWeight: "bold" //$NON-NLS-0$
						},
						other: {
							color: "#DB0FA6" //$NON-NLS-0$
						},
						parameter: {
							color: "#CD2B65" //$NON-NLS-0$
						}
					}
				}
			};
		},
		apply: function() {
			this.setTheme();
		},
		_findStyle: function(styles, name) {
			for (var i = 0; i < styles.length; i++) {
				if (styles[i].name === name) {
					return styles[i];
				}
			}
			return null;
		},
		_getCurrentStyle: function(styles, selectedName) {
			styles = styles || [];
			var themeData = this._themeData;
			var d = new Deferred();
			var style = this._findStyle(styles, selectedName);
			if (!style) {
				themeData.getDefaultTheme().then(function(defaultTheme) {
					style = this._findStyle(styles, defaultTheme) || styles[0];
					d.resolve(style);
				}.bind(this));
			} else {
				d.resolve(style);
			}
			return  d;
		},
		_parse: function(o) {
			return typeof(o) === "string" ? JSON.parse(o) : o; //$NON-NLS-0$
		},
		getTheme: function(callback) {
			var themeData = this._themeData;
			var themeInfo = themeData.getThemeStorageInfo();
			return themeData.getThemeVersion().then(function(themeVersion) {
				return this._preferences.get(themeInfo.storage).then(function(prefs) {
					return this._initialize(themeInfo, themeData, themeVersion, prefs).then(function() {
						var selected = this._parse(prefs['selected']); //$NON-NLS-0$
						var styles = this._parse(prefs[themeInfo.styleset]), style;
						if (styles) {
							/*
							 * Convert the read theme info into the new supported format if the
							 * old format is detected.
							 */
							if (styles.length && styles[0].keyword) { /* indicates old format */
								for (var i = 0; i < styles.length; i++) {
									styles[i] = this._convertThemeStylesToHierarchicalFormat(styles[i]);
								}
							}
						}
						return this._getCurrentStyle(styles, selected[themeInfo.selectedKey]).then(function (style) {
							callback({style: style, styles: styles});
						});
					}.bind(this));
				}.bind(this));
			}.bind(this));
		},
		getProtectedThemes: function(callback) {
			return this._themeData.getProtectedThemes().then(function(protectedThemes) {
				callback(protectedThemes);
			});
		},
		setTheme: function(name, styles) {
			var themeData = this._themeData;
			var themeInfo = themeData.getThemeStorageInfo();
			return themeData.getThemeVersion().then(function(themeVersion) {
				return this._preferences.get(themeInfo.storage).then(function(prefs) {
					return this._initialize(themeInfo, themeData, themeVersion, prefs).then(function() {
						var selected = this._parse(prefs['selected']); //$NON-NLS-0$
						if (!name) {
							name = selected[themeInfo.selectedKey];
						}
						selected[themeInfo.selectedKey] = name;
						prefs['selected'] = selected; //$NON-NLS-0$
						if (styles) {
							prefs[themeInfo.styleset] = styles;
						} else {
							styles = this._parse(prefs[themeInfo.styleset]);
						}
						return this._getCurrentStyle(styles, selected[themeInfo.selectedKey]).then(function(style) {
							themeData.processSettings(style);
							var versionKey = themeInfo.styleset + "Version"; //$NON-NLS-0$
							prefs[versionKey] = this._themeVersion;
							return this._preferences.put(themeInfo.storage, prefs);
						}.bind(this));
					}.bind(this));
				}.bind(this));
			}.bind(this));

		},
		setFontSize: function(size) {
			var themeData = this._themeData;
			var themeInfo = themeData.getThemeStorageInfo();

			return themeData.getThemeVersion().then(function(themeVersion) {
				return this._preferences.get(themeInfo.storage).then(function(prefs) {
					return this._initialize(themeInfo, themeData, themeVersion, prefs).then(function() {
						var selected = this._parse(prefs['selected']); //$NON-NLS-0$
						var styles = this._parse(prefs[themeInfo.styleset]), style;
						if (styles) {
							for( var s = 0; s < styles.length; s++ ){
								styles[s].styles.fontSize = size;
							}
						}
						return this._getCurrentStyle(styles, selected[themeInfo.selectedKey]).then(function(style) {
							prefs[themeInfo.styleset] = styles;
							themeData.processSettings(style);
							return this._preferences.put(themeInfo.storage, prefs);
						}.bind(this));
					}.bind(this));
				}.bind(this));
			}.bind(this));
		}
	};

	return{
		ThemePreferences: ThemePreferences
	};
});
/*******************************************************************************
 * @license
 * Copyright (c) 2013,2014 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
 
/*eslint-env browser, amd*/
define("orion/editor/textTheme", //$NON-NLS-0$
[
	'require', //$NON-NLS-0$
	'orion/editor/eventTarget', //$NON-NLS-0$
	'orion/util' //$NON-NLS-0$
], function(require, mEventTarget, util) {
	var THEME_PREFIX = "orion-theme-"; //$NON-NLS-0$
	
	var Themes = {};

	/**
	 * Constructs a new text theme. 
	 * 
	 * @class A TextTheme is a class used to specify an editor theme.
	 * @name orion.editor.TextTheme
	 * @borrows orion.editor.EventTarget#addEventListener as #addEventListener
	 * @borrows orion.editor.EventTarget#removeEventListener as #removeEventListener
	 * @borrows orion.editor.EventTarget#dispatchEvent as #dispatchEvent
	 */
	function TextTheme(options) {
		options = options || {};
		this._document = options.document || document;
	}

	/**
	 * Gets an instance of <code>orion.editor.TextTheme</code> by name. If the name
	 * paramenter is not speficed the default text theme instance is returned.
	 * Subsequent calls of <code>getTheme</code> with the same name will return
	 * the same instance.
	 */
	TextTheme.getTheme = function(name) {
		name = name || "default"; //$NON-NLS-0$
		var theme = Themes[name];
		if (!theme) {
			theme = Themes[name] = new TextTheme();
		}
		return theme;
	};

	TextTheme.prototype = /** @lends orion.editor.TextTheme.prototype */ {
		/**
		 * Returns the theme className.
		 *
		 * @see orion.editor.TextTheme#setThemeClass
		 */
		getThemeClass: function() {
			return this._themeClass;
		},
		/**
		 * @class This object represents a style sheet for a theme manager.
		 * <p>
		 * <b>See:</b><br/>
		 * {@link orion.editor.TextTheme#setThemeClass}
		 * </p>
		 * @name orion.editor.ThemeStyleSheet
		 * 
		 * @property {String} href The href of the stylesheet
		 */
		/**
		 * Sets the theme className and style sheet.
		 * <p>
		 * If the <code>stylesheet</code> parameter is a string, it represents an inline
		 * CSS and it will be added to the document as a <i>STYLE</i> tag element.  If the
		 * <code>stylesheet</code> parameter is a <code>orion.editor.ThemeStyleSheet</code>,
		 * its href property is loaded as either a <i>STYLE</i> tag element or as a <i>LINK</i>
		 * tag element.
		 * </p>
		 * <p>
		 * Listeners of the ThemeChanged event are notify once the styled sheet is loaded
		 * into the document.
		 * </p>
		 *
		 * @param {String} className the new theme className.
		 * @param {String|orion.editor.ThemeStyleSheet} styleSheet the CSS stylesheet for the new theme className.
		 *
		 * @see orion.editor.TextTheme#getThemeClass
		 * @see orion.editor.TextTheme#onThemeChanged
		 */
		 setThemeClass: function(className, styleSheet) {
			var self = this;
			var oldThemeClass = self._themeClass;	
			self._themeClass = className;
			this._load(className, styleSheet, function() {
				self.onThemeChanged({
					type: "ThemeChanged", //$NON-NLS-0$
					oldValue: oldThemeClass,
					newValue: self.getThemeClass()
				});
			});
		},
		/**
		 * @class This is the event sent when the theme className or style sheet has changed.
		 * <p>
		 * <b>See:</b><br/>
		 * {@link orion.editor.TextTheme}<br/>
		 * {@link orion.editor.TextTheme#event:onThemeChanged}
		 * </p>
		 * @name orion.editor.ThemeChangedEvent
		 * 
		 * @property {String} oldValue The old theme clasName.
		 * @property {String} newValue The new theme className.
		 */
		/**
		 * This event is sent when the theme clasName has changed and its style sheet has been loaded in the document.
		 *
		 * @event
		 * @param {orion.editor.ThemeChangedEvent} themeChangedEvent the event
		 */
		onThemeChanged: function(themeChangedEvent) {
			return this.dispatchEvent(themeChangedEvent);
		},
		buildStyleSheet: function(themeClass, settings) {
			var convertCSSname = function(name) {
				return name.replace(this._capitalRegEx, function(match) {
					return "-" + match; //$NON-NLS-0$
				}.bind(this)).toLowerCase();
			}.bind(this);

			var parseStyles = function(object, ancestors, className, isTopLevel, result) {
				var localResult = [];
				var keys = Object.keys(object);
				keys.forEach(function(key) {
					if(key !== "isTopLevel"){
						var value = object[key];
						if (typeof(value) === "string") { //$NON-NLS-0$
							localResult.push("\t" + convertCSSname(key) + ": " + value + ";"); //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
						} else {
							if(value.isTopLevel){
								parseStyles(
									value,
									className === key ? ancestors : ancestors + (isTopLevel ? " ." : ".") + key, //$NON-NLS-1$ //$NON-NLS-0$
									className,
									true,
									result);
							}else{
								parseStyles(
									value,
									className === key ? ancestors : ancestors + (isTopLevel ? " ." : ".") + key, //$NON-NLS-1$ //$NON-NLS-0$
									className,
									false,
									result);
							}
						}
					}
				});
				if (localResult.length) {
					result.push(ancestors + (isTopLevel ? ".textview" : "") + " {"); //$NON-NLS-0$
					result.push.apply(result, localResult);
					result.push("}"); //$NON-NLS-0$
				}
			};

			var result = [""];
			parseStyles(settings.styles, "." + themeClass, settings.className, true, result); //$NON-NLS-0$
			return result.join("\n"); //$NON-NLS-0$
		},

		/**
		 * @private
		 */
		_createStyle: function(className, styleSheet, callback, link) {
			var document = this._document;
			var id = THEME_PREFIX + className;
			var node = document.getElementById(id);
			if (node) {
				if (link || node.firstChild.data === styleSheet) {
					return;
				}
				node.removeChild(node.firstChild);
				node.appendChild(document.createTextNode(styleSheet));
			} else {
				if (link) {
					node = util.createElement(document, "link"); //$NON-NLS-0$
					node.rel = "stylesheet"; //$NON-NLS-0$
					node.type = "text/css"; //$NON-NLS-0$
					node.href = styleSheet;
					node.addEventListener("load", function() { //$NON-NLS-0$
						callback();
					});
				} else {
					node = util.createElement(document, "style"); //$NON-NLS-0$
					node.appendChild(document.createTextNode(styleSheet));
				}
				node.id = id;
				var head = document.getElementsByTagName("head")[0] || document.documentElement; //$NON-NLS-0$
				head.appendChild(node);
			}
			if (!link) {
				callback();
			}
		},
		/**
		 * @private
		 */
		_load: function (className, styleSheet, callback) {
			if (!className) {
				callback();
				return;
			}
			if (typeof styleSheet === "string") { //$NON-NLS-0$
				this._createStyle(className, styleSheet, callback);
				return;
			}
			var href = styleSheet.href;
			var extension = ".css"; //$NON-NLS-0$
			if (href.substring(href.length - extension.length) !== extension) {
				href += extension;
			}
			if (/^\//.test(href) || /[a-zA-Z0-9]+:\/\//i.test(href) || !require.toUrl /* almond cannot load dynamically */) {
				this._createStyle(className, href, callback, true);
			} else {
				var self = this;
				require(["text!" + href], function(cssText) { //$NON-NLS-0$
					self._createStyle(className, cssText, callback, false);
				});
			}
		},
		_capitalRegEx: /[A-Z]/g
	};
	mEventTarget.EventTarget.addMixin(TextTheme.prototype);
	
	return {
		TextTheme: TextTheme
	};
});

/*******************************************************************************
 * @license
 * Copyright (c) 2012, 2013 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 * 
 * Contributors: Anton McConville - IBM Corporation - initial API and implementation
 * 				 Casey Flynn - Google Inc - Refactor for new styles.
 ******************************************************************************/
/*eslint-env browser, amd*/

define('orion/widgets/themes/container/ThemeSheetWriter',[],
	function() {
		function writeStyleString(themeClass, settings) {
			if (!settings || !settings.styles) {
				return "";
			}
			
			var parseStyles = function(object, ancestors, className, result) {
				if (!ancestors) {
					if (className) {
						parseStyles(object, "." + className, className, result);
					} 
					return;
				}
				var localResult = [];
				var keys = Object.keys(object);
				keys.forEach(function(key) {
					var value = object[key];
					if (typeof value === "string") {
						localResult.push("\t" + key + ": " + value + ";"); 
					} else {
						parseStyles(
							value,
							className === key ? ancestors : ancestors + " " +  key,
							className,
							result);
					}
				});
				if (localResult.length) {
					result.push(ancestors +  " {");
					result.push.apply(result, localResult);
					result.push("}");
				}
			};

			var result = [""];
			parseStyles(settings.styles, "", themeClass, result);
			return result.join("\n");
		}
		
		function ThemeSheetWriter(){}
		
		function getSheet(themeClass, settings ){
			var sheet = writeStyleString(themeClass, settings);
			return sheet;
		}
		
		ThemeSheetWriter.prototype.getSheet = getSheet;

		return{
			ThemeSheetWriter:ThemeSheetWriter
		};

	}
);
/*******************************************************************************
 * @license
 * Copyright (c) 2014 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 * 
 * Contributors: Anton McConville - IBM Corporation - initial API and implementation
 * 				 Casey Flynn - Google Inc.
 ******************************************************************************/
/*eslint-env browser, amd*/
define('orion/widgets/themes/ThemeVersion',[], function() {

	/**
	 * Version string for theme data. Please update this string whenever you change the style of a themable element.
	 */
	var THEMES_VERSION = "19.1";
	return THEMES_VERSION;
});

/*******************************************************************************
 * @license
 * Copyright (c) 2015-2017 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 * 
 * Contributors: Casey Flynn - Google Inc - initial API and implementation
 ******************************************************************************/
 /*eslint-env browser,amd*/
define('orion/widgets/themes/container/LightPage',{
	"className": "lightPage",
	"name": "Light",
	"styles": {
		"#configSection": {
			"background-color": "#FFFFFF !important",
			"color": "#000000 !important"
		},
		"#log": {
			"margin": "5px",
			"width": "calc(100% - 17px)"
		},
		".auxpane": {
			"background": "#C4C5C8 !important"
		},
		".desktopmode": {
			".selectableNavRow:hover": {
				"background-color": "rgba(60, 113, 179, 0.25)"
			}
		},
		".checkedRow": {
			"background-color": "#3C71B3 !important",
			"color": "#FFFFFF !important",
			".commandButton": {
				"border-color": "#FFFFFF",
				"color": "#FFFFFF"
			},
			".commandButton:not(.primaryButton):not([disabled]):hover": {
				"background": "rgba(60, 113, 179, 0.50)",
				"box-shadow": "0 1px 2px 0 rgb(60, 113, 179)",
				"color": "#000000"
			},
			".gitStatusIcon": {
				"color": "white !important"
			},
			".gitStatusTitle": {
				"color": "white !important"
			},
			"gitStatusIcon": {
				"color": "#FFFFFF"
			},
			"gitStatusTitle": {
				"color": "#FFFFFF"
			}
		},
		".checkedRow>td>span>a":{
			"color": "#FFFFFF !important"
		},
		".commandButton": {
			"background-color": "rgba(0, 0, 0, 0)",
			"border-width": "1px",
			"border-style": "solid",
			"border-color": "#3C71B3",
			"color": "#376FB2"
		},
		".commandButton.disabled": {
			"color": "#cdcdcd",
			"border-color": "#cdcdcd"
		},
		".commandButton.orionButton.dropdownTrigger:hover": {
			"border-color": "#ccc"
		},
		".gitCommitListSection": {
			".commandButton.orionButton.dropdownTrigger:hover": {
				"background-color": "rgba(196, 197, 200, 0.25)",
			}
		},
		".commandButton:not(.primaryButton):not([disabled]):hover": {
			"background-color": "rgba(60, 113, 179, 0.25)",
			"box-shadow": "0 1px 2px 0 rgb(60, 113, 179)",
			"color": "#000000"
		},
		".content-fixedHeight": {
			"background": "#C4C5C8 !important"
		},
		".core-sprite-error": {
			"color": "red"
		},
		".dialogTitle": {
			"background-color": "#3C71B3 !important",
			"color": "#FFFFFF !important"
		},
		".dropdownButtonWithIcon": {
			"color": "#152935 !important"
		},
		".dropdownCommandName": {
			"color": "#000000 !important"
		},
		".dropdownArrowRight" : {
			"color": "#000000 !important"
		},
		".dropdownMenu": {
			".dropdownMenuItemSelected": {
				"background": "rgba(60, 113, 179, 0.25)",
				"border-left-color": "#3C71B3"
			}
		},
		".dropdownTrigger:not(.dropdownDefaultButton)": {
			"color": "#152935 !important"
		},
		".dropdownSelection.dropdownTriggerOpen": {
			"background-color": "#CEDBEC !important"
		},
		".editorViewerHeader": {
			"background": "#F5F7FA !important",
			"color": "#152935 !important"
		},
		".filesystemName": {
			"color": "#152935 !important"
		},
		".fixedToolbarHolder": {
			"background": "#FFFFFF"
		},
		".gitCommitMessage": {
			".gitCommitMessageTopRow": {
				"border-color": "#3C71B3"
			},
			".gitCommitMore":{
				"color": "#004A60 !important"
			}
		},
		".gitCommitMessageSection": {
			"background-color": "rgba(60, 113, 179, 0.25)"
		},
		".gitCommitMore": {
			"color": "#005F88 !important"
		},
		".gitStatusIcon": {
			"color": "#3C71B3 !important"
		},
		".gitStatusSection": {
			"background-color": "rgba(60, 113, 179, 0.25)"
		},
		".gitStatusTitle": {
			"color": "#035899 !important"
		},
		".label.parameterInput": {
			"color": "#FFFFFF !important"
		},
		".launchConfigurationMenuItem.dropdownMenuItemActive": {
			"background": "#F5F7FA"
		},
		".launchConfigurationsButton": {
			".commandButton.orionButton.dropdownTrigger": {
				"color": "#FFFFFF !important"
			}
		},
		".launchConfigurationsWrapper>.launchConfigurationsButton.dropdownTrigger": {
			"background-color": "#3C71B3 !important",
			"color": "#FFFFFF !important"
		},
		".launchConfsDropdown": {
			".dropdownDefaultButton": {
				"background-color": "#3C71B3 !important",
				"color": "#FFFFFF !important"
			}
		},
		".launchConfsLabel": {
			"background-color": "#3C71B3 !important",
			"color": "#FFFFFF !important"
		},
		".liveUpdateLabel": {
			"color": "#3C71B3 !important"
		},
		".mainToolbar": {
			"background-color": "#FFFFFF",
			"color": "#152935 !important",
			".commandButton.orionButton.dropdownTrigger": {
				"border-color": "#FFFFFF",
				"color": "#000000 !important",
				".dropdownTriggerButtonLabel": {
					"color": "#FFFFFF"
				}
			},
			".commandButton.orionButton.dropdownTrigger.dropdownTriggerOpen": {
				"color": "#000000 !important"
			},
			".commandButton.orionButton.dropdownTrigger.launchConfigurationsButton": {
				".dropdownArrowDown": {
					"color": "#FFFFFF"
				}
			},
			".commandImage.dropdownTrigger": {
				"color": "rgb(21, 41, 53) !important"
			},
			".gitSectionLabel": {
				"background-color": "#3C71B3 !important",
				"color": "#FFFFFF !important"
			},
			".sectionWrapper": {
				"background-color": "#3C71B3 !important",
				"color": "#FFFFFF !important"
			}
		},
		".mainpane": {
			"background": "#C4C5C8 !important"
		},
		".navbar-item-selected": {
			"background-color": "#3C71B3 !important",
			"color": "#FFFFFF !important"
		},
		".orionSwitchLabel": {
			"background-color": "#3C71B3 !important",
			"color": "#FFFFFF !important"
		},
		".outlineExplorer": {
			".treeIterationCursorRow_Dotted": {
				"background-color": "#3C71B3 !important",
				"color": "#FFFFFF !important"
			}
		},
		".primaryButton": {
			"background-color": "#3C71B3 !important",
			"border-width": "1px",
			"border-style": "solid",
			"border-color": "#3C71B3 !important",
			"border-radius": "0 !important",
			"color": "#FFFFFF !important"
		},
		".primaryButton.disabled": {
			"background-color": "rgba(60, 113, 179, 0.25) !important",
			"border-color": "white !important"
		},
		".projectNavColumn": {
			"color": "#000000"
		},
		".searchResultsWrapperDiv": {
			".selectableNavRow:hover": {
				"background": "rgba(60, 113, 179, 0.25)",
				"border-left-color": "#3C71B3"
			}
		},
		".sectionTable": {
			"background-color": "#FFFFFF",
			".preview_td": {
				"border-bottom": "1px solid #F5F7FA",
				"color": "#152935"
			}
		},
		".sideMenu": {
			"background-color": "#FFFFFF"
		},
		".sideMenuItem": {
			"color": "#152935 !important"
		},
		".sideMenuItem>.submenu-trigger:hover": {
			"color": "#3C71B3 !important"
		},
		".sideMenuItemActive": {
			"background-color": "#3C71B3 !important",
			"color": "#FFFFFF !important"
		},
		".sideMenuItemActive:hover": {
			"background": "rgba(60, 113, 179, 0.25) !important",
			"color": "#FFFFFF"
		},
		".sidebarWrapper": {
			"background": "#F5F7FA !important",
			"color": "#000000"
		},
		".slideParameters": {
			"background-color": "#3C71B3 !important",
			"color": "#FFFFFF !important"
		},
		".splash": {
			"background": "#F5F7FA !important",
			"box-shadow": "none"
		},
		".splashAbout": {
			"color": "#3C71B3 !important"
		},
		".splashDetailedMessage": {
			"color": "#000000"
		},
		".splashLoader": {
			"background": "#F5F7FA !important",
			"box-shadow": "none"
		},
		".splashLoadingImage": {
			"-webkit-animation": "rotateThis .5s infinite linear",
			"animation": "rotateThis .5s infinite linear",
			"background": "none",
			"border": "2px solid #00b299",
			"border-radius": "50%",
			"border-right-color": "transparent",
			"display": "inline-block",
			"height": "20px",
			"margin": "0",
			"opacity": ".4",
			"width": "20px"
		},
		".splashLoadingImage.initial": {
			"border-width": "4px",
			"height": "40px",
			"width": "40px"
		},
		".splashMessage": {
			"color": "#000000"
		},
		".splashVerbal": {
			"color": "#3C71B3 !important"
		},
		".split": {
			"background": "#C4C5C8"
		},
		".split:focus": {
			"background": "rgb(60, 113, 179)"
		},
		".splitThumb": {
			"background": "#C4C5C8"
		},
		".status": {
			"color": "#000000"
		},
		".statusContainer": {
			"background": "#F5F7FA",
			"color": "#000000"
		},
		".statusLight": {
			"background": "lightgray"
		},
		".statusLight.statusLightAmber": {
			"background": "#FFE141"
		},
		".statusLight.statusLightGreen": {
			"background": "#13dd6d"
		},
		".statusLight.statusLightProgress": {
			"background": "transparent",
			"border-color": "transparent lightgray lightgray lightgray",
		},
		".statusLight.statusLightRed": {
			"background": "#C1272D"
		},
		".textviewTooltip": {
			".commandButton": {
				"background-color": "inherit",
				"border": "1px solid #325C80",
				"border-color": "#FFFFFF",
				"color": "white",
				"margin-bottom": "2px"
			},
			"color": "#FFFFFF",
			"background-color": "rgb(60, 113, 179)",
			".commandButton:not(.primaryButton):focus":{
				"color": "white",
   				"background-color": "rgba(196, 197, 200, 0.25)"
			},
			".commandButton:not(.primaryButton):not([disabled]):hover":{
				"color": "white",
   				"background-color": "rgba(196, 197, 200, 0.25)"
			}
		},
		".titleActionContainer": {
			"background": "#F5F7FA !important",
			"color": "#000000"
		},
		".tooltip": {
			"background-color": "#3C71B3 !important",
			"border-width": "1px",
			"border-style": "solid",
			"border-color": "#3C71B3",
			"color": "#FFFFFF !important",
			"h2": {
				"color": "#FFFFFF !important"
			},
			".navlinkonpage": {
				"background-color": "#3C71B3 !important",
				"color": "#FFFFFF !important"
			},
			".operationError": {
				"color": "#FFFFFF !important"
			}
		},
		".tooltipTailFromabove:after": {
			"border-top-color": "#3C71B3"
		},
		".tooltipTailFromabove:before": {
			"border-top-color": "#3C71B3"
		},
		".tooltipTailFrombelow:after": {
			"border-bottom-color": "#3C71B3"
		},
		".tooltipTailFrombelow:before": {
			"border-bottom-color": "#3C71B3"
		},
		".tooltipTailFromleft:after": {
			"border-left-color": "#3C71B3"
		},
		".tooltipTailFromleft:before": {
			"border-left-color": "#3C71B3"
		},
		".tooltipTailFromright:after": {
			"border-right-color": "#3C71B3"
		},
		".tooltipTailFromright:before": {
			"border-right-color": "#3C71B3"
		},
		".treeIterationCursorRow": {
			"background-color": "rgba(60, 113, 179, 0.25)"
		},
		".treeIterationCursorRow_Dotted": {
			"background-color": "rgba(60, 113, 179, 0.25)"
		},
		".treeTableRow": {
			"span.core-sprite-closedarrow:hover" : {
				"color": "#3C71B3"
			},
			"span.core-sprite-openarrow:hover" : {
				"color": "#3C71B3"
			}
		},
		".treeTableRow.checkedRow.gitCommitListSection": {
			"span.core-sprite-closedarrow:hover" : {
				"color": "lightgray",
			},
			"span.core-sprite-openarrow:hover" : {
				"color": "lightgray",
			}
		},
		".workingTarget": {
			"background-color": "#FFFFFF"
		},
		".commandImage.dropdownTrigger": {
			"color": "#152935"
		},
		".dropdownMenuItem": {
			"color": "#F5F7FA"
		},
		".pageToolbar": {
			".dropdownTrigger:not(.dropdownDefaultButton)": {
				"color": "#C4C5C8"
			}
		},
		".editorTabCloseButton:hover": {
			"background-color": "rgba(60, 113, 179, 1)",
			"color": "#FFFFFF"
		},
		".editorTab": {
			"border-top": "1px solid #C4C5C8",
			"border-right": "1px solid #C4C5C8"
		},
		".focusedEditorTab": {
			"border-top": "2px solid #3C71B3",
			"background-color": "#FFFFFF",
			"color": "#152935"
		},
		".contentassist .selected": {
			"background-color": "#3C71B3",
			"background": "#3C71B3"
		},
		".progressWatch.running": {
			".watchButton": {
				"border-color": "black"
			},
			".watchBody": {
				"border-color": "black"
			},
			".watchBody .hand.longHour > .darkSide": {
				"background-color": "black",
			},
			".watchBody .hand.longMinute > .darkSide": {
				"background-color": "black",
			}
		}
	}
});

/*******************************************************************************
 * @license
 * Copyright (c) 2015-2017 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 * 
 * Contributors: Casey Flynn - Google Inc - initial API and implementation
 ******************************************************************************/
 /*eslint-env browser,amd*/
define('orion/widgets/themes/container/OrionPage',{
	"className": "orionPage",
	"name": "Dark",
	"styles": {
		"#configSection": {
			"background-color": "#26343F !important",
			"color": "#FFFFFF !important"
		},
		"#log": {
			"margin": "5px",
			"width": "calc(100% - 17px)"
		},
		".auxpane": {
			"background": "#3B4B54 !important"
		},
		".desktopmode": {
			".selectableNavRow:hover": {
				"background-color": "rgba(16,106,91, 0.25)"
			}
		},
		".checkedRow": {
			"background-color": "#106A5B !important",
			"color": "#FFFFFF !important",
			".commandButton": {
				"border-color": "white",
				"color": "#FFFFFF"
			},
			".commandButton:not(.primaryButton):not([disabled]):hover": {
				"background": "rgba(16,106,91,0.50)",
				"box-shadow": "0 1px 2px 0 rgb(16,106,91)",
				"color": "#FFFFFF"
			},
			".gitStatusIcon": {
				"color": "white !important"
			},
			".gitStatusTitle": {
				"color": "white !important"
			},
			"gitStatusIcon": {
				"color": "#FFFFFF"
			},
			"gitStatusTitle": {
				"color": "#FFFFFF"
			}
		},
		".checkedRow>td>span>a":{
			"color": "#FFFFFF !important"
		},
		".commandButton": {
			"background-color": "rgba(0, 0, 0, 0)",
			"border-width": "1px",
			"border-style": "solid",
			"border-color": "#106A5B",
			"color": "#106A5B"
		},
		".commandButton.disabled": {
			"color": "#cdcdcd",
			"border-color": "#cdcdcd"
		},
		".commandButton.orionButton.dropdownTrigger:hover": {
			"border-color": "#ccc"
		},
		".commandButton:not(.primaryButton):not([disabled]):hover": {
			"background-color": "rgba(16,106,91,0.25)",
			"box-shadow": "0 1px 2px 0 rgb(16,106,91)",
			"color": "black"
		},
		".content-fixedHeight": {
			"background": "#3B4B54 !important"
		},
		".core-sprite-error": {
			"color": "red"
		},
		".dialogTitle": {
			"background-color": "#106A5B !important",
			"color": "#FFFFFF !important"
		},
		".dropdownButtonWithIcon": {
			"color": "#FFFFFF !important"
		},
		".dropdownCommandName": {
			"color": "#000000 !important"
		},
		".dropdownArrowRight" : {
			"color": "#000000 !important"
		},
		".dropdownMenu": {
			".dropdownMenuItemSelected": {
				"background": "rgba(16,106,91,0.25)",
				"border-left-color": "#106A5B"
			}
		},
		".dropdownTrigger:not(.dropdownDefaultButton)": {
			"color": "#FFFFFF !important"
		},
		".dropdownSelection.dropdownTriggerOpen": {
			"background-color": "#C3DAD6 !important"
		},
		".editorViewerHeader": {
			"background": "#3B4B54 !important",
			"color": "#FFFFFF !important"
		},
		".filesystemName": {
			"color": "#FFFFFF !important"
		},
		".fixedToolbarHolder": {
			"background": "#26343F"
		},
		".gitCommitMessage": {
			".gitCommitMessageTopRow": {
				"border-color": "#106A5B"
			},
			".gitCommitMore":{
				"color": "#004e00 !important"
			}
		},
		".gitCommitMessageSection": {
			"background-color": "rgba(16,106,91,0.25)"
		},
		".gitCommitMore": {
			"color": "#006800 !important"
		},
		".gitStatusIcon": {
			"color": "#106A5B !important"
		},
		".gitStatusSection": {
			"background-color": "rgba(16,106,91,0.25)",
			".stretch":{
				"color": "#5e5e5e"
			}
		},
		".gitStatusSection.checkedRow": {
			".stretch":{
				"color": "#d7d7d7"
			}
		},
		".gitChangeListCheckLabel":{
			"color": "#5e5e5e"
		},
		".gitChangeListChangedStatus":{
			"color": "#5e5e5e"
		},
		".gitStatusTitle": {
			"color": "#0d584c !important"
		},
		".label.parameterInput": {
			"color": "#FFFFFF !important"
		},
		".launchConfigurationMenuItem.dropdownMenuItemActive": {
			"background": "#3B4B54"
		},
		".launchConfigurationsButton": {
			".commandButton.orionButton.dropdownTrigger": {
				"color": "#FFFFFF !important"
			}
		},
		".launchConfigurationsWrapper>.launchConfigurationsButton.dropdownTrigger": {
			"background-color": "#106A5B !important",
			"color": "#FFFFFF !important"
		},
		".launchConfsDropdown": {
			".dropdownDefaultButton": {
				"background-color": "#106A5B !important",
				"color": "#FFFFFF !important"
			}
		},
		".launchConfsLabel": {
			"background-color": "#106A5B !important",
			"color": "#FFFFFF !important"
		},
		".liveUpdateLabel": {
			"color": "#106A5B !important"
		},
		".mainToolbar": {
			"background-color": "#26343F",
			"color": "#FFFFFF !important",
			".commandButton.orionButton.dropdownTrigger": {
				"border-color": "#26343F",
				"color": "#FFFFFF !important",
				".dropdownTriggerButtonLabel": {
					"color": "#FFFFFF"
				}
			},
			".commandButton.orionButton.dropdownTrigger.dropdownTriggerOpen": {
				"color": "#000000 !important"
			},
			".commandButton.orionButton.dropdownTrigger.launchConfigurationsButton": {
				".dropdownArrowDown": {
					"color": "#FFFFFF"
				}
			},
			".commandImage.dropdownTrigger": {
				"color": "#FFFFFF !important"
			},
			".commandImage.dropdownTrigger.dropdownTriggerOpen": {
				"color": "#26343F !important"
			},
			".gitSectionLabel": {
				"background-color": "#106A5B !important",
				"color": "#FFFFFF !important"
			},
			".sectionWrapper": {
				"background-color": "#106A5B !important",
				"color": "#FFFFFF !important"
			},
			".commandButton:not(.primaryButton):focus": {
				"color": "#FFFFFF"
			},
			".commandButton:not(.primaryButton):not([disabled]):hover": {
				"color": "#FFFFFF"
			}
		},
		".mainpane": {
			"background": "#3B4B54 !important"
		},
		".navbar-item-selected": {
			"background-color": "#106A5B !important",
			"color": "#FFFFFF !important"
		},
		".orionSwitchLabel": {
			"background-color": "#106A5B !important",
			"color": "#FFFFFF !important"
		},
		".outlineExplorer": {
			".treeIterationCursorRow_Dotted": {
				"background-color": "#106A5B !important",
				"color": "#FFFFFF !important"
			}
		},
		".primaryButton": {
			"background-color": "#106A5B !important",
			"border-width": "1px",
			"border-style": "solid",
			"border-color": "#106A5B !important",
			"border-radius": "0 !important",
			"color": "#FFFFFF !important"
		},
		".primaryButton.disabled": {
			"background-color": "rgba(16,106,91,0.25) !important",
			"border-color": "white !important"
		},
		".projectNavColumn": {
			"color": "#FFFFFF"
		},
		".searchResultsWrapperDiv": {
			".selectableNavRow:hover": {
				"background": "rgba(16,106,91,0.25)",
				"border-left-color": "#106A5B"
			}
		},
		".sectionTable": {
			"background-color": "#FFFFFF",
			".preview_td": {
				"border-bottom": "1px solid #3B4B54",
				"color": "#FFFFFF"
			}
		},
		".sideMenu": {
			"background-color": "#26343F"
		},
		".sideMenuItem": {
			"color": "#FFFFFF !important"
		},
		".sideMenuItem>.submenu-trigger:hover": {
			"color": "#106A5B !important"
		},
		".sideMenuItemActive": {
			"background-color": "#106A5B !important",
			"color": "#FFFFFF !important"
		},
		".sideMenuItemActive:hover": {
			"background": "rgba(16,106,91,0.25) !important",
			"color": "#FFFFFF"
		},
		".sidebarWrapper": {
			"background": "#3B4B54 !important",
			"color": "#FFFFFF"
		},
		".slideParameters": {
			"background-color": "#106A5B !important",
			"color": "#FFFFFF !important"
		},
		".splash": {
			"background": "#3B4B54 !important",
			"box-shadow": "none"
		},
		".splashAbout": {
			"color": "#1BB199 !important"
		},
		".splashDetailedMessage": {
			"color": "#FFFFFF"
		},
		".splashLoader": {
			"background": "#3B4B54 !important",
			"box-shadow": "none"
		},
		".splashLoadingImage": {
			"-webkit-animation": "rotateThis .5s infinite linear",
			"animation": "rotateThis .5s infinite linear",
			"background": "none",
			"border": "2px solid #00b299",
			"border-radius": "50%",
			"border-right-color": "transparent",
			"display": "inline-block",
			"height": "20px",
			"margin": "0",
			"opacity": ".4",
			"width": "20px"
		},
		".splashLoadingImage.initial": {
			"border-width": "4px",
			"height": "40px",
			"width": "40px"
		},
		".splashMessage": {
			"color": "#FFFFFF"
		},
		".splashVerbal": {
			"color": "#1BB199 !important"
		},
		".split": {
			"background": "#3B4B54"
		},
		".split:focus": {
			"background": "#00FF00"
		},
		".splitThumb": {
			"background": "#3B4B54"
		},
		".status": {
			"color": "#FFFFFF"
		},
		".statusContainer": {
			"background": "#3B4B54",
			"color": "#FFFFFF"
		},
		".statusLight": {
			"background": "lightgray"
		},
		".statusLight.statusLightAmber": {
			"background": "#FFE141"
		},
		".statusLight.statusLightGreen": {
			"background": "#13dd6d"
		},
		".statusLight.statusLightProgress": {
			"background": "transparent",
			"border-color": "lightgray",
			"border-top-color": "transparent"
		},
		".statusLight.statusLightRed": {
			"background": "#C1272D"
		},
		".textviewTooltip": {
			".commandButton": {
				"background-color": "inherit",
				"border": "1px solid white",
				"border-color": "white",
				"color": "white",
				"margin-bottom": "2px"
			},
			"color": "#FFFFFF",
			"background-color": "rgb(16,106,91)",
			".commandButton:not(.primaryButton):focus":{
				"color": "white",
    			"background-color": "rgba(59, 75, 84, 0.5)"			
    		},
			".commandButton:not(.primaryButton):not([disabled]):hover":{
				"color": "white",
    			"background-color": "rgba(59, 75, 84, 0.5)"
			}
		},
		".titleActionContainer": {
			"background": "#3B4B54 !important",
			"color": "#FFFFFF"
		},
		".tooltip": {
			"background-color": "#106A5B !important",
			"border-width": "1px",
			"border-style": "solid",
			"border-color": "#106A5B",
			"color": "#FFFFFF !important",
			"h2": {
				"color": "#FFFFFF !important"
			},
			".navlinkonpage": {
				"background-color": "#106A5B !important",
				"color": "#FFFFFF !important"
			},
			".operationError": {
				"color": "#FFFFFF !important"
			}
		},
		".tooltipTailFromabove:after": {
			"border-top-color": "#106A5B"
		},
		".tooltipTailFromabove:before": {
			"border-top-color": "#106A5B"
		},
		".tooltipTailFrombelow:after": {
			"border-bottom-color": "#106A5B"
		},
		".tooltipTailFrombelow:before": {
			"border-bottom-color": "#106A5B"
		},
		".tooltipTailFromleft:after": {
			"border-left-color": "#106A5B"
		},
		".tooltipTailFromleft:before": {
			"border-left-color": "#106A5B"
		},
		".tooltipTailFromright:after": {
			"border-right-color": "#106A5B"
		},
		".tooltipTailFromright:before": {
			"border-right-color": "#106A5B"
		},
		".treeIterationCursorRow": {
			"background-color": "rgba(16,106,91,0.25)"
		},
		".treeIterationCursorRow_Dotted": {
			"background-color": "rgba(16,106,91,0.25)"
		},
		".treeTableRow": {
			"span.core-sprite-closedarrow:hover" : {
				"color": "#1BB199"
			},
			"span.core-sprite-openarrow:hover" : {
				"color": "#1BB199"
			}
		},
		".treeTableRow.checkedRow.gitCommitListSection": {
			"span.core-sprite-closedarrow:hover" : {
				"color": "lightgray",
			},
			"span.core-sprite-openarrow:hover" : {
				"color": "lightgray",
			},
		},
		".workingTarget": {
			"background-color": "#FFFFFF"
		},
		".commandImage.dropdownTrigger": {
			"color": "#FFFFFF"
		},
		".dropdownMenuItem": {
			"color": "#3B4B54"
		},
		".pageToolbar": {
			".dropdownTrigger:not(.dropdownDefaultButton)": {
				"color": "#3B4B54"
			}
		},
		".editorTabCloseButton:hover": {
			"background-color": "rgba(16,106,91, 1)",
			"color": "#FFFFFF"
		},
		".editorTab": {
			"border-top": "1px solid #26343F",
			"border-right": "1px solid #26343F"
		},
		".focusedEditorTab": {
			"border-top": "2px solid #106A5B",
			"background-color": "#26343F",
			"color": "#FFFFFF"
		},
		".contentassist .selected":{
			"background-color": "#106A5B",
			"background": "#106A5B"
		}
	}
});

/*******************************************************************************
 * @license
 * Copyright (c) 2012, 2017 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 * 
 * Contributors: Anton McConville - IBM Corporation - initial API and implementation
 * 				 Casey Flynn - Google Inc.
 ******************************************************************************/
/*eslint-env browser, amd*/

define('orion/widgets/themes/container/ThemeData',[
	'orion/editor/textTheme',
	'orion/widgets/themes/container/ThemeSheetWriter',
	'orion/Deferred',
	'orion/widgets/themes/ThemeVersion',
	'orion/widgets/themes/container/LightPage',
	'orion/widgets/themes/container/OrionPage'
],
	function(mTextTheme, ThemeSheetWriter, Deferred, THEMES_VERSION, LightPage, OrionPage) {

	// *******************************************************************************
	//
	// If you change any styles in this file, you must increment the version number
	// in ThemeVersion.js.
	//
	// *******************************************************************************

		function ThemeData(serviceRegistry){
			this.styles = [];
			this.styles.push(LightPage);
			this.styles.push(OrionPage);
			this.protectedThemes = ["Light", "Dark"];
			this.provider = null;
			if (serviceRegistry && serviceRegistry.getServiceReferences("orion.core.container.themes.provider").length > 0) {
				this.provider = serviceRegistry.getService("orion.core.container.themes.provider");
			}
		}
		
		function getStyles(){
			var d = new Deferred();
			var defaultStyles = this.styles;
			if (this.provider && typeof this.provider.getStyles === "function") {
				this.provider.getStyles().then(function(providedStyles) {
					d.resolve(providedStyles);
				}, function() { 
					d.resolve(defaultStyles);
				});
			} else {
				d.resolve(defaultStyles);
			}
			return d;
		}
		
		function getThemeVersion() {
			var d = new Deferred();
			if (this.provider && typeof this.provider.getThemeVersion === "function") {
				this.provider.getThemeVersion().then(function(version) {
					d.resolve(version);
				}, function() {
					d.resolve(THEMES_VERSION);
				});
			}
			else {
				d.resolve(THEMES_VERSION);
			}
			return d;
		}
		
		ThemeData.prototype.styles = [];
		ThemeData.prototype.getStyles = getStyles;
		ThemeData.prototype.getThemeVersion = getThemeVersion;
		
		function getProtectedThemes() {
			var d = new Deferred();
			var defaultProtectedThemes = this.protectedThemes;
			if (this.provider && typeof this.provider.getProtectedThemes === "function") {
				this.provider.getProtectedThemes().then(function(providedProtectedThemes) {
					d.resolve(providedProtectedThemes);
				}, function() {
					d.resolve(defaultProtectedThemes);
				});
			} else {
				d.resolve(defaultProtectedThemes);
			}
			return d;
		}

		ThemeData.prototype.getProtectedThemes = getProtectedThemes;
		
		function getDefaultTheme() {
			var d = new Deferred();
			var useLightTheme = document.body.classList.contains("lightPage");
			var defaultTheme = useLightTheme ? 'Light' : 'Dark';
			if (this.provider && typeof this.provider.getDefaultTheme === "function") {
				this.provider.getDefaultTheme().then(function(defaultTheme) {
					d.resolve(defaultTheme);
				}, function() {
					d.resolve(defaultTheme);
				});
			} else {
				d.resolve(defaultTheme);
			}
			return d;
		}
		ThemeData.prototype.getDefaultTheme = getDefaultTheme;
		
		function getThemeStorageInfo(){
			return {
				storage: '/themes',
				styleset: 'containerStyles',
				selectedKey: 'containerSelected',
			};
		}
		
		ThemeData.prototype.getThemeStorageInfo = getThemeStorageInfo;
		
		function processSettings(settings){
			var sheetMaker = new ThemeSheetWriter.ThemeSheetWriter();
			var themeClass = "orionPage";
			var theme = new mTextTheme.TextTheme.getTheme(themeClass);
			theme.setThemeClass(themeClass, sheetMaker.getSheet(themeClass, settings));
		}
		
		ThemeData.prototype.processSettings = processSettings;

		return{
			ThemeData:ThemeData,
			getStyles:getStyles
		};
	}
);

/*******************************************************************************
 * @license
 * Copyright (c) 2012, 2019 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
/*eslint-env browser, amd*/
define('orion/webui/dialog',['i18n!orion/nls/messages', 'orion/webui/littlelib', 'orion/uiUtils'], 
		function(containerMessages, lib, uiUtil) {
	/**
	 * Holds the current opened modal dialog.
	 */
	var modalDialogManager = {
		dialog: null
	};
		
	/**
	 * Dialog is used to implement common dialog behavior in Orion.
	 * Clients use the Dialog prototype and implement the following behavior:
	 *    1.  Ensure that the HTML template for the dialog content is defined in the prototype TEMPLATE variable
	 *        prior to calling the _initialize() function. Set the following fields in the dialog prior to calling the 
	 *        _initialize() function if applicable.
	 *
	 *        messages - If i18n message bindings are used in the template, set the messages field to the messages object that
	 *            should be used to bind strings.
	 *        title - If the dialog should display a title, set the title field.
	 *        buttons - If the dialog should show buttons along the bottom, set an array of button objects.  Each button should
	 *            have a text property that labels the button and a callback property that is called when the button is pushed.
	 *            Buttons may optionally have an id, and one button in the array may optionally have isDefault set to true.
	 *        modal - Set this field to true if modal behavior is desired.
	 *        firstFocus - Set this field to the id of the child element that should receive focus when the dialog is opened. Optional.
	 * 
	 *    2.  To hook event listeners to elements in the dialog, implement the _bindToDOM function.  DOM elements
	 *        in the template will be bound to variable names prefixed by a '$' character.  For example, the
	 *        element with id "myElement" can be referenced with this.$myElement
	 *
	 *    3.  Implement any of _beforeShowing, _afterShowing, _beforeHiding, _afterHiding to perform initialization and cleanup work.
	 *
	 * Usage: Not instantiated by clients.  The prototype is used by the application dialog instance.
	 * 
	 * @name orion.webui.Dialog
	 */
	function Dialog() {
	}

	Dialog.prototype = /** @lends orion.webui.Dialog.prototype */ {
	
		DISABLED: "disabled", //$NON-NLS-0$
	
		/* Not used by clients */
		CONTAINERTEMPLATE:		
		'<div class="dialog" role="dialog">' + //$NON-NLS-0$
			'<div class="dialogTitle"><span class="dialogTitleText layoutLeft"></span><button class="dismissButton closeDialog layoutRight core-sprite-close imageSprite"></button></div>' + //$NON-NLS-0$
			'<div class="dialogContent layoutBlock"></div>' + //$NON-NLS-1$ //$NON-NLS-0$
			'<div class="dialogButtons"></div>' + //$NON-NLS-1$ //$NON-NLS-0$
		'</div>', //$NON-NLS-0$

		/* 
		 * Called by clients once the dialog template has been bound to the TEMPLATE variable, and any additional options (title, buttons,
		 * messages, modal) have been set.
		 */
		_initialize: function() {
			var parent = document.body;
			this.$frameParent = parent;
			this.$$modalExclusions = this.$$modalExclusions || [];
			var range = document.createRange();
			range.selectNode(parent);
			var frameFragment = range.createContextualFragment(this.CONTAINERTEMPLATE);
			parent.appendChild(frameFragment);
			this.$frame = parent.lastChild;
			this.$frame.tabIndex = -1;
			this.$frame.style.outline = "none";
//			this.handle = lib.addAutoDismiss([this.$frame], this.hide.bind(this));
			if (this.title) {
				lib.$(".dialogTitleText", this.$frame).appendChild(document.createTextNode(this.title)); //$NON-NLS-0$
				lib.setSafeAttribute(this.$frame, "aria-label", this.title);
			}
			this.$close = lib.$(".closeDialog", this.$frame);//$NON-NLS-0$
			lib.setSafeAttribute(this.$close, "aria-label", containerMessages["Close"]);
			var self = this;
			this.$close.addEventListener("click", function(event) { //$NON-NLS-0$
				self.hide();
			}, false);
						
			this.$parent = lib.$(".dialogContent", this.$frame); //$NON-NLS-0$
			range = document.createRange();
			range.selectNode(this.$parent);
			var contentFragment = range.createContextualFragment(this.TEMPLATE);
			if (this.messages) {
				lib.processTextNodes(contentFragment, this.messages);
			}
			this.$parent.appendChild(contentFragment);
			this.$buttonContainer = lib.$(".dialogButtons", this.$frame); //$NON-NLS-0$
			this._makeButtons();
			
			// hook key handlers.  This must be done after _makeButtons so that the default callback (if any)
			// is established.
			this.$frame.addEventListener("keydown", function (e) { //$NON-NLS-0$
				if(e.keyCode === lib.KEY.ESCAPE) {
					self.hide();
					e.preventDefault();
				} else if (e.keyCode === lib.KEY.ENTER && (typeof self._defaultCallback) === "function") { //$NON-NLS-0$
					self._defaultCallback();
					e.preventDefault();
				}
			}, false);
			
			this._bindElements(this.$parent);
			if (typeof this._bindToDom === "function") { //$NON-NLS-0$
				this._bindToDom(this.$parent);
			}
		},
		
		/*
		 * Internal.  Generates any specified buttons.
		 */
		_makeButtons: function() {
			if (this.$buttonContainer && Array.isArray(this.buttons)) {
				var self = this;
				this.buttons.forEach(function(buttonDefinition) {
					var button = uiUtil.createButton(buttonDefinition.text, buttonDefinition.callback);
					if (buttonDefinition.id) {
						button.id = buttonDefinition.id;
						self['$'+ button.id] = button; //$NON-NLS-0$					
					}
					if (buttonDefinition.isDefault) {
						self._defaultCallback = buttonDefinition.callback;
						self._defaultButton = button;
						button.classList.add("primaryButton"); //$NON-NLS-0$
					}
					self.$buttonContainer.appendChild(button);
				});
			}
		},
		

		/*
		 * Internal.  Makes modal behavior by immediately returning focus to the dialog when user leaves the dialog, and by
		 * styling the background to look faded.
		 */
		_makeModal: function(parent) {
			var self = this;
			// We listen to focus lost and remember the last one with focus.  This is great for clicks away from dialog.
			this.$frame.addEventListener("blur", function(e) { //$NON-NLS-0$
				self.$lastFocusedElement = e.target;
			}, true);
			this._modalListener = function(e) { //$NON-NLS-0$
				var preventFocus =	!lib.contains(self.$frame, e.target);
				if (preventFocus) {
					for (var i = 0; i<self.$$modalExclusions.length; i++) {
						if (lib.contains(self.$$modalExclusions[i], e.target)) {
							preventFocus = false;
							break;
						}
					}
				}
				if (preventFocus) {
					window.setTimeout(function() {
						(self.$lastFocusedElement || self.$parent).focus();
					}, 0);
					lib.stop(e);
				}
			};
			this.$frameParent.addEventListener("focus", this._modalListener, true);  //$NON-NLS-0$
			this.$frameParent.addEventListener("click", this._modalListener, true);  //$NON-NLS-0$
			var children = this.$frameParent.childNodes;
			var exclude = false;
			this._addedBackdrop = [];
			for (var i=0; i<children.length; i++) {
				for (var j=0; j<this.$$modalExclusions.length; j++) {
					if (lib.contains(this.$$modalExclusions[j], children[i])) {
						exclude = true;
						break;
					}
				}
				if (!exclude && children[i] !== self.$frame && children[i].classList && !children[i].classList.contains("tooltipContainer")) { //$NON-NLS-0$
					var child = children[i];
					if (!child.classList.contains("modalBackdrop")) {  //$NON-NLS-0$
						child.classList.add("modalBackdrop"); //$NON-NLS-0$
						this._addedBackdrop.push(child);
					} 
				}
			}
			
			// When tabbing out of the dialog, using the above technique (restore to last focus) will put the focus on the last element, but
			// we want it on the first element, so let's prevent the user from tabbing out of the dialog.
			lib.trapTabs(this.$frame);
			lib.setSafeAttribute(this.$frame, "aria-modal", "true");
		},
		
		_addChildDialog: function(dialog) {
			// Allow the child dialog to take focus.
			this.$$modalExclusions.push(dialog.$frame || dialog.$parent);
		},
		
		_inModalExclusion: function(dialog) {
			// Allow the child dialog to take focus.
			return this.$$modalExclusions.some(function(item) {
				return dialog.$frame === item || dialog.$parent === item;
			});
		},
		
		/*
		 * Internal.  Binds any child nodes with id's to the matching field variables.
		 */
		_bindElements: function(node) {
			for (var i=0; i<node.childNodes.length; i++) {
				var child = node.childNodes[i];
				if (child.id) {
					this['$'+child.id] = child; //$NON-NLS-0$
				}
				this._bindElements(child);
			}
		},
		
		/*
		 * Internal.  Hides the dialog.  Clients should use the before and after
		 * hooks (_beforeHiding, _afterHiding) to do any work related to hiding the dialog, such
		 * as destroying resources.
		 */
		hide: function(keepCurrentModal) {
			lib.returnFocus(this.$frameParent, this.$originalFocus, function() {
				if(!keepCurrentModal && modalDialogManager.dialog === this) {
					modalDialogManager.dialog = null;
				}
				if (typeof this._beforeHiding === "function") { //$NON-NLS-0$
					this._beforeHiding();
				}
				if (this._modalListener) {
					this.$frameParent.removeEventListener("focus", this._modalListener, true);  //$NON-NLS-0$
					this.$frameParent.removeEventListener("click", this._modalListener, true);  //$NON-NLS-0$
				}
	
				this.$frame.classList.remove("dialogShowing"); //$NON-NLS-0$
				lib.setFramesEnabled(true);
				if (typeof this._afterHiding === "function") { //$NON-NLS-0$
					this._afterHiding();
				}
			}.bind(this));
			var self = this;
			if (!this.keepAlive) {
				window.setTimeout(function() { self.destroy(); }, 0);
			}
		}, 
		
		/*
		 * Internal.  Shows the dialog.  Clients should use the before and after
		 * hooks (_beforeShowing, _afterShowing) to do any work related to showing the dialog,
		 * such as setting initial focus.
		 */
		show: function(near) {
			if(this.modal){//Modal dialog should only appear once unless they are chain dialog
				this._makeModal();
				if(modalDialogManager.dialog) {//There is already modal dialog opened
					if(!modalDialogManager.dialog._inModalExclusion(this)) {//The dialog is NOT a child dialog of the exisitng dialog
						this.hide(true);
						return;
					}
				} else {
					modalDialogManager.dialog = this;
				}
			}
			if (typeof this._beforeShowing === "function") { //$NON-NLS-0$
				this._beforeShowing();
			}
			lib.setFramesEnabled(false);
			var rect = lib.bounds(this.$frame);
			var totalRect = lib.bounds(document.documentElement);
			var left, top;
			if (near) {
				var refRect = lib.bounds(near);
				top = refRect.top + refRect.height + 4;  // a little below
				left = refRect.left + 4; // a little offset from the left
				if (top + rect.height > totalRect.height) {
					top = Math.max(0, totalRect.height - rect.height - 4);  
				}
				if (left + rect.width > totalRect.width) {
					left = Math.max(0, totalRect.width - rect.width - 4);  
				}
			} else {
				// centered
				left = Math.max(0, (totalRect.width - rect.width) / 2);
				top = Math.max(0, (totalRect.height - rect.height) / 2);
			}
			this.$lastFocusedElement = this.$originalFocus = document.activeElement;
			this.$frame.style.top = top + "px"; //$NON-NLS-0$
			this.$frame.style.left = left + "px"; //$NON-NLS-0$ 
			this.$frame.style["max-width"] = "calc(100% - " + left + "px)";
			this.$frame.classList.add("dialogShowing"); //$NON-NLS-0$
			if (typeof this._afterShowing === "function") { //$NON-NLS-0$
				this._afterShowing();
			}
			if (!this.customFocus) {
				// We should set the focus.  Pick the first tabbable content field, otherwise use default button.
				// If neither, find any button at all.
				var focusField = this._getFirstFocusField();
				focusField.focus();
			}
		},
		
		/**
		 * Set the node that should receive focus after the dialog is closed.
		 */
		setOriginalFocus: function(node) {
			this.$originalFocus = node;
		},
		
		_getFirstFocusField: function() {
			return this.firstFocus && lib.$('#' + this.firstFocus, this.$parent) ||
				lib.firstTabbable(this.$parent) ||
				this._defaultButton ||
				lib.firstTabbable(this.$buttonContainer) ||
				this.$close;
		},
		
		/*
		 * Internal.  Cleanup and remove dom nodes.
		 */
		destroy: function() {
			if (!this.$frame) {
				return;
			}
			if(modalDialogManager.dialog === this) {
				modalDialogManager.dialog = null;
			}
			lib.setFramesEnabled(true);
			if (this._addedBackdrop && this._addedBackdrop.length > 0) {
				this._addedBackdrop.forEach(function(node) { //$NON-NLS-0$
					node.classList.remove("modalBackdrop"); //$NON-NLS-0$
				});
			}
			this.$frameParent.removeEventListener("focus", this._modalListener, true); //$NON-NLS-0$
			this.$frameParent.removeEventListener("click", this._modalListener, true); //$NON-NLS-0$
			this.$frameParent.removeChild(this.$frame);
			this.$frame = undefined;
			this.$parent = undefined;
		}
	};
	
	Dialog.prototype.constructor = Dialog;

	//return the module exports
	return {Dialog: Dialog};
});

/*******************************************************************************
 * @license
 * Copyright (c) 2012 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
/*eslint-env browser, amd*/
/**
 * @name orion.operation
 * @namespace Provides an API for handling long running operations as promises.
 */
define('orion/operation',["orion/xhr", "orion/Deferred"], function(xhr, Deferred) {

	function _isRunning(operationType) {
		if (!operationType) {
			return true;
		}
		if (operationType === "loadstart" || operationType === "progress") {
			return true;
		}
		return false;
	}

	function _deleteTempOperation(operationLocation) {
		xhr("DELETE", operationLocation, {
			headers: {
				"Orion-Version": "1"
			},
			timeout: 15000
		});
	}

	function _cancelOperation(operationLocation) {
		xhr("PUT", operationLocation, {
			headers: {
				"Orion-Version": "1"
			},
			data: JSON.stringify({
				abort: true
			}),
			timeout: 15000
		});
	}

	function _getOperation(operation, deferred, onResolve, onReject) {
		xhr("GET", operation.location, {
			headers: {
				"Orion-Version": "1"
			},
			timeout: 15000
		}).then(function(result) {
			var operationJson = result.response ? JSON.parse(result.response) : null;
			deferred.progress(operationJson);
			if (_isRunning(operationJson.type)) {
				setTimeout(function() {
					_getOperation(operation	, deferred, onResolve, onReject);
				}, operation.timeout);
				operation.timeout = Math.min(operation.timeout * 2, 2000);
				return;
			}
			if (operationJson.type === "error" || operationJson.type === "abort") {
				deferred.reject(onReject ? onReject(operationJson) : operationJson.Result);
			} else {
				deferred.resolve(onResolve ? onResolve(operationJson) : operationJson.Result.JsonData);
			}
			if (!operationJson.Location) {
				_deleteTempOperation(operation.location); //This operation should not be kept 
			}
		}, function(error) {
			var errorMessage = error;
			if (error.responseText !== undefined) {
				errorMessage = error.responseText;
				try {
					errorMessage = JSON.parse(error.responseText);
				} catch (e) {
					//ignore
				}
			}
			if (errorMessage.Message !== undefined) {
				errorMessage.HttpCode = errorMessage.HttpCode === undefined ? error.status : errorMessage.HttpCode;
				errorMessage.Severity = errorMessage.Severity === undefined ? "Error" : errorMessage.Severity;
				deferred.reject(errorMessage);
			} else {
				deferred.reject({
					Severity: "Error",
					Message: errorMessage,
					HttpCode: error.status
				});
			}
		});
	}

	function _trackCancel(operationLocation, deferred) {
		deferred.then(null, function(error) {
			if (error instanceof Error && error.name === "Cancel") {
				_cancelOperation(operationLocation);
			}
		});
	}

	/**
	 * Handles a long-running operation as a promise.
	 * @name orion.operation.handle
	 * @function
	 * @param {String} operationLocation
	 * @param {Function} [onSuccess] If provided, will be called to transform a successful operation into the resolve value of the 
	 * returned promise.
	 * @param {Function} [onError] If provided, will be called to trasnform a failed operation into the reject value of the 
	 * returned promise.
	 * @returns {orion.Promise}
	 */
	function handle(operationLocation, onSuccess, onError) {
		var def = new Deferred();
		_trackCancel(operationLocation, def);
		_getOperation({location: operationLocation, timeout: 100}, def, onSuccess, onError);
		return def;
	}

	return {
		handle: handle
	};
});
/*******************************************************************************
 * @license
 * Copyright (c) 2012, 2019 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 * 
 * Contributors: IBM Corporation - initial API and implementation
 ******************************************************************************/
/*eslint-env browser, amd*/
define('orion/widgets/UserMenu',[
	'i18n!orion/widgets/nls/messages',
	'orion/webui/littlelib',
	'orion/PageLinks',
	'orion/webui/dropdown',
	'orion/util',
	'orion/webui/dialog',
	'orion/xhr',
	'orion/operation',
	'orion/Deferred',
	'orion/urlModifier'
], function(messages, lib, PageLinks, Dropdown, util, dialog, xhr, operation, Deferred, urlModifier) {
	
	function UserMenu(options) {
		this._displaySignOut = true;
		this._init(options);		
	}
	UserMenu.prototype = /** @lends orion.widgets.UserMenu.UserMenu.prototype */ {
			
		_init: function(options) {
			this._dropdownNode = lib.node(options.dropdownNode);
			if (!this._dropdownNode) { throw "no dom node for dropdown found"; } //$NON-NLS-0$
			this._dropdown = options.dropdown;
			this._serviceRegistry = options.serviceRegistry;
			this.authenticatedServices = {};
			this.unauthenticatedServices = {};
			//Options to customize all drop down items 
			this._noSeparator = options.noSeparator;
			this._dropDownItemClass = options.dropDownItemClass;
			this._keyAssistClass = options.keyAssistClass;
			if( options.signOut !== undefined ){
				this._displaySignOut = options.signOut;
			}
			this.prefsService = options.serviceRegistry.getService("orion.core.preference");
 		},
		
		
		isSingleService : function(){
			return this.length(this.unauthenticatedServices) + this.length(this.authenticatedServices) === 1;
		},
		hasServices: function(){
			return this.length(this.unauthenticatedServices) + this.length(this.authenticatedServices) > 0;
		},
		length: function(obj) {
			var length = 0;
			for(var prop in obj) {
				if(obj.hasOwnProperty(prop)) {
					length++;
				}
			}
			return length;
		},
		
		_makeMenuItem: function(name, click) {
			var li = Dropdown.createMenuItem(name);
			var element = li.firstElementChild;
			if(typeof this._dropDownItemClass === "string") {//$NON-NLS-0$
				if(this._dropDownItemClass !== "") {
					element.classList.add(this._dropDownItemClass);
				}
			}
			
			element.addEventListener("click", click, false); //$NON-NLS-0$
			// onClick events do not register for spans when using the keyboard
			element.addEventListener("keydown", function(e) { //$NON-NLS-0$
				if (e.keyCode === lib.KEY.ENTER || e.keyCode === lib.KEY.SPACE) {	
					click();
				}
			}, false);
			return element;
		},
		
		_renderAuthenticatedService: function(key, startIndex){
			var _self = this;
			var authService = this.authenticatedServices[key].authService;
			if (authService && authService.logout && this._displaySignOut){
				if (!util.isElectron) {
					var element = this._makeMenuItem(messages["Sign Out"], function() {
						authService.logout().then(function(){
							_self.addUserItem(key, authService, _self.authenticatedServices[key].label);
							util.deleteSetting(key);
							//TODO: Bug 368481 - Re-examine localStorage caching and lifecycle
							for (var i = localStorage.length - 1; i >= 0; i--) {
								var name = localStorage.key(i);
								if (name && name.indexOf("/orion/preferences/user") === 0) { //$NON-NLS-0$
									util.deleteSetting(name);
								}
							}
							authService.getAuthForm(PageLinks.getOrionHome()).then(function(formURL) {
								window.location = urlModifier(formURL);
							});
						});
					});
					this._dropdownNode.appendChild(element.parentNode);
				}
			}
		},
		
		/*
		Category user.0 [
		                [ <Contributed links>
		                [ Keyboard Shortcuts
		---Separator---
		Category user.1 [
		                [ <Contributed links>
		                [ <Service sign-out links>
		[...]
		Category user.N [
		                [< Contributed links>
		*/
		renderServices: function(){
			var doc = document;
			var categories = [];
			function getCategory(number) {
				if (!categories[number]) {
					categories[number] = doc.createDocumentFragment();
				}
				return categories[number];
			}
			var serviceRegistry = this._serviceRegistry;
			PageLinks.getPageLinksInfo(serviceRegistry, "orion.page.link.user").then(function(pageLinksInfo) { //$NON-NLS-0$
				if(this._dropdown) {
					this._dropdown.empty();
				} else if(this._dropdownNode) {
					lib.empty(this._dropdownNode);
				}

				// Read extension-contributed links
				var pageLinks = pageLinksInfo.getAllLinks();
				pageLinks = pageLinks.sort(function(a, b){
					if (a.order && b.order){
						return a.order - b.order;
					}
					return 0;
				});
				pageLinks.forEach(function(item) {
					var categoryNumber, match;
					if (item.category && (match = /user\.(\d+)/.exec(item.category))) {
						categoryNumber = parseInt(match[1], 10);
					}
					if (typeof categoryNumber !== "number" || isNaN(categoryNumber)) { //$NON-NLS-0$
						categoryNumber = 1;
					}
					var category = getCategory(categoryNumber);

					var li = doc.createElement("li");//$NON-NLS-0$
					var link = doc.createElement("a"); //$NON-NLS-0$
					lib.setSafeAttribute(link, "role", "menuitem");
					if(typeof this._dropDownItemClass === "string") {//$NON-NLS-0$
						if(this._dropDownItemClass !== "") {
							link.classList.add(this._dropDownItemClass);
						}
					} else {
						link.classList.add("dropdownMenuItem"); //$NON-NLS-0$
					}
					link.href = item.href;
					if (link.hostname !== "localhost" && util.isElectron) {
						link.target = "_blank";
					}
					link.textContent = item.textContent;
					li.appendChild(link);
					category.appendChild(li);
					link.addEventListener("keydown", function(e) { //$NON-NLS-0$
						if (e.keyCode === lib.KEY.ENTER || e.keyCode === lib.KEY.SPACE) {	
							link.click();
						}
					}, false);
				}.bind(this));

				if(this.keyAssistFunction){
					var element = this._makeMenuItem(messages["Keyboard Shortcuts"], this.keyAssistFunction);
					if(typeof this._keyAssistClass === "string") {//$NON-NLS-0$
						if(this._keyAssistClass !== "") {
							element.classList.add(this._keyAssistClass);
						}
					} else {
						element.classList.add("key-assist-menuitem"); //$NON-NLS-0$
					}
					var keyAssist = element.parentNode;
					getCategory(0).appendChild(keyAssist);
				}

				if (util.isElectron) {
					var clearLocalStorage = this._makeMenuItem(messages["Clear Local Storage"], function() { util.clearSettings(); });
					getCategory(0).appendChild(clearLocalStorage.parentNode);
					var about = this._makeMenuItem(messages["About"], function() {
						var newDialog = new dialog.Dialog();
						newDialog.TEMPLATE =
							'<div>' +
								'<div><label id="appVersion">${Version: }<span>' + window.__electron.remote.app.getVersion() + '</span></label></div>' +
								'<div><label id="buildID">${Build ID: }<span>' + window.__electron.remote.app.buildId + '</span></label></div>' +
								'<div><label id="updateChannel">${Update Channel: }' + 
									'<select id="channelOptions"><option id="stable">${Stable}</option><option id="alpha">${Alpha}</option></select>' + 
								'</label></div>' + 
								'<div><label id="updateAvailable">${Update available. Download now?}</label></div>' +
								'<div><label id="updateUnavailable">${No updates available.}</label></div>' +
								'<div><label id="updateError">${Error occurred while checking for updates.}</label></div>' +
								'<div><label id="updateDownloading">${Update is downloading in the background.}</label></div>' +
							'</div>';
						newDialog.messages = messages;
						newDialog.title = messages["About"];
						newDialog.buttons = [
						{ 
							text: messages["Download"],
							callback: function() {
								var progress = serviceRegistry.getService("orion.page.progress"); //$NON-NLS-0$
								var progressService = serviceRegistry.getService("orion.page.message");
								var deferred = progress.progress(this.downloadUpdateOperation(), messages["Downloading"]);
								progressService.createProgressMonitor(deferred, messages["Downloading"]);
								deferred.then(function(result) {
									document.querySelector("#updateDownloading").style.display = updateDownloading;
									document.querySelector("#updateChannel").style.display = 
									document.querySelector("#aboutDownloadUpdates").style.display =
									document.querySelector("#updateAvailable").style.display = "none";
								}, function(error) {
									document.querySelector("#updateError").style.display = updateError;
									document.querySelector("#aboutDownloadUpdates").style.display =
									document.querySelector("#updateDownloading").style.display =
									document.querySelector("#updateAvailable").style.display = "none";
								});
							}.bind(this),
							id: "aboutDownloadUpdates" 
						},
						{
							text: messages["Check for Updates"],
							callback: function() {
								var	updateChannel = channelOptions.options[channelOptions.selectedIndex].id;
								var progress = serviceRegistry.getService("orion.page.progress"); //$NON-NLS-0$
								var progressService = serviceRegistry.getService("orion.page.message");
								var deferred = progress.progress(this.checkForUpdateOperation('/update/resolveNewVersion?updateChannel=' + updateChannel), messages["Checking for Update"]);
								progressService.createProgressMonitor(deferred, messages["Checking for Update"]);
								deferred.then(function(result) {
										if (result && result.newVersion) {
											document.querySelector("#aboutDownloadUpdates").style.display = aboutDownloadUpdates;
											document.querySelector("#updateAvailable").style.display = updateAvailable;
											document.querySelector("#updateUnavailable").style.display = 
											document.querySelector("#updateChannel").style.display = 
											document.querySelector("#aboutResolveNewVersion").style.display = 
											document.querySelector("#updateError").style.display = "none";
										} else {
											document.querySelector("#updateUnavailable").style.display = updateUnavailable;
										}
									}, function(error) {
										document.querySelector("#updateError").style.display = updateError;
										document.querySelector("#aboutResolveNewVersion").style.display = "none";
								});
							}.bind(this),
							id: "aboutResolveNewVersion"
						},
						{
							text: messages["Close"],
							callback: function() {
								newDialog.hide();
							}, 
							id: "aboutClose" 
						}
						];
						newDialog.modal = true;
						newDialog._initialize();
						var aboutDownloadUpdates = document.querySelector("#aboutDownloadUpdates").style.display;
						var updateUnavailable = document.querySelector("#updateUnavailable").style.display;
						var updateAvailable = document.querySelector("#updateAvailable").style.display;
						var updateError = document.querySelector("#updateError").style.display;
						var updateDownloading = document.querySelector("#updateDownloading").style.display;
						var channelOptions = document.getElementById('channelOptions');
						document.querySelector("#aboutDownloadUpdates").style.display = 
						document.querySelector("#updateAvailable").style.display = 
						document.querySelector("#updateUnavailable").style.display = 
						document.querySelector("#updateError").style.display = 
						document.querySelector("#updateDownloading").style.display = "none";
						this.prefsService.get("/updateChannel").then(function(prefs) {
							channelOptions.selectedIndex = prefs.name && prefs.name === "alpha" ? 1 : 0;
						});
						channelOptions.addEventListener("change", function(event){
							this.prefsService.put("/updateChannel", {
								name : channelOptions[channelOptions.selectedIndex].id
							});
						}.bind(this));
						newDialog.show();
					}.bind(this));
					getCategory(0).appendChild(about.parentNode);
				}

				// Add categories to _dropdownNode
				var _self = this;
				categories.sort(function(a, b) { return a - b; }).forEach(function(category, i) {
					if (i < categories.length - 1 && !this._noSeparator) {
						// Add a separator
						var li = Dropdown.createSeparator();
						category.appendChild(li);
					}
					_self._dropdownNode.appendChild(category);
				}.bind(this));

				if(this.isSingleService()){
					//add sign out only for single service.
					for(var i in this.authenticatedServices){
						if (this.authenticatedServices.hasOwnProperty(i)) {
							this._renderAuthenticatedService(i, 0);
						}
					}
				}
			}.bind(this));
		},
		
		setKeyAssist: function(keyAssistFunction){
			this.keyAssistFunction = keyAssistFunction;
			this.renderServices();
		},
	
		addUserItem: function(key, authService, label, jsonData){
			if(jsonData){
				if(this.unauthenticatedServices[key]){
					delete this.unauthenticatedServices[key];
				}
				this.authenticatedServices[key] = {authService: authService, label: label, data: jsonData};
			}else{
				if(this.authenticatedServices[key]){
					delete this.authenticatedServices[key];
				}
				if(this.unauthenticatedServices[key]){
					this.unauthenticatedServices[key] = {authService: authService, label: label, pending: this.unauthenticatedServices[key].pending};
				}else{
					this.unauthenticatedServices[key] = {authService: authService, label: label};
				}
			}
			this.renderServices();
		},
		checkForUpdateOperation : function(updateChannel){
			var service = this;
			var clientDeferred = new Deferred();
			xhr("GET", updateChannel)
			.then(function(result) {
				service._getUpdateServiceResponse(clientDeferred, result);
			}, function(error){
				service._handleUpdateServiceResponseError(clientDeferred, error);
			});
			return clientDeferred;
		},
		downloadUpdateOperation : function(){
			var service = this;
			var clientDeferred = new Deferred();
			xhr("POST", '/update/downloadUpdates')
			.then(function(result) {
				service._getUpdateServiceResponse(clientDeferred, result);
			}, function(error){
				service._handleUpdateServiceResponseError(clientDeferred, error);
			});
			return clientDeferred;
		},
		_getUpdateServiceResponse : function(deferred, result) {
			var response =  result.response ? JSON.parse(result.response) : null;
			
			if (result.xhr && result.xhr.status === 202) {
				var def = operation.handle(response.Location);
				def.then(deferred.resolve, function(data) {
					data.failedOperation = response.Location;
					deferred.reject(data);
				}, deferred.progress);
				deferred.then(null, function(error){def.reject(error);});
				return;
			}
			deferred.resolve(response);
			return;
		},
		_handleUpdateServiceResponseError: function(deferred, error){
			deferred.reject(error);
		}
	};
	UserMenu.prototype.constructor = UserMenu;
	//return the module exports
	return {UserMenu: UserMenu};

});

/*******************************************************************************
 * @license
 * Copyright (c) 2010, 2019 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 * 
 * Contributors: IBM Corporation - initial API and implementation
 ******************************************************************************/

/*eslint-env browser, amd*/
define('orion/webui/treetable',['i18n!orion/nls/messages', 'orion/webui/littlelib', 'orion/Deferred'], function(messages, lib, Deferred) {

	/**
	 * Constructs a new TableTree with the given options.
	 * 
	 * @param options 
	 * @name orion.treetable.TableTree 
	 * @class Generates an HTML table where one of the columns is indented according to depth of children.
	 * <p>Clients must supply a model that generates children items, and a renderer can be supplied which
	 * generates the HTML table row for each child. Custom rendering allows clients to use checkboxes,
	 * images, links, etc. to describe each  element in the tree.  Renderers handle all clicks and other
	 * behavior via their supplied row content.</p>
	 * 
	 * <p>The table tree parent can be specified by id or DOM node.</p>
	 * 
	 * <p>The tree provides API for the client to programmatically expand and collapse
	 * nodes, based on the client renderer's definition of how that is done (click on icon, etc.).
	 * The tree will manage the hiding and showing of child DOM elements and proper indent</p>
	 * 
	 * The model must implement:
	 * <ul>
	 *   <li>getRoot(onItem)</li>
	 *   <li>getChildren(parentItem, onComplete)</li>
	 *   <li>getId(item)  // must be a valid DOM id</li>
	 *   <li>(optional) getAnnotations() // returns an array of Annotation</li>
	 * </ul>
	 * 
	 * Renderers must implement:
	 * <ul>
	 *   <li>initTable(tableNode) // set up table attributes and a header if desired</li>
	 *   <li>render(item, tr) // generate tds for the row</li>
	 *   <li>labelColumnIndex() // 0 based index of which td contains the primary label which will be indented</li>
	 *   <li>rowsChanged // optional, perform any work (such as styling) that should happen after the row content changes</li>
	 *   <li>updateExpandVisuals(row, isExpanded) // update any expand/collapse visuals for the row based on the specified state</li>
	 * </ul>
	 *   TODO DOC
	 *   wrapperCallback
	 *   tableCallback
	 *   bodyCallback
	 *   rowCallback
	 */
	function TableTree (options) {
		this._init(options);
	}
	TableTree.prototype = /** @lends orion.treetable.TableTree.prototype */ {
		_init: function(options) {
			var parent = options.parent;
			var tree = this;
			parent = lib.node(parent);
			if (!parent) { throw messages["no parent"]; }
			if (!options.model) { throw messages["no tree model"]; }
			if (!options.renderer) { throw messages["no renderer"]; }
			this._parent = parent;
			this._treeModel = options.model;
			this._onComplete = options.onComplete;
			this._renderer = options.renderer;
			this._showRoot = options.showRoot === undefined ? false : options.showRoot;
			this._indent = options.indent === undefined ? 16 : options.indent;
			this._preCollapse = options.preCollapse;
			this._onCollapse = options.onCollapse;
			this._labelColumnIndex = options.labelColumnIndex === undefined ? 0 : options.labelColumnIndex;
			this._id = options.id === undefined ? "treetable" : options.id; //$NON-NLS-0$
			this._role = options.role;
			this._name = options.name;
			this._tableStyle = options.tableStyle;
			this._tableElement = options.tableElement || "table"; //$NON-NLS-0$
			this._tableBodyElement = options.tableBodyElement || "tbody"; //$NON-NLS-0$
			this._tableRowElement = options.tableRowElement || "tr"; //$NON-NLS-0$
			this._annotationRefreshRequested = false;
			
			// Generate the table
			this._treeModel.getRoot(function (root) {
				tree._root = root;
				if (tree._showRoot) {
					root._depth = 0;
					tree._generate([root], 0);
				}
				else {
					tree._treeModel.getChildren(root, function(children) {
						if (tree.destroyed) { return; }
						tree._generate(children, 0);
					});
				}
			});
		},
		
		destroy: function() {
			this.destroyed = true;
			this._removeAllRows();
		},
		
		_generate: function(children, indentLevel) {
			lib.empty(this._parent);
			var wrapper = document.createElement("div"); //$NON-NLS-0$
			if (this._renderer.wrapperCallback) {
				this._renderer.wrapperCallback(wrapper);
			}
			var table = this._table = document.createElement(this._tableElement); //$NON-NLS-0$
			if (this._renderer.tableCallback) {
				this._renderer.tableCallback(table);
			}
			table.id = this._id;
			lib.setSafeAttribute(table, "role", this._role || "presentation");
			if (this._name) {
				lib.setSafeAttribute(table, "aria-label", this._name);
			}
			if (this._tableStyle) {
				table.classList.add(this._tableStyle);
			}
			this._renderer.initTable(table, this);
			this._bodyElement = document.createElement(this._tableBodyElement); //$NON-NLS-0$
			if (this._renderer.bodyCallback) {
				this._renderer.bodyCallback(this._bodyElement);
			}
			this._bodyElement.id = this._id+"tbody"; //$NON-NLS-0$
			if (children.length === 0) {
				if (this._renderer.emptyCallback) {
					this._renderer.emptyCallback(this._bodyElement);
				}
			} else {
				this._generateChildren(children, indentLevel); //$NON-NLS-0$
			}
			table.appendChild(this._bodyElement);
			wrapper.appendChild(table);
			this._parent.appendChild(wrapper);
			this._rowsChanged();
			if (this._onComplete) {
				this._onComplete(this);
			}
		},
		
		_generateChildren: function(children, indentLevel, referenceNode) {
			for (var i=0; i<children.length; i++) {
				var row = document.createElement(this._tableRowElement); //$NON-NLS-0$
				if (this._role === "treegrid") {
					if (this._tableRowElement !== "tr") {
						lib.setSafeAttribute(row, "role", "row");
					}
					lib.setSafeAttribute(row, "aria-level", indentLevel + 1);
					lib.setSafeAttribute(row, "aria-setsize", children.length);
					lib.setSafeAttribute(row, "aria-posinset", i + 1);
				} else if (this._role === "tree") {
					if (this._tableRowElement !== "tr") {
						lib.setSafeAttribute(row, "role", "treeitem");
					}
					lib.setSafeAttribute(row, "aria-level", indentLevel + 1);
					lib.setSafeAttribute(row, "aria-setsize", children.length);
					lib.setSafeAttribute(row, "aria-posinset", i + 1);
				} else if (this._role === "grid") {
					if (this._tableRowElement !== "tr") {
						lib.setSafeAttribute(row, "role", "row");
					}
				}
				if(this._renderer && typeof this._renderer.initSelectableRow === "function") { //$NON-NLS-0$
					this._renderer.initSelectableRow(children[i], row);
				}
				this._generateRow(children[i], row, indentLevel, referenceNode);
				if (referenceNode) {
					this._bodyElement.insertBefore(row, referenceNode.nextSibling);
					referenceNode = row;
				} else {
					this._bodyElement.appendChild(row);
				}
			}
		},
		
		_generateRow: function(child, row, indentLevel) {
			row.id = this._treeModel.getId(child);
			row._depth = indentLevel;
			// This is a perf problem and potential leak because we're bashing a dom node with
			// a javascript object.  (Whereas above we are using simple numbers/strings). 
			// We should consider an item map.
			row._item = child;
			this._renderer.render(child, row);
			// generate an indent
			var indent = this._indent * indentLevel;
			row.childNodes[Math.min(row.childNodes.length - 1, this._labelColumnIndex)].style.paddingLeft = indent +"px";  //$NON-NLS-0$
			if(this._renderer.updateExpandVisuals) {
			    this._renderer.updateExpandVisuals(row, row._expanded);
			}
			if (this._renderer.rowCallback) {
				this._renderer.rowCallback(row, child);
			}
		},
		
		_rowsChanged: function() {
			// notify the renderer if it has implemented the function
			if (this._renderer.rowsChanged) {
				this._renderer.rowsChanged();
			}
			this.requestAnnotationRefresh();
		},

		/**
		 * Redraw the annotation according to model.getAnnotations().
		 * 
		 * This function assumes model.getAnnotations() exists.
		 */
		_redrawAnnotation: function() {
			// TODO: should I move this part to renderer? If so, how?
			var tree = this;
			var annotations = tree._treeModel.getAnnotations();
			// Remove existing annotations
			var existingAnnotations = this._parent.getElementsByClassName('treeAnnotationOn');
			var annotationsToRemove = [];
			for (var i = 0; i < existingAnnotations.length; i++){
				annotationsToRemove.push(existingAnnotations[i]);
			};
			annotationsToRemove.forEach(function(annotation) {
				while (annotation.firstChild) {
					annotation.removeChild(annotation.firstChild);
				}
				annotation.classList.remove('treeAnnotationOn');
			})
			// Add new annotations
			// A map from tree item ID to a list of its annotation HTML elements
			var annotationElementsByItem = {};
			var promises = [];
			annotations.forEach(function(annotation) {
				var promise = new Deferred();
				promises.push(promise);
				annotation.findDeepestFitId(tree._treeModel, function(id) {
					// Make sure there is a place to show the annotation
					if (!id) {
						promise.resolve();
						return;
					}
					var container = document.getElementById(id + 'Annotation');
					if (!container) {
						promise.resolve();
						return;
					}
					var annotationElement = annotation.generateHTML();
					if (!annotationElement) {
						promise.resolve();
						return;
					}
					if (!annotationElementsByItem[id]) {
						annotationElementsByItem[id] = [];
					}
					annotationElement.annotation = annotation;
					annotationElementsByItem[id].push(annotationElement);
					promise.resolve();
				});
			});
			Deferred.all(promises).then(function() {
				// All async calls ends. Add these annotations now.
				for (var elementid in annotationElementsByItem) {
					if (annotationElementsByItem.hasOwnProperty(elementid)) {
						var annotationsToAdd = annotationElementsByItem[elementid];
						var container = document.getElementById(elementid + 'Annotation');
						container.classList.add('treeAnnotationOn');
						// var html = annotationsToAdd[0];
						// container.appendChild(html);
						// if (annotationsToAdd.length > 1) {
						// 	var overlay = document.createElement('div');
						// 	overlay.classList.add('overlay');
						// 	container.appendChild(overlay);
						// }
						var showEditing = false;
						annotationsToAdd.forEach(function (html) {
						    container.appendChild(html);
							// Tooltip
							// TODO: make it general
							html.addEventListener('click', function(e) {
								if (tree.tooltip) {
									//tree.tooltip.remove();
								}
								var tooltip = document.createElement('div');
								lib.setSafeInnerHTML(tooltip, html.annotation.getDescription());
								tooltip.classList.add("treetable-tooltip");
								tooltip.style.left = e.clientX + 'px';
								tooltip.style.top = e.clientY + 'px';
								var cross = document.createElement('div');
								lib.setSafeInnerHTML(cross, '×');
								cross.classList.add("cross");
								tooltip.appendChild(cross);
								document.body.appendChild(tooltip);
								tooltip.remove = function (e2) {
									window.removeEventListener('click', tooltip.remove);
									document.body.removeChild(tooltip);
									tree.tooltip = null;
								};
								setTimeout(function() {
									window.addEventListener('click', tooltip.remove);
								}, 0);
								tree.tooltip = tooltip;
							});
						});
					}
				}
			});
		},
		
		getSelected: function() {
			return this._renderer.getSelected();
		},
		
		redraw: function(item) {
			var itemId = this._treeModel.getId(item);
			var row = lib.node(itemId);
			if (!row) return;
			lib.empty(row);
			this._generateRow(item, row, row._depth);
		},
		
		refresh: function(item, children, /* optional */ forceExpand) {
			var parentId = this._treeModel.getId(item);
			var tree;
			if (parentId === this._id) {  // root of tree
				this._removeChildRows(parentId);
				this._generateChildren(children, 0);
				this._rowsChanged();
			} else if (parentId === this._treeModel.getId(this._root) && item.removeAll) {
				this._removeAllRows();
				this._generateChildren(children, 0);
				this._rowsChanged();
			} else {  // node in the tree
				var row = lib.node(parentId);
				if (row) {
					// if it is showing children, refresh what is showing
					lib.returnFocus(this._table, row, function() {
						row._item = item;
						// If the row should be expanded
						if (row && (forceExpand || row._expanded)) {
							this._removeChildRows(parentId);
							if(children){
								row._expanded = true;
								if(this._renderer.updateExpandVisuals) {
									this._renderer.updateExpandVisuals(row, true);
								}
								this._generateChildren(children, row._depth+1, row); //$NON-NLS-0$
								this._rowsChanged();
							} else {
								tree = this;
								if(this._renderer.updateExpandVisuals) {
								    this._renderer.updateExpandVisuals(row, "progress"); //$NON-NLS-0$
								}
								children = this._treeModel.getChildren(row._item, function(children) {
									if (tree.destroyed) { return; }
									if(tree._renderer.updateExpandVisuals) {
									    tree._renderer.updateExpandVisuals(row, true);
									}
									if (!row._expanded) {
										row._expanded = true;
										tree._generateChildren(children, row._depth+1, row); //$NON-NLS-0$
										tree._rowsChanged();
									}
								});
							}
						} else {
							if(this._renderer.updateExpandVisuals) {
								this._renderer.updateExpandVisuals(row, false);
							}
						}
					}.bind(this));
				} else {
					// the item wasn't found.  We could refresh the root here, but for now
					// let's log it to figure out why.
					console.log(messages["could not find table row "] + parentId);
				}
			}
		},

		/**
		 * Request an annotation refresh using the information provided by
		 * model.getAnnotations().
		 */
		requestAnnotationRefresh: function() {
			if (!this._treeModel.getAnnotations) {
				return;
			}

			if (this._annotationRefreshRequested) {
				return;
			}

			// Refresh annotation in next tick to avoid duplicate requests
			var tree = this;
			this._annotationRefreshRequested = true;
			setTimeout(function() {
				tree._annotationRefreshRequested = false;
				tree._redrawAnnotation();
			}, 0);
		},
		
		getContentNode: function() {
			return this._bodyElement;
		},
		
		getItem: function(itemOrId) {  // a dom node, a dom id, or the item
			var node = lib.node(itemOrId);
			if (node && node._item) {
				return node._item;
			}
			return itemOrId;  // return what we were given
		},
		
		toggle: function(id) {
			var row = lib.node(id);
			if (row) {
				if (row._expanded) {
					this.collapse(id, true);
				}
				else {
					this.expand(id);
				}
			}
		},
		
		isExpanded: function(itemOrId) {
			var id = typeof(itemOrId) === "string" ? itemOrId : this._treeModel.getId(itemOrId); //$NON-NLS-0$
			var row =lib.node(id);
			if (row) {
				return row._expanded;
			}
			return false;
		},
		
		expand: function(itemOrId , postExpandFunc , args) {
			var id = typeof(itemOrId) === "string" ? itemOrId : this._treeModel.getId(itemOrId); //$NON-NLS-0$
			var row = lib.node(id);
			if (row) {
				lib.setSafeAttribute(row, "aria-expanded", true);
				var gridcell = row.querySelector('span[role="gridcell"]');
				if (gridcell !== null) {
					// if navigating by gridcells, need expanded on gridcell
					lib.setSafeAttribute(gridcell, "aria-expanded", true);
				}
				var tree = this;
				if (row._expanded) {
					if (postExpandFunc) {
						postExpandFunc.apply(tree, args);
					}
					return;
				}
				if(this._renderer.updateExpandVisuals) {
				    this._renderer.updateExpandVisuals(row, "progress"); //$NON-NLS-0$
				}
				this._treeModel.getChildren(row._item, function(children) {
					if (tree.destroyed) { return; }
					if(tree._renderer.updateExpandVisuals) {
					   tree._renderer.updateExpandVisuals(row, true);
					}
					if (!row._expanded) {
						row._expanded = true;
						tree._generateChildren(children, row._depth+1, row); //$NON-NLS-0$
						tree._rowsChanged();
					}
					if (postExpandFunc) {
						postExpandFunc.apply(tree, args);
					}
				});
			}
		}, 
		
		_removeChildRows: function(parentId) {
			// true if we are removing directly from table
			var foundParent = parentId === this._id;
			var parentRow;
			var stop = false;
			var parentDepth = -1;
			var toRemove = [];
			var rows = lib.$$array(".treeTableRow", this._parent); //$NON-NLS-0$
			for (var i=0; i < rows.length; i++) {
				var row = rows[i];
				if (stop) {
					break;
				}
				if (foundParent) {
					if (!parentRow || row.parentNode === parentRow.parentNode) {
						if (row._depth > parentDepth) {
							toRemove.push(row);
						}
						else {
							stop = true;  // we reached a sibling to our parent
						}
					}
				} else {
					if (row.id === parentId) {
						foundParent = true;
						parentDepth = row._depth;
						parentRow = row;
					}
				}
			}
			for (var j=0; j<toRemove.length; j++) {
				var child = toRemove[j];
				if(child &&  child._item && typeof child._item.destroy === "function") { //$NON-NLS-0$
					child._item.destroy();
				}
				child.parentNode.removeChild(child);
			}
		},
		
		_removeAllRows: function() {
			var rows = lib.$$array(".treeTableRow", this._parent); //$NON-NLS-0$
			for (var j=0; j<rows.length; j++) {
				if(rows[j] &&  rows[j]._item && typeof rows[j]._item.destroy === "function") { //$NON-NLS-0$
					rows[j]._item.destroy();
				}
				rows[j].parentNode.removeChild(rows[j]);
			}
		},
		
		_collapse : function(id, row) {
			lib.returnFocus(this._table, row, function() {
				row._expanded = false;
				if(this._renderer.updateExpandVisuals) {
				    this._renderer.updateExpandVisuals(row, false);
				}
				this._removeChildRows(id);
				this._rowsChanged();
				if(this._onCollapse){
					this._onCollapse(row._item);
				}
			}.bind(this));
		},
		
		collapse: function(itemOrId, byToggle) {
			var id = typeof(itemOrId) === "string" ? itemOrId : this._treeModel.getId(itemOrId); //$NON-NLS-0$
			var row = lib.node(id);
			if (row) {
				lib.setSafeAttribute(row, "aria-expanded", false);
				var gridcell = row.querySelector('span[role="gridcell"]');
				if (gridcell !== null) {
					// if navigating by gridcells, need expanded on gridcell
					lib.setSafeAttribute(gridcell, "aria-expanded", false);
				}
				if (!row._expanded) {
					return;
				}
				if(byToggle && this._preCollapse){
					this._preCollapse(row._item, row).then(function(result) {
						if(result) {
							this._collapse(id, row);
						} else {
							return;
						}
					}.bind(this));
				} else {
					this._collapse(id, row);
				}
			}
		},
		
		/**
		 * Returns this tree's indentation increment
		 */
		getIndent: function() {
			return this._indent;
		}
	};  // end prototype
	TableTree.prototype.constructor = TableTree;

	/**
	 * Annotation descriptor.
	 * 
	 * Note: I'd like to use the annotation in editor bundle. However that one
	 *       is not in ui bundle and coupling to the editor too much.
	 * 
	 * @interface
	 * @name {orion.treetable.TableTree.IAnnotation}
	 */
	TableTree.IAnnotation = function() {};

	/**
	 * Get the deepest item that this annotation should display at.
	 * 
	 * @example
	 *     Suppose we have a file located in /folder/subfolder/file.ext and
	 *     the tree table is in this status:
	 *     - (/)
	 *        - (/folder)
	 *           + (/folder/subfolder)    <- this folder collapses
	 *     Then the annotation of /folder/subfolder/file.ext should be at
	 *     /folder/subfolder since it is the deepest item fits it.
	 * 
	 * @abstract
	 * 
	 * @param {orion.explorer.ExplorerModel} model - the model of the tree
	 * @param {Function} - callback that takes the DOM ID of an item from the
	 *     model as parameter
	 */
	TableTree.IAnnotation.prototype.findDeepestFitId = function(model, callback) {
		throw new Error('Not implemented.');
	};

	/**
	 * Get description of this annotation which can be used in for examole
	 * tooltip.
	 * 
	 * @abstract
	 * 
	 * @return {string} - description
	 */
	TableTree.IAnnotation.prototype.getDescription = function() {
		throw new Error('Not implemented.');
	};

	/**
	 * Generate a new HTML element of this annotation.
	 * 
	 * @abstract
	 * 
	 * @return {Element} - the HTML element of this annotation
	 */
	TableTree.IAnnotation.prototype.generateHTML = function() {
		throw new Error('Not implemented.');
	};

	//return module exports
	return {TableTree: TableTree};
});

/*******************************************************************************
 * @license
 * Copyright (c) 2011, 2012 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 * 
 * Contributors: IBM Corporation - initial API and implementation
 ******************************************************************************/

/*eslint-env browser, amd*/
define('orion/treeModelIterator',[], function(){

var exports = {};

exports.TreeModelIterator = (function() {
	/**
	 * Creates a new tree iterator.
	 *
	 * @name orion.TreeModelIterator.TreeModelIterator
	 * @class A tree model based iterator component.
	 * @param {list} firstLevelChildren The first level children of the tree root, each item has children and parent property recursively.
	 * @param {Object} options The options object which provides iterate patterns and all call back functions when iteration happens.
	 */
	function TreeModelIterator(firstLevelChildren, options) {
		this.firstLevelChildren = firstLevelChildren;
		this.reset();
		this._init(options);
	}
	TreeModelIterator.prototype = /** @lends orion.TreeModelIterator.TreeModelIterator.prototype */ {
		
		_init: function(options){
			if(!options){
				return;
			}
			this.isExpanded = options.isExpanded;//optional callback providing that if a model item is expanded even if it has children. Default is true if it has children.
			this.isExpandable = options.isExpandable;//optional  callback providing that if a model item is expandable.Default is true .
			this.forceExpandFunc = options.forceExpandFunc;//optional  callback providing the expansion on the caller side.
			this.getChildrenFunc = options.getChildrenFunc;//optional  callback providing the of a parent, instead of using the .children property.
		},
			
		topLevel: function(modelItem) {
			return modelItem.parent ? (modelItem.parent === this.root) : true;
		},
		
		_getChildren: function(model){
			if(typeof this.getChildrenFunc === "function") {
				return this.getChildrenFunc(model);
			}
			return model ? model.children : null;
		},
		
		_expanded: function(model){
			if(!model){
				return true;//root is always expanded
			}
			var children = this._getChildren(model);
			var expanded = (children && children.length > 0);
			if(this.isExpanded && expanded){
				expanded = this.isExpanded(model);
			}
			return expanded;
		},
		
		//This is for the force expand
		_expandable: function(model){
			if(!model){
				return true;//root is always expandable
			}
			if(this.isExpandable){
				return this.isExpandable(model);
			}
			return false;//If there is no isExpandable provided, we assume nothing is expandable
		},
		
		_diveIn: function(model){
			if( this._expanded(model)){
				var children = this._getChildren(model);
				this.setCursor(children[0]);
				return this.cursor();
			}
			return null;
		},
		
		_drillToLast: function(model){
			if( this._expanded(model)){
				var children = this._getChildren(model);
				return this._drillToLast(children[children.length-1]);
			}
			return model;
		},
		
		_forward: function(forceExpand){
			//first we will try to dive into the current cursor
			if(!this._cursor){
				return null;
			}
			var next = this._diveIn(this._cursor);
			if(!next){
				if(forceExpand && this._expandable(this._cursor) && this.forceExpandFunc){
					var that = this;
					return this.forceExpandFunc(this._cursor, "first", function(model){if(model){that.setCursor(model);}}); //$NON-NLS-0$
				}
				next = this._findSibling(this._cursor, true);
				if(next){
					this.setCursor(next);
				} 
			}
			return next;
		},
		
		_backward: function(forceExpand){
			if(!this._cursor){
				return null;
			}
			var previous = this._findSibling(this._cursor, false);
			if(previous && previous !== this._cursor.parent){
				previous = this._drillToLast(previous);
			}
			if(forceExpand && previous && this._expandable(previous) && this.forceExpandFunc && previous !== this._cursor.parent){
				var that = this;
				return this.forceExpandFunc(previous, "last", function(model){if(model){that.setCursor(model);}}); //$NON-NLS-0$
			}
			if(previous){
				this.setCursor(previous);
			} 
			return previous;
		},
		
		_findSibling: function(current, forward){
			var isTopLevel = this.topLevel(current);
			var children = this._getChildren(current.parent);
			var siblings = isTopLevel ? this.firstLevelChildren: children;
			for(var i = 0; i < siblings.length; i++){
				if(siblings[i] === current){
					if((i === 0 && !forward) ){
						return isTopLevel ? null : current.parent;
					} else if (i === (siblings.length-1) && forward) {
						return isTopLevel ? null : this._findSibling(current.parent, forward);
					} else {
						return forward ? siblings[i+1] : siblings[i-1];
					}
				}
			}
			return null;
		},
		
		_inParentChain: function(model, compareTo){
			var parent = model.parent;
			while(parent){
				if(parent === compareTo){
					return true;
				}
				parent = parent.parent;
			}
			return false;
		},
		
		_getTopLevelParent: function(model){
			if(this.topLevel(model)){
				return model;
			}
			var parent = model.parent;
			while(parent){
				if(this.topLevel(parent)){
					return parent;
				}
				parent = parent.parent;
			}
			return null;
		},
		
		_onCollapse: function(model){
			if(this._expanded(model.parent)){
				return model;
			}
			return this._onCollapse(model.parent);
		},
		
		_scan: function(forward, from, to){
			this.setCursor(from);
			var selection = [];
			selection.push(from);
			while(true){
				if(this.iterate(forward)){
					selection.push(this.cursor());
				} else {
					break;
				}
				if(to === this.cursor()){
					return selection;
				}
			}
			selection = [];
			return null;
		},
		
		/**
		 * Set the cursor to the given model
		 * @param {Object} the given model
		 */
		setCursor: function(modelItem) {
			this._prevCursor = this._cursor;
			this._cursor = modelItem;
		},
		
		/**
		 * Set the the first level children
		 * @param {list} the first level children
		 */
		setTree: function(firstLevelChildren) {
			this.firstLevelChildren = firstLevelChildren;
			if(this.firstLevelChildren.length > 0){
				this.root = this.firstLevelChildren[0].parent;
			}
		},
		
		/**
		 * Iterate from the current cursor
		 * @param {object} from the model object that the selection range starts from. Will be included in the return array.
		 * @param {object} to the model object that the selection range ends at. Will be included in the return array.
		 * @returns {Array} The selection of models in the array.
		 */
		scan: function(from, to) {
			var currentCursor = this.cursor();
			var selection = this._scan(true, from, to);
			if(!selection){
				selection = this._scan(false, from, to);
			}
			this.setCursor(currentCursor);
			return selection;
		},
		
		/**
		 * scan a selection range 
		 * @param {boolean} forward the iteration direction. If true then iterate to next, otherwise previous.
		 * @param {boolean} forceExpand optional. the flag for the current cursor to dive into its children. 
		 *                  If the cursor has no children yet or its children are not expanded, this method will call forceExpandFunc.
		 *                  If there is no forceExpandFunc defined it will not expand.
		 */
		iterate: function(forward, forceExpand) {
			return forward ? this._forward(forceExpand) : this._backward(forceExpand);
		},
		
		/**
		 * Iterate from the current cursor only on the top level children
		 * @param {boolean} forward the iteration direction. If true then iterate to next, otherwise previous.
		 * @param {boolean} roundTrip the round trip flag. If true then iterate to the beginning at bottom or end at beginning.
		 */
		iterateOnTop: function(forward, roundTrip) {
			var topSibling = this._findSibling(this._getTopLevelParent(this.cursor()), forward);
			if(topSibling){
				this.setCursor(topSibling);
			} else if(roundTrip && this.firstLevelChildren.length > 0) {
				this.setCursor(forward ? this.firstLevelChildren[0] : this.firstLevelChildren[this.firstLevelChildren.length - 1]);
			}
		},
		
		/**
		 * When the parent model containing the cursor is collapsed, the cursor has to be surfaced to the parent
		 */
		collapse: function(collapsedModel) {
			if(!this._cursor){
				return null;
			}
			if(this._inParentChain(this._cursor, collapsedModel)){
				this.setCursor(collapsedModel);
				return this._cursor;
			}
			return null;
		},
		
		/**
		 * Reset cursor and previous cursor
		 */
		reset: function(){
			this._cursor = null;
			this._prevCursor = null;
			this.root = null;
			//By default the cursor is pointed to the first child 
			if(this.firstLevelChildren.length > 0){
				this._cursor = this.firstLevelChildren[0];
				this.root = this.firstLevelChildren[0].parent;
			}
		},
		
		/**
		 * Convenient method to see if last iterate action moved the cursor
		 */
		cursorMoved: function(){
			return this._cursor !== this._prevCursor;
		},
		
		/**
		 * Get current selected model by the iteration
		 */
		cursor: function(){
			return this._cursor;
		},
		
		/**
		 * Get previously selected model by the iteration
		 */
		prevCursor: function(){
			return this._prevCursor;
		}
	};
	return TreeModelIterator;
}());

return exports;
});

/*******************************************************************************
 * @license
 * Copyright (c) 2011, 2019 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 * 
 * Contributors: IBM Corporation - initial API and implementation
 ******************************************************************************/

/*eslint-env browser, amd*/
define('orion/explorers/explorerNavHandler',[
	'orion/webui/littlelib',
	'orion/treeModelIterator',
	'orion/uiUtils',
	'orion/urlModifier'
], function(lib, mTreeModelIterator, UiUtils, urlModifier) {

var exports = {};
var userAgent = navigator.userAgent;
var isPad = userAgent.indexOf("iPad") !== -1; //$NON-NLS-0$
var isMac = window.navigator.platform.indexOf("Mac") !== -1; //$NON-NLS-0$

exports.ExplorerNavHandler = (function() {

	/**
	 * Creates a new tree iteration handler
	 * 
	 * @name orion.explorerNavHandler.ExplorerNavHandler
	 * @class A tree iteration handler based on an explorer.
	 * @param {Object} explorer The {@link orion.explorer.Explorer} instance.
	 * @param {Object} options The options object which provides iterate patterns and all call back functions when iteration happens.
	 * @param {String} [options.gridClickSelectionPolicy="none"] Controls how clicking on a grid model item -- for example, a link or a button -- affects
	 * the selection (or how it affects the cursor, if the <code>selectionPolicy</code> is <code>"cursorOnly"</code>). Allowed values are:
	 * <ul>
	 * <li><code>"none"</code>: Clicking on a grid item will not change the selection (or cursor). This is the default.</li>
	 * <li><code>"active"</code>: Clicking on a grid item will change the selection (or cursor).</li>
	 * </ul>
	 * @param {String} [options.selectionPolicy=null] Selection policy for this explorer. Allowed values are:
	 * <ul>
	 * <li><code>"cursorOnly"</code>: No selection of model items is allowed.</li>
	 * <li><code>"singleSelection"</code>: Up to 1 model item can be selected.</li>
	 * <li><code>"readonlySelection"</code>: Selection cannot be changed while this selection policy is set.</li>
	 * <li><code>null</code>: Zero or more model items can be selected. This is the default.</li>
	 * </ul>
	 * @param {Function} [options.postDefaultFunc] If this function provides addtional behaviors after the default behavior. Some explorers may want to do something else when the cursor is changed, etc.
	 * @param {Function} [options.preventDefaultFunc] If this function returns true then the default behavior of all key press will stop at this time.
	 * The key event is passed to preventDefaultFunc. It can implement its own behavior based on the key event.
	 */
	function ExplorerNavHandler(explorer, navDict, options) {
		this.explorer = explorer;
		this.model = this.explorer.model;
		this._navDict = navDict;
		
		this._listeners = [];
		this._selections = [];

		this._currentColumn = 0;
		var parentDiv = this._getEventListeningDiv();
		this._parentDiv = parentDiv;
		parentDiv.tabIndex = 0;
		parentDiv.classList.add("selectionModelContainer"); //$NON-NLS-0$
		var self = this;
		this._modelIterator = new mTreeModelIterator.TreeModelIterator([], {
			isExpanded: this.isExpanded.bind(this),		
			getChildrenFunc: options.getChildrenFunc,
			isExpandable: this.explorer.renderer.isExpandable ? 
				function(model) { return self.explorer.renderer.isExpandable(model); } : 
				function(model) { return self.isExpandable(model); },
			forceExpandFunc: this.explorer.forceExpandFunc ? 
				function(modelToExpand, childPosition, callback) {
					return self.explorer.forceExpandFunc(modelToExpand, childPosition, callback);
				} : undefined
		});
		this._init(options);
		
		var keyListener = function (e) { 
			if(UiUtils.isFormElement(e.target)) {
				// Not for us
				return true;
			}
			if(self.explorer.preventDefaultFunc && self.explorer.preventDefaultFunc(e, self._modelIterator.cursor())){
				return true;
			}
			if(e.keyCode === lib.KEY.DOWN) {
				return self.onDownArrow(e);
			} else if(e.keyCode === lib.KEY.UP) {
				return self.onUpArrow(e);
			} else if(e.keyCode === lib.KEY.RIGHT) {
				return self.onRightArrow(e);
			} else if(e.keyCode === lib.KEY.LEFT) {
				return self.onLeftArrow(e);
			} else if(e.keyCode === lib.KEY.SPACE) {
				return self.onSpace(e);
			} else if(e.keyCode === lib.KEY.ENTER) {
				return self.onEnter(e);
			} else if (e.keyCode === lib.KEY.TAB && e.shiftKey) {
				if (document.activeElement.classList.contains("treeTableRow")
				  || document.activeElement.classList.contains("treeTableGridCell")) {
					  parentDiv.tabIndex = -1;
				}
			}
		};
		parentDiv.addEventListener("keydown", keyListener, false); //$NON-NLS-0$
		this._listeners.push({type: "keydown", listener: keyListener}); //$NON-NLS-0$
		var mouseListener = function (e) {
			if(UiUtils.isFormElement(e.target)) {
				// Not for us
				return true;
			}
			if (e.shiftKey && self._shiftSelectionAnchor) {
				lib.stop(e);
			}
		};
		parentDiv.addEventListener("mousedown", mouseListener, false); //$NON-NLS-0$
		this._listeners.push({type: "mousedown", listener: mouseListener}); //$NON-NLS-0$
		var offsetParent = lib.getOffsetParent(this._parentDiv);
		var scrollListener = function() {
			self._scrollTop = offsetParent ? offsetParent.scrollTop : 0;
		};
		offsetParent.addEventListener("scroll", scrollListener);
		this._listeners.push({type: "scroll", listener: scrollListener}); //$NON-NLS-0$
		var l1 = this._blurListener = function (e) { 
			self.toggleCursor(null, false, e);
			if(self.explorer.onFocus){
				self.explorer.onFocus(false);
			}
		};
		parentDiv.addEventListener("blur", l1, false); //$NON-NLS-0$
		this._listeners.push({type: "blur", listener: l1}); //$NON-NLS-0$
		var l2 = this._focusListener = function (e) {
			offsetParent.scrollTop = self._scrollTop;
			self.toggleCursor(null, true, e);
			if(self.explorer.onFocus){
				self.explorer.onFocus(true);
			}
		};
		parentDiv.addEventListener("focus", l2, false); //$NON-NLS-0$
		this._listeners.push({type: "focus", listener: l2}); //$NON-NLS-0$
		if(!options || options.setFocus !== false){
			this.focus();
		}
	}
	
	ExplorerNavHandler.prototype = /** @lends orion.explorerNavHandler.ExplorerNavHandler.prototype */ {
		
		destroy: function() {
			this._parentDiv.classList.remove("selectionModelContainer"); //$NON-NLS-0$
			this.removeListeners();	
		},
		
		_init: function(options){
			this._linearGridMove = false;//temporary. If true right key on the last grid will go to first grid of next row
			                            // Left key on the first grid will go to the last line grid of the previous line
			if(!options){
				return;
			}
			this._selectionPolicy = options.selectionPolicy;
			this.gridClickSelectionPolicy = options.gridClickSelectionPolicy || "none"; //$NON-NLS-0$
			this.preventDefaultFunc = options.preventDefaultFunc;
			this.postDefaultFunc = options.postDefaultFunc;
		},
		
		_ctrlKeyOn: function(e){
			return isMac ? e.metaKey : e.ctrlKey;
		},
		
		removeListeners: function(){
			if(this._listeners){
				for (var i=0; i < this._listeners.length; i++) {
					this._parentDiv.removeEventListener(this._listeners[i].type, this._listeners[i].listener, false);
				}
			}
		},
		
		focus: function(){
		    var parentDiv = this._getEventListeningDiv();
		    if(parentDiv){
				parentDiv.focus();
		    }
		},
		
		_getEventListeningDiv: function(secondLevel){
			if(this.explorer.keyEventListeningDiv && typeof this.explorer.keyEventListeningDiv === "function"){ //$NON-NLS-0$
				return this.explorer.keyEventListeningDiv(secondLevel);
			}
			return lib.node(this.explorer._parentId);
		},
		
		isExpandable: function(model){
			if(!model){
				return false;
			}
			var expandImage = lib.node(this.explorer.renderer.expandCollapseImageId(this.model.getId(model)));
			return expandImage ? true: false;
		},
		
		isExpanded: function(model){
			if(!model){
				return false;
			}
			return this.explorer.myTree.isExpanded(this.model.getId(model));
		},
		
		refreshSelection: function(noScroll, visually){
			var that = this;
			if(this.explorer.selection){
				this.explorer.selection.getSelections(function(selections) {
					that._clearSelection(visually);
					for (var i = 0; i < selections.length; i++){
						that._selections.push(selections[i]);
					}
					if(that._selections.length > 0){
						that.cursorOn(that._selections[0], true, false, noScroll);
					} else {//If there is no selection, we should just the first item as the cursored items.  
						that.cursorOn(null, false, false, noScroll);
					}
					//If shift selection anchor exists and in the refreshed selection range, we just keep it otherwise clear the anchor
					//See https://bugs.eclipse.org/bugs/show_bug.cgi?id=419170
					if(!(that._shiftSelectionAnchor && that._inSelection(that._shiftSelectionAnchor) >= 0)){
						that._shiftSelectionAnchor = null;
					}
				});
			}
		},
		
		refreshModel: function(navDict, model, topIterationNodes, noReset){
		    this._currentColumn = 0;
			this.topIterationNodes = [];
			this.model = model;
			this._navDict = navDict;
			if(this.model.getTopIterationNodes){
				this.topIterationNodes = this.model.getTopIterationNodes();
			} else if(topIterationNodes){
				this.topIterationNodes = topIterationNodes;
			}
			this._modelIterator.setTree(this.topIterationNodes);
			if(!noReset && this.explorer.selection){
				//refresh the current cursor visual, otherwise the next cursorOn() call will not remove the previoous cursor visual properly.
				this.toggleCursor(this._modelIterator.cursor(), false);
				this._modelIterator.reset();
			}
			this.refreshSelection(true);
		},
		
		getTopLevelNodes: function(){
			return this._modelIterator.firstLevelChildren;
		},
		
		_inSelection: function(model){
			var modelId = this.model.getId(model);
			for(var i = 0; i < this._selections.length; i++){
				if(modelId === this.model.getId(this._selections[i])){
					return i;
				}
			}
			return -1;
		},
		
		
		_clearSelection: function(visually){
			if(visually){
				for(var i = 0; i < this._selections.length; i++){
					this._checkRow(this._selections[i], true);
				}
			}
			this._selections = [];
		},
		
		getSelectionPolicy: function() {
			return this._selectionPolicy;
		},
		
		setSelectionPolicy: function(policy) {
			if (this._selectionPolicy === policy) {
				return;
			}
			if(this._selectionPolicy === "readonlySelection" || policy === "readonlySelection"){
				this._toggleSelectionClass("disabledRow", policy==="readonlySelection");
			}
			this._selectionPolicy = policy;
			if(this._selectionPolicy === "cursorOnly"){ //$NON-NLS-0$
				this._clearSelection(true);
			}
		},
		
		setSelection: function(model, toggling, shiftSelectionAnchor){
			if(this._selectionPolicy === "readonlySelection"){
				return false;
			}
			if(this._selectionPolicy === "cursorOnly"){ //$NON-NLS-0$
				if(toggling && this.explorer.renderer._useCheckboxSelection){
					this._checkRow(model,true);
					return true;
				}
				return false;
			}
			if(!this._isRowSelectable(model)){
				return false;
			}
			if(!toggling || this._selectionPolicy === "singleSelection"){//$NON-NLS-0$
				this._clearSelection(true);
				this._checkRow(model,false);		
				this._selections.push(model);
				this._lastSelection = model;
			} else{
				var index = this._inSelection(model);
				if(index >= 0){
					this._checkRow(model, true);
					this._selections.splice(index, 1);
				} else {
					this._checkRow(model,false);		
					this._selections.push(model);
					this._lastSelection = model;
				}
			}
			if(shiftSelectionAnchor){
				this._shiftSelectionAnchor = this._lastSelection;
			}
			if (this.explorer.selection) {
				this.explorer.renderer.storeSelections();
				this.explorer.selection.setSelections(this._selections);		
			}
			return true;
		},
		
		moveColumn: function(model, offset){
			if(!model){
				model = this.currentModel();
			}
			var gridChildren = this._getGridChildren(model);
			if((gridChildren && gridChildren.length > 1) || (offset === 0 && gridChildren)){
				if(offset !== 0){
					this.toggleCursor(model, false);
				}
				var column = this._currentColumn;
				var rowChanged= true;
				column = column + offset;
				if(column < 0){
					if(this._linearGridMove && offset !== 0){
						if(this._modelIterator.iterate(false)){
							model = this.currentModel();
						} else {
							rowChanged = false;
						}
					}
					column = rowChanged ? gridChildren.length - 1 : this._currentColumn;
				} else if(column >= gridChildren.length){
					if(this._linearGridMove && offset !== 0){
						if(this._modelIterator.iterate(true)){
							model = this.currentModel();
						} else {
							rowChanged = false;
						}
					}
					column = rowChanged ? 0 : this._currentColumn;
				}
				this._currentColumn = column;
				if(offset !== 0){
					this.toggleCursor(model, true);
				}
				return true;
			}
			return false;
		},
		
		_getGridChildren: function(model){
			if(this._navDict){
				return this._navDict.getGridNavHolder(model);
			}
			return null;
		},
		
		getCurrentGrid:  function(model){
			if(!model){
				model = this.currentModel();
			}
			var gridChildren = this._getGridChildren(model);
			if(gridChildren && gridChildren.length > 0){
				return gridChildren[this._currentColumn];
			}
			return null;
		},

		getFocusableElems: function(root) {
			var nodeList = root.querySelectorAll('a,button,input,select,textarea,[tabIndex]');
			return Array.prototype.slice.call(nodeList);
		},
		
		getAllRows: function() {
			var nodeList = this._parentDiv.querySelectorAll(".treeTableRow");
			return Array.prototype.slice.call(nodeList);
		},
		
		rowsChanged: function() {
			this.getAllRows().forEach(function(row) {
				var model = this._modelIterator.cursor();
				if (!model) {
					model = row._item;
					this._modelIterator.setCursor(model);
					if (this._parentDiv === document.activeElement) {
						this.toggleCursor(model, true);
					}
				} 
				if (!row._focusListener) {
					row._focusListener = this._focusListener;
					row.addEventListener("focus", this._focusListener);
				}
				if (!row._blurListener) {
					row._blurListener = this._blurListener;
					row.addEventListener("blur", this._blurListener);
				}
			}.bind(this));
		},

		toggleCursor:  function(model, on, evt){
			if (!model) {
				if (on && evt && evt.target._item) {
					model = evt.target._item;
					this._modelIterator.setCursor(model);
				}
			}
			if (!model) {
				model = this._modelIterator.cursor();
			}
			if (!model) {
				model = this.model.root && this.model.root.children && this.model.root.children[0];
				this._modelIterator.setCursor(model);
			}
			var currentRow = this.getRowDiv(model);
			var currentgrid = this.getCurrentGrid(model);
			var gridChildren = this._getGridChildren(model);
			if (on) {
				this.getFocusableElems(this._parentDiv).forEach(function(element) {
					if (element.savedTabIndex === undefined) {
						element.savedTabIndex = element.tabIndex;
					}
					element.tabIndex = -1;
				});
			}
			var handleRow = function (className) {
				if(currentRow){
					if (on) {
						if (this._parentDiv === document.activeElement || document.activeElement.parentNode === currentRow.parentNode
						    || (currentgrid && document.activeElement.parentNode === currentRow)) {
							currentRow.classList.add(className);
							currentRow.tabIndex = "0";
							this.getFocusableElems(currentRow).forEach(function(element) {
								if (element.savedTabIndex === -1) {
									return;
								}
								element.tabIndex = 0;
							});
							this._parentDiv.removeAttribute("tabindex");
							if (!(evt && evt.target !== this._parentDiv) && document.activeElement !== currentRow) {
								currentRow.focus();
								this.scroll();
							}
						}
					} else {
						currentRow.tabIndex = "-1";
						this._parentDiv.tabIndex = "0";
						currentRow.classList.remove(className);
					}
				}
			}.bind(this);
			if(currentgrid) {
				handleRow("treeIterationCursorRow"); //$NON-NLS-0$
				if(currentgrid.domNode && gridChildren.length > 1){
					if (on) {
						currentgrid.domNode.classList.add("treeIterationCursor"); //$NON-NLS-0$
						currentgrid.domNode.tabIndex = 0;
						currentgrid.domNode.focus();
					} else {
						currentgrid.domNode.classList.remove("treeIterationCursor"); //$NON-NLS-0$
						currentgrid.domNode.tabIndex = -1;
					}
				}
			} else {
				handleRow("treeIterationCursorRow_Dotted"); //$NON-NLS-0$
			}
		},
		
		currentModel: function(){
			return this._modelIterator.cursor();
		},
		
		getScrollParent: function(node) {
			if (!node) {
				return null;
			}
			var overflow = window.getComputedStyle(node).overflowY;
			if (!(overflow === "visible" || overflow === "hidden")) {
				return node;
			}
			return this.getScrollParent(node.parentElement);
		},
		
		scroll: function(next) {
			var currentRowDiv = this.getRowDiv();
			if(currentRowDiv) {
				var offsetParent = lib.getOffsetParent(currentRowDiv);
				if (offsetParent) {
					var visible = true;
					var offset = this.getScrollParent(currentRowDiv) !== this._parentDiv ? this._parentDiv.offsetTop : 0;
					var rowTop = offset + currentRowDiv.offsetTop;
					var clientHeight = offsetParent.clientHeight;
					if(rowTop <= offsetParent.scrollTop){
						visible = false;
						if(next === undefined){
							next = false;
						}
					}else if((rowTop + currentRowDiv.offsetHeight) >= (offsetParent.scrollTop + offsetParent.clientHeight)){
						visible = false;
						if(next === undefined){
							next = true;
						}
					}
					if(!visible){
						var scrollTop = offset + currentRowDiv.offsetTop - (next ? clientHeight * 3 / 4 : clientHeight / 4);
						this._scrollTop = scrollTop;
						offsetParent.scrollTop = scrollTop; 
						//currentRowDiv.scrollIntoView(!next);
					}
				}
			}
		},
		
		cursorOn: function(model, force, next, noScroll){
			var previousModel, currentModel;
			if(model || force){
				if(currentModel === this._modelIterator.cursor()){
					return;
				}
				previousModel = this._modelIterator.cursor();
				currentModel = model;
				this._modelIterator.setCursor(currentModel);
			} else {
				previousModel = this._modelIterator.prevCursor();
				currentModel = this._modelIterator.cursor();
			}
			if(previousModel === currentModel && !force){
				return;
			}
			this.toggleCursor(previousModel, false);
			if(force && !currentModel){
				return;
			}
			this.moveColumn(null, 0);
			this.toggleCursor(currentModel, true);
			if(!noScroll) {
				this.scroll(next);
			}
			if(this.explorer.onCursorChanged){
				this.explorer.onCursorChanged(previousModel, currentModel);
			}
		},
		
		getSelection: function(){
			return this._selections;
		},
		
		getSelectionIds: function(){
			var ids = [];
			for (var i = 0; i < this._selections.length; i++) {
				ids.push(this.model.getId(this._selections[i]));
			}
			return ids;
		},
		
		getRowDiv: function(model){
			var rowModel = model ? model: this._modelIterator.cursor();
			if(!rowModel){
				return null;
			}
			var modelId = this.model.getId(rowModel);
			var value = this._navDict.getValue(modelId);
			return value && value.rowDomNode ? value.rowDomNode :  lib.node(modelId);
		},
		
		iterate: function(forward, forceExpand, selecting, selectableOnly /* optional */)	{
			var currentItem = null;
			
			if(!this.topIterationNodes || this.topIterationNodes.length === 0){
				return;
			}
				
			if (selectableOnly) {
				var previousItem = this.currentModel();
				
				currentItem = this._modelIterator.iterate(forward, forceExpand);
				if(currentItem){
					this._setCursorOnItem(forward, selecting);
				}
				
				while (currentItem && currentItem.isNotSelectable) {
					currentItem = this._modelIterator.iterate(forward, forceExpand);
					if(currentItem){
						this._setCursorOnItem(forward, selecting);
					}
				}
				
				if (!currentItem) {
					// got to the end of the list and didn't find anything selectable, iterate back
					this.cursorOn(previousItem, true, false, true);
					this._setCursorOnItem(forward, selecting);
				}
			} else {
				currentItem = this._modelIterator.iterate(forward, forceExpand);
				if(currentItem){
					this._setCursorOnItem(forward, selecting);
				}
			}
		},
		
		_toggleSelectionClass: function(className, on){
			this._selections.forEach(function(selection){
				var selectedDiv = this.getRowDiv(selection);
				if(!selectedDiv){
					return;
				}
				if(on){
					selectedDiv.classList.add(className);
				} else {
					selectedDiv.classList.remove(className);
				}
			}.bind(this));
		},
		
		_setCursorOnItem: function(forward, selecting) {
			this.cursorOn(null, false, forward);
			if(selecting){
				var previousModelInSelection = this._inSelection(this._modelIterator.prevCursor());
				var currentModelInselection = this._inSelection(this._modelIterator.cursor());
				if(previousModelInSelection >= 0 && currentModelInselection >= 0) {
					this.setSelection(this._modelIterator.prevCursor(), true);
				} else {
					this.setSelection(this.currentModel(), true);
				}
			}
		},
		
		_checkRow: function(model, toggle) {
			if(this.explorer.renderer._useCheckboxSelection && this._selectionPolicy !== "singleSelection"){
				var tableRow = this.getRowDiv(model);
				if(!tableRow){
					return;
				}
				var checkBox  = lib.node(this.explorer.renderer.getCheckBoxId(tableRow.id));
				var checked = toggle ? !checkBox.checked : true;
				if(checked !== checkBox.checked){
					this.explorer.renderer.onCheck(tableRow, checkBox, checked, true, false, model);
				}
			} else {
				this._select(model, toggle);
			}
		},
		
		_select: function(model, toggling){
			if(!model){
				model = this._modelIterator.cursor();
			}
			var rowDiv = this.getRowDiv(model);
			if(rowDiv){
				if (this._inSelection(model) < 0) {
					lib.setSafeAttribute(rowDiv, "aria-selected", true);
					rowDiv.classList.add("checkedRow"); //$NON-NLS-0$
				} else {
					lib.setSafeAttribute(rowDiv, "aria-selected", false);
					rowDiv.classList.remove("checkedRow"); //$NON-NLS-0$
				}
			}
		},
		
		_onModelGrid: function(model, mouseEvt){
			var gridChildren = this._getGridChildren(model);
			if(gridChildren){
				for(var i = 0; i < gridChildren.length; i++){
					if(mouseEvt.target === gridChildren[i].domNode){
						return true;
					}
				}
			}
			return false;
		},
		
		onClick: function(model, mouseEvt)	{
			if(mouseEvt && UiUtils.isFormElement(mouseEvt.target)) {
				// Not for us
				return true;
			}
			if (this._selectionPolicy === "readonlySelection" || this.isDisabled(this.getRowDiv(model))) { //$NON-NLS-0$
				lib.stop(mouseEvt);
			} else {
				var twistieSpan = lib.node(this.explorer.renderer.expandCollapseImageId(this.model.getId(model)));
				if(mouseEvt.target === twistieSpan){
					return;
				}
				this.explorer.isDesktopSelectionMode().then(function(desktopMode) {
					if(!desktopMode && this.gridClickSelectionPolicy === "none" && this._onModelGrid(model, mouseEvt)){ //$NON-NLS-0$
						return;
					}
					this.cursorOn(model, true, false, true);
					if(isPad){
						this.setSelection(model, true);
					} else if(this._ctrlKeyOn(mouseEvt)){
						this.setSelection(model, true, true);
					} else if(mouseEvt.shiftKey && this._shiftSelectionAnchor){
						var scannedSel = this._modelIterator.scan(this._shiftSelectionAnchor, model);
						if(scannedSel){
							this._clearSelection(true);
							for(var i = 0; i < scannedSel.length; i++){
								this.setSelection(scannedSel[i], true);
							}
						}
					} else {
						this.setSelection(model, false, true);
					}
				}.bind(this));
			}
		},
		
		onCollapse: function(model)	{
			if(this._modelIterator.collapse(model)){
				this.cursorOn(model);
			}
		},
		
		//Up arrow key iterates the current row backward. If control key is on, browser's scroll up behavior takes over.
		//If shift key is on, it toggles the check box and iterates backward.
		onUpArrow: function(e) {
			this.iterate(false, false, e.shiftKey, true);
			if(!this._ctrlKeyOn(e) && !e.shiftKey){
				this.setSelection(this.currentModel(), false, true);
			}
			e.preventDefault();
			return false;
		},

		//Down arrow key iterates the current row forward. If control key is on, browser's scroll down behavior takes over.
		//If shift key is on, it toggles the check box and iterates forward.
		onDownArrow: function(e) {
			this.iterate(true, false, e.shiftKey, true);
			if(!this._ctrlKeyOn(e) && !e.shiftKey){
				this.setSelection(this.currentModel(), false, true);
			}
			e.preventDefault();
			return false;
		},

		_shouldMoveColumn: function(e, right){
			var model = this.currentModel();
			var gridChildren = this._getGridChildren(model);
			if(gridChildren && gridChildren.length > 1){
				if(this._currentColumn === 0){
				  if (!right || (right && this.isExpandable(model) && !this.isExpanded(model))) {
				    return this._ctrlKeyOn(e);
				  }
				}
				return true;
			} else {
				return false;
			}
		},
		
		//Left arrow key collapses the current row. If current row is not expandable(e.g. a file in file navigator), move the cursor to its parent row.
		//If current row is expandable and expanded, collapse it. Otherwise move the cursor to its parent row.
		onLeftArrow:  function(e) {
			if(this._shouldMoveColumn(e)){
				this.moveColumn(null, -1);
				e.preventDefault();
				return true;
			}
			var curModel = this._modelIterator.cursor();
			if(!curModel){
				return false;
			}
			if(this.isExpandable(curModel)){
				if(this.isExpanded(curModel)){
					this.explorer.myTree.collapse(curModel);
					e.preventDefault();
					return true;
				}
			}
			if(!this._modelIterator.topLevel(curModel)){
				this.cursorOn(curModel.parent);
				this.setSelection(curModel.parent, false, true);
			//The cursor is now on a top level item which is collapsed. We need to ask the explorer is it wants to scope up.	
			} else if (this.explorer.scopeUp && typeof this.explorer.scopeUp === "function"){ //$NON-NLS-0$
				this.explorer.scopeUp();
			}
		},
		
		//Right arrow key expands the current row if it is expandable and collapsed.
		onRightArrow: function(e) {
			if(this._shouldMoveColumn(e, true)){
				this.moveColumn(null, 1);
				e.preventDefault();
				return true;
			}
			var curModel = this._modelIterator.cursor();
			if(!curModel){
				return false;
			}
			if(this.isExpandable(curModel)){
				if(!this.isExpanded(curModel)){
					this.explorer.myTree.expand(curModel);
					if (this.explorer.postUserExpand) {
						this.explorer.postUserExpand(this.model.getId(curModel));
					}
					e.preventDefault();
					return false;
				}
			}
		},
		
		_isRowSelectable: function(model){
			return this.explorer.isRowSelectable ? this.explorer.isRowSelectable(model) : true;
		},

		//Space key toggles the check box on the current row if the renderer uses check box
		onSpace: function(e) {
			if (!e.target.classList.contains("treeTableRow")) return;
			if(this.setSelection(this.currentModel(), true, true)) {
				e.preventDefault();
			}
		},
		
		//Enter key simulates a href call if the current row has an href link rendered. The render has to provide the getRowActionElement function that returns the href DIV.
		onEnter: function(e) {
			var currentGrid = this.getCurrentGrid(this._modelIterator.cursor());
			if(currentGrid){
				if(currentGrid.widget){
					if(typeof currentGrid.onClick === "function"){ //$NON-NLS-0$
						currentGrid.onClick();
					} else if(typeof currentGrid.widget.focus === "function"){ //$NON-NLS-0$
						currentGrid.widget.focus();
					}
				} else {
					var evt = document.createEvent("MouseEvents"); //$NON-NLS-0$
					evt.initMouseEvent("click", true, true, window, //$NON-NLS-0$
							0, 0, 0, 0, 0, this._ctrlKeyOn(e), false, false, false, 0, null);
					currentGrid.domNode.dispatchEvent(evt);
				}
				return;
			}
			
			var curModel = this._modelIterator.cursor();
			if(!curModel){
				return;
			}
			
			if(this.explorer.renderer.getRowActionElement){
				var div = this.explorer.renderer.getRowActionElement(this.model.getId(curModel));
				if(div.href){
					if(this._ctrlKeyOn(e)){
						window.open(urlModifier(div.href));
					} else {
						window.location.href = urlModifier(div.href);
					}
				}
			}
			if(this.explorer.renderer.performRowAction){
				this.explorer.renderer.performRowAction(e, curModel);
				e.preventDefault();
				return false;
			}
		},
		
		/**
		 * Sets the isNotSelectable attribute on the specified model.
		 * @param {Object} model
		 * @param {Boolean} isNotSelectable true makes the this.iterate() with selectableOnly specified skip the item
		 */
		setIsNotSelectable: function(model, isNotSelectable) {
			model.isNotSelectable = isNotSelectable;
		},
		
		/**
		 * Disables the specified model making it no longer respond 
		 * to user input such as mouse click or key presses. The
		 * CSS style of corresponding row node is also modified to
		 * reflect its disabled state.
		 * 
		 * @param {Object} model
		 */
		disableItem: function(model) {
			var rowDiv = this.getRowDiv(model);
			if (this.isExpandable(model) && this.isExpanded(model)) {
				this._modelIterator.collapse(model);
				this.explorer.myTree.toggle(rowDiv.id); // collapse tree visually
			}
			rowDiv.classList.remove("checkedRow"); //$NON-NLS-0$
			rowDiv.classList.add("disabledNavRow"); //$NON-NLS-0$
			this.setIsNotSelectable(model, true);
		},
		
		/**
		 * Checks if the specified html row node is disabled.
		 * @return true if the specified node's classList contains the 
		 * 			"disabledNavRow" class, false otherwise
		 */
		isDisabled: function(rowDiv) {
			return rowDiv ? rowDiv.classList.contains("disabledNavRow") : true; //$NON-NLS-0$
		},
		
		/**
		 * Enables the specified model.
		 * 
		 * @param {Object} model
		 */
		enableItem: function(model) {
			var rowDiv = this.getRowDiv(model);
			if (rowDiv) {
				rowDiv.classList.remove("disabledNavRow"); //$NON-NLS-0$
				this.setIsNotSelectable(model, false);
			}
		},
	};
	return ExplorerNavHandler;
}());

exports.ExplorerNavDict = (function() {
	/**
	 * Creates a new explorer navigation dictionary. The key of the dictionary is the model id. The value is a wrapper object that holds .modelItem, .rowDomNode and .gridChildren properties.
	 * The .modelItem property helps quickly looking up a model object by a given id. The .rowDomNode also helps to find out the row DOM node instead of doing a query. 
	 * The .gridChildren is an array representing all the grid navigation information, which the caller has to fill the array out.
	 *
	 * @name orion.explorerNavHandler.ExplorerNavDict
	 * @class A explorer navigation dictionary.
	 * @param {Object} model The model object that represent the overall explorer.
	 */
	function ExplorerNavDict(model) {
		this._dict= {};
		this._model = model;
	}
	ExplorerNavDict.prototype = /** @lends orion.explorerNavHandler.ExplorerNavDict.prototype */ {
		
		/**
		 * Add a row to the dictionary.
		 * @param {Object} modelItem The model item object that represent a row.
		 * @param {domNode} rowDomNode optional The DOM node that represent a row. If 
		 */
		addRow: function(modelItem, rowDomNode){
			var modelId = this._model.getId(modelItem);
			this._dict[modelId] = {model: modelItem, rowDomNode: rowDomNode};
		},
			
		/**
		 * Get the value of a key by model id.
		 *  @param {String} id The model id.
		 * @returns {Object} The value of the id from the dictionary.
		 */
		getValue: function(id) {
			return this._dict[id];
		},
		
		/**
		 * Get the grid navigation holder from a row navigation model.
		 *  @param {Object} modelItem The model item object that represent a row.
		 * @returns {Array} The .gridChildren property of the value keyed by the model id.
		 */
		getGridNavHolder: function(modelItem, lazyCreate) {
			if(!modelItem){
				return null;
			}
			var modelId = this._model.getId(modelItem);
			if(this._dict[modelId]){
				if(!this._dict[modelId].gridChildren && lazyCreate){
					this._dict[modelId].gridChildren = [];
				}
				return this._dict[modelId].gridChildren;
			}
			return null;
		},
		
		/**
		 * Initialize the grid navigation holder to null.
		 *  @param {Object} modelItem The model item object that represent a row.
		 */
		initGridNavHolder: function(modelItem) {
			if(!modelItem){
				return null;
			}
			var modelId = this._model.getId(modelItem);
			if(this._dict[modelId]){
				this._dict[modelId].gridChildren = null;
			}
		}
	};
	return ExplorerNavDict;
}());

return exports;
});

/*******************************************************************************
 * @license
 * Copyright (c) 2011, 2019 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 * 
 * Contributors: IBM Corporation - initial API and implementation
 ******************************************************************************/

/*eslint-env browser, amd*/
define('orion/explorers/explorer',[
	'i18n!orion/nls/messages',
	'orion/webui/littlelib',
	'orion/webui/treetable',
	'orion/explorers/explorerNavHandler',
	'orion/Deferred',
	'orion/uiUtils',
	'orion/commands',
	'orion/util'
], function(messages, lib, mTreeTable, mNavHandler, Deferred, UiUtils, mCommands, util){

var exports = {};

exports.Explorer = (function() {
	/**
	 * Creates a new explorer.
	 *
	 * @name orion.explorer.Explorer
	 * @class A table-based explorer component.
	 * @param {orion.serviceregistry.ServiceRegistry} serviceRegistry The service registry to
	 * use for any services required by the explorer
	 * @param {orion.selection.Selection} selection The initial selection
	 * @param renderer
	 * @param {orion.commandregistry.CommandRegistry} commandRegistry The command registry to use for commands.  Optional.
	 */
	function Explorer(serviceRegistry, selection, renderer, commandRegistry) {
		this.registry = serviceRegistry;
		this.selection = selection;
		this.commandService = commandRegistry;
		this.setRenderer(renderer);
		
		this.myTree = null;
	}
	Explorer.prototype = /** @lends orion.explorer.Explorer.prototype */ {
	
		setRenderer: function(renderer) {
			if(this.renderer && typeof this.renderer.destroy === "function") { //$NON-NLS-0$
				 this.renderer.destroy();
			}
			this.renderer = renderer;
			if(this.renderer){
				this.renderer.explorer = this;
			}
		},
		destroy: function() {
			if (this._navHandler) {
				this._navHandler.destroy();
			}
			if (this.model) {
				this.model.destroy();
			}
			if (this.myTree) {
				this.myTree.destroy();
			}
			this.destroyed = true;
		},
		isDesktopSelectionMode: function() {
			return new Deferred().resolve(false);
		},
		isEditorTabsEnabled: function() {
			return new Deferred().resolve(false);
		},
		handleLinkDoubleClick: function(linkNode, doubleClickEvt) {
            this.isDesktopSelectionMode().then(function(desktopMode){
            	if(desktopMode) {
            		doubleClickEvt.preventDefault();
					var evt = document.createEvent("MouseEvents");
					if(util.isMac){
						evt.initMouseEvent("click", true, true, window,
				        0, 0, 0, 0, 0, false, false, evt.shiftKey, true, 0, null);
					}else{
					    evt.initMouseEvent("click", true, true, window,
					        0, 0, 0, 0, 0, true, false, evt.shiftKey, false, 0, null);
					}
				    linkNode.dispatchEvent(evt); 
            	}
            });
		},
		// we have changed an item on the server at the specified parent node
		changedItem: function(parent, children) {
			if (this.myTree) {
				this.myTree.refresh.bind(this.myTree)(parent, children, true);
			}
		},
		updateCommands: function(item){
			// update the commands in the tree if the tree exists.
			if (this.myTree) {
				this.myTree._renderer.updateCommands.bind(this.myTree._renderer)(item);
			}
		},
		
		makeNewItemPlaceholder: function(item, domId, insertAfter) {
			var placeholder = null;
			var tr = document.createElement("tr"); //$NON-NLS-0$
			tr.id = domId+"placeHolderRow"; //$NON-NLS-0$
			tr.classList.add("navRow"); //$NON-NLS-0$
			var td = document.createElement("td"); //$NON-NLS-0$
			td.id = domId+"placeHolderCol"; //$NON-NLS-0$
			td.classList.add("navColumn"); //$NON-NLS-0$
			tr.appendChild(td);
			placeholder = {
				wrapperNode: tr, 
				refNode: td,
				destroyFunction: function() {
					try {
						if (tr && tr.parentNode) {
							tr.parentNode.removeChild(tr);
						}	
					} catch (err) {
						// tr already removed, do nothing
					}
				}
			};
			var itemRow = this.getRow(item), parentNode;
			if (itemRow) {
				parentNode = itemRow.parentNode;
				// make a row and empty column so that the new name appears after checkmarks/expansions
				if (insertAfter) {
					// insert tr after itemRow, i.e. right before itemRow's nextSibling in the parent
					var nextSibling = itemRow.nextSibling;
					parentNode.insertBefore(tr, nextSibling);
				} else {
					// insert tr before itemRow
					parentNode.insertBefore(tr, itemRow);
				}
				
				td.style.paddingLeft = itemRow.firstChild.style.paddingLeft; //itemRow is a <tr>, we want the indentation of its <td>
			} else {
				parentNode = this.myTree.getContentNode();
				parentNode.appendChild(tr);
			}
			
			return placeholder;
		},

		getRow: function(item) {
			var rowId = this.model.getId(item);
			if (rowId) {
				return lib.node(rowId);
			}
		},
		
		/**
		 * Collapse all the nodes in the explorer
		 */
		collapseAll: function() {
			var topLevelNodes = this._navHandler.getTopLevelNodes();
			for (var i = 0; i < topLevelNodes.length ; i++){
				this.myTree.collapse(topLevelNodes[i]);
			}
		},
		
		/**
		 * Expand all the nodes under a node in the explorer
		 * @param nodeModel {Object} the node model to be expanded. If not provided the whole tree is expanded recursively
		 */
		expandAll: function(nodeModel, excludes) {
			if(nodeModel){
				this._expandRecursively(nodeModel, excludes);
			} else {
				if(!this._navHandler){
					return;
				}
				//We already know what the top level children is under the root, from the navigation handler.
				var topLevelNodes = this._navHandler.getTopLevelNodes();
				for (var i = 0; i < topLevelNodes.length ; i++){
					this._expandRecursively(topLevelNodes[i], excludes);
				}
			}
		},
		
		_inExcludes: function(node, excludes) {
			if(this.model && this.model.getId && Array.isArray(excludes)) {
				var matchFound = excludes.some(function(exclude) {
					return exclude === this.model.getId(node);
				}.bind(this));
				return matchFound;				
			}
			return false;
		},
		
		_expandRecursively: function(node, excludes){
			//If a node is not expandable, we stop here.
			if(!this._navHandler || !this._navHandler.isExpandable(node) || this._inExcludes(node, excludes)){
				return;
			}
			var that = this;
			this.myTree.expand(node, function(){
				that.model.getChildren(node, function(children){
					if(children === undefined || children === null) {
						return;
					}
					var len = children.length;
					for (var i = 0; i < len ; i++){
						that._expandRecursively(children[i], excludes);
					}
				});
			});
		},
		
		/**
		 * Displays tree table containing filled with data provided by given model
		 * 
		 * @param {String|Element} parentId id of parent dom element, or the element itself
		 * @param {Object} model providing data to display
		 * @param {Object} options optional parameters of the tree(custom indent, onCollapse callback)
		 */
		createTree: function (parentId, model, options){
			parentId = typeof parentId === "string" ? parentId : (parentId.id || parentId); //$NON-NLS-0$
			if(this.selection) {
				this.selection.setSelections([]);
			}
			if(this.getNavHandler()){
				this.getNavHandler().destroy();
				this._navHandler = null;
			}
			var treeId = parentId + "innerTree"; //$NON-NLS-0$
			var existing = lib.node(treeId);
			if (existing) {
				lib.empty(existing);
			}
			if (model){
				model.rootId = treeId + "Root"; //$NON-NLS-0$
			}
			this.model = model;
			this._parentId = parentId;
			this.role = options && options.role;
			this._treeOptions = options;
			var useSelection = !options || (options && !options.noSelection);
			if(useSelection){
				this.selectionPolicy = options ? options.selectionPolicy : "";
				this._navDict = new mNavHandler.ExplorerNavDict(this.model);
			}
			this.myTree = new mTreeTable.TableTree({
				id: treeId,
				role: options ? options.role : undefined,
				name: options ? options.name : undefined,
				model: model,
				parent: parentId,
				onComplete: function(tree) {
					if(this.selectionPolicy === "cursorOnly"){ //$NON-NLS-0$
						this.initNavHandler();
						var navHandler = this.getNavHandler();
						if (navHandler) {
							navHandler.rowsChanged();
						}
					}
					if (options.onComplete) options.onComplete(tree);
				}.bind(this),
				labelColumnIndex: this.renderer.getLabelColumnIndex(),
				renderer: this.renderer,
				showRoot: options ? !!options.showRoot : false,  
				indent: options ? options.indent: undefined,
				preCollapse: options ? options.preCollapse: undefined,
				onCollapse: options && options.onCollapse ? options.onCollapse : function(model) {
					var navHandler = this.getNavHandler();
					if (navHandler) {
						navHandler.onCollapse(model);
					}
				}.bind(this),
				navHandlerFactory: options ? options.navHandlerFactory: undefined,
				tableElement: options ? options.tableElement : undefined,
				tableBodyElement: options ? options.tableBodyElement : undefined,
				tableRowElement: options ? options.tableRowElement : undefined
			});
			this.renderer._initializeUIState();
		},
		getNavHandler: function(){
			return this._navHandler;
		},
		
		getNavDict: function(){
			return this._navDict;
		},
		
		select: function(item, toggle) {
			var navHandler = this.getNavHandler();
			if (navHandler) {
				navHandler.cursorOn(item, true);
				navHandler.setSelection(item, toggle);
			}
		},
		
		refreshSelection: function(){
			if(this.selection) {
				var navHandler = this.getNavHandler();
				var selections = [];
				if(navHandler && this.getNavDict()){
					var existingSels = navHandler.getSelection();
					for(var i = 0; i < existingSels.length; i++){
						var rowDiv = navHandler.getRowDiv(existingSels[i]);
						if(rowDiv && rowDiv.parentNode){
							var value = this.getNavDict().getValue(this.model.getId(existingSels[i]));
							if(value.model){
								selections.push(value.model);
							}
						}
					}
				}
				this.selection.setSelections(selections);
			}
		},
		
		getRootPath: function() {
			if (this.model && this.model.root) {
				return this.model.root.Location;
			}
			return null;
		},
		
		initNavHandler: function(){
			var options = this._treeOptions;
			
			var useSelection = !options || (options && !options.noSelection);
			if(!useSelection){
				return;
			}
			if(!this.getNavHandler()){
				if (options && options.navHandlerFactory && typeof options.navHandlerFactory.createNavHandler === "function") { //$NON-NLS-0$
					this._navHandler = options.navHandlerFactory.createNavHandler(this, this._navDict, options);
				} else {
					var getChildrenFunc = options ? options.getChildrenFunc : null;
					this._navHandler = new mNavHandler.ExplorerNavHandler(this, this._navDict, {getChildrenFunc: getChildrenFunc, setFocus: options && options.setFocus, 
														selectionPolicy: (options ? options.selectionPolicy : null),
														gridClickSelectionPolicy: (options ? options.gridClickSelectionPolicy : null)});
				}
			}
			var that = this;
			this.model.getRoot(function(itemOrArray){
				if(itemOrArray instanceof Array){
					that.getNavHandler().refreshModel(that.getNavDict(), that.model, itemOrArray);
				} else if(itemOrArray.children && itemOrArray.children instanceof Array){
					that.getNavHandler().refreshModel(that.getNavDict(), that.model, itemOrArray.children);
				}
				if(options && options.setFocus){
					that.getNavHandler().cursorOn(null, false, false, true);
				}
			});
		},
	    
	    _lastHash: null,
	    checkbox: false
	};
	return Explorer;
}());

/**
 * Creates generic explorer commands, like expand all and collapse all.
 * @param {orion.commands.CommandService} commandService the command service where the commands wil be added
 * @param {Function} visibleWhen optional if not provided we always display the commands
 */
exports.createExplorerCommands = function(commandService, visibleWhen, commandIdExpand, commandIdCollaspe) {
	function isVisible(item){
		if( typeof(item.getItemCount) === "function"){ //$NON-NLS-0$
			if(item.getItemCount() > 0){
				return visibleWhen ? visibleWhen(item) : true; 
			}
			return false;
		}
		return false;
	}
	var expandAllCommand = new mCommands.Command({
		name : messages["Expand all"],
		tooltip : messages["Expand all"],
		imageClass : "core-sprite-expandAll", //$NON-NLS-0$
		id: commandIdExpand ? commandIdExpand : "orion.explorer.expandAll", //$NON-NLS-0$
		groupId: "orion.explorerGroup", //$NON-NLS-0$
		visibleWhen : function(item) {
			return isVisible(item);
		},
		callback : function(data) {
			data.items.expandAll();
	}});
	var collapseAllCommand = new mCommands.Command({
		name : messages["Collapse all"],
		tooltip : messages["Collapse all"],
		imageClass : "core-sprite-collapseAll", //$NON-NLS-0$
		id: commandIdCollaspe ? commandIdCollaspe : "orion.explorer.collapseAll", //$NON-NLS-0$
		groupId: "orion.explorerGroup", //$NON-NLS-0$
		visibleWhen : function(item) {
			return isVisible(item);
		},
		callback : function(data) {
			if(typeof data.items.preCollapseAll === "function") { //$NON-NLS-0$
				data.items.preCollapseAll().then(function (result){
					if(!result) {
						return;
					}
					data.items.collapseAll();
				});
			} else {
				data.items.collapseAll();
			}
	}});
	commandService.addCommand(expandAllCommand);
	commandService.addCommand(collapseAllCommand);
};

exports.ExplorerModel = (function() {
	/**
	 * Creates a new explorer model instance.
	 * @name orion.explorer.ExplorerModel
	 * @class Simple tree model using Children and ChildrenLocation attributes to fetch children
	 * and calculating id based on Location attribute.
	 */
	function ExplorerModel(rootPath, /* function returning promise */fetchItems, idPrefix) {
		this.rootPath = rootPath;
		this.fetchItems = fetchItems;
		this.idPrefix = idPrefix || "";
	}
	ExplorerModel.prototype = /** @lends orion.explorer.ExplorerModel.prototype */{
		destroy: function(){
			this.destroyed = true;
		},
		getRoot: function(onItem){
			var self = this;
			this.fetchItems(this.rootPath).then(function(item){
				self.root = item;
				onItem(item);
			});
		},
		getChildren: function(parentItem, /* function(items) */ onComplete){
			// the parent already has the children fetched
			if (parentItem.Children) {
				onComplete(parentItem.Children);
			} else if (parentItem.ChildrenLocation) {
				this.fetchItems(parentItem.ChildrenLocation).then( 
					function(Children) {
						parentItem.Children = Children;
						onComplete(Children);
					}
				);
			} else {
				onComplete([]);
			}
		},
		getId: function(/* item */ item){
			if (item.Location === this.root.Location) {
				return this.rootId;
			} 
			// first strip slashes so we aren't processing path separators.
			var stripSlashes = item.Location.replace(/[\\\/]/g, "");
			// these id's are used in the DOM, so we can't use characters that aren't valid in DOM id's.
			// However we need a unique substitution string for these characters, so that we don't duplicate id's
			// So we are going to substitute ascii values for invalid characters.
			// See https://bugs.eclipse.org/bugs/show_bug.cgi?id=363062
			
			var id = this.idPrefix;
			for (var i=0; i<stripSlashes.length; i++) {
				if (stripSlashes[i].match(/[^\.\:\-\_0-9A-Za-z]/g)) {
					id += stripSlashes.charCodeAt(i);
				} else {
					id += stripSlashes[i];
				}
			}
			return id;
		}
	};
	return ExplorerModel;
}());

exports.ExplorerFlatModel = (function() {
	/**
	 * Creates a new flat explorer model.
	 * @name orion.explorer.ExplorerFlatModel
	 * @class Tree model used by orion.explorer.Explorer for flat structures
	 * @param {String} rootPath path to load tree table root, response should contain a list of items
	 * @param {Function} fetchItems A function that returns a promise that resolves to the
	 * items at the provided location.
	 */
	function ExplorerFlatModel(rootPath, fetchItems, root) {
		this.rootPath = rootPath;
		this.fetchItems = fetchItems;
		this.root = root;
	}
	
	ExplorerFlatModel.prototype = new exports.ExplorerModel();
	
	ExplorerFlatModel.prototype.getRoot = function(onItem){
		if(this.root){
			onItem(this.root);
		} else {
			var self = this;
			this.fetchItems(this.rootPath).then(function(item){
				self.root = item;
				onItem(item);
			});
		}
	};
	
	ExplorerFlatModel.prototype.getChildren = function(parentItem, /* function(items) */ onComplete){
		if(parentItem === this.root){
			onComplete(this.root);
		}else{
			onComplete([]);
		}
	};
	
	return ExplorerFlatModel;
}());

/********* Rendering json items into columns in the tree **************/
exports.ExplorerRenderer = (function() {
	function ExplorerRenderer (options, explorer) {
		this.explorer = explorer;
		this._init(options);
		this._expandImageClass = "core-sprite-openarrow"; //$NON-NLS-0$
		this._collapseImageClass = "core-sprite-closedarrow"; //$NON-NLS-0$
		this._progressImageClass = "core-sprite-progress"; //$NON-NLS-0$
		this._twistieSpriteClass = "modelDecorationSprite"; //$NON-NLS-0$
	}
	ExplorerRenderer.prototype = {
	
		_init: function(options) {
			if (options) {
				this._useCheckboxSelection = options.checkbox === undefined ? false : options.checkbox;
				this.selectionPolicy = options.singleSelection ? "singleSelection" : "";//$NON-NLS-0$
				this._cachePrefix = options.cachePrefix;
				if (options.getCheckedFunc) {
					this.getCheckedFunc = options.getCheckedFunc;
				}
				if (options.onCheckedFunc) {
					this.onCheckedFunc = options.onCheckedFunc;
				}
				this._noRowHighlighting = options.noRowHighlighting; // Whether to have alternating light/dark rows
				this._highlightSelection = true;
				this._treeTableClass = options.treeTableClass || "treetable";  //$NON-NLS-0$
				if (options.highlightSelection === false){
					this._highlightSelection = false;
				}
				if (!this.actionScopeId) {
					this.actionScopeId = options.actionScopeId;
				}
				if (!this.commandService) {
					this.commandService = options.commandService;
				}
			}
		},
		
		getLabelColumnIndex: function() {
			return this.explorer.checkbox ? 1 : 0;  // 0 if no checkboxes
		}, 
		
		initTable: function (tableNode, tableTree) {
			this.tableTree = tableTree;
			this.tableNode = tableNode;
			if (!this.selectionPolicy && this.role) {
				lib.setSafeAttribute(this.tableNode, "aria-multiselectable", true);
			}
			lib.empty(tableNode);
			if (this._treeTableClass) {
				tableNode.classList.add(this._treeTableClass); 
			}
			this.renderTableHeader(tableNode);
			var self = this;
			tableNode.addEventListener("mousedown", function(evt) {
				var target = evt.target;
				var tableRow = target;
				while (tableRow && tableRow !== tableNode) {
					if (tableRow._item) break;
					tableRow = tableRow.parentNode;
				}
				if (!tableRow) return;
				var expandImage = lib.node(self.expandCollapseImageId(tableRow.id));
				if (!expandImage) return;
				if (expandImage !== target) {
					var item = tableRow._item;
					if (!self.explorer.isRowSelectable || self.explorer.isRowSelectable(item)) {
						if (item.selectable === undefined || item.selectable) return;
					}
					if (UiUtils.isFormElement(target, tableRow)) {
						return;
					}
				}
				if (!self.explorer.getNavHandler().isDisabled(tableRow)) {
					self.tableTree.toggle(tableRow.id);
					var expanded = self.tableTree.isExpanded(tableRow.id);
					if (expanded) {
						self._expanded.push(tableRow.id);
						if (self.explorer.postUserExpand) {
							self.explorer.postUserExpand(tableRow.id);
						}
					} else {
						for (var i in self._expanded) {
							if (self._expanded[i] === tableRow.id) {
								self._expanded.splice(i, 1);
								break;
							}
						}
					}
					var prefPath = self._getUIStatePreferencePath();
					if (prefPath && window.sessionStorage) {
						self._storeExpansions(prefPath);
					}
					evt.stopPropagation();
					evt.preventDefault();
				}
			});
		},
		getActionsColumn: function(item, tableRow, renderType, columnClass, renderAsGrid){
			renderType = renderType || "tool"; //$NON-NLS-0$
			var actionsColumn = document.createElement('td'); //$NON-NLS-0$
			actionsColumn.id = tableRow.id + "actionswrapper"; //$NON-NLS-0$
			if (columnClass) {
				actionsColumn.classList.add(columnClass);
			}
			// contact the command service to render appropriate commands here.
			if (this.actionScopeId && this.commandService) {
				this.commandService.renderCommands(this.actionScopeId, actionsColumn, item, this.explorer, renderType, null, (renderAsGrid && this.explorer.getNavDict()) ? this.explorer.getNavDict().getGridNavHolder(item, true) : null);
			} else {
				window.console.log("Warning, no command service or action scope was specified.  No commands rendered."); //$NON-NLS-0$
			}
			return actionsColumn;
		},
		initCheckboxColumn: function(tableNode){
			if (this._useCheckboxSelection) {
				var th = document.createElement('th'); //$NON-NLS-0$
				return th;
			}
		},
		getCheckboxColumn: function(item, tableRow){
			if (this._useCheckboxSelection) {
				var checkColumn = document.createElement('td'); //$NON-NLS-0$
				var check = document.createElement("span"); //$NON-NLS-0$
				check.id = this.getCheckBoxId(tableRow.id);
				check.classList.add("core-sprite-check"); //$NON-NLS-0$
				check.classList.add("selectionCheckmarkSprite"); //$NON-NLS-0$
				check.rowId = tableRow.id;
				if(this.getCheckedFunc){
					check.checked = this.getCheckedFunc(item);
					lib.setSafeAttribute(tableRow, "aria-selected", check.checked);
					if (check.checked) {
						if(this._highlightSelection){
							tableRow.classList.add("checkedRow"); //$NON-NLS-0$
						}
						check.classList.add("core-sprite-check_on"); //$NON-NLS-0$
					} else {
						if(this._highlightSelection){
							tableRow.classList.remove("checkedRow"); //$NON-NLS-0$
						}
						check.classList.remove("core-sprite-check_on");  //$NON-NLS-0$
					}
				}
				checkColumn.appendChild(check);
				var self = this;
				check.addEventListener("mousedown", function(evt) { //$NON-NLS-0$
					var newValue = evt.target.checked ? false : true;
					lib.setSafeAttribute(tableRow, "aria-selected", newValue);
					self.onCheck(tableRow, evt.target, newValue, true, false, item);
					lib.stop(evt);
				}, false);
				return checkColumn;
			}
		},
		
		getCheckBoxId: function(rowId){
			return rowId + "selectedState"; //$NON-NLS-0$
		},
			
		onCheck: function(tableRow, checkBox, checked, manually, setSelection, item){
			checkBox.checked = checked;
			if (checked) {
				checkBox.classList.add("core-sprite-check_on"); //$NON-NLS-0$
			} else {
				checkBox.classList.remove("core-sprite-check_on"); //$NON-NLS-0$
			}
			if(this.onCheckedFunc){
				this.onCheckedFunc(checkBox.rowId, checked, manually, item);
			}
			if(this.explorer.getNavHandler() && setSelection){
				this.explorer.getNavHandler().setSelection(this.explorer.getNavDict().getValue(tableRow.id).model, true);	
			}
		},
		
		storeSelections: function() {
			if(this.explorer.getNavHandler()){
				var selectionIDs = this.explorer.getNavHandler().getSelectionIds();
				var prefPath = this._getUIStatePreferencePath();
				if (prefPath && window.sessionStorage) {
					window.sessionStorage[prefPath+"selection"] = JSON.stringify(selectionIDs); //$NON-NLS-0$
				}
			}
		},
		
		_restoreSelections: function(prefPath) {
			var navDict = this.explorer.getNavDict();
			var navHandler = this.explorer.getNavHandler();
			if (!navHandler || !navDict || navHandler.getSelectionPolicy() === "cursorOnly") { //$NON-NLS-0$
				return;
			}
			var selections = window.sessionStorage[prefPath+"selection"]; //$NON-NLS-0$
			if (typeof selections === "string") { //$NON-NLS-0$
				if (selections.length > 0) {
					selections = JSON.parse(selections);
				} else {
					selections = null;
				}
			}
			var i;
			if (selections) {
				var selectedItems = [];
				for (i=0; i<selections.length; i++) {
					var wrapper = navDict.getValue(selections[i]);
					if(wrapper && wrapper.rowDomNode && wrapper.model){
						selectedItems.push(wrapper.model);
						if(this._highlightSelection){
							wrapper.rowDomNode.classList.add("checkedRow"); //$NON-NLS-0$
						}
						var check = lib.node(this.getCheckBoxId(wrapper.rowDomNode.id));
						if (check) {
							check.checked = true;
							check.classList.add("core-sprite-check_on"); //$NON-NLS-0$
						}
					}
				}
				// notify the selection service of our new selections
				if(this.explorer.selection) {
					this.explorer.selection.setSelections(selectedItems);
					if(this.explorer.getNavHandler()){
						this.explorer.getNavHandler().refreshSelection();
					}
				}
			}	
		},
		
		_storeExpansions: function(prefPath) {
			window.sessionStorage[prefPath+"expanded"] = JSON.stringify(this._expanded); //$NON-NLS-0$
		},
		
		// returns true if the selections also need to be restored.
		_restoreExpansions: function(prefPath) {
			var didRestoreSelections = false;
			var expanded = window.sessionStorage[prefPath+"expanded"]; //$NON-NLS-0$
			if (typeof expanded=== "string") { //$NON-NLS-0$
				if (expanded.length > 0) {
					expanded= JSON.parse(expanded);
				} else {
					expanded = null;
				}
			}
			var i;
			if (expanded) {
				for (i=0; i<expanded.length; i++) {
					var row= lib.node(expanded[i]);
					if (row) {
						this._expanded.push(expanded[i]);
						// restore selections after expansion in case an expanded item was selected.
						var self = this;
						this.tableTree.expand(expanded[i], function() {
							self._restoreSelections(prefPath);
						});
						didRestoreSelections = true;
					}
				}
			}
			return !didRestoreSelections;
		},
		
		_getUIStatePreferencePath: function() {
			if (this.explorer) {
				var rootPath = this.explorer.getRootPath();
				if (this._cachePrefix && rootPath) {
					var rootSegmentId = rootPath.replace(/[^\.\:\-\_0-9A-Za-z]/g, "");
					return "/" + this._cachePrefix + "/" + rootSegmentId + "/uiState"; //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
				}
			}
			return null;
						
		},
		
		expandCollapseImageId: function(rowId) {
			return rowId+"__expand"; //$NON-NLS-0$
		},
		
		updateExpandVisuals: function(tableRow, isExpanded) {
			var expandImage = lib.node(this.expandCollapseImageId(tableRow.id));
			if (expandImage) {
				expandImage.classList.remove(this._expandImageClass);
				expandImage.classList.remove(this._collapseImageClass);
				expandImage.classList.remove(this._progressImageClass);
				expandImage.classList.add(isExpanded === "progress" ? this._progressImageClass : isExpanded ? this._expandImageClass : this._collapseImageClass); //$NON-NLS-0$
			}
		},

		/**
		 * Appends the image node with expand/collapse behavior
		 * @param {Element} tableRow
		 * @param {Element} placeHolder
		 * @param {String} decorateImageClass
		 * @param {String} spriteClass
		 * @returns {Element} The image node
		 */
		getExpandImage: function(tableRow, placeHolder, /* optional extra decoration */ decorateImageClass, /* optional sprite class for extra decoration */ spriteClass){
			var expandImage = document.createElement("span"); //$NON-NLS-0$
			expandImage.id = this.expandCollapseImageId(tableRow.id);
			placeHolder.appendChild(expandImage);
			expandImage.classList.add(this._twistieSpriteClass);
			expandImage.classList.add(this._collapseImageClass);
			lib.setSafeAttribute(expandImage, "aria-hidden", true);
			lib.setSafeAttribute(tableRow, "aria-expanded", false);
			if (decorateImageClass) {
				var decorateImage = document.createElement("span"); //$NON-NLS-0$
				placeHolder.appendChild(decorateImage);
				decorateImage.classList.add(spriteClass || "imageSprite"); //$NON-NLS-0$
				decorateImage.classList.add(decorateImageClass);
			}
			return expandImage;
		},
		
		render: function(item, tableRow){
			tableRow.classList.add("navRow"); //$NON-NLS-0$
			if (this.explorer.role) {
				tableRow.tabIndex = -1;
			}
			this.renderRow(item, tableRow);
		},
		
		rowsChanged: function() {
			// notify the selection service of the change in state.
			if(this.explorer.selectionPolicy !== "cursorOnly"){ //$NON-NLS-0$
				this.explorer.refreshSelection();
				this.explorer.initNavHandler();			
			}
			var navHandler = this.explorer.getNavHandler();
			if (navHandler) {
				navHandler.rowsChanged();
			}
			if (!this._noRowHighlighting){
				var even = "darkSectionTreeTableRow"; //$NON-NLS-0$
				var odd = "lightSectionTreeTableRow"; //$NON-NLS-0$
				if(lib.$(".sectionTreeTable", this.tableNode.parentNode) || lib.$(".treetable", this.tableNode.parentNode)) { //$NON-NLS-1$ //$NON-NLS-0$
					lib.$$array(".treeTableRow", this.tableNode).forEach(function(node, i) { //$NON-NLS-0$
						var on = (!(i % 2)) ? odd : even;
						var off = (on === odd) ? even : odd;
						node.classList.add(on);
						node.classList.remove(off);
					});
				}
			}
		},
		updateCommands: function(){
			if (this.commandService) {
				var rows = lib.$$array(".treeTableRow"); //$NON-NLS-0$
				for (var i=0; i<rows.length; i++) {
					var node = rows[i];			
					var actionsWrapperId = node.id + "actionswrapper"; //$NON-NLS-0$
					var actionsWrapper = lib.node(actionsWrapperId);
					this.commandService.destroy(actionsWrapper);
					// contact the command service to render appropriate commands here.
					if (this.actionScopeId) {
						this.commandService.renderCommands(this.actionScopeId, actionsWrapper, node._item, this.explorer, "tool"); //$NON-NLS-0$
					}
				}
			}
		},
		
		_initializeUIState: function() {
			this._expanded = [];
			var prefsPath = this._getUIStatePreferencePath();
			if (prefsPath && window.sessionStorage) {
				if (this._restoreExpansions(prefsPath)) {
					this._restoreSelections(prefsPath);
				}
			}
		}
	};
	return ExplorerRenderer;
}());

var CHECK_COLUMN_ID = 0;

/**
 * @name orion.explorer.SelectionRenderer
 * @class This  renderer renders a tree table and installs a selection and cursoring model to
 * allow the user to make selections without using checkboxes.
 * Override {@link orion.explorer.SelectionRenderer#getCellHeaderElement}  and
 * {@link orion.explorer.SelectionRenderer#getCellElement} to generate table content.
 */
exports.SelectionRenderer = (function(){
	/**
	 * Create a selection renderer with the specified options.  Options are defined in
	 * ExplorerRenderer.  An additional option is added here.
	 * @param {Boolean}singleSelection If true, set the selection policy to "singleSelection".
	 *
	 */
	function SelectionRenderer(options, explorer) {
		this._init(options);
		this.explorer = explorer;
	}
	SelectionRenderer.prototype = new exports.ExplorerRenderer();

	SelectionRenderer.prototype.renderTableHeader = function(tableNode){
		var thead = document.createElement('thead'); //$NON-NLS-0$
		thead.classList.add("navTableHeading"); //$NON-NLS-0$
		var rowCount = this.getHeaderRowCount ? this.getHeaderRowCount() : 1;
		var empty = rowCount === 1;
		for (var r=0; r<rowCount; r++) {
			var row = document.createElement('tr'); //$NON-NLS-0$
			row.tabIndex = -1;
			if (this._useCheckboxSelection) {
				var col = this.initCheckboxColumn(tableNode);
				col.id = this._checkColumnId = "checkColumn_" + CHECK_COLUMN_ID++;
				row.appendChild(col);
			}
			
			var i = 0;
			var cell = this.getCellHeaderElement(i, r);
			while(cell){
				if (cell.innerHTML.length > 0 && !this.getPrimColumnStyle) {
					cell.classList.add("navColumn"); //$NON-NLS-0$
				}
				row.appendChild(cell);			
				cell = this.getCellHeaderElement(++i, r);
			}
			thead.appendChild(row);
			if (i > 0 && empty) {
				empty = false;
			}
		}
		if (!empty) {
			tableNode.appendChild(thead);
		}
	};
	
	SelectionRenderer.prototype.initSelectableRow = function(item, tableRow) {
		var _self = this;
		tableRow.addEventListener("click", function(evt) { //$NON-NLS-0$
			var navHandler = _self.explorer.getNavHandler();
			if(navHandler){
				navHandler.onClick(item, evt);
				if(navHandler.gridClickSelectionPolicy === "true") {
                    var link = lib.$("a", tableRow);
                    if (link && link !== evt.target) {
                    		link.click();
                    }
				}
			}
		}, false);
	};
	
	SelectionRenderer.prototype.renderRow = function(item, tableRow) {
		tableRow.verticalAlign = "baseline"; //$NON-NLS-0$
		tableRow.classList.add("treeTableRow"); //$NON-NLS-0$

		var navDict = this.explorer.getNavDict();
		if(navDict){
			if (this.explorer.selectionPolicy !== "cursorOnly") { //$NON-NLS-0$
				tableRow.classList.add("selectableNavRow"); //$NON-NLS-0$
			}
			
			navDict.addRow(item, tableRow);
		}
		var checkColumn = this.getCheckboxColumn(item, tableRow);
		if(checkColumn) {
			if (this._checkColumnId) {
				lib.setSafeAttribute(checkColumn, "headers", this._checkColumnId);
			}
			if (item.selectable !== undefined && !item.selectable) {
				checkColumn.style.opacity = 0;
				lib.setSafeAttribute(checkColumn, "aria-hidden", true);
			}
			checkColumn.classList.add('checkColumn'); //$NON-NLS-0$
			tableRow.appendChild(checkColumn);
		}

		var i = 0;
		var cell = this.getCellElement(i, item, tableRow);
		while(cell){
			if (tableRow.getAttribute("role") === "row" && cell.getAttribute("role") !== "none") {
				lib.setSafeAttribute(cell, "role", "gridcell");
			}
			tableRow.appendChild(cell);
			if (i===0) {
				if(this.getPrimColumnStyle){
					cell.classList.add(this.getPrimColumnStyle(item)); //$NON-NLS-0$
				} else {
					cell.classList.add("navColumn"); //$NON-NLS-0$
				}
			} else {
				if(this.getSecondaryColumnStyle){
					cell.classList.add(this.getSecondaryColumnStyle(i)); //$NON-NLS-0$
				} else {
					cell.classList.add("secondaryColumn"); //$NON-NLS-0$
				}
			}
			cell = this.getCellElement(++i, item, tableRow);
		}
	};

	/**
	 * Override to return a dom element containing table header, preferably <code>th</code>
	 * @name orion.explorer.SelectionRenderer#getCellHeaderElement
	 * @function
	 * @param col_no number of column
	 */
	SelectionRenderer.prototype.getCellHeaderElement = function(col_no){};

	/**
	 * Override to return a dom element containing table cell, preferable <code>td</code>
	 * @name orion.explorer.SelectionRenderer#getCellElement
	 * @function
	 * @param col_no number of column
	 * @param item item to be rendered
	 * @param tableRow the current table row
	 */
	SelectionRenderer.prototype.getCellElement = function(col_no, item, tableRow){};
	
	return SelectionRenderer;
}());

exports.SimpleFlatModel = (function() {	
	/**
	 * Creates a new flat model based on an array of items already known.
	 *
	 * @name orion.explorer.SimpleFlatModel
	 * @param {Array} items the items in the model
	 * @param {String} idPrefix string used to prefix generated id's
	 * @param {Function} getKey function used to get the property name used for generating an id in the model
	 */
	function SimpleFlatModel(items, idPrefix, getKey) {
		this.items = items;
		this.getKey = getKey;
		this.idPrefix = idPrefix;
		this.root = {children: items};
	}
	
	SimpleFlatModel.prototype = new exports.ExplorerModel();
		
	SimpleFlatModel.prototype.getRoot = function(onItem){
		onItem(this.root);
	};
	
	SimpleFlatModel.prototype.getId = function(/* item */ item){
		var key = this.getKey(item);
		// this might be a path, so strip slashes
		var stripSlashes = key.replace(/[\\\/]/g, "");
		var id = "";
		for (var i=0; i<stripSlashes.length; i++) {
			if (stripSlashes[i].match(/[^\.\:\-\_0-9A-Za-z]/g)) {
				id += stripSlashes.charCodeAt(i);
			} else {
				id += stripSlashes[i];
			}
		}
		return this.idPrefix + id;
	};
		
	SimpleFlatModel.prototype.getChildren = function(parentItem, /* function(items) */ onComplete){
		if(parentItem === this.root){
			onComplete(this.items);
		}else{
			onComplete([]);
		}
	};
	return SimpleFlatModel;
}());

return exports;
});

/*******************************************************************************
 * @license
 * Copyright (c) 2009, 2019 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 * 
 * Contributors: IBM Corporation - initial API and implementation
 ******************************************************************************/
/*eslint-env browser, amd*/
define('orion/explorers/navigatorRenderer',[
	'i18n!orion/navigate/nls/messages',
	'orion/Deferred',
	'orion/explorers/explorer',
	'orion/explorers/navigationUtils',
	'orion/extensionCommands',
	'orion/objects',
	'orion/URITemplate',
	'orion/contentTypes',
	'orion/webui/littlelib',
	'orion/bidiUtils'
], function(messages, Deferred, mExplorer, mNavUtils, mExtensionCommands, objects, URITemplate, mContentTypes, lib, bidiUtils) {
		
	var max_more_info_column_length = 60;
	/* Internal */
	function addImageToLink(contentType, link, location, replace) {
		var image;
		if (contentType) {
			var imageClass = contentType.imageClass, imageURL = contentType.image;
			if (imageClass) {
				image = document.createElement("span"); //$NON-NLS-0$
				image.className += imageClass; // may be several classes in here
				image.classList.add("thumbnail"); //$NON-NLS-0$
			} else if (imageURL) {
				image = document.createElement("img"); //$NON-NLS-0$
				image.src = imageURL;
				// to minimize the height/width in case of a large one
				image.classList.add("thumbnail"); //$NON-NLS-0$
			}
			if (image) {
				link.replaceChild(image, replace);
			}
		}
		return image ? image : replace;
	}
	
	var uriTemplate = new URITemplate("#{,resource,params*}"); //$NON-NLS-0$
	
	var clickedItem;
	/**
	 * Returns the last item clicked by links created with #createLink.
	 * @name orion.explorer.NavigatorRenderer.getClickedItem
	 * @function
	 */
	function getClickedItem() {
		return clickedItem;
	}
		
	/**
	 * Exported so that it can be used by other UI that wants to use navigator-style links. commandService and contentTypeService  are necessary to compute 
	 * the proper editor for a file.
	 * @name orion.explorer.NavigatorRenderer.createLink
	 * @function
	 * @param {String} folderPageURL the page you want to direct folders to (such as navigator).  Using a blank string will just hash the current page.
	 * @param {Object} item a json object describing an Orion file or folder
	 * @param {Object} commandService necessary to compute the proper editor for a file. Must be a synchronous, in-page service, not retrieved 
	 * from the service registry.
	 * @param {Object[]} [openWithCommands] The "open with" commands used to generate link hrefs. If this parameter is not provided, the caller must
	 * have already processed the service extension and added to the command registry (usually by calling {@link orion.extensionCommands.createAndPlaceFileCommandsExtension}).
	 * @param {Object} [linkProperties] gives additional properties to mix in to the HTML anchor element.
	 * @param {Object} [uriParams] A map giving additional parameters that will be provided to the URI template that generates the href.
	 * @param {Object} [separateImageHolder] Separate image holder object. {holderDom: dom}. If separateImageHolder is not defined, the file icon image is rendered in the link as the first child.
	 * @param {NavigatorRenderer} [renderer] The renderer object. Optional. If defined, renderer.updateFileNode() is called to update the file element for sub classes.
	 * If separateImageHolder is defined with holderDom property, the file icon iamge is rendered in separateImageHolder.holderDom.
	 * IF separateImageHolder is defined as an empty object, {}, the file icon iamge is not rendered at all.
	 */
	function createLink(folderPageURL, item, commandService, contentTypeService, openWithCommands, linkProperties, uriParams, separateImageHolder, renderer) {
		// TODO FIXME folderPageURL is bad; need to use URITemplates here.
		// TODO FIXME refactor the async href calculation portion of this function into a separate function, for clients who do not want the <A> created.
		item = objects.clone(item);
		var link;
		var linkName = item.Name || '';
		if (bidiUtils.isBidiEnabled()) {
			linkName = bidiUtils.enforceTextDirWithUcc(linkName);
		}
		if (item.Directory) {
			link = document.createElement("a"); //$NON-NLS-0$
			link.tabIndex = -1;
			link.className = "navlinkonpage"; //$NON-NLS-0$
			var template = !folderPageURL ? uriTemplate : new URITemplate(folderPageURL + "#{,resource,params*}"); //$NON-NLS-0$
			link.href = template.expand({resource: item.ChildrenLocation});
			if(item.Name){
				link.appendChild(document.createTextNode(linkName));
			}
		} else {
			if (!openWithCommands) {
				openWithCommands = mExtensionCommands.getOpenWithCommands(commandService);
			}
			link = document.createElement("a"); //$NON-NLS-0$
			link.tabIndex = -1;
			link.className= "navlink targetSelector"; //$NON-NLS-0$
			if (linkProperties && typeof linkProperties === "object") { //$NON-NLS-0$
				Object.keys(linkProperties).forEach(function(property) {
					link[property] = linkProperties[property];
				});
			}
			var imageHolderDom = null, image = null;
			if(separateImageHolder) {
				imageHolderDom = separateImageHolder.holderDom;
			} else {
				imageHolderDom = link;
			}
			if(imageHolderDom) {
				image = document.createElement("span"); //$NON-NLS-0$
				image.className = "core-sprite-file modelDecorationSprite thumbnail"; //$NON-NLS-0$
				imageHolderDom.appendChild(image);
			}
			if(item.Name){
				link.appendChild(document.createTextNode(linkName));
			}
			var href = item.Location;
			if (uriParams && typeof uriParams === "object") { //$NON-NLS-0$
				item.params = {};
				objects.mixin(item.params, uriParams);
			}
			var openWithCommand = mExtensionCommands.getOpenWithCommand(commandService, item, openWithCommands);
			if (openWithCommand && typeof(openWithCommand.hrefCallback) === 'function') {
				href = openWithCommand.hrefCallback({items: item});
			}
			Deferred.when(contentTypeService.getFileContentType(item), function(contentType) {
				var iconElement;
				if(imageHolderDom) {
					iconElement = addImageToLink(contentType, imageHolderDom, item.Location, image);
				}
				link.href = href;
				if(renderer && typeof renderer.updateFileNode === 'function') { //$NON-NLS-0$
					renderer.updateFileNode(item, link, mContentTypes.isImage(contentType), iconElement);
				}
			});
		}
		link.addEventListener("click", function() { //$NON-NLS-0$
			clickedItem = item;
		}.bind(this), false);
		return link;
	}
		
	/**
	 * @name orion.explorer.NavigatorRenderer
	 * @class Renderer for a tree-table of files, like the Orion Navigator.
	 * @description Renderer for a tree-table of files, like the Orion Navigator.
	 * @param {Object} options
	 * @param {orion.explorer.Explorer} explorer
	 * @param {orion.commandregistry.CommandRegistry} commandRegistry
	 * @param {orion.core.ContentTypeRegistry} contentTypeService
	 */
	function NavigatorRenderer (options, explorer, commandService, contentTypeService) {
		this.explorer = explorer;
		this.commandService = commandService;
		this.contentTypeService = contentTypeService;
		this.openWithCommands = null;
		this.actionScopeId = options.actionScopeId;
		
		this._init(options);
	}
	NavigatorRenderer.prototype = new mExplorer.SelectionRenderer(); 

	NavigatorRenderer.prototype.wrapperCallback = function(wrapperElement) {
	};

	NavigatorRenderer.prototype.tableCallback = function(tableElement) {
	};

	/**
	 * @param {Element} rowElement
	 */
	NavigatorRenderer.prototype.rowCallback = function(rowElement, model) {
	};
	
	
	/**
	 * @param {Element} bodyElement
	 */
	NavigatorRenderer.prototype.emptyCallback = function(bodyElement) {
		var tr = document.createElement("tr"); //$NON-NLS-1$
		var td = document.createElement("td"); //$NON-NLS-1$
		td.colSpan = this.oneColumn ? 1 : 3;
		var noFile = document.createElement("div"); //$NON-NLS-1$
		noFile.classList.add("noFile"); //$NON-NLS-1$
		noFile.textContent = messages["NoFile"];
		var plusIcon = document.createElement("span"); //$NON-NLS-1$
		plusIcon.appendChild(document.createTextNode(messages["File"]));
		lib.processDOMNodes(noFile, [plusIcon]);
		td.appendChild(noFile);
		tr.appendChild(td);
		bodyElement.appendChild(tr);
	};

	/**
	 * @param {int|string} the local time stamp
	 */
	NavigatorRenderer.prototype.getDisplayTime = function(timeStamp) {
		return new Date(timeStamp).toLocaleString();
	};
	
	/**
	 * @param {Element} parent the parent dom where the commit info is rendered
	 * @param {Object} commitInfo the commit info
	 */
	NavigatorRenderer.prototype.getCommitRenderer = function(parent, commitInfo) {
		return null;
	};
	
	/**
	 * Creates a image DOM Element for the specified folder.
	 * @name orion.explorer.NavigatorRenderer#getFolderImage
	 * @type {Function}
	 * @param {Object} folder The folder to create an image for.
	 * @returns {Element} The folder image element.
	 */
	NavigatorRenderer.prototype.getFolderImage = function(folder) {
		if (!this.showFolderImage) {
			return null;
		}
		var span = document.createElement("span"); //$NON-NLS-0$
		span.className = "core-sprite-folder modelDecorationSprite"; //$NON-NLS-0$
		return span;
	};

	/**
	* Subclasses can override this function to customize the DOM Element that is created to represent a folder.
	 * The default implementation creates either a hyperlink or a plain text node.
	 * @name orion.explorer.NavigatorRenderer#createFolderNode
	 * @type {Function}
	 * @see orion.explorer.NavigatorRenderer#showFolderLinks
	 * @see orion.explorer.NavigatorRenderer#folderLink
	 * @param {Object} folder The folder to create a node for.
	 * @returns {Element} The folder element.
	 */
	// The returned element must have an <code>id</code> property.
	NavigatorRenderer.prototype.createFolderNode = function(folder) {
		var itemNode;
		if (this.showFolderLinks) { //$NON-NLS-0$
			// TODO see https://bugs.eclipse.org/bugs/show_bug.cgi?id=400121
			itemNode = createLink(this.folderLink || "", folder, this.commandService, this.contentTypeService); //$NON-NLS-0$
			var image = this.getFolderImage(folder);
			if (image) {
				itemNode.insertBefore(image, itemNode.firstChild);
			}
		} else {
			itemNode = document.createElement("span"); //$NON-NLS-0$
			itemNode.textContent = folder.Name;
		}
		return itemNode;
	};

	/**
	 * Subclasses can override this function to customize the DOM Element that is created to represent a file.
	 * The returned element must have an <code>id</code> property.
	 * The default implementation does nothing.
	 * @name orion.explorer.NavigatorRenderer#updateFileNode
	 * @type {Function}
	 * @param {Object} file The file model to update for.
	 * @param {Element} fileNode The file node to update.
	 * @param {Boolean} isImage The flag to indicate if the file is an image file.
	 */
	NavigatorRenderer.prototype.updateFileNode = function(file, fileNode, isImage) {
	};

	/**
	 * Whether the default implementation of {@link #createFolderNode} should show folders should as links (<code>true</code>),
	 * or just plain text (<code>false</code>).
	 * @name orion.explorer.NavigatorRenderer#showFolderLinks
	 * @type {Boolean}
	 * @default true
	 */
	NavigatorRenderer.prototype.showFolderLinks = true;
	/**
	 * Gives the base href to be used by the default implementation of {@link #createFolderNode} for creating folder links.
	 * This property only takes effect if {@link #showFolderLinks} is <code>true</code>. 
	 * TODO see <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=400121">Bug 400121</a>
	 * @name orion.explorer.NavigatorRenderer#folderLink
	 * @type {String}
	 * @default ""
	 */
	/**
	 * Generate the DOM element for a cell. If you override this function, you will most likely have to override {@link orion.explorers.FileExplorer#getNameNode}
	 * in your explorer class.
	 * @name orion.explorer.NavigatorRenderer#getCellElement
	 * @function
	 * @returns {Element}
	 */
	NavigatorRenderer.prototype.getCellElement = function(col_no, item, tableRow){
		var timeStampCase = item.LastCommit ? 2 : 1;
		var sizeCase = item.LastCommit ? 3 : 2;
		var commitCase = item.LastCommit ? 1 : -1;
		switch(col_no){
		case 0:
			var col = document.createElement('td'); //$NON-NLS-0$
			var span = document.createElement("span"); //$NON-NLS-0$
			span.id = tableRow.id+"MainCol"; //$NON-NLS-0$
			lib.setSafeAttribute(span, "role", "presentation");
			col.appendChild(span);
			span.className = "mainNavColumn"; //$NON-NLS-0$
			// Append annotation container
			var annotation = document.createElement("span"); //$NON-NLS-0$
			annotation.id = tableRow.id + "Annotation"; //$NON-NLS-0$
			annotation.classList.add("treeAnnotation");
			annotation.classList.add("navAnnotation");
			col.appendChild(annotation);
			var itemNode;
			if(this.explorer._parentId === "pageSidebar"){
				var isDesktopMode = this.explorer._parentNode.parentNode.classList.contains("desktopmode");
			}
			if (item.Directory) {
				// defined in ExplorerRenderer.  Sets up the expand/collapse behavior
				this.getExpandImage(tableRow, span);
				itemNode = this.createFolderNode(item);
				span.appendChild(itemNode);
				if(!isDesktopMode){
					this.explorer._makeDropTarget(item, itemNode);
					this.explorer._makeDropTarget(item, tableRow);
				}
			} else {
				if (!this.openWithCommands) {
					this.openWithCommands = mExtensionCommands.getOpenWithCommands(this.commandService);
				}
				itemNode = createLink("", item, this.commandService, this.contentTypeService, this.openWithCommands, null, null, null, this);
				span.appendChild(itemNode); //$NON-NLS-0$
			}
			if(isDesktopMode){
				lib.setSafeAttribute(span, 'draggable', true);
				this.explorer._makeDropTarget(item, span);
				this.explorer._makeDropTarget(item, tableRow);
			}
			if (itemNode) {
				// orion.explorers.FileExplorer#getNameNode
				itemNode.id = tableRow.id + "NameLink"; //$NON-NLS-0$
				if (itemNode.nodeType === 1) {
					mNavUtils.addNavGrid(this.explorer.getNavDict(), item, itemNode);
					lib.setSafeAttribute(itemNode, "role", "link");
					lib.setSafeAttribute(itemNode, "tabindex", "-1");
				}
			}
			// render any inline commands that are present.
			if (this.actionScopeId) {
				this.commandService.renderCommands(this.actionScopeId, span, item, this.explorer, "tool", null, true); //$NON-NLS-0$
			}
			return col;
		case timeStampCase:
			// TODO see https://bugs.eclipse.org/bugs/show_bug.cgi?id=400121
			if (this.oneColumn) {
				return null;
			}
			var dateColumn = document.createElement('td'); //$NON-NLS-0$
			if (item.LocalTimeStamp) {
				dateColumn.textContent = this.getDisplayTime(item.LocalTimeStamp);
			}
			return dateColumn;
		case sizeCase:
			// TODO see https://bugs.eclipse.org/bugs/show_bug.cgi?id=400121
			if (this.oneColumn) {
				return null;
			}
			var sizeColumn = document.createElement('td'); //$NON-NLS-0$
			if (!item.Directory && typeof item.Length === "number") { //$NON-NLS-0$
				var length = parseInt(item.Length, 10),
					kb = length / 1024;
				sizeColumn.textContent = Math.ceil(kb).toLocaleString() + " KB"; //$NON-NLS-0$
			} else {
				sizeColumn.textContent = "--";
			}
			sizeColumn.style.textAlign = "left"; //$NON-NLS-0$
			return sizeColumn;
		case commitCase:// LastCommit field is optional. For file services that dod not return this properties, we do not have to render this column.
			if (this.oneColumn || !item.LastCommit) {
				return null;
			}
			var messageColumn = document.createElement('td'); //$NON-NLS-0$
			var renderer = this.getCommitRenderer(messageColumn, item.LastCommit);
			if(renderer) {
				renderer.renderSimple(max_more_info_column_length);
			}
			return messageColumn;
		}
	};
	
	
	/**
	 * override SelectionRenderer's prototype
	 */
	NavigatorRenderer.prototype.getCellHeaderElement = function(col_no) {
		var labelText = "";
		switch (col_no) {
		case 0:
			labelText = messages["Name"];
			break;
		case 1:
			if (this.oneColumn) {
				return null;
			}
			labelText = messages["Date Modified"];
			break;
		case 2:
			if (this.oneColumn) {
				return null;
			}
			labelText = messages["Size"];
			break;
		default:
			return null;
		}
		var th = document.createElement("th"); //$NON-NLS-0$
		if (this.oneColumn) {
			th.className = "visuallyhidden"; //$NON-NLS-0$
		}
		th.style.paddingTop = th.style.paddingLeft = "4px"; //$NON-NLS-0$
		th.textContent = labelText;
		return th;
	};
	
	NavigatorRenderer.prototype.constructor = NavigatorRenderer;
	
	//return module exports
	return {
		NavigatorRenderer: NavigatorRenderer,
		getClickedItem: getClickedItem,
		createLink: createLink
	};
});

/*******************************************************************************
 * @license
 * Copyright (c) 2013 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made
 * available under the terms of the Eclipse Public License v1.0
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html).
 *
 * Contributors:  IBM Corporation - initial API and implementation
 ******************************************************************************/
/*eslint-env browser, amd*/

define('orion/commonPreferences',[
	'orion/EventTarget'
], function(EventTarget) {
	function mergeSettings(defaults, settings) {
		for (var property in defaults) {
			if (!settings.hasOwnProperty(property)) {
				settings[property] = defaults[property];
			}
		}
		return settings;
	}
	
	function CommonPreferences(preferences, callback) {
		this._preferences = preferences;
		EventTarget.attach(this);
		preferences.addEventListener("changed", function (e) {
			if (e.namespace === this.getPrefsSection()) {
				this.dispatchEvent({type: "Changed"}); //$NON-NLS-0$
			}
		}.bind(this));
		if (callback) {
			this.addEventListener("Changed", function(evt) { //$NON-NLS-0$
				callback(evt.preferences);
			});
		}
	}

	CommonPreferences.prototype = /** @lends edit.EditorPreferences.prototype */ {
		_initialize: function(prefs) {
			var settings = prefs[this.getPrefsKey()] || {};
			var defaults = this.getDefaults();
			return mergeSettings(defaults, settings);
		},
		getDefaults: function() {
			return {};
		},
		getPrefsSection: function() {
			return "common/settings"; //$NON-NLS-0$
		},
		getPrefsKey: function() {
			return "commonSettings"; //$NON-NLS-0$
		},
		getPrefs: function(callback) {
			return this._preferences.get(this.getPrefsSection()).then(function(prefs) {
				var object = this._initialize(prefs);
				if (typeof object === "string") { //$NON-NLS-0$
					object = JSON.parse(object);
				}
				if (callback) {
					callback(object);
				}
				return object;
			}.bind(this));
		},
		setPrefs: function(object, callback) {
			var data = {};
			data[this.getPrefsKey()] = object;
			this._preferences.put(this.getPrefsSection(), data).then(function() {
				object = this._initialize(data);
				if (callback) {
					callback(object);
				}
				this.dispatchEvent({type: "Changed", preferences: object}); //$NON-NLS-0$
			}.bind(this));
		}
	};

	return { CommonPreferences: CommonPreferences,
			 mergeSettings: mergeSettings};
});

/*******************************************************************************
 * @license
 * Copyright (c) 2013, 2017 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made
 * available under the terms of the Eclipse Public License v1.0
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html).
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *     Casey Flynn - Google Inc.
 ******************************************************************************/
/*eslint-env browser, amd*/

define('orion/generalPreferences',[
	'orion/objects',
	'orion/commonPreferences',
	'orion/util'
], function(objects, mCommonPreferences, util) {
	var CommonPreferences = mCommonPreferences.CommonPreferences;

	var GENERAL_SECTION = "/general/settings"; //$NON-NLS-0$
	var GENERAL_KEY = "generalSettings"; //$NON-NLS-0$

	var defaults = {
		desktopSelectionPolicy: true,
		filteredResources: '.git, .DS_Store',
		enableEditorTabs: util.isElectron ? true: false,
		maximumEditorTabs: 0,
		enableFileCreationAtRoot: false,
		enableFolderCreationAtRoot: false,
		enableProjectCreation: true,
		enableLinkProjectCreation: true,
		enableRefreshButton: false,
		enableDebugger: false
	};

	function GeneralPreferences(preferences, callback) {
		CommonPreferences.apply(this, arguments);
	}
	GeneralPreferences.prototype = Object.create(CommonPreferences.prototype);
	objects.mixin(GeneralPreferences.prototype, /** @lends edit.GeneralPreferences.prototype */ {
		getDefaults: function() {
			return defaults;
		},
		getPrefsSection: function() {
			return GENERAL_SECTION;
		},
		getPrefsKey: function() {
			return GENERAL_KEY;
		}
	});
	return { GeneralPreferences: GeneralPreferences };
});

/*******************************************************************************
 * @license
 * Copyright (c) 2010, 2019 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *     Andy Clement (vmware) - bug 344614
 *******************************************************************************/
/*eslint-env browser, amd*/
/*global define document console window*/
define('orion/webui/dialogs/OpenResourceDialog',[
	'i18n!orion/widgets/nls/messages', 
	'i18n!orion/search/nls/messages',
	'orion/extensionCommands', 
	'orion/i18nUtil', 
	'orion/bidiUtils',
	'orion/searchUtils', 
	'orion/explorers/navigatorRenderer', 
	'orion/contentTypes', 
	'require', 
	'orion/webui/littlelib', 
	'orion/util', 
	'orion/webui/dialog', 
	'orion/metrics',
	'orion/generalPreferences',
	'orion/Deferred',
	'orion/urlModifier'
], function(messages, searchMSG, extensionCommands, i18nUtil, bidiUtils, mSearchUtils, navigatorRenderer, mContentTypes, require, lib, util, dialog, mMetrics, mGeneralPreferences, Deferred, urlModifier) {
	//default search renderer until we factor this out completely
	function DefaultSearchRenderer(serviceRegistry, commandRegistry) {
		this.serviceRegistry = serviceRegistry;
		this.commandRegistry = commandRegistry;
		this.openWithCommands = null;
	}
	/**
	 * Create a renderer to display search results.
	 * @public
     * @param {DOMNode} resultsNode Node under which results will be added.
	 * @param {String} [heading] the heading text, or null if none required
	 * @param {Function(DOMNode)} [onResultReady] If any results were found, this is called on the resultsNode.
	 * @param {Function(DOMNode)} [decorator] A function to be called that knows how to decorate each row in the result table
	 *   This function is passed a <td> element.
	 * @returns a render function.
	 */
	DefaultSearchRenderer.prototype.makeRenderFunction = function(contentTypeService, resultsNode, heading, onResultReady, decorator) {
		var serviceRegistry = this.serviceRegistry, commandRegistry = this.commandRegistry;
		this.openWithCommands = this.openWithCommands || extensionCommands.createOpenWithCommands(serviceRegistry, contentTypeService, commandRegistry);

		/**
		 * Displays links to resources under the given DOM node.
		 * @param {Object[]} resources array of resources. The shape of a resource is {name, path, lineNumber, directory, isExternalResource}
		 *	Both directory and isExternalResource cannot be true at the same time.
		 * @param {String} [queryName] A human readable name to display when there are no matches.  If 
		 *  not used, then there is nothing displayed for no matches
		 * @param {String} [error] A human readable error to display.
		 * @param {Object} [searchParams] Search params used
		 */
		var _self = this;
		function render(resources, queryName, error, searchParams) {
			return Deferred.when(_self.openWithCommands, function(openWithCommands) {
				if (error) {
					lib.empty(resultsNode);
					var message = document.createElement("div"); //$NON-NLS-0$
					message.appendChild(document.createTextNode(searchMSG["Search failed."]));
					resultsNode.appendChild(message);
					if (typeof(onResultReady) === "function") { //$NON-NLS-0$
						onResultReady(resultsNode);
					}
					return;
				} 
			
				//Helper function to append a path String to the end of a search result dom node 
				var appendPath = (function() { 
				
					//Map to track the names we have already seen. If the name is a key in the map, it means
					//we have seen it already. Optionally, the value associated to the key may be a function' 
					//containing some deferred work we need to do if we see the same name again.
					var namesSeenMap = {};
					
					function doAppend(domElement, resource) {
						var path = resource.folderName ? resource.folderName : resource.path;
						var pathNode = document.createElement('span'); //$NON-NLS-0$
						pathNode.id = path.replace(/[^a-zA-Z0-9_\.:\-]/g,'');
						pathNode.appendChild(document.createTextNode(' - ' + path + ' ')); //$NON-NLS-1$ //$NON-NLS-0$
						domElement.appendChild(pathNode);
					}
					
					function appendPath(domElement, resource) {
						var name = resource.name;
						if (namesSeenMap.hasOwnProperty(name)) {
							//Seen the name before
							doAppend(domElement, resource);
							var deferred = namesSeenMap[name];
							if (typeof(deferred)==='function') { //$NON-NLS-0$
								//We have seen the name before, but prior element left some deferred processing
								namesSeenMap[name] = null;
								deferred();
							}
						} else {
							//Not seen before, so, if we see it again in future we must append the path
							namesSeenMap[name] = function() { doAppend(domElement, resource); };
						}
					}
					return appendPath;
				}()); //End of appendPath function
	
				var foundValidHit = false;
				lib.empty(resultsNode);
				if (resources && resources.length > 0) {
					var table = document.createElement('table'); //$NON-NLS-0$
					lib.setSafeAttribute(table, 'role', 'presentation');
					for (var i=0; i < resources.length; i++) {
						var resource = resources[i];
						var col;
						if (!foundValidHit) {
							foundValidHit = true;
							// Every caller is passing heading === false, consider removing this code.
							if (heading) {
								var headingRow = table.insertRow(0);
								col = headingRow.insertCell(0);
								col.textContent = heading;
							}
						}
						var row = table.insertRow(-1);
						col = row.insertCell(0);
						col.colspan = 2;
						if (decorator) {
							decorator(col);
						}
	
						// Transform into File object that navigatorRenderer can consume
						var item = {
							Name: resource.name,
							Location: resource.location
						};
						var params = null;
						if (typeof resource.LineNumber === "number") { //$NON-NLS-0$
							params = {};
							params.line = resource.LineNumber;
						}
						if (searchParams && searchParams.keyword && !searchParams.nameSearch) {
							var searchHelper = mSearchUtils.generateSearchHelper(searchParams);
							params = params || {};
							params.find = searchHelper.inFileQuery.searchStr;
							params.regEx = searchHelper.inFileQuery.wildCard ? true : undefined;
						}
						var resourceLink = navigatorRenderer.createLink(require.toUrl("edit/edit.html"), item, commandRegistry, contentTypeService,
							openWithCommands, {
								"aria-describedby": (resource.folderName ? resource.folderName : resource.path).replace(/[^a-zA-Z0-9_\.:\-]/g,''), //$NON-NLS-0$
								style: {
									verticalAlign: "middle" //$NON-NLS-0$
								}
							}, params);
						resourceLink.resource = resource;
						if (resource.LineNumber) { // FIXME LineNumber === 0 
							resourceLink.appendChild(document.createTextNode(' (Line ' + resource.LineNumber + ')'));
						}
	
						col.appendChild(resourceLink);
						appendPath(col, resource);
					}
					resultsNode.appendChild(table);
					if (typeof(onResultReady) === "function") { //$NON-NLS-0$
						onResultReady(resultsNode);
					}
				}
				if (!foundValidHit) {
					// only display no matches found if we have a proper name
					if (queryName) {
						var errorStr = i18nUtil.formatMessage(searchMSG["NoMatchFound"], bidiUtils.enforceTextDirWithUcc(queryName)); 
						lib.empty(resultsNode);
						resultsNode.appendChild(document.createTextNode(errorStr)); 
						if (typeof(onResultReady) === "function") { //$NON-NLS-0$
							onResultReady(resultsNode);
						}
					}
				} 
			});
		} // end render
		return render;
	};//end makeRenderFunction

	/**
	 * Usage: <code>new OpenResourceDialog(options).show();</code>
	 * 
	 * @name orion.webui.dialogs.OpenResourceDialog
	 * @class A dialog that searches for files by name or wildcard.
	 * @param {String} [options.title] Text to display in the dialog's titlebar.
	 * @param {orion.searchClient.Searcher} options.searcher The searcher to use for displaying results.
	 * @param {Function} options.onHide a function to call when the dialog is hidden.  Optional.
	 */
	function OpenResourceDialog(options) {
		this._init(options);
	}
	
	OpenResourceDialog.prototype = new dialog.Dialog();


	OpenResourceDialog.prototype.TEMPLATE = 
		'<div>' + //$NON-NLS-0$
			'<div><label id="fileNameMessage" for="fileName">${Type the name of a file to open (? = any character, * = any string):}</label></div>' + //$NON-NLS-0$
			'<div><input id="fileName" type="text" class="openResourceDialogInput" aria-autocomplete="list" style="min-width: 25em; width:90%;"/></div>' + //$NON-NLS-0$
			'<div><label for="searchScope"><input id="searchScope" type="checkbox" style="width: auto" class="openResourceDialogInput"/>${Search In All Folders}</label></input></div>' + //$NON-NLS-0$
			'<div id="progress" style="padding: 2px 0 0; width: 100%;"><img src="'+ require.toUrl("../../../images/progress_running.gif") + '" class="progressPane_running_dialog" id="crawlingProgress"></img></div>' +  //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
			'<div id="results" style="max-height:250px; height:auto; overflow-y:auto;" aria-live="off"></div>' + //$NON-NLS-0$
			'<div id="statusbar"></div>' + //$NON-NLS-0$
		'</div>'; //$NON-NLS-0$

	OpenResourceDialog.prototype._init = function(options) {
		this.title = options.title || messages['FindFileNamed'];
		this.modal = true;
		this.messages = messages;
		this.serviceRegistry = options.serviceRegistry;
		this.commandRegistry = options.commandRegistry;
		this._searcher = options.searcher;
		this._progress = options.progress;
		this._prefService = options.prefService;
		this._onHide = options.onHide;
		this._contentTypeService = new mContentTypes.ContentTypeRegistry(this.serviceRegistry);
		if (!this._searcher) {
			throw new Error("Missing required argument: searcher"); //$NON-NLS-0$
		}	
		this._searchDelay = options.searchDelay || 500;
		this._time = 0;
		this._forceUseCrawler = false;
		this._initialText = options.initialText;
		this._message = options.message;
		this._nameSearch = true;
		if (options.nameSearch !== undefined) {
			this._nameSearch = options.nameSearch;
		}
		this._searchOnRoot = false; // true;
		this._fileClient = this._searcher.getFileService();
		if (!this._fileClient) {
			throw new Error(messages['Missing required argument: fileService']);
		}
		this._searchRenderer = new DefaultSearchRenderer(this.serviceRegistry, this.commandRegistry);
		this._initialize();
	};
	
	OpenResourceDialog.prototype._bindToDom = function(parent) {
		var self = this;
		
		var gs = this.getSearchPref();
		this.$searchScope.checked = gs;
		this.updateTitle();
		this.$searchScope.addEventListener("click", function(e) {
			mMetrics.logEvent("preferenceChange", "searchScope", null, this.$searchScope.checked ? 0 : 1); //$NON-NLS-1$ //$NON-NLS-2$
			util.saveSetting("/searchScope", this.$searchScope.checked); //$NON-NLS-1$
			
			this.updateTitle();
			this.doSearch();
		}.bind(this));
		
		self.$crawlingProgress.style.display = "none"; //$NON-NLS-0$
		if(this._nameSearch) {
			lib.setSafeAttribute(this.$fileName, "placeholder", messages["FileName FolderName"]);
		} else {
			lib.setSafeAttribute(this.$fileName, "placeholder", messages["Search"]);
		}
		bidiUtils.initInputField(this.$fileName);
		this.$fileName.addEventListener("input", function(evt) { //$NON-NLS-0$
			self.checkSearch();
		}, false);
		this.$fileName.addEventListener("keydown",function(evt) { //$NON-NLS-0$
			if (evt.keyCode === lib.KEY.ENTER) {
				var link = lib.$("a", self.$results); //$NON-NLS-0$
				if (link) {
					lib.stop(evt);
					if(util.isMac ? evt.metaKey : evt.ctrlKey){
						window.open(urlModifier(link.href));
					} else {
						window.location.href = urlModifier(link.href);
						self.hide();
					}
					self._saveOpenedFileName(link.resource);
				}
			}
		}, false);
		parent.addEventListener("keydown", function(evt) { //$NON-NLS-0$
			var links, searchFieldNode, currentFocus, currentSelectionIndex, ele;
			var incrementFocus = function(currList, index, nextEntry) {
				if (index < currList.length - 1) {
					return currList[index+1];
				} else {
					return nextEntry;
				}
			};
			var decrementFocus = function(currList, index, prevEntry) {
				if (index > 0) {
					return currList[index-1];
				} else {
					return prevEntry;
				}
			};
			
			if (evt.keyCode === lib.KEY.DOWN || evt.keyCode === lib.KEY.UP) {
				links = lib.$$array("a", self.$results); //$NON-NLS-0$
				currentFocus = document.activeElement;
				currentSelectionIndex = links.indexOf(currentFocus);
				if (evt.keyCode === lib.KEY.DOWN) {
					if (currentSelectionIndex >= 0) {
						currentFocus.classList.remove("treeIterationCursor");
						ele = incrementFocus(links, currentSelectionIndex, links[0]);
						ele.focus();
						ele.classList.add("treeIterationCursor");
					} else if (links.length > 0) {
						// coming from the searchFieldNode
						ele = incrementFocus(links, -1, links[0]);
						ele.focus();
						ele.classList.add("treeIterationCursor");
					}   
				} else {
					if (currentSelectionIndex >= 0) {
						// jump to searchFieldNode if index === 0
						currentFocus.classList.remove("treeIterationCursor");
						searchFieldNode = self.$fileName;
						ele = decrementFocus(links, currentSelectionIndex, searchFieldNode);
						ele.focus();
						if(currentSelectionIndex > 0) {
							ele.classList.add("treeIterationCursor");
						}
					} else if (links.length > 0) {
						// coming from the searchFieldNode go to end of list
						links[links.length-1].focus();
						links[links.length-1].classList.add("treeIterationCursor");
					}
				}
				lib.stop(evt);
			}
		});
		parent.addEventListener("mouseup", function(e) { //$NON-NLS-0$
			// WebKit focuses <body> after link is clicked; override that
			e.target.focus();
		}, false);
		setTimeout(function() {
			if(self._forceUseCrawler || !self._fileClient.getService(self._searcher.getSearchLocation())["search"]){//$NON-NLS-0$
				var searchLoc = self._searchOnRoot ? self._searcher.getSearchRootLocation() : self._searcher.getChildrenLocation();
				self._crawler = self._searcher._createCrawler({resource: searchLoc}, {searchOnName: true}); 
				self._crawler.buildSkeleton(function() {
					self.$crawlingProgress.style.display = "inline"; //$NON-NLS-0$
					self.$progress.appendChild(document.createTextNode(messages['Building file skeleton...']));
					}, function(){
						self.$crawlingProgress.style.display = "none"; //$NON-NLS-0$
						self.$progress.removeChild(self.$progress.lastChild);
					});
			}
		}, 0);
		if (this._message) {
			this.$fileNameMessage.removeChild(this.$fileNameMessage.firstChild);
			this.$fileNameMessage.appendChild(document.createTextNode(this._message));
		}
		if (this._initialText) {
			this.$fileName.value = this._initialText;
			this.doSearch();
		}
	};

	/** @private */
	OpenResourceDialog.prototype.updateTitle = function() {
		var isGlobalSearch = this.$searchScope.checked;

		var newTitle, scope;
		if (!isGlobalSearch) {
			scope = "\'" + this._searcher.getSearchLocationName() + "\'"; //$NON-NLS-1$ //$NON-NLS-2$
			newTitle = util.formatMessage(this.title, bidiUtils.enforceTextDirWithUcc(scope));
		} else {
			scope = messages["FileFileGlobal"];
			newTitle = messages["FindFileGlobal"];
		}
		
		var titleDiv = lib.$("span", this.$frame); //$NON-NLS-1$
		titleDiv.textContent = newTitle;
		lib.setSafeAttribute(this.$frame, "aria-label", newTitle);
		
		// Hide the checkbox if this search must be global
		if (this.forcedGlobalSearch()) {
			this.$searchScope.parentNode.style.display = "none"; //$NON-NLS-1$
		}
		this._showRecentSearchedOpenedFiles();
	};

	/** @private */
	OpenResourceDialog.prototype.checkSearch = function() {
		if (this._timeoutId) clearTimeout(this._timeoutId);
		this._timeoutId = setTimeout(this.doSearch.bind(this), this._searchDelay); //$NON-NLS-0$
	};

	/** @private */
	OpenResourceDialog.prototype.forcedGlobalSearch = function() {
		var loc = this._searcher.getSearchLocation();
		var rootLoc = this._searcher.getSearchRootLocation();
		return loc === rootLoc;
	};

	/** @private */
	OpenResourceDialog.prototype.getSearchPref = function() {
		if (this.forcedGlobalSearch())
			return true;
			
		var globalSearch = util.readSetting("/searchScope") === 'true'; //$NON-NLS-0$
		return globalSearch;
	};

	/** @private */
	OpenResourceDialog.prototype._detectFolderKeyword = function(text) {
		var regex, match, keyword = text, folderKeyword = null;
		if(this._nameSearch){
			regex = /(\S+)\s*(.*)/;
			match = regex.exec(text);
			if(match && match.length === 3){
				if(match[1]){
					keyword = match[1];
				}
				if(match[2]){
					folderKeyword = match[2];
				}
			}
		} else {
			//TODO: content search has to do similar thing. E.g. "foo bar" folder123
		}
		return {keyword: keyword, folderKeyword: folderKeyword};
	};

	/** @private */
	OpenResourceDialog.prototype.doSearch = function() {
		var text = this.$fileName.value;

		// don't do a server-side query for an empty text box
		if (text) {
			// Gives Webkit a chance to show the "Searching" message
			var keyword = this._detectFolderKeyword(text);
			
			// Capture the checkbox state
			this._searchOnRoot = this.$searchScope.checked;
			return new mGeneralPreferences.GeneralPreferences(this._prefService).getPrefs().then(function(prefs) {
				if(typeof prefs.filteredResources === 'string') {
					var excludeFilesFromSetting = prefs.filteredResources.split(',');
				}
				var searchParams = this._searcher.createSearchParams(keyword.keyword, this._nameSearch, this._searchOnRoot,{exclude:excludeFilesFromSetting});
				var renderFunction = this._searchRenderer.makeRenderFunction(this._contentTypeService, this.$results, false, this.decorateResult.bind(this));
				var div = document.createElement("div"); //$NON-NLS-0$
				div.appendChild(document.createTextNode(this._nameSearch ? messages['Searching...'] : util.formatMessage(messages["SearchOccurences"], text)));
				lib.empty(this.$results);
				this.$results.appendChild(div);
				if (this._searchPending) {
					this._searchPending.cancel();
				}
				var currentSearch = this._searchPending = this._searcher.search(searchParams).then(function(searchResult) {
					this._searchPending =  null;
					var filteredResult = searchResult.filter(function(item) {
						return keyword.folderKeyword ? item.path.indexOf(keyword.folderKeyword) >= 0 : true;
					});
					renderFunction(filteredResult, searchParams.keyword, null, searchParams);
				}.bind(this), function(error) {
					if (currentSearch === this._searchPending) {
						this._searchPending = null;
						renderFunction(null, null, error, null);
					}
				}.bind(this));
			}.bind(this));
		}
		this._showRecentSearchedOpenedFiles();
	};
	
	/** @private */
	OpenResourceDialog.prototype.decorateResult = function(resultsDiv) {
		var self = this;
		var links = lib.$$array("a", resultsDiv); //$NON-NLS-0$
		function clicked(evt) { //$NON-NLS-0$
			if (evt.button === 0 && !evt.ctrlKey && !evt.metaKey) {
				self.hide();
			}
			var resource = evt.target ? evt.target.resource : evt.srcElement.resource;
			self._saveOpenedFileName(resource);
		}
		for (var i=0; i<links.length; i++) {
			var link = links[i];
			link.addEventListener("click", clicked, false);
		}
	};
	/** @private */
	OpenResourceDialog.prototype._saveOpenedFileName = function(resource) {
		var exsitingSearchedOpenedFileList = JSON.parse(sessionStorage.getItem("lastSearchedOpendFiles")) || [];
		var MAX_LENGTH = 10;
		if(exsitingSearchedOpenedFileList.length > 0){
			var oldIndex = indexofFileLink(exsitingSearchedOpenedFileList, resource);
			if(oldIndex !== -1){
				exsitingSearchedOpenedFileList.splice(oldIndex, 1);
			}
		}
		if(exsitingSearchedOpenedFileList.length < MAX_LENGTH){
			exsitingSearchedOpenedFileList.unshift(resource);
		}else if(exsitingSearchedOpenedFileList.length === MAX_LENGTH){
			exsitingSearchedOpenedFileList.pop();
			exsitingSearchedOpenedFileList.unshift(resource);
		}
		sessionStorage.setItem("lastSearchedOpendFiles", JSON.stringify(exsitingSearchedOpenedFileList)); //$NON-NLS-1$
		function indexofFileLink(array,link){
			for( var k=0; k < array.length ; k++){
				if(array[k].location === link.location){
					return k;
				}
			}
			return -1;
		}
	};
	
	/** @private */
	OpenResourceDialog.prototype._showRecentSearchedOpenedFiles = function() {
		var exsitingSearchedOpenedFileList = JSON.parse(sessionStorage.getItem("lastSearchedOpendFiles"));
		if(exsitingSearchedOpenedFileList && exsitingSearchedOpenedFileList.length > 0 ){
			var renderFunction = this._searchRenderer.makeRenderFunction(this._contentTypeService, this.$results, messages["Recently Opened Files"], this.decorateResult.bind(this));
			renderFunction(exsitingSearchedOpenedFileList, null, null, null);
		}
	};
	
	/** @private */
	OpenResourceDialog.prototype._beforeHiding = function() {
		clearTimeout(this._timeoutId);
		this._timeoutId = 0;
	};
	
	OpenResourceDialog.prototype._afterHiding = function() {
		if (this._onHide) {
			this._searcher.setLocationbyURL(this._searcher.getSearchLocation());
			this._onHide();
		}
	};
	
	OpenResourceDialog.prototype.constructor = OpenResourceDialog;
	//return the module exports
	return {OpenResourceDialog: OpenResourceDialog};
});

define('text!orion/banner/banner.html',[],function () { return '<div id="banner" class="headerLayout"></div>\n<div id="notificationArea" class="notificationHide">\n\t<div class="notifications" id="notifications" aria-live="assertive" aria-atomic="true"></div>\n\t<div class="layoutRight"><button type="button" id="closeNotifications" aria-label="${Close}" class="dismissButton layoutRight core-sprite-close imageSprite"></button></div>\n</div>\n';});

/*******************************************************************************
 * @license
 * Copyright (c) 2015 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
/*eslint-env browser, amd*/
define('orion/banner/banner',['i18n!orion/nls/messages', 'orion/webui/littlelib', 'text!orion/banner/banner.html'], function(messages, lib, template) {
	
	function Banner() {
	}
	
	Banner.prototype.create = function(parentNode) {
		if (!document.getElementById("banner")) {
			var range = document.createRange();
			range.selectNode(parentNode);
			var headerFragment = range.createContextualFragment(template);
			// do the i18n string substitutions
			lib.processTextNodes(headerFragment, messages);
	
			if (parentNode.firstChild) {
				parentNode.insertBefore(headerFragment, parentNode.firstChild);
			} else {
				parentNode.appendChild(headerFragment);
			}
		}
	};
	
	return Banner;
});


define('text!orion/banner/footer.html',[],function () { return '<footer id="footerContent" class="layoutBlock footerLayout" role="contentinfo">\n\t<div class="logoFooter commandSprite core-sprite-orion-logo"></div>\n\t<div class="footerBlock"></div>\n\t<div class="footerBlock footerBlockShutdown">${ShutdownWarning}</div>\n\t<div class="footerRightBlock">\n\t\t<ul>\n\t\t\t<li><a href="http://www.eclipse.org/legal/privacy.php" target="_blank">${Privacy Policy}</a></li>\n\t\t\t<li><a href="http://www.eclipse.org/legal/termsofuse.php" target="_blank">${Terms of Use}</a></li>\n\t\t\t<li><a href="http://www.eclipse.org/legal/copyright.php" target="_blank">${Copyright Agent}</a></li>\n\t\t</ul>\n\t</div>\n</footer>';});


define('text!orion/banner/toolbar.html',[],function () { return '<div class="layoutLeft runBar"></div>\n<ul class="layoutLeft commandList pageActions" id="globalActions"></ul>\n<ul class="layoutLeft commandList pageActions" id="pageActions"></ul>\n<ul class="layoutLeft commandList pageActions" id="selectionTools"></ul>\n<ul class="layoutLeft commandList pageActions" id="navActions"></ul>\n<div class="layoutLeft" style="padding-left:7px;padding-right:7px;margin-top:2px;" id="filterBox" style="visibility: hidden;"></div>\n<div class="layoutFlexStretch"></div>\n<div class="layoutRight status" id="statusPane" role="status" aria-live="off"></div>\n<button class="layoutRight progressWatch" id="progressPane">\n\t<div class="progressWatchWrapper">\n\t<div id="watchButton" class="watchButton"></div>\n\t<div id="watchBody" class="watchBody">\n\t\t<span class="hand longMinute">\n\t\t\t<span class="darkSide"></span>\n\t\t</span>\n\t\t<span class="hand longHour">\n\t\t\t<span class="darkSide"></span>\n\t\t</span>\n\t</div>\n\t</div>\n</button>\n<ul class="layoutRight commandList pageActions" id="pageNavigationActions"></ul>\n<ul class="layoutRight commandList pageActions" role="none" id="settingsActions"></ul>\n<ul class="layoutRight commandList pageActions userMenu" role="none" id="userMenu">\n\t<li role="none">\n\t\t<button id="userTrigger" class="dropdownTrigger commandImage" aria-haspopup="menu" aria-expanded="false">\n\t\t\t<span class="commandSprite"></span>\n\t\t</button>\n\t\t<ul id="userDropdown" class="dropdownMenu" role="menu"></ul>\n\t</li>\n</ul>\n';});


define('text!orion/widgets/projects/RunBar.html',[],function () { return '<div id="runBarWrapper" class="runBarWrapper">\r\n\t<div class="launchConfigurationsWrapper">\r\n\t\t<span class="dropdownTriggerButtonLabel">\r\n\t\t\t<span class="statusLight"></span>\r\n\t\t\t<span class="appName"></span>\r\n\t\t\t<span class="appInfoSpan"></span>\r\n\t\t</span>\r\n\t</div>\r\n\t<button id="runBarPlayButton" class="commandImage playButton core-sprite-play"></button>\r\n\t<button id="runBarStopButton" class="commandImage stopButton core-sprite-stop"></button>\r\n\t<a id="runBarAppLink" class="commandImage appLink core-sprite-open" target="_blank"></a>\r\n\t<a id="runBarLogsLink" class="commandImage logsLink core-sprite-runlogs" target="_blank"></a>\r\n</div>';});


define('text!orion/webui/RichDropdown.html',[],function () { return '<div>\r\n\t<button class="dropdownTrigger dropdownDefaultButton orionButton commandButton">\r\n\t\t<span class="dropdownTriggerButtonLabel"></span>\r\n\t\t<span class="dropdownArrowDown core-sprite-openarrow"></span>\r\n\t</button>\r\n\t<ul class="dropdownMenu" tabindex="0"></ul>\r\n</div>';});

/*******************************************************************************
 * @license
 * Copyright (c) 2014, 2019 IBM Corporation and others. 
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 * 
 * Contributors: IBM Corporation - initial API and implementation
 ******************************************************************************/
/*eslint-env browser, amd*/
define('orion/webui/RichDropdown',[
	'orion/objects',
	'orion/webui/littlelib',
	'text!orion/webui/RichDropdown.html',
	'orion/webui/dropdown'
], function(
	objects, lib, RichDropdownTemplate, mDropdown
) {
	/**
	 * Creates a generic RichDropdown which can be appended to any dom node.
	 * 
	 * @param {DOMNode} options.parentNode The DOM node which this rich dropdown will be appended to
	 * @param {Function} options.populateFunction The function which will populate the dropdown when it is opened (see @ref orion.webui.dropdown)	 
	 * @param {String} options.buttonName Optional. A string to display on the dropdown trigger button.
	 * @param {DOMNode} options.buttonDecorator Optional. A DOM node will be inserted into the dropdown trigger button as a decorator.
	 * @param {Boolean} options.noDropdownArrow Optional. A boolean indicating that the dropdown arrow should be omitted from the dropdown trigger button.
	 */
	function RichDropdown(options) {
		this._parentNode = options.parentNode;
		this._buttonName = options.buttonName;
		this._id = options.id || "dropDown";
		this._buttonDecorator = options.buttonDecorator;
		this._populateFunction = options.populateFunction;
		this._noDropdownArrow = options.noDropdownArrow;
		this._initialize();
	}

	objects.mixin(RichDropdown.prototype, /** @lends orion.webui.RichDropdown.prototype */ {
		_initialize: function() {
			var wrapperNode = lib.createNodes(RichDropdownTemplate);
			
			this._dropdownTriggerButton = lib.$("button.dropdownTrigger", wrapperNode); //$NON-NLS-0$
			this._dropdownTriggerButton.id = this._id + "Button"; //$NON-NLS-0$
			this._dropdownTriggerButtonLabel = lib.$(".dropdownTriggerButtonLabel", this._dropdownTriggerButton); //$NON-NLS-0$
			this._dropdownTriggerButtonLabel.id = this._id + "Label"; //$NON-NLS-0$
			
			this._dropdownNode = lib.$("ul.dropdownMenu", wrapperNode); //$NON-NLS-0$
			this._dropdownNode.id = this._id + "Dropdown"; //$NON-NLS-0$
			
			if (this._buttonName) {
				this.setDropdownTriggerButtonName(this._buttonName, this._buttonDecorator);
			}
			
			var dropdownArrow = lib.$(".dropdownArrowDown", this._dropdownTriggerButton); //$NON-NLS-0$
			if (this._noDropdownArrow) {
				this._dropdownTriggerButton.removeChild(dropdownArrow);
			} else {
				this._dropdownButtonArrow = dropdownArrow;
			}
			lib.setSafeAttribute(this._dropdownTriggerButton, "aria-haspopup", "menu");
			lib.setSafeAttribute(this._dropdownTriggerButton, "aria-expanded", "false");
			lib.setSafeAttribute(this._dropdownTriggerButton, "aria-controls", this._dropdownNode.id);
			lib.setSafeAttribute(this._dropdownNode, "role", "menu");
						
			this._parentNode.appendChild(this._dropdownTriggerButton);
			this._parentNode.appendChild(this._dropdownNode);
			
			this._dropdownTriggerButton.dropdown = new mDropdown.Dropdown({dropdown: this._dropdownNode, populate: this._populateFunction, trapTabs: true});
		},
		
		/**
		 * @return {DOMNode} The DOM node of this dropdown's trigger button
		 */
		getDropdownTriggerButton: function() {
			return this._dropdownTriggerButton;
		},
		
		/**
		 * @return {DOMNode} The DOM node of this dropdown's dropdown list
		 */
		getDropdownNode: function() {
			return this._dropdownNode;
		},
		
		/**
		 * Sets the text label displayed in this dropdown's trigger button
		 * @param {String} name The string to display on the dropdown trigger button.
		 * @param {DOMNode} decorator Optional. A dom node which will be placed in front of the button name.
		 * @param {String} title Optional. A string to display as the dropdown trigger button's title.
		 */
		setDropdownTriggerButtonName: function(name, decorator, title) {
			var titleText = title || ""; //$NON-NLS-0$
			lib.empty(this._dropdownTriggerButtonLabel);
			
			if (decorator) {
				this._dropdownTriggerButtonLabel.appendChild(decorator);
			}
			
			var nameNode = document.createTextNode(name);
			this._dropdownTriggerButtonLabel.appendChild(nameNode);
			
			this._dropdownTriggerButton.title = titleText;
		},
		
		/**
		 * Replaces this dropdown's default trigger button label node with the one specified.
		 * 
		 * @param {DOMNode} labelNode A dom node which will replace the dropdownTriggerButtonLabel
		 */
		setCustomTriggerButtonLabelNode: function(labelNode) {
			labelNode.id = this._dropdownTriggerButtonLabel.id;
			this._dropdownTriggerButton.replaceChild(labelNode, this._dropdownTriggerButtonLabel);
			this._dropdownTriggerButtonLabel = labelNode;
		},
		
		/**
		 * @return {orion.webui.dropdown.Dropdown} This rich dropdown's generic dropdown javascript object
		 */
		getDropdown: function() {
			return this._dropdownTriggerButton.dropdown;
		},
		
		/**
		 * Destroys this dropdown and cleans up its resources.
		 */
		destroy: function() {
			if (this._dropdownTriggerButton) {
				if (this._dropdownTriggerButton.dropdown) {
					this._dropdownTriggerButton.dropdown.destroy();
					this._dropdownTriggerButton.dropdown = null;
				}
				this._dropdownTriggerButton = null;
			}
		}
	});
	

	return {
		RichDropdown: RichDropdown
	};
});


define('text!orion/webui/dialogs/confirmdialog.html',[],function () { return '<div>\r\n\t<div class="promptDialogMessage" id="confirmDialogMessage">${ConfirmMessage}</div>\r\n\t<div class="checkboxWrapper">\r\n\t\t<label class="checkboxMessage">\r\n\t\t\t<input type="checkbox" class="confirmDialogCheckbox"/>\r\n\t\t\t${CheckboxMessage}\r\n\t\t</label>\r\n\t</div>\r\n</div>';});

/*******************************************************************************
 * @license
 * Copyright (c) 2014 IBM Corporation and others. 
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 * 
 * Contributors: IBM Corporation - initial API and implementation
 ******************************************************************************/
/*eslint-env browser, amd*/
define('orion/webui/dialogs/ConfirmDialog',[
	'i18n!orion/widgets/nls/messages',
	'orion/webui/dialog',
	'text!orion/webui/dialogs/confirmdialog.html',
	'orion/EventTarget',
	'orion/webui/littlelib',
], function(messages, mDialog, ConfirmDialogFragment, EventTarget, lib) {
	var Dialog = mDialog.Dialog;

	/**
	 * Dispatched when the user dismisses the ConfirmDialog.
	 * @name orion.webui.dialogs.DismissEvent
	 * @property {Boolean} value The confirmation value: <tt>true</tt> if the user gave an affirmative response
	 * (eg. clicking Yes/OK); <tt>false</tt> if they gave a negative response (eg. clicking Cancel/no/close button).
	 */

	/**
	 * Creates a modal confirm dialog.
	 * <p>Dispatches a {@link orion.webui.dialogs.DismissEvent} giving the confirmation value.</p>
	 * 
	 * @name orion.webui.dialogs.ConfirmDialog
	 * @class
	 * @extends orion.webui.Dialog
	 * 
	 * @param {Object} options The options for this dialog. Only options specific to ConfirmDialog are
	 *   documented here; see @{link orion.webui.Dialog} for a list of other usable options.
	 * @param {String} [options.title] The title to be displayed in the dialog's title bar.
	 * @param {String} options.confirmMessage The message to be displayed in the dialog.
	 * @param {Boolean} [options.yesNoDialog=false] A boolean which if true indicates that this dialog should have yes/no buttons instead of ok/cancel buttons.
	 */
	function ConfirmDialog(options) {
		EventTarget.attach(this);
		this._init(options);
	}
	
	ConfirmDialog.prototype = Object.create(Dialog.prototype);
	ConfirmDialog.prototype.constructor = ConfirmDialog;
	
	ConfirmDialog.prototype.TEMPLATE = ConfirmDialogFragment;
	
	ConfirmDialog.prototype._init = function(options) {
		this.title = options.title || document.title;
		
		this.messages = {
			ConfirmMessage: options.confirmMessage
		};
		
		if (options.checkboxMessage) {
			this.messages.CheckboxMessage = options.checkboxMessage;
		}
		
		this.modal = true;
		
		if (options.yesNoDialog) {
			this.buttons = [
				{id: "yesButton", text: messages["Yes"], callback: this._dismiss.bind(this, true), isDefault: true}, //$NON-NLS-1$ //$NON-NLS-0$
				{id: "noButton", text: messages["No"], callback: this._dismiss.bind(this, false)} //$NON-NLS-1$ //$NON-NLS-0$
			];
		} else {
			this.buttons = [
				{id: "okButton", text: messages["OK"], callback: this._dismiss.bind(this, true), isDefault: true}, //$NON-NLS-1$ //$NON-NLS-0$
				{id: "cancelButton", text: messages["Cancel"], callback: this._dismiss.bind(this, false)} //$NON-NLS-1$ //$NON-NLS-0$
			];
		}
		
		this._initialize(); //superclass function
		this.$frame.classList.add("confirmDialog"); //$NON-NLS-0$
		
		var checkboxWrapper = lib.$(".checkboxWrapper", this.$frame); //$NON-NLS-0$
		
		if (options.checkboxMessage) {
			this._checkbox = lib.$("input.confirmDialogCheckbox", checkboxWrapper); //$NON-NLS-0$
		} else {
			checkboxWrapper.parentNode.removeChild(checkboxWrapper);
		}
	};

	ConfirmDialog.prototype._bindToDom = function(/*parent*/) {
		var cancel = this._dismiss.bind(this, false);
		this.$close.addEventListener("click", cancel); //$NON-NLS-0$
		this.escListener = function (e) { //$NON-NLS-0$
			if(e.keyCode === lib.KEY.ESCAPE) {
				cancel();
			}
		};
		this.$frameParent.addEventListener("keydown", this.escListener); //$NON-NLS-0$
	};

	ConfirmDialog.prototype.destroy = function() {
		this.$frameParent.removeEventListener("keydown", this.escListener); //$NON-NLS-0$
		Dialog.prototype.destroy.apply(this, arguments);
	};

	/**
	 * Dispatches a {@link orion.webui.dialogs.DismissEvent} and hides the dialog. 
	 */
	ConfirmDialog.prototype._dismiss = function(value) {
		var event = { type: "dismiss", value: value }; //$NON-NLS-0$
		if (this._checkbox) {
			event.checkboxValue = this._checkbox.checked;
		}
		
		this.hide();
		this.dispatchEvent(event);
	};

	return {ConfirmDialog: ConfirmDialog};
});
/******************************************************************************* 
 * @license
 * Copyright (c) 2014, 2019 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 * 
 * Contributors: IBM Corporation - initial API and implementation
 ******************************************************************************/
/*eslint-env browser, amd*/
define('orion/widgets/projects/RunBar',[
	'orion/objects',
	'i18n!orion/widgets/nls/messages',
	'text!orion/widgets/projects/RunBar.html',
	'orion/webui/littlelib',
	'orion/i18nUtil',
	'orion/webui/RichDropdown',
	'orion/webui/tooltip',
	'orion/metrics',
	'orion/webui/dialogs/ConfirmDialog',
	'orion/URITemplate',
	'orion/PageLinks',
	'orion/Deferred'
], function(objects, messages, RunBarTemplate, lib, i18nUtil, mRichDropdown, mTooltip, mMetrics, mConfirmDialog, URITemplate, PageLinks, Deferred) {
	
	var METRICS_LABEL_PREFIX = "RunBar"; //$NON-NLS-0$
	var REDEPLOY_RUNNING_APP_WITHOUT_CONFIRMING = "doNotConfirmRedeployRunningApp"; //$NON-NLS-0$
	var STATUS_POLL_INTERVAL_MS = 30000;
	
	/**
	 * Creates a new RunBar.
	 * @class RunBar
	 * @name orion.projects.RunBar
	 * @param options
	 * @param options.parentNode
	 * @param options.serviceRegistry
	 * @param options.commandRegistry
	 * @param options.fileClient
	 * @param options.progressService
	 * @param options.preferencesService
	 * @param options.statusService
	 * @param options.actionScopeId
	 * @param options.generalPreferences
	 */
	function RunBar(options) {
		this._project = null;
		this._parentNode = options.parentNode;
		this._serviceRegistry = options.serviceRegistry;
		this._commandRegistry = options.commandRegistry;
		this._fileClient = options.fileClient;
		this._progressService = options.progressService;
		this._preferencesService = options.preferencesService;
		this.statusService = options.statusService;
		this.actionScopeId = options.actionScopeId;
		this._projectCommands = options.projectCommands;
		this._projectClient = options.projectClient;
		this._preferences = options.preferences;
		this._editorInputManager = options.editorInputManager;
		this._generalPreferences = options.generalPreferences;
		
		this._initialize();
		this._setLaunchConfigurationsLabel(null);
		this._disableAllControls(); // start with controls disabled until a launch configuration is selected
	}
	
	objects.mixin(RunBar.prototype, /** @lends orion.projects.RunBar.prototype */ {
		_initialize: function() {
			this._domNode = lib.createNodes(RunBarTemplate);
			if (this._domNode) {
				this._parentNode.appendChild(this._domNode);
				
				this._undestroyedTooltips = []; // an array of all the tooltips that need to be destroyed when this widget is destroyed
								
				this._playButton = lib.$("button.playButton", this._domNode); //$NON-NLS-0$
				this._boundPlayButtonListener = this._runBarButtonListener.bind(this, this._playButtonCommand);
				this._playButton.addEventListener("click", this._boundPlayButtonListener); //$NON-NLS-0$ 
				
				this._stopButton = lib.$("button.stopButton", this._domNode); //$NON-NLS-0$
				this._boundStopButtonListener = this._runBarButtonListener.bind(this, "orion.launchConfiguration.stopApp"); //$NON-NLS-0$
				this._stopButton.addEventListener("click", this._boundStopButtonListener); //$NON-NLS-0$
				
				var playCommand = this._commandRegistry.findCommand("orion.launchConfiguration.deploy"); //$NON-NLS-0$
				if (playCommand.name) {
					this._setNodeName(this._playButton, playCommand.name);
				}
				if (playCommand.tooltip) {
					this._setNodeTooltip(this._playButton, playCommand.tooltip);
				}
				var stopCommand = this._commandRegistry.findCommand("orion.launchConfiguration.stopApp"); //$NON-NLS-0$
				if (stopCommand.name) {
					this._setNodeName(this._stopButton, stopCommand.name);
				}
				if (stopCommand.tooltip) {
					this._setNodeTooltip(this._stopButton, stopCommand.tooltip);
				}
				
				this._launchConfigurationDispatcher = this._projectCommands.getLaunchConfigurationDispatcher();
				this._launchConfigurationEventTypes = ["create", "delete", "changeState", "deleteAll"]; //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-4$
				this._boundLaunchConfigurationListener = this._launchConfigurationListener.bind(this);
				this._launchConfigurationEventTypes.forEach(function(eventType) {
					this._launchConfigurationDispatcher.addEventListener(eventType, this._boundLaunchConfigurationListener);
				}, this);
				
				this._createLaunchConfigurationsDropdown();
				
				//app link
				this._boundLinkClickListener = this._linkClickListener.bind(this);

				this._appLink = lib.$(".appLink", this._domNode); //$NON-NLS-0$
				this._appLink.addEventListener("click", this._boundLinkClickListener); //$NON-NLS-0$
				this._setNodeName(this._appLink, messages["openApp"]); //$NON-NLS-0$
				this._setNodeTooltip(this._appLink, messages["openAppTooltip"]); //$NON-NLS-0$
				this._disableLink(this._appLink);
				
				this._logsLink = lib.$(".logsLink", this._domNode); //$NON-NLS-0$
				this._logsLink.addEventListener("click", this._boundLinkClickListener); //$NON-NLS-0$
				this._setNodeName(this._logsLink, messages["openLogs"]); //$NON-NLS-0$
				this._setNodeTooltip(this._logsLink, messages["openLogsTooltip"]); //$NON-NLS-0$
				this._disableLink(this._logsLink);

				this._editorInputManager.addEventListener("InputChanged", function(e) { //$NON-NLS-0$
					this._projectClient.getProject(e.metadata).then(function(project) {
						this.setProject (project);
					}.bind(this));
				}.bind(this));
				
				window.addEventListener("blur", function() {
					this._stopStatusPolling();
				}.bind(this));
				
				window.addEventListener("focus", function() {
					this._checkStatus();
				}.bind(this));
			} else {
				throw new Error("this._domNode is null"); //$NON-NLS-0$
			}
		},
		
		getProject: function () {
			return this._project;
		},
		
		setProject: function (project) {
			if (this._project === project) return;
			if (!this._project && !project) return;
			if (this._project && project) {
				if (this._project.Location === project.Location) return;
			}
			this.loadLaunchConfigurations(this._project = project);
		},
	
		_createLaunchConfigurationsDropdown: function() {
			this._launchConfigurationsWrapper = lib.$(".launchConfigurationsWrapper", this._domNode); //$NON-NLS-0$
			this._cachedLaunchConfigurations = {};
			
			var separator;
			
			// function which populates the launch configurations dropdown menu
			var populateFunction = function(paren) {
				if (this._menuItemsCache && this._menuItemsCache.length > 0) {
					this._menuItemsCache.forEach(function(menuItem){
						paren.appendChild(menuItem);
					});
				} else {
					this._menuItemsCache = []; // clear launch configurations menu items cache
					var dropdown = this._launchConfigurationsDropdown.getDropdown();
					var launchConfiguration, menuItem, domNodeWrapperList;
					
					var sortedHashes = Object.keys(this._cachedLaunchConfigurations);

					sortedHashes.sort(function(hash1, hash2) {
						return this._cachedLaunchConfigurations[hash1].Name
								.localeCompare(this._cachedLaunchConfigurations[hash2].Name);
					}.bind(this));

					sortedHashes.forEach( function(hash) {
						if (this._cachedLaunchConfigurations.hasOwnProperty(hash)) {
							launchConfiguration = this._cachedLaunchConfigurations[hash];
							menuItem = dropdown.appendMenuItem(this._getDisplayName(launchConfiguration));
							menuItem.classList.add("launchConfigurationMenuItem"); //$NON-NLS-0$
							menuItem.id = launchConfiguration.Name + "_RunBarMenuItem"; //$NON-NLS-0$

							if (launchConfiguration === this.getSelectedLaunchConfiguration()) {
								menuItem.classList.add("dropdownMenuItemActive"); //$NON-NLS-0$
							}

							menuItem.addEventListener("click", /* @callback */ function(currentHash, evnt){ //$NON-NLS-0$
								// Use currentHash to get cached launch config again because it will be updated 
								// by the listener as events occur. Using currentHash directly here to avoid 
								// unnecessarily keeping old copies of the launchConfiguration alive.
								var cachedConfig = this._cachedLaunchConfigurations[currentHash];
								var checkStatus = true;
								if (cachedConfig.status && ("PROGRESS" === cachedConfig.status.State) ) { //$NON-NLS-0$
									//do not check status if it is in PROGRESS
									checkStatus = false;
								}
								this.selectLaunchConfiguration(cachedConfig, checkStatus);
							}.bind(this, hash)); // passing in hash here because using it directly in function only creates a reference which ends up with the last value of hash
							
							this._commandRegistry.registerCommandContribution(menuItem.id, "orion.launchConfiguration.edit", 1); //$NON-NLS-0$
							this._commandRegistry.registerCommandContribution(menuItem.id, "orion.launchConfiguration.delete", 2); //$NON-NLS-0$
							domNodeWrapperList = [];
							this._commandRegistry.renderCommands(menuItem.id, menuItem.firstChild, launchConfiguration, this, "tool", null, domNodeWrapperList); //$NON-NLS-0$
							if (domNodeWrapperList.length > 0){
								domNodeWrapperList[0].domNode.classList.add("launchConfigurationEditButton"); //$NON-NLS-0$
								if (domNodeWrapperList.length > 1) {
									domNodeWrapperList[1].domNode.classList.remove("commandMargins"); //$NON-NLS-0$
									domNodeWrapperList[1].domNode.classList.add("launchConfigurationDeleteButton"); //$NON-NLS-0$
								}
							}
							
							this._menuItemsCache.push(menuItem);
							
							separator = dropdown.appendSeparator();
							this._menuItemsCache.push(separator);
						}
					}.bind(this));
					
					separator = dropdown.appendSeparator();
					this._menuItemsCache.push(separator);

					var createNewItem = dropdown.appendMenuItem(); //$NON-NLS-0$
					createNewItem.id = "CreateNew_RunBarMenuItem"; //$NON-NLS-0$
					this._menuItemsCache.push(createNewItem);
					
					var dropdownMenuItemSpan = lib.$(".dropdownMenuItem", createNewItem); //$NON-NLS-0$
					dropdownMenuItemSpan.classList.add("addNewMenuItem"); //$NON-NLS-0$
					
					var defaultDeployCommands = this._projectCommands.getDeployProjectCommands(this._commandRegistry);
					if (defaultDeployCommands) {
						domNodeWrapperList = [];
						if (defaultDeployCommands.length === 1) {
							this._commandRegistry.registerCommandContribution(createNewItem.id, defaultDeployCommands[0].id, 1);
							this._commandRegistry.renderCommands(createNewItem.id, dropdownMenuItemSpan, this._project, this, "button", null, domNodeWrapperList);
							domNodeWrapperList[0].domNode.textContent = "+";
							lib.setSafeAttribute(domNodeWrapperList[0].domNode, "aria-label", defaultDeployCommands[0].name);
							this._setNodeTooltip(domNodeWrapperList[0].domNode, defaultDeployCommands[0].tooltip);
						} else {
							this._commandRegistry.addCommandGroup(createNewItem.id, "orion.deployServiceGroup", 1000, "+", null, null, null, "+", null, true);
							for (var i = 0; i < defaultDeployCommands.length; i++) {
								this._commandRegistry.registerCommandContribution(createNewItem.id, defaultDeployCommands[i].id, 1100 + i * 100, "orion.deployServiceGroup");
							}
							var menuWrapper = document.createElement('div');
							menuWrapper.classList.add('dropdownSubMenu'); // Prevent auto dismiss
							dropdownMenuItemSpan.appendChild(menuWrapper);
							this._commandRegistry.renderCommands(createNewItem.id, menuWrapper, this._project, this, "tool", null, domNodeWrapperList);
						}
					}
				}
			}.bind(this);
			
			this._launchConfigurationsDropdown = new mRichDropdown.RichDropdown({
				parentNode: this._launchConfigurationsWrapper,
				id: "launchConfig",  //$NON-NLS-0$
				populateFunction: populateFunction
			});
			this._launchConfigurationsDropdownTriggerButton = this._launchConfigurationsDropdown.getDropdownTriggerButton();
			this._launchConfigurationsDropdownTriggerButton.classList.remove("dropdownDefaultButton"); //$NON-NLS-0$
			this._launchConfigurationsDropdownTriggerButton.classList.add("launchConfigurationsButton"); //$NON-NLS-0$
			lib.setSafeAttribute(this._launchConfigurationsDropdownTriggerButton, "aria-label", messages["launchConfiguration"]);
			lib.setSafeAttribute(this._launchConfigurationsDropdownTriggerButton, "aria-labelledby", "launchConfigButton launchConfigLabel");
			var dropdownNode = this._launchConfigurationsDropdown.getDropdownNode();
			lib.setSafeAttribute(dropdownNode, "aria-label", messages["launchConfigurations"]);
			
			this._disableLaunchConfigurationsDropdown(); // start with control greyed out until launch configs are set
			
			this._launchConfigurationsLabel = lib.$(".dropdownTriggerButtonLabel", this._launchConfigurationsWrapper); //$NON-NLS-0$
			this._appName = lib.$(".appName", this._launchConfigurationsLabel); //$NON-NLS-0$
			this._statusLight = lib.$(".statusLight", this._launchConfigurationsLabel); //$NON-NLS-0$
			this._appInfoSpan = lib.$(".appInfoSpan", this._launchConfigurationsLabel); //$NON-NLS-0$
			
			this._launchConfigurationsWrapper.removeChild(this._launchConfigurationsLabel);
			this._launchConfigurationsDropdown.setCustomTriggerButtonLabelNode(this._launchConfigurationsLabel);
			
			this._boundTriggerButtonEventListener = function(evnt){ 
				mMetrics.logEvent("ui", "invoke", METRICS_LABEL_PREFIX + ".launchConfigurationsDropdownTriggerButton.clicked", evnt.which); //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$ //$NON-NLS-3$
			}.bind(this);
			this._launchConfigurationsDropdownTriggerButton.addEventListener("click", this._boundTriggerButtonEventListener); //$NON-NLS-0$
		},
		
		destroy: function() {
			this._stopStatusPolling();
			
			// remove node from DOM
			if (this._parentNode && this._domNode) {
				this._parentNode.removeChild(this._domNode);
				this._domNode = null;
				this._parentNode = null;
			}
			
			// destroy tooltips
			if (this._undestroyedTooltips) {
				this._undestroyedTooltips.forEach(function(tooltip){
					tooltip.destroy();
				}, this);
				this._undestroyedTooltips = null;
			}
			
			// remove event listeners
			if (this._launchConfigurationEventTypes) {
				this._launchConfigurationEventTypes.forEach(function(eventType) {
					this._launchConfigurationDispatcher.removeEventListener(eventType, this._boundLaunchConfigurationListener);
				}, this);
			}
			
			if (this._playButton) {
				this._playButton.removeEventListener("click", this._boundPlayButtonListener); //$NON-NLS-0$
				this._playButton = null;
			}
			
			if (this._stopButton) {
				this._stopButton.removeEventListener("click", this._boundStopButtonListener); //$NON-NLS-0$
				this._stopButton = null;
			}
			
			if (this._launchConfigurationsDropdown) {
				if (this._launchConfigurationsDropdownTriggerButton && this._boundTriggerButtonEventListener) {
					this._launchConfigurationsDropdownTriggerButton.removeEventListener("click", this._boundTriggerButtonEventListener); //$NON-NLS-0$
					this._launchConfigurationsDropdownTriggerButton = null;
				}
				this._launchConfigurationsDropdown.destroy();
				this._launchConfigurationsDropdown = null;
			}
			
			if (this._appLink) {
				this._appLink.removeEventListener("click", this._boundLinkClickListener); //$NON-NLS-0$
				this._appLink = null;
			}
			
			if (this._logsLink) {
				this._logsLink.removeEventListener("click", this._boundLinkClickListener); //$NON-NLS-0$
				this._logsLink = null;
			}
		},
		
		focus: function() {
			if (this._launchConfigurationsDropdownTriggerButton) {
				this._launchConfigurationsDropdownTriggerButton.focus();
			}
		},
		
		_launchConfigurationListener: function(evnt) {
			var newConfig = evnt.newValue;
			
			if((evnt.type === "changeState") && newConfig){ //$NON-NLS-0$
				this._logsLink.classList.remove('logStatusProgress');
				if (newConfig && newConfig.status){
					if (newConfig.status.State === "PROGRESS"){
						this._logsLink.classList.add('logStatusProgress');
					}
				}
				this._updateLaunchConfiguration(newConfig);
			} else {
				this._menuItemsCache = []; // clear launch configurations menu items cache
				
				if((evnt.type === "create") && newConfig){ //$NON-NLS-0$
					// cache and select new launch config
					this._putInLaunchConfigurationsCache(newConfig);					
					this.selectLaunchConfiguration(newConfig, true); //check the status of newly created configs
				} else if(evnt.type === "delete"){ //$NON-NLS-0$
					var deletedFile = evnt.oldValue.File;
					
					// iterate over cached launch configs, find and delete 
					// the one that matches the deleted file
					for (var hash in this._cachedLaunchConfigurations) {
						if (this._cachedLaunchConfigurations.hasOwnProperty(hash)) {
							var current = this._cachedLaunchConfigurations[hash];
							if (current.File.Location === deletedFile.Location) {
								if (current === this._selectedLaunchConfiguration) {
									this.selectLaunchConfiguration(null);
								}
								var element = document.getElementById(current.Name + '_RunBarMenuItem'); //$NON-NLS-1$
								if (element) {
									var paren = element.parentNode;
									var sep = element.previousSibling;
									if (sep && sep.className === "dropdownSeparator") {
										paren.removeChild(sep);
									}
									paren.removeChild(element);										
								}
								//TODO: this has left a menu iteme separator in the dom still 
								this._removeFromLaunchConfigurationsCache(current);
								break;
							}
						}
					}
				} else if(evnt.type === "deleteAll"){ //$NON-NLS-0$
					this._cacheLaunchConfigurations([]);
					this.selectLaunchConfiguration(null);
				}
			}
		},
	
		/**
		 * Selects the specified launch configuration
		 * 
		 * @param {Object} launchConfiguration The launch configuration to select
		 * @param {Boolean} checkStatus Specifies whether or not the status of the launchConfiguration should be checked
		 */
		selectLaunchConfiguration: function(launchConfiguration, checkStatus) {
			var errorHandler = function (error) {
				// stop the progress spinner in the launch config dropdown trigger
				this.setStatus({
					error: error || true //if no error was passed in we still want to ensure that the error state is recorded
				});
			}.bind(this);
			
			if (launchConfiguration) {
				this._selectedLaunchConfiguration = launchConfiguration;
				this._setLaunchConfigurationsLabel(launchConfiguration);
				
				if (checkStatus) {
					this._displayStatusCheck(launchConfiguration);
					var startTime = Date.now();
					this._checkLaunchConfigurationStatus(launchConfiguration).then(function(_status) {
						var interval = Date.now() - startTime;
						mMetrics.logTiming("deployment", "check status (launch config)", interval, launchConfiguration.Type); //$NON-NLS-1$ //$NON-NLS-2$

						launchConfiguration.status = _status;
						this._updateLaunchConfiguration(launchConfiguration);
					}.bind(this), errorHandler);
				} else {
					// do not check the status, only set it in the UI if it is already in the launchConfiguration
					if (launchConfiguration.status) {
						this.setStatus(launchConfiguration.status);
					}
				}
			} else {
				this._stopStatusPolling(); //stop before clearing selected config
				this._selectedLaunchConfiguration = null;
				this._setLaunchConfigurationsLabel(null);
				this.setStatus({});
			}
			this._menuItemsCache = [];
		},

		_displayStatusCheck: function(launchConfiguration) {
			var appName = this._getDisplayName(launchConfiguration);
			var progressMessage = i18nUtil.formatMessage(messages["checkingStateMessage"], appName); //$NON-NLS-0$
			
			// start progress spinner in launch config dropdown trigger and indicate that we are checking the status
			this.setStatus({
				State: "PROGRESS", //$NON-NLS-0$
				Message: progressMessage,
				ShortMessage: messages["checkingStateShortMessage"], //$NON-NLS-0$
				Url: (launchConfiguration.status && launchConfiguration.status.Url) ? launchConfiguration.status.Url : null
			});
		},
		
		_updateLaunchConfiguration: function(launchConfiguration) {
			var cachedHash = this._getHash(launchConfiguration);
			var selectedHash = this._getHash(this._selectedLaunchConfiguration);
			
			if (cachedHash === selectedHash) {
				// select launch configuration if it replaces the currently selected one
				var checkStatus = launchConfiguration.status && launchConfiguration.status.CheckState; // check status again if status.CheckState is set
				this.selectLaunchConfiguration(launchConfiguration, checkStatus);
			}
			
			// replace cached launch config
			this._putInLaunchConfigurationsCache(launchConfiguration);
		},
					
		_checkLaunchConfigurationStatus: function(launchConfiguration) {
			return this._projectClient.getProjectDeployService(launchConfiguration.ServiceId, launchConfiguration.Type).then(
				function(service){
					if(service && service.getState){
						return service.getState(launchConfiguration).then(function(_status){
								return _status;
							}.bind(this),
							function(error){
								launchConfiguration.status = {error: error};
								if (error.Retry) {
									// authentication error, gather required parameters and try again
									launchConfiguration.parametersRequested = launchConfiguration.status.error.Retry.parameters;
									launchConfiguration.optionalParameters = launchConfiguration.status.error.Retry.optionalParameters;
									
									// run command because it knows how to collect params first then check the status again
									this._commandRegistry.runCommand("orion.launchConfiguration.checkStatus", launchConfiguration, this, null, null, this._statusLight); //$NON-NLS-0$
								} else {
									if(error.Alert && error.Alert === true)
										this._progressService.setProgressResult(error);
									this._launchConfigurationDispatcher.dispatchEvent({type: "changeState", newValue: launchConfiguration}); //$NON-NLS-0$
								}
							}.bind(this)
						);
					}
				}.bind(this)
			);
		},
		
		setStatus: function(_status) {
			this._authenticationFailed = false;
			var longStatusText = null;
			var tooltipText = "";
			var uriTemplate = null;
			var uriParams = null;
			var logLocationTemplate = null;			
			var appName = this._getDisplayName(this._selectedLaunchConfiguration);
			var appInfoText = this._getAppInfoText(_status);

			
			// logLocationTemplate in status takes precendence because it comes from the 
			// service implementation's method rather than from the service properties
			logLocationTemplate = (_status && _status.logLocationTemplate) || (this._selectedLaunchConfiguration && this._selectedLaunchConfiguration.Params && this._selectedLaunchConfiguration.Params.LogLocationTemplate);
			
			// turn status light off
			this._statusLight.classList.remove("statusLightGreen"); //$NON-NLS-0$
			this._statusLight.classList.remove("statusLightRed"); //$NON-NLS-0$
			this._statusLight.classList.remove("statusLightProgress"); //$NON-NLS-0$
			
			this._setText(this._appInfoSpan, null);
			
			if(_status.Info && _status.Info === "Deploying"){
				this._disableControl(this._playButton);
				this._disableControl(this._stopButton);
			} else {
				this._disableAllControls(); // applicable controls will be re-enabled further below
			}
			
			if (_status) {
				if (_status.error) {
					this._enableControl(this._playButton);
					
					if (!_status.error.Retry) {
						// this is a real error
						if (_status.error.Message && !_status.error.HTML) {
							longStatusText = _status.error.Message;
						}
					}
				} else {
					switch (_status.State) {
						case "PROGRESS": //$NON-NLS-0$
							this._statusLight.classList.add("statusLightProgress"); //$NON-NLS-0$
							this._stopStatusPolling(); // do not poll while status is in a transitive state
							break;
						case "STARTED": //$NON-NLS-0$
							this._enableControl(this._playButton);
							this._enableControl(this._stopButton);
							this._statusLight.classList.add("statusLightGreen"); //$NON-NLS-0$
							break;
						case "STOPPED": //$NON-NLS-0$
							this._enableControl(this._playButton);
							this._statusLight.classList.add("statusLightRed"); //$NON-NLS-0$
							break;
						case "PAUSED": //$NON-NLS-0$
							this._enableControl(this._playButton);
							this._enableControl(this._stopButton);
							this._statusLight.classList.add("statusLightAmber"); //$NON-NLS-0$
							break;
						default:
							break;
					}
					longStatusText = _status.Message;
				}
				
				if (!_status.error && ("PROGRESS" !== _status.State)) {
					this._startStatusPolling();
				} else if (_status.error && _status.error.HttpCode === 401) {
					this._authenticationFailed = true;
					this._stopStatusPolling();
				}
			}
			
			if (appName) {
				tooltipText = appName;
				if (appInfoText) {
					tooltipText += " (" + appInfoText + ")"; //$NON-NLS-1$ //$NON-NLS-0$
				}
				if (appInfoText !== longStatusText) {
					if(longStatusText){
						tooltipText += " : " + longStatusText; //$NON-NLS-0$
					}					
				}
				
			}
			this._setNodeTooltip(this._launchConfigurationsDropdownTriggerButton, tooltipText);
			
			if (appInfoText) {
				this._setText(this._appInfoSpan, "(" + appInfoText + ")"); //$NON-NLS-1$ //$NON-NLS-0$
			} else {
				this._setText(this._appInfoSpan, null);
			}
			
			if (this._project) {
				if (_status && _status.Url) {
					this._enableLink(this._appLink, _status.Url);
				}
				if (logLocationTemplate) {
					uriTemplate = new URITemplate(logLocationTemplate);
					uriParams = {
						OrionHome: PageLinks.getOrionHome(),
						Name: "",
						Target: {
							launchConfLocation: this._selectedLaunchConfiguration.File.Location
						}
					};
					this._enableLink(this._logsLink, uriTemplate.expand(uriParams));
				} else {
					var service = this._serviceRegistry.getService("orion.project.deploy"); //$NON-NLS-1$
					if (service && service.getLogLocationTemplate) {
						service.getLogLocationTemplate(this._selectedLaunchConfiguration).then(function(result){
							uriTemplate = new URITemplate(result);
							var config = this._selectedLaunchConfiguration ? this._selectedLaunchConfiguration.File.Location : '';
							uriParams = {
								OrionHome: PageLinks.getOrionHome(),
								Name: "",
								Target: {
									launchConfLocation: config
								}
							};
							this._enableLink(this._logsLink, uriTemplate.expand(uriParams));
						}.bind(this));
					}
				}
			}
		},
		
		_getAppInfoText: function(_status) {
			var appInfoText = ""; //$NON-NLS-0$
			
			if (_status) {
				if (_status.error) {
					if (_status.error.Retry) {
						appInfoText = _status.ShortMessage || messages["appInfoUnknown"]; //$NON-NLS-0$
					} else {
						appInfoText = _status.ShortMessage || _status.error.ShortMessage ||
							(!_status.error.HTML && _status.error.Message) || messages["appInfoError"]; //$NON-NLS-0$
					}
				} else {
					switch (_status.State) {
						case "PROGRESS": //$NON-NLS-0$
							if (_status.ShortMessage || _status.Message) {
								appInfoText = _status.ShortMessage || _status.Message;
							}
							break;
						case "STARTED": //$NON-NLS-0$
							appInfoText = messages["appInfoRunning"]; //$NON-NLS-0$
							break;
						case "STOPPED": //$NON-NLS-0$
							appInfoText = messages["appInfoStopped"]; //$NON-NLS-0$
							break;
					}
				}
			}
			
			return appInfoText;
		},
		
		/**
		 * Get launch configurations from the specified project and load them into this run bar.
		 * 
		 * @param[in] {Object} project The project from which to load the launch configurations
		 */
		loadLaunchConfigurations: function (project) {
			if (project) {
				this._projectClient.getProjectLaunchConfigurations(project).then(function(launchConfigurations){
					if (project !== this._project) return;
					this._setLaunchConfigurations(launchConfigurations);
				}.bind(this));
			} else {
				this._setLaunchConfigurations(null);
			}
		},
		
		/**
		 * Sets the list of launch configurations to be used by this run bar.
		 * This method may be called more than once. Any previously cached
		 * launch configurations will be replaced with the newly specified ones.
		 * 
		 * @param {Array} launchConfigurations An array of launch configurations
		 */
		_setLaunchConfigurations: function(launchConfigurations) {
			if (launchConfigurations) {
				this._enableLaunchConfigurationsDropdown();
				launchConfigurations.sort(function(launchConf1, launchConf2) {
					return launchConf1.Name.localeCompare(launchConf2.Name);
				});
			} else {
				this._disableLaunchConfigurationsDropdown();
			}
			
			this._cacheLaunchConfigurations(launchConfigurations);
			
			if (launchConfigurations && launchConfigurations[0]) {
				// select first launch configuration
				var hash = this._getHash(launchConfigurations[0]);
				var cachedConfig = this._cachedLaunchConfigurations[hash];
				this.selectLaunchConfiguration(cachedConfig, true);
			} else {
				this.selectLaunchConfiguration(null);
			}
		},
		
		_cacheLaunchConfigurations: function(launchConfigurations) {
			this._cachedLaunchConfigurations = {};
			if (launchConfigurations) {
				launchConfigurations.forEach(function(launchConfig){
					this._putInLaunchConfigurationsCache(launchConfig);
				}, this);
			}
		},
		
		_getHash: function(launchConfiguration) {
			var hash = null;
			if (launchConfiguration) {
				hash = launchConfiguration.Name + ":" + launchConfiguration.ServiceId; //$NON-NLS-0$
			}
			return hash;
		},
		
		_putInLaunchConfigurationsCache: function(launchConfiguration) {
			var hash = this._getHash(launchConfiguration);
			if (!launchConfiguration.project) {
				// TODO Find a better way to get this info
				launchConfiguration.project = this._project;
			}
			this._cachedLaunchConfigurations[hash] = launchConfiguration;
		},
		
		_removeFromLaunchConfigurationsCache: function(launchConfiguration) {
			var hash = this._getHash(launchConfiguration);
			delete this._cachedLaunchConfigurations[hash];
		},
		
		/**
		 * Implements a generic button listener which executes the specified
		 * command when it is invoked and collects metrics
		 * 
		 * @param[in] {String | Function} command A String containing the id of the command to run or a Function to call
		 * @param[in] {Event} event The event which triggered the listener
		 */
		_runBarButtonListener: function(command, evnt) {
			var buttonNode = evnt.target;
			var id = buttonNode.id;
			var isEnabled = this._isEnabled(buttonNode);
			var disabled = isEnabled ? "" : ".disabled"; //$NON-NLS-1$ //$NON-NLS-0$
			
			mMetrics.logEvent("ui", "invoke", METRICS_LABEL_PREFIX + "." + id +".clicked" + disabled, evnt.which); //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
			
			if (isEnabled) {
				if (typeof command === "function") { //$NON-NLS-0$
					command.call(this, buttonNode);
				} else {
					this._commandRegistry.runCommand(command, this._selectedLaunchConfiguration, this, null, null, buttonNode); //$NON-NLS-0$
				}
			}
		},
		
		getSelectedLaunchConfiguration: function() {
			return this._selectedLaunchConfiguration;
		},
		
		_disableAllControls: function() {
			this._disableControl(this._playButton);
			this._disableControl(this._stopButton);
			this._disableLink(this._appLink);
			this._disableLink(this._logsLink);
		},
		
		_enableControl: function(domNode) {
			domNode.classList.remove("disabled"); //$NON-NLS-0$
			domNode.removeAttribute("disabled"); //$NON-NLS-0$
			domNode.removeAttribute("aria-disabled"); //$NON-NLS-0$
		},
		
		_disableControl: function(domNode) {
			domNode.classList.add("disabled"); //$NON-NLS-0$
			lib.setSafeAttribute(domNode, "disabled", "true");
			lib.setSafeAttribute(domNode, "aria-disabled", "true");
		},
		
		_isEnabled: function(domNode) {
			return !domNode.classList.contains("disabled"); //$NON-NLS-0$
		},
		
		_disableSwitch: function(wrapperNode){
			this._disableControl(wrapperNode);
			
			var switchNode = lib.$("div.orionSwitch", wrapperNode); //$NON-NLS-0$
			if (switchNode) {
				switchNode.removeAttribute("tabindex"); //$NON-NLS-0$
			}
		},
		
		_enableSwitch: function(wrapperNode){
			this._enableControl(wrapperNode);
			
			var switchNode = lib.$("div.orionSwitch", wrapperNode); //$NON-NLS-0$
			if (switchNode) {
				lib.setSafeAttribute(switchNode, "tabindex", "0");
			}
		},
		
		_enableLink: function(linkNode, href) {
			linkNode.href = href;
			this._enableControl(linkNode);
		},
		
		_disableLink: function(linkNode) {
			linkNode.removeAttribute("href"); //$NON-NLS-0$
			this._disableControl(linkNode);
		},
		
		_isLinkDisabled: function(linkNode) {
			return !linkNode.hasAttribute("href") || !linkNode.href; //$NON-NLS-0$
		},
		
		_linkClickListener: function(evnt) {
			var domNode = evnt.target;
			var id = domNode.id;
			var disabled = this._isLinkDisabled(domNode) ? ".disabled" : ""; //$NON-NLS-1$ //$NON-NLS-0$
			
			mMetrics.logEvent("ui", "invoke", METRICS_LABEL_PREFIX + "." + id +".clicked" + disabled, evnt.which); //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
		},
		
		_setNodeName: function(domNode, text) {
			lib.setSafeAttribute(domNode, "aria-label", text);
		},
		
		_setNodeTooltip: function(domNode, text) {
			var index = -1;
			if (domNode.tooltip) {
				domNode.tooltip.destroy();
				index = this._undestroyedTooltips.indexOf(domNode.tooltip);
				if (-1 !== index) {
					this._undestroyedTooltips.splice(index, 1);
				}
			}
			if (text) {
				domNode.tooltip = new mTooltip.Tooltip({
					node: domNode,
					text: text,
					trigger: "mouseover", //$NON-NLS-0$
					position: ["above", "below", "right", "left"] //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-4$
				});
				this._undestroyedTooltips.push(domNode.tooltip);
			}
		},
		
		_setText: function(domNode, text) {
			lib.empty(domNode);
			if (text) {
				var textNode = document.createTextNode(text);
				domNode.appendChild(textNode);
			}
		},
		
		_getDisplayName: function(launchConfiguration) {
			if (!launchConfiguration) {
				return null;
			}
			var displayName = launchConfiguration.Name;
			
			if (!displayName || "default" === displayName) { //$NON-NLS-0$
				displayName = launchConfiguration.Params.Name;
				
				if (launchConfiguration.Params.Target && launchConfiguration.Params.Target.Space) {
					displayName += messages["displayNameSeparator"] + launchConfiguration.Params.Target.Space; //$NON-NLS-0$
					
					if (launchConfiguration.Params.Target.Org) {
						displayName += " / " + launchConfiguration.Params.Target.Org; //$NON-NLS-0$
					}
				}
			}
			
			return displayName;
		},
		
		_setLaunchConfigurationsLabel: function(launchConfiguration) {
			if (launchConfiguration) {
				var displayName = this._getDisplayName(launchConfiguration); //$NON-NLS-0$
				
				lib.empty(this._launchConfigurationsLabel);
				
				this._setText(this._appName, displayName);
				this._setText(this._appInfoSpan, null);
				
				this._launchConfigurationsLabel.appendChild(this._statusLight);
				this._launchConfigurationsLabel.appendChild(this._appName);
				this._launchConfigurationsLabel.appendChild(this._appInfoSpan);
			} else {
				this._setText(this._launchConfigurationsLabel, messages["selectLaunchConfig"]); //$NON-NLS-0$
			}
		},
		
		_playButtonCommand: function(buttonNode) {
			var launchConfiguration = this._selectedLaunchConfiguration;
			
			var deployFunction = function() {
				this._commandRegistry.runCommand("orion.launchConfiguration.deploy", launchConfiguration, this, null, null, buttonNode); //$NON-NLS-0$
			}.bind(this);
			
			var cancelFunction = function() {
				this._updateLaunchConfiguration(launchConfiguration);
			}.bind(this);
			
			this._preferences.get("/RunBar").then(function(prefs) { //$NON-NLS-0$
				var redeployWithoutConfirming = prefs[REDEPLOY_RUNNING_APP_WITHOUT_CONFIRMING];
				if (redeployWithoutConfirming) {
					deployFunction(); //user does not want a confirmation dialog, just deploy again
				} else {
					// need to confirm with user before redeploying over a running app
					// get the latest app status
					this._displayStatusCheck(launchConfiguration);
					var startTime = Date.now();
					this._checkLaunchConfigurationStatus(launchConfiguration).then(function(_status) {
						var interval = Date.now() - startTime;
						mMetrics.logTiming("deployment", "check status (deploy)", interval, launchConfiguration.Type); //$NON-NLS-1$ //$NON-NLS-2$

						var dialogTitle = messages["redeployConfirmationDialogTitle"]; //$NON-NLS-0$
						var appName = this._getDisplayName(launchConfiguration);
						var confirmMessage = i18nUtil.formatMessage(messages["redeployConfirmationDialogMessage"], appName); //$NON-NLS-0$
						
						launchConfiguration.status = _status;
						
						if (_status && ("STARTED" === _status.State)) { //$NON-NLS-0$
							this._confirmBeforeRedeploy(dialogTitle, confirmMessage, REDEPLOY_RUNNING_APP_WITHOUT_CONFIRMING, deployFunction, cancelFunction);
						} else {
							// app is not running, just deploy again
							deployFunction();
						}
					}.bind(this), deployFunction);
				}
			}.bind(this));
		},
		
		_confirmBeforeRedeploy: function(dialogTitle, confirmMessage, preferenceName, deployFunction, cancelFunction){
			// app is running, confirm with user if they wish to stop it and redeploy
			var confirmDialog = new mConfirmDialog.ConfirmDialog({
				title: dialogTitle,
				confirmMessage: confirmMessage,
				checkboxMessage: messages["redeployConfirmationDialogCheckboxMessage"] //$NON-NLS-0$
			});
			
			var handleDismiss = function(evnt) {
				var confirmed = evnt.value;
				var doNotConfirmAnymore = evnt.checkboxValue;
				
				if (doNotConfirmAnymore) {
					// save user preference to no longer display confirmation dialog
					var data = {};
					data[preferenceName] = true;
					this._preferences.put("/RunBar", data); //$NON-NLS-1$
				}
				
				if (confirmed) {
					deployFunction();
				} else {
					cancelFunction();
				}
			}.bind(this);

			// add listener which uses project name entered by user to create a new project
			confirmDialog.addEventListener("dismiss", handleDismiss); //$NON-NLS-0$
			confirmDialog.show();
		},
		
		_enableLaunchConfigurationsDropdown: function() {
			this._enableControl(this._launchConfigurationsWrapper);
			this._launchConfigurationsDropdownTriggerButton.disabled = false;
		},
		
		_disableLaunchConfigurationsDropdown: function() {
			this._disableControl(this._launchConfigurationsWrapper);
			this._launchConfigurationsDropdownTriggerButton.disabled = true;
		},
		
		_checkStatus: function() {
			var launchConfiguration = this._selectedLaunchConfiguration;
			if (!launchConfiguration) {
				this._stopStatusPolling();
				return;
			}
			if (launchConfiguration.status && launchConfiguration.status.State === "PROGRESS") {
				return;
			}
			var startTime = Date.now();
			if (this._pendingCheckStatus) {
				return;
			}
			this._pendingCheckStatus = this._checkLaunchConfigurationStatus(launchConfiguration);
			this._pendingCheckStatus.then(function(_status) {
				this._pendingCheckStatus = null;
				var interval = Date.now() - startTime;
				mMetrics.logTiming("deployment", "check status (poll)", interval, launchConfiguration.Type); //$NON-NLS-1$ //$NON-NLS-2$

				if (_status) {
					launchConfiguration.status = _status;
				}
				this._updateLaunchConfiguration(launchConfiguration);
			}.bind(this), function() {
				this._pendingCheckStatus = null;
			}.bind(this));
		},
		
		_startStatusPolling: function() {
			if (!this._statusPollingIntervalID) {
				this._statusPollingIntervalID = window.setInterval(this._checkStatus.bind(this), STATUS_POLL_INTERVAL_MS);
			}
		},
		
		_stopStatusPolling: function() {
			if (this._statusPollingIntervalID) {
				window.clearInterval(this._statusPollingIntervalID);
				this._statusPollingIntervalID = null;
			}
		}
	});

	return {
		RunBar: RunBar,
		METRICS_LABEL_PREFIX: METRICS_LABEL_PREFIX
	};
});

/*******************************************************************************
 * @license Copyright (c) 2013 IBM Corporation and others. All rights
 *          reserved. This program and the accompanying materials are made
 *          available under the terms of the Eclipse Public License v1.0
 *          (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse
 *          Distribution License v1.0
 *          (http://www.eclipse.org/org/documents/edl-v10.html).
 * 
 * Contributors: IBM Corporation - initial API and implementation
 ******************************************************************************/
/*eslint-env browser, amd*/

define('orion/customGlobalCommands',['orion/Deferred', 'orion/widgets/projects/RunBar'],
function(Deferred, mRunBar){
	
	function createRunBar(options) {
		var runBarDeferred = new Deferred();
		var runBar = new mRunBar.RunBar(options);
		runBarDeferred.resolve(runBar);
		return runBarDeferred;
	}
	
	return {
		createRunBar: createRunBar
	};
});
/*******************************************************************************
 * @license
 * Copyright (c) 2014, 2019 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 * 
 * Contributors: Anton McConville - IBM Corporation - initial API and implementation
 ******************************************************************************/
/*eslint-env browser, amd*/
/*global URL*/
define('orion/webui/SideMenu',[
	'i18n!orion/nls/messages', 
	'orion/webui/littlelib', 
	'orion/PageUtil', 
	'orion/webui/tooltip', 
	'orion/util', 
	'orion/URL-shim'
], function(messages, lib, PageUtil, mTooltip, util) {

	var LOCAL_STORAGE_NAME = "sideMenuNavigation";
	var OPEN_STATE = "open";
	var CLOSED_STATE = "closed";
	var DEFAULT_STATE = OPEN_STATE;
	var TRANSITION_DURATION_MS = 301; /* this should always be greater than the duration of the left transition of .content-fixedHeight */

	function SideMenu(parentNode, contentNode) {
		this._parentNode = lib.node(parentNode);
		if (!this._parentNode) {
			throw new Error("Missing parentNode"); //$NON-NLS-0$
		}
		this._contentNode = lib.node(contentNode);

		this._categoryInfos = [];
		this._categorizedPageLinks = {};
		this._categorizedRelatedLinks = {};

		this._categorizedAnchors = null;
		this._state = util.readSetting(LOCAL_STORAGE_NAME) || DEFAULT_STATE;
		this._currentCategory = "";
		this._notificationTimeout = null;
		this._renderTimeout = null;
	}

	SideMenu.prototype = {
		constructor: SideMenu.prototype.constructor,
		// Should only be called once
		setCategories: function(categories) {
			this._categoryInfos = categories.getCategoryIDs().map(function(catId) {
				return categories.getCategory(catId);
			}).sort(function(c1, c2) {
				var o1 = c1.order || 100;
				var o2 = c2.order || 100;
				if (o1 < o2) {
					return -1;
				} else if (o2 < o1) {
					return 1;
				}
				return c1.textContent.localeCompare(c2.textContent);
			});
		},
		// Should only be called once
		setPageLinks: function(pageLinks) {
			this._categorizedPageLinks = {};
			pageLinks.getAllLinks().forEach(function(link) {
				var category = link.category;
				this._categorizedPageLinks[category] = this._categorizedPageLinks[category] || [];
				this._categorizedPageLinks[category].push({
					title: link.textContent,
					order: link.order || 100,
					href: link.href
				});
			}, this);
		},
		/**
		 * Called whenever the page target changes.
		 * @param {Object} relatedLinks
		 * @param {String[]} exclusions List of related link IDs that the page has requested to not be shown.
		 */
		setRelatedLinks: function(relatedLinks, exclusions) {
			this._categorizedRelatedLinks = {};
			relatedLinks.forEach(function(info) {
				var relatedLink = info.relatedLink;
				var command = info.command;
				var invocation = info.invocation;
				if (!exclusions || exclusions.indexOf(relatedLink.id) === -1) {
					var category = relatedLink.category;
					this._categorizedRelatedLinks[category] = this._categorizedRelatedLinks[category] || [];
					this._categorizedRelatedLinks[category].push({
						title: command.name,
						order: relatedLink.order || 100,
						href: command.hrefCallback.call(invocation.handler, invocation)
					});
				}
			}, this);
			this._updateCategoryAnchors();
			this._updateCategoryNotifications();
		},
		// Should only be called once
		render: function() {
			if (this._categorizedAnchors === null) {
				this._categorizedAnchors = {};
				var pageURL = new URL(window.location.href);
				pageURL.hash = "";

				this._currentCategory = "";
				Object.keys(this._categorizedPageLinks).some(function(category) {
					var links = this._categorizedPageLinks[category];
					if (links.some(function(link) {
						var linkURL = new URL(link.href);
						link.hash = "";
						return pageURL.pathname === linkURL.pathname;
					})) {
						this._currentCategory = category;
						return true;
					}
				}, this);
				
				var sideMenuHome = document.createElement("div"); //$NON-NLS-0$
				sideMenuHome.classList.add("sideMenuHome"); //$NON-NLS-0$
				this._sideMenuHome = sideMenuHome;
				
				var sideMenuList = document.createElement("ul"); //$NON-NLS-0$
				sideMenuList.classList.add("sideMenuList"); //$NON-NLS-0$
				this._sideMenuList = sideMenuList;

				this._categoryInfos.forEach(function(categoryInfo) {
					var listItem = document.createElement('li'); //$NON-NLS-0$
					listItem.classList.add("sideMenuItem"); //$NON-NLS-0$
					listItem.classList.add("sideMenu-notification"); //$NON-NLS-0$
					if (this._currentCategory === categoryInfo.id) {
						listItem.classList.add("sideMenuItemActive");
					}
					listItem.categoryId = categoryInfo.id;
					listItem.categoryName = categoryInfo.textContent || categoryInfo.id;
					var anchor = document.createElement("a"); //$NON-NLS-0$
					anchor.classList.add("submenu-trigger"); // styling
					if (typeof categoryInfo.imageDataURI === "string" && categoryInfo.imageDataURI.indexOf("data:image") === 0) {
						var img = document.createElement("img");
						img.width = "16";
						img.height = "16";
						img.src = categoryInfo.imageDataURI;
						anchor.appendChild(img);
					} else {
						var imageClass = categoryInfo.imageClass || "core-sprite-blank-menu-item";
						anchor.classList.add(imageClass);
					}
					listItem.appendChild(anchor);
					sideMenuList.appendChild(listItem);
					lib.setSafeAttribute(anchor, "aria-label", listItem.categoryName);
					if (this._currentCategory === categoryInfo.id) {
						lib.setSafeAttribute(anchor, "aria-current", "page");
					}
					anchor.commandTooltip = new mTooltip.Tooltip({
						node: anchor,
						text: listItem.categoryName,
						position: ["right", "above", "below", "left"] //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
					});
					this._categorizedAnchors[categoryInfo.id] = anchor;
				}, this);
				
				// create top scroll button
				this._topScrollButton = document.createElement("button"); //$NON-NLS-0$
				this._topScrollButton.classList.add("sideMenuScrollButton"); //$NON-NLS-0$
				this._topScrollButton.classList.add("sideMenuTopScrollButton"); //$NON-NLS-0$
				this._topScrollButton.classList.add("core-sprite-openarrow"); //$NON-NLS-0$
				lib.setSafeAttribute(this._topScrollButton, "aria-label", messages["Up"]);
				this._topScrollButton.tabIndex = -1;
								
				this._topScrollButton.addEventListener("mousedown", function(){ //$NON-NLS-0$
					if (this._activeScrollInterval) {
						window.clearInterval(this._activeScrollInterval);
					}
					this._activeScrollInterval = window.setInterval(this._scrollUp.bind(this), 10);
				}.bind(this));
				this._topScrollButton.addEventListener("mouseup", function(){ //$NON-NLS-0$
					if (this._activeScrollInterval) {
						window.clearInterval(this._activeScrollInterval);
						this._activeScrollInterval = null;
					}
				}.bind(this));
				
				// create bottom scroll button
				this._bottomScrollButton = document.createElement("button"); //$NON-NLS-0$
				this._bottomScrollButton.classList.add("sideMenuScrollButton"); //$NON-NLS-0$
				this._bottomScrollButton.classList.add("sideMenuBottomScrollButton"); //$NON-NLS-0$
				this._bottomScrollButton.classList.add("core-sprite-openarrow"); //$NON-NLS-0$
				lib.setSafeAttribute(this._bottomScrollButton, "aria-label", messages["Down"]);
				this._bottomScrollButton.tabIndex = -1;
				
				this._bottomScrollButton.addEventListener("mousedown", function(){ //$NON-NLS-0$
					if (this._activeScrollInterval) {
						window.clearInterval(this._activeScrollInterval);
					}
					this._activeScrollInterval = window.setInterval(this._scrollDown.bind(this), 10);
				}.bind(this));
				this._bottomScrollButton.addEventListener("mouseup", function(){ //$NON-NLS-0$
					if (this._activeScrollInterval) {
						window.clearInterval(this._activeScrollInterval);
						this._activeScrollInterval = null;
					}
				}.bind(this));
				
				// add resize listener to window to update the scroll button visibility if necessary
				window.addEventListener("resize", function(){ //$NON-NLS-0$
					this._updateScrollButtonVisibility();
				}.bind(this));

				this._updateCategoryAnchors();
				this._show = function() {
					lib.setSafeAttribute(this._parentNode, "aria-label", messages.sidebar);
					this._parentNode.appendChild(sideMenuHome);
					this._parentNode.appendChild(this._topScrollButton);
					this._parentNode.appendChild(sideMenuList);
					this._parentNode.appendChild(this._bottomScrollButton);
					var activeLink = lib.$(".sideMenuItemActive", this._parentNode); //$NON-NLS-0$
					if (activeLink && activeLink.scrollIntoView) {
						activeLink.scrollIntoView();
					}
					this._updateScrollButtonVisibility();
					this._show = SideMenu.prototype._show;
				};				
				window.setTimeout(function() {
					this._show(); // this._show can be re-assigned
				}.bind(this), 1000); // we delay rendering to give a chance to set related links
			}

			if (this._state === CLOSED_STATE) {
				this._contentNode.classList.add("content-sideMenu-closed"); //$NON-NLS-0$
				if (this._renderTimeout) {
					window.clearTimeout(this._renderTimeout);
					this._renderTimeout = null;
				}
				this._renderTimeout = window.setTimeout(function() {
					this._parentNode.classList.add("sideMenu-closed"); //$NON-NLS-0$
					this._renderTimeout = null;
				}.bind(this), TRANSITION_DURATION_MS);
				this._parentNode.classList.add("animating"); //$NON-NLS-0$
			} else {
				if (this._renderTimeout) {
					window.clearTimeout(this._renderTimeout);
					this._renderTimeout = null;
				}
				this._parentNode.classList.remove("animating"); //$NON-NLS-0$
				this._parentNode.classList.remove("sideMenu-closed"); //$NON-NLS-0$
				this._contentNode.classList.remove("content-sideMenu-closed"); //$NON-NLS-0$
			}
		},
		_updateScrollButtonVisibility: function() {
			if (this._sideMenuList.scrollHeight > this._sideMenuList.offsetHeight) {
				if (0 < this._sideMenuList.scrollTop) {
					// show up arrow
					this._topScrollButton.classList.add("visible"); //$NON-NLS-0$
				} else {
					// hide up arrow
					this._topScrollButton.classList.remove("visible"); //$NON-NLS-0$
				}
				
				if (this._sideMenuList.scrollHeight > (this._sideMenuList.scrollTop + this._sideMenuList.offsetHeight)) {
					// show bottom arrow
					this._bottomScrollButton.classList.add("visible"); //$NON-NLS-0$
				} else {
					// hide bottom arrow
					this._bottomScrollButton.classList.remove("visible"); //$NON-NLS-0$
				}
			} else {
				// no overflow, hide both arrows
				this._topScrollButton.classList.remove("visible"); //$NON-NLS-0$
				this._bottomScrollButton.classList.remove("visible"); //$NON-NLS-0$
			}
		},
		_scrollDown: function(){
			this._sideMenuList.scrollTop = this._sideMenuList.scrollTop + 1;
			this._updateScrollButtonVisibility();
		},
		_scrollUp: function() {
			this._sideMenuList.scrollTop = this._sideMenuList.scrollTop - 1;
			this._updateScrollButtonVisibility();
		},
		hide: function() {
			util.saveSetting(LOCAL_STORAGE_NAME, CLOSED_STATE);
			this._parentNode.classList.add("sideMenu-closed"); //$NON-NLS-0$
			this._contentNode.classList.add("content-sideMenu-closed"); //$NON-NLS-0$
		},
		toggle: function() {
			// add animation if necessary
			var pageContent = this._contentNode;
			if (pageContent) {
				pageContent.classList.add("content-fixedHeight-animation"); //$NON-NLS-0$
			}

			if (this._state === OPEN_STATE) {
				this._state = CLOSED_STATE;
			} else {
				this._state = OPEN_STATE;
			}

			if (this._state === DEFAULT_STATE) {
				util.deleteSetting(LOCAL_STORAGE_NAME);
			} else {
				util.saveSetting(LOCAL_STORAGE_NAME, this._state);
			}
			this.render();
		},
		_updateCategoryAnchors: function() {			
			// treat *-scm and git categories as singleton if a related link exists
			var scmInScope = [];
			Object.keys(this._categorizedRelatedLinks).forEach(function(category) {
				if (category === "git" || category.match(/-scm$/)) {
					scmInScope.push(category);
				}
			});
			
			Object.keys(this._categorizedAnchors).forEach(function(category) {
				var anchor = this._categorizedAnchors[category];
				var links = [];
				if (category === this._currentCategory) {
					anchor.parentElement.style.display = "";
					anchor.href = "";
					anchor.onclick = function() {
						return false;
					};
					return;
				}

				if (this._categorizedPageLinks[category]) {
					links.push.apply(links, this._categorizedPageLinks[category]);
				}
				if (this._categorizedRelatedLinks[category]) {
					links.push.apply(links, this._categorizedRelatedLinks[category]);
				}
				if (links.length === 0 || (scmInScope.length !== 0 && (category === "git" || category.match(/-scm$/)) && scmInScope.indexOf(category) === -1)) {
					anchor.href = "";
					anchor.parentElement.style.display = "none";
				} else {
					anchor.parentElement.style.display = "";
					links.sort(function compareLinks(link1, link2) {
						if (link1.order < link2.order) {
							return -1;
						} else if (link2.order < link1.order) {
							return 1;
						}
						return link1.title.localeCompare(link2.title);
					});
					var bestLink = links.shift();
					anchor.href = bestLink.href;
					if(util.isElectron){
						anchor.target = "_blank";
					}
				}
			}, this);
			this._show();
		},
		_updateCategoryNotifications: function() {
			clearTimeout(this._notificationTimeout);
			this._notificationTimeout = setTimeout(this._updateCategoryNotifications.bind(this), 300000); // 5 minutes
			var resource = PageUtil.matchResourceParameters().resource;
			var resourceURL = new URL(resource, window.location.href).href;
			this._categoryInfos.forEach(function(categoryInfo) {
				if (categoryInfo.service && categoryInfo.service.getNotifications) {
					var listItem = this._categorizedAnchors[categoryInfo.id].parentElement;
					categoryInfo.service.getNotifications(resourceURL).then(function(notifications) {
						if (resource === PageUtil.matchResourceParameters().resource) {
							var level = "";
							notifications.forEach(function(notification) {
								if (notification.level === "info" && !level) {
									level = "info";
								} else if (notification.level === "warn" && (!level || level === "info")) {
									level = "warn";
								} else if (notification.level === "error" && level !== "error") {
									level = "error";
								}
							});
							if (level) {
								lib.setSafeAttribute(listItem, "level", level);
							} else {
								listItem.removeAttribute("level");
							}
						}
					}, function(err) {
						window.console.log(err);
					});
				}
			}, this);
		},
		_show : function(){
		}
	};
	return SideMenu;
});
/*******************************************************************************
 * @license
 * Copyright (c) 2011, 2019 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made
 * available under the terms of the Eclipse Public License v1.0
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html).
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
/*eslint-env browser, amd*/
define('orion/globalCommands',[
	'module',
	'i18n!orion/nls/messages', 
	'i18n!orion/widgets/nls/messages', 
	'i18n!orion/edit/nls/messages',  
	'require', 
	'orion/commonHTMLFragments', 
	'orion/keyBinding', 
	'orion/EventTarget', 
	'orion/commands',
	'orion/parameterCollectors', 
	'orion/extensionCommands', 
	'orion/webui/littlelib', 
	'orion/i18nUtil',
	'orion/webui/splitter', 
	'orion/webui/dropdown', 
	'orion/webui/tooltip', 
	'orion/contentTypes', 
	'orion/keyAssist',
	'orion/widgets/themes/ThemePreferences', 
	'orion/widgets/themes/container/ThemeData', 
	'orion/Deferred',
	'orion/widgets/UserMenu',
	'orion/PageLinks', 
	'orion/webui/dialogs/OpenResourceDialog', 
	'!orion/banner/banner',
	'text!orion/banner/footer.html', 
	'text!orion/banner/toolbar.html',
	'orion/util', 
	'orion/customGlobalCommands', 
	'orion/webui/SideMenu', 
	'orion/objects', 
	"orion/metrics"
], function (module, messages, widgetMessages, editMessages, require, commonHTML, KeyBinding, EventTarget, mCommands, mParameterCollectors, mExtensionCommands,
		lib, i18nUtil, mSplitter, mDropdown, mTooltip, mContentTypes, mKeyAssist, mThemePreferences, mThemeData, Deferred,
		mUserMenu, PageLinks, openResource, Banner, FooterTemplate, ToolbarTemplate, util, mCustomGlobalCommands, SideMenu, objects, mMetrics) {
	/**
	 * This class contains static utility methods. It is not intended to be instantiated.
	 *
	 * @class This class contains static utility methods for creating and managing global commands.
	 * @name orion.globalCommands
	 */

	var METRICS_MAXLENGTH = 256;

	var customGlobalCommands = {
		createMenuGenerator: mCustomGlobalCommands.createMenuGenerator || function (serviceRegistry, keyAssistFunction) {
			var userMenuPlaceholder = lib.node("userMenu"); //$NON-NLS-0$
			if (!userMenuPlaceholder) {
				return;
			}
			if (util.isElectron) {
				lib.$("span", lib.node("userTrigger")).className += " core-sprite-questionmark";
			}
			else {
				lib.$("span", lib.node("userTrigger")).className += " core-sprite-silhouette";
			}
			
			var optionsLabel = widgetMessages['Help'];
			var dropdownNode = lib.node("userDropdown"); //$NON-NLS-0$
			var userDropdown = new mDropdown.Dropdown({
				dropdown: dropdownNode,
				name: optionsLabel,
				selectionClass: "dropdownSelection" //$NON-NLS-0$
			});
			var menuGenerator = new mUserMenu.UserMenu({
				dropdownNode: dropdownNode,
				dropdown: userDropdown,
				serviceRegistry: serviceRegistry
			});
			var dropdownTrigger = lib.node("userTrigger"); //$NON-NLS-0$
			lib.setSafeAttribute(dropdownTrigger, "aria-label", optionsLabel);

			dropdownTrigger.tooltip = new mTooltip.Tooltip({
				node: dropdownTrigger,
				text: optionsLabel,
				position: ["below", "left"] //$NON-NLS-1$ //$NON-NLS-0$
			});

			/*
			 * To add user name call: setUserName(serviceRegistry, dropdownTrigger);
			 */
			menuGenerator.setKeyAssist(keyAssistFunction);

			return menuGenerator;
		},
		beforeGenerateRelatedLinks: mCustomGlobalCommands.beforeGenerateRelatedLinks || function (serviceRegistry, item, exclusions, commandRegistry, alternateItem) {
			return true;
		},
		// each relatedLink is { relatedLink: Object, command: Command, invocation: CommandInvocation }
		addRelatedLinkCommands: mCustomGlobalCommands.addRelatedLinkCommands || function (commandRegistry, relatedLinks, inactive, exclusions) {
			if (this.sideMenu) {
				this.sideMenu.setRelatedLinks(relatedLinks, exclusions);
			}
		},
		afterGenerateRelatedLinks: mCustomGlobalCommands.afterGenerateRelatedLinks || function (serviceRegistry, item, exclusions, commandRegistry, alternateItem) {},
		afterSetPageTarget: mCustomGlobalCommands.afterSetPageTarget || function (options) {},
		generateNavigationMenu: mCustomGlobalCommands.generateNavigationMenu || function (parentId, serviceRegistry, commandRegistry, prefsService, searcher, handler, /* optional */ editor) {
			var sideMenuParent = lib.node("sideMenu"); //$NON-NLS-0$
			if (sideMenuParent) {
				this.sideMenu = new SideMenu(sideMenuParent, lib.node("pageContent")); //$NON-NLS-0$
				var nav = lib.node('centralNavigation'); //$NON-NLS-0$
				if (nav) {
					new mTooltip.Tooltip({
						node: nav,
						text: messages["CentralNavTooltip"],
						position: ["right"] //$NON-NLS-0$
					});
					nav.addEventListener("click", this.sideMenu.toggle.bind(this.sideMenu));
				}

				var sideMenuToggle = lib.node("sideMenuToggle"); //$NON-NLS-0$
				if (sideMenuToggle) {
					sideMenuToggle.addEventListener("click", this.sideMenu.toggle.bind(this.sideMenu));
				}
			}
		},
		afterGenerateNavigationMenu: mCustomGlobalCommands.afterGenerateNavigationMenu || function (parentId, serviceRegistry, commandRegistry, prefsService, searcher, handler, /* optional */ editor) {
			// No-op
		},
		afterGenerateBanner: mCustomGlobalCommands.afterGenerateBanner || function (parentId, serviceRegistry, commandRegistry, prefsService, searcher, handler, /* optional */ editor) {}
	};

	var authenticationIds = [];
	var authRendered = {};

	function getLabel(authService, serviceReference) {
		return authService.getLabel ? authService.getLabel() : new Deferred().resolve(serviceReference.properties.name);
	}

	function startProgressService(serviceRegistry) {
		var progressPane = lib.node("progressPane"); //$NON-NLS-0$
		lib.setSafeAttribute(progressPane, "aria-label", messages['Operations']);
		var progressService = serviceRegistry.getService("orion.page.progress"); //$NON-NLS-0$
		if (progressService) {
			progressService.init.bind(progressService)("progressPane"); //$NON-NLS-0$
		}
	}

	/**
	 * Adds the user-related commands to the toolbar
	 *
	 * @name orion.globalCommands#generateUserInfo
	 * @function
	 */

	function generateUserInfo(serviceRegistry, keyAssistFunction, prefsService) {
		prefsService.get("/userMenu").then(function(prefs) {
			if (Boolean(prefs) && prefs.disabled === true) {
				var menu = lib.node("userMenu");
				if (Boolean(menu)) {
					menu.parentElement.removeChild(menu);
				}
				return;
			}
			var authServices = serviceRegistry.getServiceReferences("orion.core.auth"); //$NON-NLS-0$
			authenticationIds = [];

			var menuGenerator = customGlobalCommands.createMenuGenerator.call(this, serviceRegistry, keyAssistFunction, prefsService);

			if (!menuGenerator) { return; }

			for (var i = 0; i < authServices.length; i++) {
				var servicePtr = authServices[i];
				var authService = serviceRegistry.getService(servicePtr);
				getLabel(authService, servicePtr).then(function (label) {
					authService.getKey().then(function (key) {
						authenticationIds.push(key);
						authService.getUser().then(function (jsonData) {
							menuGenerator.addUserItem(key, authService, label, jsonData);
						}, function (errorData, jsonData) {
							menuGenerator.addUserItem(key, authService, label, jsonData);
						});
						window.addEventListener("storage", function (e) {
							if (authRendered[key] === util.readSetting(key)) {
								return;
							}

							authRendered[key] = util.readSetting(key);

							authService.getUser().then(function (jsonData) {
								menuGenerator.addUserItem(key, authService, label, jsonData);
							}, function (errorData) {
								menuGenerator.addUserItem(key, authService, label);
							});
						}, false);
					});
				});
			}
		});
	}

	// Related links menu management. The related menu is reused as content changes. If the menu becomes empty, we hide the dropdown.
	var pageItem;
	var exclusions = [];
	var title;

	/**
	 * Adds the related links to the banner
	 *
	 * @name orion.globalCommands#generateRelatedLinks
	 * @function
	 */
	function generateRelatedLinks(serviceRegistry, item, exclusions, commandRegistry, alternateItem) {
		var globalArguments = arguments;
		var contentTypesCache;

		function getContentTypes() {
			if (contentTypesCache) {
				return contentTypesCache;
			}
			var contentTypeService = serviceRegistry.getService("orion.core.contentTypeRegistry"); //$NON-NLS-0$
			// TODO Shouldn't really be making service selection decisions at this level. See bug 337740
			if (!contentTypeService) {
				contentTypeService = new mContentTypes.ContentTypeRegistry(serviceRegistry);
				contentTypeService = serviceRegistry.getService("orion.core.contentTypeRegistry"); //$NON-NLS-0$
			}
			return contentTypeService.getContentTypes().then(function (ct) {
				contentTypesCache = ct;
				return contentTypesCache;
			});
		}
		function getServiceProperties(serviceReference) {
			var info = {}, keys = serviceReference.getPropertyKeys(), key;
			for (var i=0; i < keys.length; i++) {
				key = keys[i];
				info[key] = serviceReference.getProperty(key);
			}
			return info;
		}
		function getNavCommandRef(navCommandsRefs, id) {
			var commandRef = null;
			navCommandsRefs.some(function(ref) {
				if (id === ref.getProperty("id")) { //$NON-NLS-0$
					return !!(commandRef = ref);
				}
				return false;
			});
			return commandRef;
		}
		var alternateItemDeferred;
		/**
		 * Creates a CommandInvocation for given commandItem.
		 * @returns {orion.Promise} A promise resolving to: commandItem with its "invocation" field set, or undefined if we failed
		 */
		function setInvocation(commandItem) {
			var command = commandItem.command;
			if (!command.visibleWhen || command.visibleWhen(item)) {
				commandItem.invocation = new mCommands.CommandInvocation(item, item, null, command, commandRegistry);
				return new Deferred().resolve(commandItem);
			} else if (typeof alternateItem === "function") {
				if (!alternateItemDeferred) {
					alternateItemDeferred = alternateItem();
				}
				return Deferred.when(alternateItemDeferred, function (newItem) {
					if (newItem && (item === pageItem)) {
						// there is an alternate, and it still applies to the current page target
						if (!command.visibleWhen || command.visibleWhen(newItem)) {
							commandItem.invocation = new mCommands.CommandInvocation(newItem, newItem, null, command, commandRegistry);
							return commandItem;
						}
					}
				});
			}
			return new Deferred().resolve();
		}
		/**
		 * @returns {orion.Promise} resolving to a commandItem { relatedLink: Object, command: Command}
		*/
		function commandItem(relatedLink, commandOptionsPromise, command) {
			if (command) {
				return new Deferred().resolve({ relatedLink: relatedLink, command: command});
			}
			return commandOptionsPromise.then(function(commandOptions) {
				return { relatedLink: relatedLink, command: new mCommands.Command(commandOptions) };
			});
		}

		var contributedLinks = serviceRegistry && serviceRegistry.getServiceReferences("orion.page.link.related"); //$NON-NLS-0$
		if (!contributedLinks || contributedLinks.length === 0) {
			return;
		}

		var thisGlobalCommands = this;
		Deferred.when(getContentTypes(), function () {
			if (!customGlobalCommands.beforeGenerateRelatedLinks.apply(thisGlobalCommands, globalArguments)) {
				return;
			}

			// assemble the related links.
			var navCommands = serviceRegistry.getServiceReferences("orion.navigate.command"); //$NON-NLS-0$
			var deferredCommandItems = [];
			contributedLinks.forEach(function(contribution) {
				var info = getServiceProperties(contribution);
				if (!info.id) {
					return; // skip
				}
				// First see if we have a uriTemplate and name, which is enough to build a command internally.
				var commandOptionsPromise;
				if (((info.nls && info.nameKey) || info.name) && info.uriTemplate) {
					commandOptionsPromise = mExtensionCommands._createCommandOptions(info, contribution, serviceRegistry, contentTypesCache, true);
					deferredCommandItems.push(commandItem(info, commandOptionsPromise, null));
					return;
				}
				// Otherwise, check if this related link references an orion.navigate.command contribution
				var navRef = getNavCommandRef(navCommands, info.id);
				if (!navRef)
					return; // skip: no nav command

				// Build relatedLink info by merging the 2 contributions. info has "id", "category"; navInfo has everything else
				var navInfo = getServiceProperties(navRef), relatedLink = {};
				objects.mixin(relatedLink, navInfo, info); // {} <- navInfo <- info
				var command;
				if ((command = commandRegistry.findCommand(info.id))) {
					// A Command exists already, use it
					deferredCommandItems.push(commandItem(relatedLink, null, command));
				} else {
					// Create a new Command for the nav contribution
					commandOptionsPromise = mExtensionCommands._createCommandOptions(navInfo, navRef, serviceRegistry, contentTypesCache, true);
					deferredCommandItems.push(commandItem(relatedLink, commandOptionsPromise, null));
				}
			});

			function continueOnError(error) {
				return error;
			}

			Deferred.all(deferredCommandItems, continueOnError).then(function(commandItems) {
				commandItems.sort(function(a, b) {
					return a.command.name.localeCompare(b.command.name);
				});
				return Deferred.all(commandItems.map(setInvocation), continueOnError).then(function(invoked) {
					var nonInvoked = [];
					// Filter out any holes caused by setInvocation() failing
					invoked = invoked.filter(function(item, i) {
						if (item) {
							return true;
						}
						nonInvoked.push(commandItems[i]);
						return false;
					});
					// Finally pass the relatedLinks data to customGlobalCommands
					customGlobalCommands.addRelatedLinkCommands.call(thisGlobalCommands, commandRegistry, invoked, nonInvoked, exclusions);
					customGlobalCommands.afterGenerateRelatedLinks.apply(thisGlobalCommands, globalArguments);
				});
			});
		});
	}

	function renderGlobalCommands(commandRegistry) {
		var globalTools = lib.node("globalActions"); //$NON-NLS-0$
		if (globalTools) {
			commandRegistry.destroy(globalTools);
			commandRegistry.renderCommands(globalTools.id, globalTools, {}, {}, "tool"); //$NON-NLS-0$
		}
	}

	/**
	 * Support for establishing a page item associated with global commands and related links
	 */
	function setPageCommandExclusions(excluded) {
		exclusions = excluded;
	}

	/**
	 * Set a dirty indicator for the page. An in-page indicator will always be set. If the document has a title (set via setPageTarget), then
	 * the title will also be updated with a dirty indicator.
	 */
	function setDirtyIndicator(isDirty) {
		if (title) {
			if (title.charAt(0) === '*' && !isDirty) {
				title = title.substring(1);
			}
			if (isDirty && title.charAt(0) !== '*') {
				title = '*' + title;
			}
			window.document.title = title;
		}
	}

	/**
	 * Set the target of the page so that common infrastructure (breadcrumbs, related menu, etc.) can be added for the page.
	 * @name orion.globalCommands#setPageTarget
	 * @function
	 *
	 * @param {Object} options The target options object.
	 * @param {String} options.task the name of the user task that the page represents.
	 * @param {Object} options.target the metadata describing the page resource target. Optional.
	 * @param {String} options.name the name of the resource that is showing on the page. Optional. If a target parameter is supplied, the
	 * target metadata name will be used if a name is not specified in the options.
	 * @param {String} options.title the title to be used for the page. Optional. If not specified, a title will be constructed using the task
	 * and/or name.
	 * @param {Function} options.makeAlternate a function that can supply alternate metadata for the related pages menu if the target does not
	 * validate against a contribution. Optional.
	 * Optional. If not specified, and if a target is specified, the breadcrumb link will refer to the Navigator.
	 * @param {orion.serviceregistry.ServiceRegistry} options.serviceRegistry the registry to use for obtaining any unspecified services. Optional. If not specified, then
	 * any banner elements requiring Orion services will not be provided.
	 * @param {orion.commandregistry.CommandRegistry} options.commandService the commandService used for accessing related page commands. Optional. If not specified, a
	 * related page menu will not be shown.
	 * @param {orion.searchClient.Searcher} options.searchService the searchService used for scoping the searchbox. Optional. If not specified, the searchbox will
	 * not be scoped.
	 * @param {orion.fileClient.FileClient} options.fileService the fileService used for retrieving additional metadata and managing the breadcrumb for multiple
	 * file services. If not specified, there may be reduced support for multiple file implementations.
	 */
	function setPageTarget(options) {
		var pageName;
		var serviceRegistry = options.serviceRegistry;
		if (options.target) { // we have metadata
			if (options.searchService) {
				options.searchService.setLocationByMetaData(options.target, {index: "last"});
			}
			pageName = options.name || options.target.Name;
			pageItem = options.target;
			generateRelatedLinks.call(this, serviceRegistry, options.target, exclusions, options.commandService, options.makeAlternate);
		} else {
			pageName = options.name;
			generateRelatedLinks.call(this, serviceRegistry, {NoTarget: ""}, exclusions, options.commandService, options.makeAlternate);
		}
		title = options.title;
		if (!title) {
			if (pageName) {
				title = i18nUtil.formatMessage(messages["PageTitleFormat"], pageName, options.task);
			} else {
				title = options.task;
			}
		}
		window.document.title = title;
		customGlobalCommands.afterSetPageTarget.apply(this, arguments);
	}

	function boundingNode(node) {
		var style = window.getComputedStyle(node, null);
		if (style === null) {
			return node;
		}
		var position = style.getPropertyValue("position"); //$NON-NLS-0$
		if (position === "absolute" || !node.parentNode || node === document.body) {
			return node;
		}
		return boundingNode(node.parentNode);
	}

	function getToolbarElements(toolNode) {
		var elements = {};
		var toolbarNode = null;
		if (typeof toolNode === "string") {
			toolNode = lib.node(toolNode);
		}
		// no reference node has been given, so use the main toolbar.
		if (!toolNode) {
			toolNode = lib.node("pageActions"); //$NON-NLS-0$
		}
		var node = toolNode;
		// the trickiest part is finding where to start looking (section or main toolbar).
		// We need to walk up until we find a "toolComposite"
		while (node && node.classList) {
			if (node.classList.contains("toolComposite")) { //$NON-NLS-0$
				toolbarNode = node;
				break;
			}
			node = node.parentNode;
		}
		if (toolNode.classList.contains("commandMarker")) { //$NON-NLS-0$
			elements.commandNode = toolNode;
		}
		if (!toolbarNode) {
			toolbarNode = lib.node("pageToolbar"); //$NON-NLS-0$
		}
		if (toolbarNode) {
			elements.slideContainer = lib.$(".slideParameters", toolbarNode); //$NON-NLS-0$
			elements.parameterArea = lib.$(".parameters", toolbarNode); //$NON-NLS-0$
			elements.dismissArea = lib.$(".parametersDismiss", toolbarNode); //$NON-NLS-0$
			elements.notifications = lib.$("#notificationArea", toolbarNode); //$NON-NLS-0$
			if (toolbarNode.parentNode) {
				elements.toolbarTarget = lib.$(".toolbarTarget", toolbarNode.parentNode); //$NON-NLS-0$
				if (elements.toolbarTarget) {
					var bounds = lib.bounds(elements.toolbarTarget);
					var parentBounds = lib.bounds(boundingNode(elements.toolbarTarget.parentNode));
					elements.toolbarTargetY = bounds.top - parentBounds.top;
					elements.toolbar = toolbarNode;
				}
			}
		}
		return elements;
	}

	function layoutToolbarElements(elements) {
		var slideContainer = elements.slideContainer;
		if (slideContainer) {
			slideContainer.style.left = "";
			slideContainer.style.top = "";
			if (slideContainer.classList.contains("slideContainerActive")) { //$NON-NLS-0$
				var bounds = lib.bounds(slideContainer);
				var parentBounds = lib.bounds(slideContainer.parentNode);
				slideContainer.style.left = ((parentBounds.width - bounds.width) / 2) + "px"; //$NON-NLS-0$
				slideContainer.style.top = "0"; //$NON-NLS-0$
			}
		}
	}

	var mainSplitter = null;

	function getMainSplitter() {
		return mainSplitter;
	}

	var keyAssist = null;
	function getKeyAssist() {
		return keyAssist;
	}

	var globalEventTarget = new EventTarget();
	function getGlobalEventTarget() {
		return globalEventTarget;
	}

	/**
	 * Generates the banner at the top of a page.
	 *
	 * @name orion.globalCommands#generateBanner
	 * @function
	 *
	 * @param parentId
	 * @param serviceRegistry
	 * @param commandRegistry
	 * @param prefsService
	 * @param searcher
	 * @param handler
	 * @param editor - no longer used
	 * @param {Boolean} closeSplitter true to make the splitter's initial state "closed".
	 */
	function generateBanner(parentId, serviceRegistry, commandRegistry, prefsService, searcher, handler, /* optional */ editor, closeSplitter, fileClient) {
		serviceRegistry.registerService("orion.metrics", {
			/** @callback */
			logEvent: function(category, action, label, value) {
			},
			logTiming: function(timingCategory, timingVar, timingValue, timingLabel) {
				if (timingCategory === "page" && timingVar === "complete") {
					var pageLoader = require.defined("orion/splash") && require("orion/splash").getPageLoader();
					if (pageLoader) pageLoader.takeDown();
				}
				if (util.readSetting("consoleMetrics")) {
					window.console.log(timingCategory + " " + timingVar + " " + timingValue + " " + timingLabel);
				}
			},
			/** @callback */
			pageLoad: function(href, page, title, args) {
			}
		}, {});
		var metrics = new mMetrics.Metrics(serviceRegistry);
		prefsService.addChangeListener(function(name, value) {
			if (value.length < METRICS_MAXLENGTH && name.indexOf("/git/credentials/") !== 0) { //$NON-NLS-0$
				metrics.logEvent("preferenceChange", name, value); //$NON-NLS-0$
			}
		});
		window.addEventListener("error", function(e) {
			var index = e.filename.lastIndexOf("/");
			var filename = e.filename.substring(index + 1);
			if (filename) {
				var errorString = e.message + " (" + filename + ": " + e.lineno + (e.colno ? ", " + e.colno : "") + ")"; //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
				metrics.logEvent("runtime", "uncaughtError", errorString); //$NON-NLS-1$ //$NON-NLS-0$
			} else {
				errorString = e.message + " (" + e.filename + ": " + e.lineno + (e.colno ? ", " + e.colno : "") + ")"; //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
				metrics.logEvent("runtime", "uncaughtErrorUnknownFile", errorString); //$NON-NLS-1$ //$NON-NLS-0$
			}

			if (e.error) {
				var stackString = e.error.stack.replace(new RegExp(window.location.origin, "g"), "");
				metrics.logEvent("runtime", "uncaughtErrorStack", stackString); //$NON-NLS-1$ //$NON-NLS-0$
			}
		});

		var themeVal = util.readSetting("pageTheme");
		if (themeVal && typeof themeVal === "string" || themeVal instanceof String && themeVal.length > 0) {
			themeVal.split(" ").forEach(function(clazz) {
				if (!document.body.classList.contains(clazz)) {
					document.body.classList.add(clazz);
				}
			});
		}
		
		// forward the preference service on to the command registry
		commandRegistry.setServiceRegistry(serviceRegistry);

		new mThemePreferences.ThemePreferences(prefsService, new mThemeData.ThemeData(serviceRegistry)).apply();

		var parent = lib.node(parentId);

		if (!parent) {
			throw i18nUtil.formatMessage("could not find banner parent, id was ${0}", parentId);
		}
		// place the HTML fragment for the header.
		new Banner().create(parent);
		
		// TODO not entirely happy with this. Dynamic behavior that couldn't be in the html template, maybe it could be
		// dynamically bound in a better way like we do with NLS strings
		var home = lib.node("home"); //$NON-NLS-0$
		if (home) {
			home.href = require.toUrl("edit/edit.html"); //$NON-NLS-0$
			lib.setSafeAttribute(home, "aria-label", messages['Orion Home']);
		}

		var toolbar = lib.node("pageToolbar"); //$NON-NLS-0$
		if (toolbar) {
			lib.setSafeAttribute(toolbar, "aria-label", messages.toolbar);
			toolbar.classList.add("toolbarLayout"); //$NON-NLS-0$
			lib.setSafeInnerHTML(toolbar, ToolbarTemplate + commonHTML.slideoutHTMLFragment("mainToolbar"));
		}
		var closeNotification = lib.node("closeNotifications"); //$NON-NLS-0$
		if (closeNotification) {
			lib.setSafeAttribute(closeNotification, "aria-label", messages['Close notification']);
		}

		//Hack for FF17 Bug#415176
		if (util.isFirefox <= 17) {
			var staticBanner = lib.node("staticBanner"); //$NON-NLS-0$
			if (staticBanner) {
				staticBanner.style.width = "100%"; //$NON-NLS-0$
				staticBanner.style.MozBoxSizing = "border-box"; //$NON-NLS-0$
			}
		}

		var footer = lib.node("footer"); //$NON-NLS-0$
		if (footer && FooterTemplate) {
			lib.setSafeInnerHTML(footer, FooterTemplate);
			// do the i18n string substitutions
			var config = module.config && module.config() || {};
			if (config.ShutdownDate) {
				messages.ShutdownWarning = i18nUtil.formatMessage(messages.ShutdownWarning, config.ShutdownDate);
			} else {
				messages.ShutdownWarning = " ";
			}
			lib.processTextNodes(footer, messages);
			var sideMenuNode = lib.node("sideMenu"); //$NON-NLS-0$
			if (sideMenuNode) {
				sideMenuNode.classList.add("content-fixedHeight-withFooter");
			}
			var content = lib.$(".content-fixedHeight"); //$NON-NLS-0$
			if (content) {
				content.classList.add("content-fixedHeight-withFooter");
			}
			footer.classList.add("footer-visible");
		}

		// Set up a custom parameter collector that slides out of adjacent tool areas.
		commandRegistry.setParameterCollector(new mParameterCollectors.CommandParameterCollector(getToolbarElements, layoutToolbarElements));

		document.addEventListener("keydown", function (e) {
			if (e.keyCode === lib.KEY.ESCAPE) {
				var statusService = serviceRegistry.getService("orion.page.message"); //$NON-NLS-0$
				if (statusService) {
					statusService.setProgressMessage("");
				}
			}
		}, false);

		customGlobalCommands.generateNavigationMenu.apply(this, arguments);
		customGlobalCommands.afterGenerateNavigationMenu.apply(this, arguments);

		// generate primary nav links.
		var categoriesPromise = PageLinks.getCategoriesInfo(serviceRegistry);
		var pageLinksPromise = PageLinks.getPageLinksInfo(serviceRegistry, "orion.page.link");
		Deferred.all([ categoriesPromise, pageLinksPromise ]).then(function(results) {
			if (this.sideMenu) {
				var categoriesInfo = results[0], pageLinksInfo = results[1];
				this.sideMenu.setCategories(categoriesInfo);
				this.sideMenu.setPageLinks(pageLinksInfo);

				// Now we have enough to show the sidemenu with its close-to-final layout
				this.sideMenu.render();
			}
		}.bind(this));

		// hook up split behavior - the splitter widget and the associated global command/key bindings.
		var splitNode = lib.$(".split"); //$NON-NLS-0$
		if (splitNode) {
			var side = lib.$(".sidePanelLayout"); //$NON-NLS-0$
			var main = lib.$(".mainPanelLayout"); //$NON-NLS-0$
			if (side && main) {
				mainSplitter = {
					side: side,
					main: main
				};
				mainSplitter.splitter = new mSplitter.Splitter({
					node: splitNode,
					sidePanel: side,
					mainPanel: main,
					toggle: true,
					closeByDefault: closeSplitter
				});
				var toggleSidePanelCommand = new mCommands.Command({
					name: messages["Toggle Side Panel"],
					tooltip: messages["Open or close the side panel"],
					id: "orion.toggleSidePane", //$NON-NLS-0$
					callback: function () {
						mainSplitter.splitter.toggleSidePanel();
					}
				});
				commandRegistry.addCommand(toggleSidePanelCommand);
				commandRegistry.registerCommandContribution("pageActions", "orion.toggleSidePane", 1, null, true, new KeyBinding.KeyBinding('l', util.isMac ? false : true, true, false, util.isMac ? true : false)); //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
			}
		}

		// Assemble global commands, those that could be available from any page due to header content or common key bindings.

		// open resource
		var showingResourceDialog = false;
		var openResourceDialog = function (searcher, serviceRegistry, commandRegistry) {
			if (showingResourceDialog) {
				return;
			}
			var progress = serviceRegistry.getService("orion.page.progress"); //$NON-NLS-0$
			var prefs = serviceRegistry.getService("orion.core.preference"); //$NON-NLS-0$
			var dialog = new openResource.OpenResourceDialog({
				searcher: searcher,
				progress: progress,
				prefService: prefs,
				serviceRegistry: serviceRegistry,
				commandRegistry: commandRegistry,
				searchRenderer: searcher.defaultRenderer,
				onHide: function () {
					showingResourceDialog = false;
				}
			});
			window.setTimeout(function () {
				showingResourceDialog = true;
				dialog.show();
			}, 0);
		};

		var openResourceCommand = new mCommands.Command({
			name: messages["FindFile"],
			tooltip: messages["ChooseFileOpenEditor"],
			id: "orion.openResource", //$NON-NLS-0$
			callback: function (data) {
				openResourceDialog(searcher, serviceRegistry, commandRegistry);
			}
		});

		commandRegistry.addCommand(openResourceCommand);
		commandRegistry.registerCommandContribution("globalActions", "orion.openResource", 100, null, true, new KeyBinding.KeyBinding('f', true, true)); //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
		var noBanner = false;
		var toggleBannerFunc = function () {
			if (noBanner) {
				return false;
			}
			var header = lib.node("banner"); //$NON-NLS-0$
			var footer = lib.node("footer"); //$NON-NLS-0$
			var sideMenuNode = lib.node("sideMenu"); //$NON-NLS-0$
			var content = lib.$(".content-fixedHeight"); //$NON-NLS-0$
			var maximized = header.classList.contains("banner-maximized"); //$NON-NLS-0$
			if (maximized) {
				header.classList.remove("banner-maximized"); //$NON-NLS-0$
				footer.classList.remove("footer-maximized"); //$NON-NLS-0$
				content.classList.remove("content-fixedHeight-maximized"); //$NON-NLS-0$
				if (sideMenuNode) {
					sideMenuNode.classList.remove("sideMenu-maximized"); //$NON-NLS-0$
				}
			} else {
				header.classList.add("banner-maximized"); //$NON-NLS-0$
				footer.classList.add("footer-maximized"); //$NON-NLS-0$
				content.classList.add("content-fixedHeight-maximized"); //$NON-NLS-0$
				if (sideMenuNode) {
					sideMenuNode.classList.add("sideMenu-maximized"); //$NON-NLS-0$
				}
			}
			getGlobalEventTarget().dispatchEvent({type: "toggleTrim", maximized: !maximized}); //$NON-NLS-0$
			return true;
		};


		var noTrim = window.orionNoTrim || util.readSetting("orionNoTrim") || false;
		if (noTrim) {
			toggleBannerFunc();
			noBanner = true;
			if (noTrim !== "bannerOnly") this.sideMenu.hide();
		} else {
			// Toggle trim command
			var toggleBanner = new mCommands.Command({
				name: messages["Toggle Banner and Footer"],
				tooltip: messages["HideShowBannerFooter"],
				id: "orion.toggleTrim", //$NON-NLS-0$
				callback: toggleBannerFunc
			});
			commandRegistry.addCommand(toggleBanner);
			commandRegistry.registerCommandContribution("globalActions", "orion.toggleTrim", 100, null, true, new KeyBinding.KeyBinding("m", true, true)); //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$

			// Background Operations Page, Ctrl+Shift+O
			var operationsCommand = new mCommands.Command({
				name: messages["Background Operations"],
				tooltip: messages["Background Operations Tooltip"],
				id: "orion.backgroundOperations", //$NON-NLS-0$
				hrefCallback: function () {
					return require.toUrl("operations/list.html"); //$NON-NLS-0$
				}
			});

			commandRegistry.addCommand(operationsCommand);
			commandRegistry.registerCommandContribution("globalActions", "orion.backgroundOperations", 100, null, true, new KeyBinding.KeyBinding('o', true, true)); //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$

			var showTooltipCommand = new mCommands.Command({
				name: editMessages.showTooltip,
				tooltip: editMessages.showTooltipTooltip,
				id: "orion.edit.showTooltip", //$NON-NLS-0$
				visibleWhen: /** @callback */ function(items, data) {
					return true;
				},
				callback: function() {
					var domFocus = document.activeElement, label, tooltip;
					if (this.editor && this.editor._domNode.contains(domFocus)) {
						var editor = this.editor;
						tooltip = editor.getTooltip();
						var tv = editor.getTextView();
						var offset = tv.getCaretOffset();
						var pos = tv.getLocationAtOffset(offset);
						tooltip.show({
							x: pos.x,
							y: pos.y,
							getTooltipInfo: function() {
								return editor._getTooltipInfo(this.x, this.y);
							}
						}, false, true);
					} else if (domFocus.commandTooltip || domFocus.tooltip) {
						tooltip = domFocus.commandTooltip ? domFocus.commandTooltip : domFocus.tooltip;
						tooltip._showByKB = true;
						tooltip.show(0);
					} else if (domFocus.id && (label = document.querySelector("label[for=" + domFocus.id.replace(/./g, "\\.") + "]")) && label.tooltip) {
						tooltip = label.tooltip;
						tooltip._showByKB = true;
						tooltip.show(0);
					}
				}
			});
			commandRegistry.addCommand(showTooltipCommand);
			commandRegistry.registerCommandContribution("globalActions" , "orion.edit.showTooltip", 1, null, true, new KeyBinding.KeyBinding(112, false, true), null, this);//$NON-NLS-1$

			var focusNextSplitter = new mCommands.Command({
				name: messages.nextSplitter,
				tooltip: messages.nextSplitterTooltip,
				id: "orion.focusSplitter", //$NON-NLS-0$
				visibleWhen: /** @callback */ function(items, data) {
					return true;
				},
				callback: function() {
					var curFocus = document.activeElement;
					
					var items = lib.$$array(".split", document.body, true); //$NON-NLS-0$
					if (items.length > 0) {
						var theSplitter = items[0];
						
						// Filter out invisible splitters
						for (var j = 0; j < items.length; j++) {
							if (!items[j].offsetParent) {
								items.slice(items[j], 1);
							}
						}
							
						for (var i = 0; i < items.length; i++) {
							var splitter = items[i];
							// If a splitter is the current focus then we choose the next one..
							if (splitter === curFocus) {
								if (i < items.length-1) {
									theSplitter = items[i+1];
									break;
								}
							}
						}
						
						theSplitter.tabIndex = "0"; // Allow the splitter to take focus
						theSplitter.focus();
					}
				}
			});
			commandRegistry.addCommand(focusNextSplitter);
			commandRegistry.registerCommandContribution("globalActions" , "orion.focusSplitter", 1, null, true, new KeyBinding.KeyBinding(190, true, true), null, this);//$NON-NLS-1$

			// Key assist
			keyAssist = new mKeyAssist.KeyAssistPanel({
				commandRegistry: commandRegistry
			});
			var keyAssistCommand = mKeyAssist.createCommand(keyAssist, "globalActions", commandRegistry);

			renderGlobalCommands(commandRegistry);

			generateUserInfo(serviceRegistry, keyAssistCommand.callback, prefsService);
		}


		// now that footer containing progress pane is added
		startProgressService(serviceRegistry);

		// check for commands in the hash
		window.addEventListener("hashchange", function () {
			commandRegistry.processURL(window.location.href);
		}, false);
		
	    // System Editor
		if (util.isElectron) {
			serviceRegistry.registerService("orion.navigate.command", {
				run: function(item) {
					prefsService.get("/workspace").then(function(prefs) {
						var workspaceDir = prefs.currentWorkspace.replace(/\\/g, "/");
						window.__electron.shell.openItem(workspaceDir+item[0].Location.slice(5)); // slice off '/file'
					});
				}
			}, {
				name: messages["Orion System Editor"],
				id: "orion.system.editor",
				tooltip: messages["System Editor Tooltip"]
			});
		}

		return customGlobalCommands.afterGenerateBanner.apply(this, arguments);
	}

	// return the module exports
	return {
		generateBanner: generateBanner,
		getToolbarElements: getToolbarElements,
		getMainSplitter: getMainSplitter,
		getKeyAssist: getKeyAssist,
		getGlobalEventTarget: getGlobalEventTarget,
		layoutToolbarElements: layoutToolbarElements,
		setPageTarget: setPageTarget,
		setDirtyIndicator: setDirtyIndicator,
		setPageCommandExclusions: setPageCommandExclusions
	};
});
/*!
 * Socket.IO v4.4.1
 * (c) 2014-2022 Guillermo Rauch
 * Released under the MIT License.
 */
(function (global, factory) {
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
  typeof define === 'function' && define.amd ? define('socket.io/socket.io',factory) :
  (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.io = factory());
})(this, (function () { 'use strict';

  function _typeof(obj) {
    "@babel/helpers - typeof";

    if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
      _typeof = function (obj) {
        return typeof obj;
      };
    } else {
      _typeof = function (obj) {
        return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
      };
    }

    return _typeof(obj);
  }

  function _classCallCheck(instance, Constructor) {
    if (!(instance instanceof Constructor)) {
      throw new TypeError("Cannot call a class as a function");
    }
  }

  function _defineProperties(target, props) {
    for (var i = 0; i < props.length; i++) {
      var descriptor = props[i];
      descriptor.enumerable = descriptor.enumerable || false;
      descriptor.configurable = true;
      if ("value" in descriptor) descriptor.writable = true;
      Object.defineProperty(target, descriptor.key, descriptor);
    }
  }

  function _createClass(Constructor, protoProps, staticProps) {
    if (protoProps) _defineProperties(Constructor.prototype, protoProps);
    if (staticProps) _defineProperties(Constructor, staticProps);
    return Constructor;
  }

  function _extends() {
    _extends = Object.assign || function (target) {
      for (var i = 1; i < arguments.length; i++) {
        var source = arguments[i];

        for (var key in source) {
          if (Object.prototype.hasOwnProperty.call(source, key)) {
            target[key] = source[key];
          }
        }
      }

      return target;
    };

    return _extends.apply(this, arguments);
  }

  function _inherits(subClass, superClass) {
    if (typeof superClass !== "function" && superClass !== null) {
      throw new TypeError("Super expression must either be null or a function");
    }

    subClass.prototype = Object.create(superClass && superClass.prototype, {
      constructor: {
        value: subClass,
        writable: true,
        configurable: true
      }
    });
    if (superClass) _setPrototypeOf(subClass, superClass);
  }

  function _getPrototypeOf(o) {
    _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {
      return o.__proto__ || Object.getPrototypeOf(o);
    };
    return _getPrototypeOf(o);
  }

  function _setPrototypeOf(o, p) {
    _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
      o.__proto__ = p;
      return o;
    };

    return _setPrototypeOf(o, p);
  }

  function _isNativeReflectConstruct() {
    if (typeof Reflect === "undefined" || !Reflect.construct) return false;
    if (Reflect.construct.sham) return false;
    if (typeof Proxy === "function") return true;

    try {
      Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
      return true;
    } catch (e) {
      return false;
    }
  }

  function _assertThisInitialized(self) {
    if (self === void 0) {
      throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
    }

    return self;
  }

  function _possibleConstructorReturn(self, call) {
    if (call && (typeof call === "object" || typeof call === "function")) {
      return call;
    } else if (call !== void 0) {
      throw new TypeError("Derived constructors may only return object or undefined");
    }

    return _assertThisInitialized(self);
  }

  function _createSuper(Derived) {
    var hasNativeReflectConstruct = _isNativeReflectConstruct();

    return function _createSuperInternal() {
      var Super = _getPrototypeOf(Derived),
          result;

      if (hasNativeReflectConstruct) {
        var NewTarget = _getPrototypeOf(this).constructor;

        result = Reflect.construct(Super, arguments, NewTarget);
      } else {
        result = Super.apply(this, arguments);
      }

      return _possibleConstructorReturn(this, result);
    };
  }

  function _superPropBase(object, property) {
    while (!Object.prototype.hasOwnProperty.call(object, property)) {
      object = _getPrototypeOf(object);
      if (object === null) break;
    }

    return object;
  }

  function _get(target, property, receiver) {
    if (typeof Reflect !== "undefined" && Reflect.get) {
      _get = Reflect.get;
    } else {
      _get = function _get(target, property, receiver) {
        var base = _superPropBase(target, property);

        if (!base) return;
        var desc = Object.getOwnPropertyDescriptor(base, property);

        if (desc.get) {
          return desc.get.call(receiver);
        }

        return desc.value;
      };
    }

    return _get(target, property, receiver || target);
  }

  function _unsupportedIterableToArray(o, minLen) {
    if (!o) return;
    if (typeof o === "string") return _arrayLikeToArray(o, minLen);
    var n = Object.prototype.toString.call(o).slice(8, -1);
    if (n === "Object" && o.constructor) n = o.constructor.name;
    if (n === "Map" || n === "Set") return Array.from(o);
    if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
  }

  function _arrayLikeToArray(arr, len) {
    if (len == null || len > arr.length) len = arr.length;

    for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];

    return arr2;
  }

  function _createForOfIteratorHelper(o, allowArrayLike) {
    var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"];

    if (!it) {
      if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") {
        if (it) o = it;
        var i = 0;

        var F = function () {};

        return {
          s: F,
          n: function () {
            if (i >= o.length) return {
              done: true
            };
            return {
              done: false,
              value: o[i++]
            };
          },
          e: function (e) {
            throw e;
          },
          f: F
        };
      }

      throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
    }

    var normalCompletion = true,
        didErr = false,
        err;
    return {
      s: function () {
        it = it.call(o);
      },
      n: function () {
        var step = it.next();
        normalCompletion = step.done;
        return step;
      },
      e: function (e) {
        didErr = true;
        err = e;
      },
      f: function () {
        try {
          if (!normalCompletion && it.return != null) it.return();
        } finally {
          if (didErr) throw err;
        }
      }
    };
  }

  /**
   * Parses an URI
   *
   * @author Steven Levithan <stevenlevithan.com> (MIT license)
   * @api private
   */
  var re = /^(?:(?![^:@]+:[^:@\/]*@)(http|https|ws|wss):\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?((?:[a-f0-9]{0,4}:){2,7}[a-f0-9]{0,4}|[^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/;
  var parts = ['source', 'protocol', 'authority', 'userInfo', 'user', 'password', 'host', 'port', 'relative', 'path', 'directory', 'file', 'query', 'anchor'];

  var parseuri = function parseuri(str) {
    var src = str,
        b = str.indexOf('['),
        e = str.indexOf(']');

    if (b != -1 && e != -1) {
      str = str.substring(0, b) + str.substring(b, e).replace(/:/g, ';') + str.substring(e, str.length);
    }

    var m = re.exec(str || ''),
        uri = {},
        i = 14;

    while (i--) {
      uri[parts[i]] = m[i] || '';
    }

    if (b != -1 && e != -1) {
      uri.source = src;
      uri.host = uri.host.substring(1, uri.host.length - 1).replace(/;/g, ':');
      uri.authority = uri.authority.replace('[', '').replace(']', '').replace(/;/g, ':');
      uri.ipv6uri = true;
    }

    uri.pathNames = pathNames(uri, uri['path']);
    uri.queryKey = queryKey(uri, uri['query']);
    return uri;
  };

  function pathNames(obj, path) {
    var regx = /\/{2,9}/g,
        names = path.replace(regx, "/").split("/");

    if (path.substr(0, 1) == '/' || path.length === 0) {
      names.splice(0, 1);
    }

    if (path.substr(path.length - 1, 1) == '/') {
      names.splice(names.length - 1, 1);
    }

    return names;
  }

  function queryKey(uri, query) {
    var data = {};
    query.replace(/(?:^|&)([^&=]*)=?([^&]*)/g, function ($0, $1, $2) {
      if ($1) {
        data[$1] = $2;
      }
    });
    return data;
  }

  /**
   * URL parser.
   *
   * @param uri - url
   * @param path - the request path of the connection
   * @param loc - An object meant to mimic window.location.
   *        Defaults to window.location.
   * @public
   */

  function url(uri) {
    var path = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "";
    var loc = arguments.length > 2 ? arguments[2] : undefined;
    var obj = uri; // default to window.location

    loc = loc || typeof location !== "undefined" && location;
    if (null == uri) uri = loc.protocol + "//" + loc.host; // relative path support

    if (typeof uri === "string") {
      if ("/" === uri.charAt(0)) {
        if ("/" === uri.charAt(1)) {
          uri = loc.protocol + uri;
        } else {
          uri = loc.host + uri;
        }
      }

      if (!/^(https?|wss?):\/\//.test(uri)) {
        if ("undefined" !== typeof loc) {
          uri = loc.protocol + "//" + uri;
        } else {
          uri = "https://" + uri;
        }
      } // parse


      obj = parseuri(uri);
    } // make sure we treat `localhost:80` and `localhost` equally


    if (!obj.port) {
      if (/^(http|ws)$/.test(obj.protocol)) {
        obj.port = "80";
      } else if (/^(http|ws)s$/.test(obj.protocol)) {
        obj.port = "443";
      }
    }

    obj.path = obj.path || "/";
    var ipv6 = obj.host.indexOf(":") !== -1;
    var host = ipv6 ? "[" + obj.host + "]" : obj.host; // define unique id

    obj.id = obj.protocol + "://" + host + ":" + obj.port + path; // define href

    obj.href = obj.protocol + "://" + host + (loc && loc.port === obj.port ? "" : ":" + obj.port);
    return obj;
  }

  var hasCors = {exports: {}};

  /**
   * Module exports.
   *
   * Logic borrowed from Modernizr:
   *
   *   - https://github.com/Modernizr/Modernizr/blob/master/feature-detects/cors.js
   */

  try {
    hasCors.exports = typeof XMLHttpRequest !== 'undefined' && 'withCredentials' in new XMLHttpRequest();
  } catch (err) {
    // if XMLHttp support is disabled in IE then it will throw
    // when trying to create
    hasCors.exports = false;
  }

  var hasCORS = hasCors.exports;

  var globalThis = (function () {
    if (typeof self !== "undefined") {
      return self;
    } else if (typeof window !== "undefined") {
      return window;
    } else {
      return Function("return this")();
    }
  })();

  // browser shim for xmlhttprequest module
  function XMLHttpRequest$1 (opts) {
    var xdomain = opts.xdomain; // XMLHttpRequest can be disabled on IE

    try {
      if ("undefined" !== typeof XMLHttpRequest && (!xdomain || hasCORS)) {
        return new XMLHttpRequest();
      }
    } catch (e) {}

    if (!xdomain) {
      try {
        return new globalThis[["Active"].concat("Object").join("X")]("Microsoft.XMLHTTP");
      } catch (e) {}
    }
  }

  function pick(obj) {
    for (var _len = arguments.length, attr = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
      attr[_key - 1] = arguments[_key];
    }

    return attr.reduce(function (acc, k) {
      if (obj.hasOwnProperty(k)) {
        acc[k] = obj[k];
      }

      return acc;
    }, {});
  } // Keep a reference to the real timeout functions so they can be used when overridden

  var NATIVE_SET_TIMEOUT = setTimeout;
  var NATIVE_CLEAR_TIMEOUT = clearTimeout;
  function installTimerFunctions(obj, opts) {
    if (opts.useNativeTimers) {
      obj.setTimeoutFn = NATIVE_SET_TIMEOUT.bind(globalThis);
      obj.clearTimeoutFn = NATIVE_CLEAR_TIMEOUT.bind(globalThis);
    } else {
      obj.setTimeoutFn = setTimeout.bind(globalThis);
      obj.clearTimeoutFn = clearTimeout.bind(globalThis);
    }
  }

  /**
   * Expose `Emitter`.
   */

  var Emitter_1 = Emitter;
  /**
   * Initialize a new `Emitter`.
   *
   * @api public
   */

  function Emitter(obj) {
    if (obj) return mixin(obj);
  }
  /**
   * Mixin the emitter properties.
   *
   * @param {Object} obj
   * @return {Object}
   * @api private
   */


  function mixin(obj) {
    for (var key in Emitter.prototype) {
      obj[key] = Emitter.prototype[key];
    }

    return obj;
  }
  /**
   * Listen on the given `event` with `fn`.
   *
   * @param {String} event
   * @param {Function} fn
   * @return {Emitter}
   * @api public
   */


  Emitter.prototype.on = Emitter.prototype.addEventListener = function (event, fn) {
    this._callbacks = this._callbacks || {};
    (this._callbacks['$' + event] = this._callbacks['$' + event] || []).push(fn);
    return this;
  };
  /**
   * Adds an `event` listener that will be invoked a single
   * time then automatically removed.
   *
   * @param {String} event
   * @param {Function} fn
   * @return {Emitter}
   * @api public
   */


  Emitter.prototype.once = function (event, fn) {
    function on() {
      this.off(event, on);
      fn.apply(this, arguments);
    }

    on.fn = fn;
    this.on(event, on);
    return this;
  };
  /**
   * Remove the given callback for `event` or all
   * registered callbacks.
   *
   * @param {String} event
   * @param {Function} fn
   * @return {Emitter}
   * @api public
   */


  Emitter.prototype.off = Emitter.prototype.removeListener = Emitter.prototype.removeAllListeners = Emitter.prototype.removeEventListener = function (event, fn) {
    this._callbacks = this._callbacks || {}; // all

    if (0 == arguments.length) {
      this._callbacks = {};
      return this;
    } // specific event


    var callbacks = this._callbacks['$' + event];
    if (!callbacks) return this; // remove all handlers

    if (1 == arguments.length) {
      delete this._callbacks['$' + event];
      return this;
    } // remove specific handler


    var cb;

    for (var i = 0; i < callbacks.length; i++) {
      cb = callbacks[i];

      if (cb === fn || cb.fn === fn) {
        callbacks.splice(i, 1);
        break;
      }
    } // Remove event specific arrays for event types that no
    // one is subscribed for to avoid memory leak.


    if (callbacks.length === 0) {
      delete this._callbacks['$' + event];
    }

    return this;
  };
  /**
   * Emit `event` with the given args.
   *
   * @param {String} event
   * @param {Mixed} ...
   * @return {Emitter}
   */


  Emitter.prototype.emit = function (event) {
    this._callbacks = this._callbacks || {};
    var args = new Array(arguments.length - 1),
        callbacks = this._callbacks['$' + event];

    for (var i = 1; i < arguments.length; i++) {
      args[i - 1] = arguments[i];
    }

    if (callbacks) {
      callbacks = callbacks.slice(0);

      for (var i = 0, len = callbacks.length; i < len; ++i) {
        callbacks[i].apply(this, args);
      }
    }

    return this;
  }; // alias used for reserved events (protected method)


  Emitter.prototype.emitReserved = Emitter.prototype.emit;
  /**
   * Return array of callbacks for `event`.
   *
   * @param {String} event
   * @return {Array}
   * @api public
   */

  Emitter.prototype.listeners = function (event) {
    this._callbacks = this._callbacks || {};
    return this._callbacks['$' + event] || [];
  };
  /**
   * Check if this emitter has `event` handlers.
   *
   * @param {String} event
   * @return {Boolean}
   * @api public
   */


  Emitter.prototype.hasListeners = function (event) {
    return !!this.listeners(event).length;
  };

  var PACKET_TYPES = Object.create(null); // no Map = no polyfill

  PACKET_TYPES["open"] = "0";
  PACKET_TYPES["close"] = "1";
  PACKET_TYPES["ping"] = "2";
  PACKET_TYPES["pong"] = "3";
  PACKET_TYPES["message"] = "4";
  PACKET_TYPES["upgrade"] = "5";
  PACKET_TYPES["noop"] = "6";
  var PACKET_TYPES_REVERSE = Object.create(null);
  Object.keys(PACKET_TYPES).forEach(function (key) {
    PACKET_TYPES_REVERSE[PACKET_TYPES[key]] = key;
  });
  var ERROR_PACKET = {
    type: "error",
    data: "parser error"
  };

  var withNativeBlob$1 = typeof Blob === "function" || typeof Blob !== "undefined" && Object.prototype.toString.call(Blob) === "[object BlobConstructor]";
  var withNativeArrayBuffer$2 = typeof ArrayBuffer === "function"; // ArrayBuffer.isView method is not defined in IE10

  var isView$1 = function isView(obj) {
    return typeof ArrayBuffer.isView === "function" ? ArrayBuffer.isView(obj) : obj && obj.buffer instanceof ArrayBuffer;
  };

  var encodePacket = function encodePacket(_ref, supportsBinary, callback) {
    var type = _ref.type,
        data = _ref.data;

    if (withNativeBlob$1 && data instanceof Blob) {
      if (supportsBinary) {
        return callback(data);
      } else {
        return encodeBlobAsBase64(data, callback);
      }
    } else if (withNativeArrayBuffer$2 && (data instanceof ArrayBuffer || isView$1(data))) {
      if (supportsBinary) {
        return callback(data);
      } else {
        return encodeBlobAsBase64(new Blob([data]), callback);
      }
    } // plain string


    return callback(PACKET_TYPES[type] + (data || ""));
  };

  var encodeBlobAsBase64 = function encodeBlobAsBase64(data, callback) {
    var fileReader = new FileReader();

    fileReader.onload = function () {
      var content = fileReader.result.split(",")[1];
      callback("b" + content);
    };

    return fileReader.readAsDataURL(data);
  };

  /*
   * base64-arraybuffer 1.0.1 <https://github.com/niklasvh/base64-arraybuffer>
   * Copyright (c) 2021 Niklas von Hertzen <https://hertzen.com>
   * Released under MIT License
   */
  var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; // Use a lookup table to find the index.

  var lookup$1 = typeof Uint8Array === 'undefined' ? [] : new Uint8Array(256);

  for (var i$1 = 0; i$1 < chars.length; i$1++) {
    lookup$1[chars.charCodeAt(i$1)] = i$1;
  }

  var decode$1 = function decode(base64) {
    var bufferLength = base64.length * 0.75,
        len = base64.length,
        i,
        p = 0,
        encoded1,
        encoded2,
        encoded3,
        encoded4;

    if (base64[base64.length - 1] === '=') {
      bufferLength--;

      if (base64[base64.length - 2] === '=') {
        bufferLength--;
      }
    }

    var arraybuffer = new ArrayBuffer(bufferLength),
        bytes = new Uint8Array(arraybuffer);

    for (i = 0; i < len; i += 4) {
      encoded1 = lookup$1[base64.charCodeAt(i)];
      encoded2 = lookup$1[base64.charCodeAt(i + 1)];
      encoded3 = lookup$1[base64.charCodeAt(i + 2)];
      encoded4 = lookup$1[base64.charCodeAt(i + 3)];
      bytes[p++] = encoded1 << 2 | encoded2 >> 4;
      bytes[p++] = (encoded2 & 15) << 4 | encoded3 >> 2;
      bytes[p++] = (encoded3 & 3) << 6 | encoded4 & 63;
    }

    return arraybuffer;
  };

  var withNativeArrayBuffer$1 = typeof ArrayBuffer === "function";

  var decodePacket = function decodePacket(encodedPacket, binaryType) {
    if (typeof encodedPacket !== "string") {
      return {
        type: "message",
        data: mapBinary(encodedPacket, binaryType)
      };
    }

    var type = encodedPacket.charAt(0);

    if (type === "b") {
      return {
        type: "message",
        data: decodeBase64Packet(encodedPacket.substring(1), binaryType)
      };
    }

    var packetType = PACKET_TYPES_REVERSE[type];

    if (!packetType) {
      return ERROR_PACKET;
    }

    return encodedPacket.length > 1 ? {
      type: PACKET_TYPES_REVERSE[type],
      data: encodedPacket.substring(1)
    } : {
      type: PACKET_TYPES_REVERSE[type]
    };
  };

  var decodeBase64Packet = function decodeBase64Packet(data, binaryType) {
    if (withNativeArrayBuffer$1) {
      var decoded = decode$1(data);
      return mapBinary(decoded, binaryType);
    } else {
      return {
        base64: true,
        data: data
      }; // fallback for old browsers
    }
  };

  var mapBinary = function mapBinary(data, binaryType) {
    switch (binaryType) {
      case "blob":
        return data instanceof ArrayBuffer ? new Blob([data]) : data;

      case "arraybuffer":
      default:
        return data;
      // assuming the data is already an ArrayBuffer
    }
  };

  var SEPARATOR = String.fromCharCode(30); // see https://en.wikipedia.org/wiki/Delimiter#ASCII_delimited_text

  var encodePayload = function encodePayload(packets, callback) {
    // some packets may be added to the array while encoding, so the initial length must be saved
    var length = packets.length;
    var encodedPackets = new Array(length);
    var count = 0;
    packets.forEach(function (packet, i) {
      // force base64 encoding for binary packets
      encodePacket(packet, false, function (encodedPacket) {
        encodedPackets[i] = encodedPacket;

        if (++count === length) {
          callback(encodedPackets.join(SEPARATOR));
        }
      });
    });
  };

  var decodePayload = function decodePayload(encodedPayload, binaryType) {
    var encodedPackets = encodedPayload.split(SEPARATOR);
    var packets = [];

    for (var i = 0; i < encodedPackets.length; i++) {
      var decodedPacket = decodePacket(encodedPackets[i], binaryType);
      packets.push(decodedPacket);

      if (decodedPacket.type === "error") {
        break;
      }
    }

    return packets;
  };

  var protocol$1 = 4;

  var Transport = /*#__PURE__*/function (_Emitter) {
    _inherits(Transport, _Emitter);

    var _super = _createSuper(Transport);

    /**
     * Transport abstract constructor.
     *
     * @param {Object} options.
     * @api private
     */
    function Transport(opts) {
      var _this;

      _classCallCheck(this, Transport);

      _this = _super.call(this);
      _this.writable = false;
      installTimerFunctions(_assertThisInitialized(_this), opts);
      _this.opts = opts;
      _this.query = opts.query;
      _this.readyState = "";
      _this.socket = opts.socket;
      return _this;
    }
    /**
     * Emits an error.
     *
     * @param {String} str
     * @return {Transport} for chaining
     * @api protected
     */


    _createClass(Transport, [{
      key: "onError",
      value: function onError(msg, desc) {
        var err = new Error(msg); // @ts-ignore

        err.type = "TransportError"; // @ts-ignore

        err.description = desc;

        _get(_getPrototypeOf(Transport.prototype), "emit", this).call(this, "error", err);

        return this;
      }
      /**
       * Opens the transport.
       *
       * @api public
       */

    }, {
      key: "open",
      value: function open() {
        if ("closed" === this.readyState || "" === this.readyState) {
          this.readyState = "opening";
          this.doOpen();
        }

        return this;
      }
      /**
       * Closes the transport.
       *
       * @api public
       */

    }, {
      key: "close",
      value: function close() {
        if ("opening" === this.readyState || "open" === this.readyState) {
          this.doClose();
          this.onClose();
        }

        return this;
      }
      /**
       * Sends multiple packets.
       *
       * @param {Array} packets
       * @api public
       */

    }, {
      key: "send",
      value: function send(packets) {
        if ("open" === this.readyState) {
          this.write(packets);
        }
      }
      /**
       * Called upon open
       *
       * @api protected
       */

    }, {
      key: "onOpen",
      value: function onOpen() {
        this.readyState = "open";
        this.writable = true;

        _get(_getPrototypeOf(Transport.prototype), "emit", this).call(this, "open");
      }
      /**
       * Called with data.
       *
       * @param {String} data
       * @api protected
       */

    }, {
      key: "onData",
      value: function onData(data) {
        var packet = decodePacket(data, this.socket.binaryType);
        this.onPacket(packet);
      }
      /**
       * Called with a decoded packet.
       *
       * @api protected
       */

    }, {
      key: "onPacket",
      value: function onPacket(packet) {
        _get(_getPrototypeOf(Transport.prototype), "emit", this).call(this, "packet", packet);
      }
      /**
       * Called upon close.
       *
       * @api protected
       */

    }, {
      key: "onClose",
      value: function onClose() {
        this.readyState = "closed";

        _get(_getPrototypeOf(Transport.prototype), "emit", this).call(this, "close");
      }
    }]);

    return Transport;
  }(Emitter_1);

  var alphabet = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_'.split(''),
      length = 64,
      map = {},
      seed = 0,
      i = 0,
      prev;
  /**
   * Return a string representing the specified number.
   *
   * @param {Number} num The number to convert.
   * @returns {String} The string representation of the number.
   * @api public
   */

  function encode(num) {
    var encoded = '';

    do {
      encoded = alphabet[num % length] + encoded;
      num = Math.floor(num / length);
    } while (num > 0);

    return encoded;
  }
  /**
   * Return the integer value specified by the given string.
   *
   * @param {String} str The string to convert.
   * @returns {Number} The integer value represented by the string.
   * @api public
   */


  function decode(str) {
    var decoded = 0;

    for (i = 0; i < str.length; i++) {
      decoded = decoded * length + map[str.charAt(i)];
    }

    return decoded;
  }
  /**
   * Yeast: A tiny growing id generator.
   *
   * @returns {String} A unique id.
   * @api public
   */


  function yeast() {
    var now = encode(+new Date());
    if (now !== prev) return seed = 0, prev = now;
    return now + '.' + encode(seed++);
  } //
  // Map each character to its index.
  //


  for (; i < length; i++) {
    map[alphabet[i]] = i;
  } //
  // Expose the `yeast`, `encode` and `decode` functions.
  //


  yeast.encode = encode;
  yeast.decode = decode;
  var yeast_1 = yeast;

  var parseqs = {};

  /**
   * Compiles a querystring
   * Returns string representation of the object
   *
   * @param {Object}
   * @api private
   */

  parseqs.encode = function (obj) {
    var str = '';

    for (var i in obj) {
      if (obj.hasOwnProperty(i)) {
        if (str.length) str += '&';
        str += encodeURIComponent(i) + '=' + encodeURIComponent(obj[i]);
      }
    }

    return str;
  };
  /**
   * Parses a simple querystring into an object
   *
   * @param {String} qs
   * @api private
   */


  parseqs.decode = function (qs) {
    var qry = {};
    var pairs = qs.split('&');

    for (var i = 0, l = pairs.length; i < l; i++) {
      var pair = pairs[i].split('=');
      qry[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]);
    }

    return qry;
  };

  var Polling = /*#__PURE__*/function (_Transport) {
    _inherits(Polling, _Transport);

    var _super = _createSuper(Polling);

    function Polling() {
      var _this;

      _classCallCheck(this, Polling);

      _this = _super.apply(this, arguments);
      _this.polling = false;
      return _this;
    }
    /**
     * Transport name.
     */


    _createClass(Polling, [{
      key: "name",
      get: function get() {
        return "polling";
      }
      /**
       * Opens the socket (triggers polling). We write a PING message to determine
       * when the transport is open.
       *
       * @api private
       */

    }, {
      key: "doOpen",
      value: function doOpen() {
        this.poll();
      }
      /**
       * Pauses polling.
       *
       * @param {Function} callback upon buffers are flushed and transport is paused
       * @api private
       */

    }, {
      key: "pause",
      value: function pause(onPause) {
        var _this2 = this;

        this.readyState = "pausing";

        var pause = function pause() {
          _this2.readyState = "paused";
          onPause();
        };

        if (this.polling || !this.writable) {
          var total = 0;

          if (this.polling) {
            total++;
            this.once("pollComplete", function () {
              --total || pause();
            });
          }

          if (!this.writable) {
            total++;
            this.once("drain", function () {
              --total || pause();
            });
          }
        } else {
          pause();
        }
      }
      /**
       * Starts polling cycle.
       *
       * @api public
       */

    }, {
      key: "poll",
      value: function poll() {
        this.polling = true;
        this.doPoll();
        this.emit("poll");
      }
      /**
       * Overloads onData to detect payloads.
       *
       * @api private
       */

    }, {
      key: "onData",
      value: function onData(data) {
        var _this3 = this;

        var callback = function callback(packet) {
          // if its the first message we consider the transport open
          if ("opening" === _this3.readyState && packet.type === "open") {
            _this3.onOpen();
          } // if its a close packet, we close the ongoing requests


          if ("close" === packet.type) {
            _this3.onClose();

            return false;
          } // otherwise bypass onData and handle the message


          _this3.onPacket(packet);
        }; // decode payload


        decodePayload(data, this.socket.binaryType).forEach(callback); // if an event did not trigger closing

        if ("closed" !== this.readyState) {
          // if we got data we're not polling
          this.polling = false;
          this.emit("pollComplete");

          if ("open" === this.readyState) {
            this.poll();
          }
        }
      }
      /**
       * For polling, send a close packet.
       *
       * @api private
       */

    }, {
      key: "doClose",
      value: function doClose() {
        var _this4 = this;

        var close = function close() {
          _this4.write([{
            type: "close"
          }]);
        };

        if ("open" === this.readyState) {
          close();
        } else {
          // in case we're trying to close while
          // handshaking is in progress (GH-164)
          this.once("open", close);
        }
      }
      /**
       * Writes a packets payload.
       *
       * @param {Array} data packets
       * @param {Function} drain callback
       * @api private
       */

    }, {
      key: "write",
      value: function write(packets) {
        var _this5 = this;

        this.writable = false;
        encodePayload(packets, function (data) {
          _this5.doWrite(data, function () {
            _this5.writable = true;

            _this5.emit("drain");
          });
        });
      }
      /**
       * Generates uri for connection.
       *
       * @api private
       */

    }, {
      key: "uri",
      value: function uri() {
        var query = this.query || {};
        var schema = this.opts.secure ? "https" : "http";
        var port = ""; // cache busting is forced

        if (false !== this.opts.timestampRequests) {
          query[this.opts.timestampParam] = yeast_1();
        }

        if (!this.supportsBinary && !query.sid) {
          query.b64 = 1;
        } // avoid port if default for schema


        if (this.opts.port && ("https" === schema && Number(this.opts.port) !== 443 || "http" === schema && Number(this.opts.port) !== 80)) {
          port = ":" + this.opts.port;
        }

        var encodedQuery = parseqs.encode(query);
        var ipv6 = this.opts.hostname.indexOf(":") !== -1;
        return schema + "://" + (ipv6 ? "[" + this.opts.hostname + "]" : this.opts.hostname) + port + this.opts.path + (encodedQuery.length ? "?" + encodedQuery : "");
      }
    }]);

    return Polling;
  }(Transport);

  /**
   * Empty function
   */

  function empty() {}

  var hasXHR2 = function () {
    var xhr = new XMLHttpRequest$1({
      xdomain: false
    });
    return null != xhr.responseType;
  }();

  var XHR = /*#__PURE__*/function (_Polling) {
    _inherits(XHR, _Polling);

    var _super = _createSuper(XHR);

    /**
     * XHR Polling constructor.
     *
     * @param {Object} opts
     * @api public
     */
    function XHR(opts) {
      var _this;

      _classCallCheck(this, XHR);

      _this = _super.call(this, opts);

      if (typeof location !== "undefined") {
        var isSSL = "https:" === location.protocol;
        var port = location.port; // some user agents have empty `location.port`

        if (!port) {
          port = isSSL ? "443" : "80";
        }

        _this.xd = typeof location !== "undefined" && opts.hostname !== location.hostname || port !== opts.port;
        _this.xs = opts.secure !== isSSL;
      }
      /**
       * XHR supports binary
       */


      var forceBase64 = opts && opts.forceBase64;
      _this.supportsBinary = hasXHR2 && !forceBase64;
      return _this;
    }
    /**
     * Creates a request.
     *
     * @param {String} method
     * @api private
     */


    _createClass(XHR, [{
      key: "request",
      value: function request() {
        var opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};

        _extends(opts, {
          xd: this.xd,
          xs: this.xs
        }, this.opts);

        return new Request(this.uri(), opts);
      }
      /**
       * Sends data.
       *
       * @param {String} data to send.
       * @param {Function} called upon flush.
       * @api private
       */

    }, {
      key: "doWrite",
      value: function doWrite(data, fn) {
        var _this2 = this;

        var req = this.request({
          method: "POST",
          data: data
        });
        req.on("success", fn);
        req.on("error", function (err) {
          _this2.onError("xhr post error", err);
        });
      }
      /**
       * Starts a poll cycle.
       *
       * @api private
       */

    }, {
      key: "doPoll",
      value: function doPoll() {
        var _this3 = this;

        var req = this.request();
        req.on("data", this.onData.bind(this));
        req.on("error", function (err) {
          _this3.onError("xhr poll error", err);
        });
        this.pollXhr = req;
      }
    }]);

    return XHR;
  }(Polling);
  var Request = /*#__PURE__*/function (_Emitter) {
    _inherits(Request, _Emitter);

    var _super2 = _createSuper(Request);

    /**
     * Request constructor
     *
     * @param {Object} options
     * @api public
     */
    function Request(uri, opts) {
      var _this4;

      _classCallCheck(this, Request);

      _this4 = _super2.call(this);
      installTimerFunctions(_assertThisInitialized(_this4), opts);
      _this4.opts = opts;
      _this4.method = opts.method || "GET";
      _this4.uri = uri;
      _this4.async = false !== opts.async;
      _this4.data = undefined !== opts.data ? opts.data : null;

      _this4.create();

      return _this4;
    }
    /**
     * Creates the XHR object and sends the request.
     *
     * @api private
     */


    _createClass(Request, [{
      key: "create",
      value: function create() {
        var _this5 = this;

        var opts = pick(this.opts, "agent", "pfx", "key", "passphrase", "cert", "ca", "ciphers", "rejectUnauthorized", "autoUnref");
        opts.xdomain = !!this.opts.xd;
        opts.xscheme = !!this.opts.xs;
        var xhr = this.xhr = new XMLHttpRequest$1(opts);

        try {
          xhr.open(this.method, this.uri, this.async);

          try {
            if (this.opts.extraHeaders) {
              xhr.setDisableHeaderCheck && xhr.setDisableHeaderCheck(true);

              for (var i in this.opts.extraHeaders) {
                if (this.opts.extraHeaders.hasOwnProperty(i)) {
                  xhr.setRequestHeader(i, this.opts.extraHeaders[i]);
                }
              }
            }
          } catch (e) {}

          if ("POST" === this.method) {
            try {
              xhr.setRequestHeader("Content-type", "text/plain;charset=UTF-8");
            } catch (e) {}
          }

          try {
            xhr.setRequestHeader("Accept", "*/*");
          } catch (e) {} // ie6 check


          if ("withCredentials" in xhr) {
            xhr.withCredentials = this.opts.withCredentials;
          }

          if (this.opts.requestTimeout) {
            xhr.timeout = this.opts.requestTimeout;
          }

          xhr.onreadystatechange = function () {
            if (4 !== xhr.readyState) return;

            if (200 === xhr.status || 1223 === xhr.status) {
              _this5.onLoad();
            } else {
              // make sure the `error` event handler that's user-set
              // does not throw in the same tick and gets caught here
              _this5.setTimeoutFn(function () {
                _this5.onError(typeof xhr.status === "number" ? xhr.status : 0);
              }, 0);
            }
          };

          xhr.send(this.data);
        } catch (e) {
          // Need to defer since .create() is called directly from the constructor
          // and thus the 'error' event can only be only bound *after* this exception
          // occurs.  Therefore, also, we cannot throw here at all.
          this.setTimeoutFn(function () {
            _this5.onError(e);
          }, 0);
          return;
        }

        if (typeof document !== "undefined") {
          this.index = Request.requestsCount++;
          Request.requests[this.index] = this;
        }
      }
      /**
       * Called upon successful response.
       *
       * @api private
       */

    }, {
      key: "onSuccess",
      value: function onSuccess() {
        this.emit("success");
        this.cleanup();
      }
      /**
       * Called if we have data.
       *
       * @api private
       */

    }, {
      key: "onData",
      value: function onData(data) {
        this.emit("data", data);
        this.onSuccess();
      }
      /**
       * Called upon error.
       *
       * @api private
       */

    }, {
      key: "onError",
      value: function onError(err) {
        this.emit("error", err);
        this.cleanup(true);
      }
      /**
       * Cleans up house.
       *
       * @api private
       */

    }, {
      key: "cleanup",
      value: function cleanup(fromError) {
        if ("undefined" === typeof this.xhr || null === this.xhr) {
          return;
        }

        this.xhr.onreadystatechange = empty;

        if (fromError) {
          try {
            this.xhr.abort();
          } catch (e) {}
        }

        if (typeof document !== "undefined") {
          delete Request.requests[this.index];
        }

        this.xhr = null;
      }
      /**
       * Called upon load.
       *
       * @api private
       */

    }, {
      key: "onLoad",
      value: function onLoad() {
        var data = this.xhr.responseText;

        if (data !== null) {
          this.onData(data);
        }
      }
      /**
       * Aborts the request.
       *
       * @api public
       */

    }, {
      key: "abort",
      value: function abort() {
        this.cleanup();
      }
    }]);

    return Request;
  }(Emitter_1);
  Request.requestsCount = 0;
  Request.requests = {};
  /**
   * Aborts pending requests when unloading the window. This is needed to prevent
   * memory leaks (e.g. when using IE) and to ensure that no spurious error is
   * emitted.
   */

  if (typeof document !== "undefined") {
    // @ts-ignore
    if (typeof attachEvent === "function") {
      // @ts-ignore
      attachEvent("onunload", unloadHandler);
    } else if (typeof addEventListener === "function") {
      var terminationEvent = "onpagehide" in globalThis ? "pagehide" : "unload";
      addEventListener(terminationEvent, unloadHandler, false);
    }
  }

  function unloadHandler() {
    for (var i in Request.requests) {
      if (Request.requests.hasOwnProperty(i)) {
        Request.requests[i].abort();
      }
    }
  }

  var nextTick = function () {
    var isPromiseAvailable = typeof Promise === "function" && typeof Promise.resolve === "function";

    if (isPromiseAvailable) {
      return function (cb) {
        return Promise.resolve().then(cb);
      };
    } else {
      return function (cb, setTimeoutFn) {
        return setTimeoutFn(cb, 0);
      };
    }
  }();
  var WebSocket = globalThis.WebSocket || globalThis.MozWebSocket;
  var usingBrowserWebSocket = true;
  var defaultBinaryType = "arraybuffer";

  var isReactNative = typeof navigator !== "undefined" && typeof navigator.product === "string" && navigator.product.toLowerCase() === "reactnative";
  var WS = /*#__PURE__*/function (_Transport) {
    _inherits(WS, _Transport);

    var _super = _createSuper(WS);

    /**
     * WebSocket transport constructor.
     *
     * @api {Object} connection options
     * @api public
     */
    function WS(opts) {
      var _this;

      _classCallCheck(this, WS);

      _this = _super.call(this, opts);
      _this.supportsBinary = !opts.forceBase64;
      return _this;
    }
    /**
     * Transport name.
     *
     * @api public
     */


    _createClass(WS, [{
      key: "name",
      get: function get() {
        return "websocket";
      }
      /**
       * Opens socket.
       *
       * @api private
       */

    }, {
      key: "doOpen",
      value: function doOpen() {
        if (!this.check()) {
          // let probe timeout
          return;
        }

        var uri = this.uri();
        var protocols = this.opts.protocols; // React Native only supports the 'headers' option, and will print a warning if anything else is passed

        var opts = isReactNative ? {} : pick(this.opts, "agent", "perMessageDeflate", "pfx", "key", "passphrase", "cert", "ca", "ciphers", "rejectUnauthorized", "localAddress", "protocolVersion", "origin", "maxPayload", "family", "checkServerIdentity");

        if (this.opts.extraHeaders) {
          opts.headers = this.opts.extraHeaders;
        }

        try {
          this.ws = usingBrowserWebSocket && !isReactNative ? protocols ? new WebSocket(uri, protocols) : new WebSocket(uri) : new WebSocket(uri, protocols, opts);
        } catch (err) {
          return this.emit("error", err);
        }

        this.ws.binaryType = this.socket.binaryType || defaultBinaryType;
        this.addEventListeners();
      }
      /**
       * Adds event listeners to the socket
       *
       * @api private
       */

    }, {
      key: "addEventListeners",
      value: function addEventListeners() {
        var _this2 = this;

        this.ws.onopen = function () {
          if (_this2.opts.autoUnref) {
            _this2.ws._socket.unref();
          }

          _this2.onOpen();
        };

        this.ws.onclose = this.onClose.bind(this);

        this.ws.onmessage = function (ev) {
          return _this2.onData(ev.data);
        };

        this.ws.onerror = function (e) {
          return _this2.onError("websocket error", e);
        };
      }
      /**
       * Writes data to socket.
       *
       * @param {Array} array of packets.
       * @api private
       */

    }, {
      key: "write",
      value: function write(packets) {
        var _this3 = this;

        this.writable = false; // encodePacket efficient as it uses WS framing
        // no need for encodePayload

        var _loop = function _loop(i) {
          var packet = packets[i];
          var lastPacket = i === packets.length - 1;
          encodePacket(packet, _this3.supportsBinary, function (data) {
            // always create a new object (GH-437)
            var opts = {};
            // have a chance of informing us about it yet, in that case send will
            // throw an error


            try {
              if (usingBrowserWebSocket) {
                // TypeError is thrown when passing the second argument on Safari
                _this3.ws.send(data);
              }
            } catch (e) {}

            if (lastPacket) {
              // fake drain
              // defer to next tick to allow Socket to clear writeBuffer
              nextTick(function () {
                _this3.writable = true;

                _this3.emit("drain");
              }, _this3.setTimeoutFn);
            }
          });
        };

        for (var i = 0; i < packets.length; i++) {
          _loop(i);
        }
      }
      /**
       * Closes socket.
       *
       * @api private
       */

    }, {
      key: "doClose",
      value: function doClose() {
        if (typeof this.ws !== "undefined") {
          this.ws.close();
          this.ws = null;
        }
      }
      /**
       * Generates uri for connection.
       *
       * @api private
       */

    }, {
      key: "uri",
      value: function uri() {
        var query = this.query || {};
        var schema = this.opts.secure ? "wss" : "ws";
        var port = ""; // avoid port if default for schema

        if (this.opts.port && ("wss" === schema && Number(this.opts.port) !== 443 || "ws" === schema && Number(this.opts.port) !== 80)) {
          port = ":" + this.opts.port;
        } // append timestamp to URI


        if (this.opts.timestampRequests) {
          query[this.opts.timestampParam] = yeast_1();
        } // communicate binary support capabilities


        if (!this.supportsBinary) {
          query.b64 = 1;
        }

        var encodedQuery = parseqs.encode(query);
        var ipv6 = this.opts.hostname.indexOf(":") !== -1;
        return schema + "://" + (ipv6 ? "[" + this.opts.hostname + "]" : this.opts.hostname) + port + this.opts.path + (encodedQuery.length ? "?" + encodedQuery : "");
      }
      /**
       * Feature detection for WebSocket.
       *
       * @return {Boolean} whether this transport is available.
       * @api public
       */

    }, {
      key: "check",
      value: function check() {
        return !!WebSocket && !("__initialize" in WebSocket && this.name === WS.prototype.name);
      }
    }]);

    return WS;
  }(Transport);

  var transports = {
    websocket: WS,
    polling: XHR
  };

  var Socket$1 = /*#__PURE__*/function (_Emitter) {
    _inherits(Socket, _Emitter);

    var _super = _createSuper(Socket);

    /**
     * Socket constructor.
     *
     * @param {String|Object} uri or options
     * @param {Object} opts - options
     * @api public
     */
    function Socket(uri) {
      var _this;

      var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

      _classCallCheck(this, Socket);

      _this = _super.call(this);

      if (uri && "object" === _typeof(uri)) {
        opts = uri;
        uri = null;
      }

      if (uri) {
        uri = parseuri(uri);
        opts.hostname = uri.host;
        opts.secure = uri.protocol === "https" || uri.protocol === "wss";
        opts.port = uri.port;
        if (uri.query) opts.query = uri.query;
      } else if (opts.host) {
        opts.hostname = parseuri(opts.host).host;
      }

      installTimerFunctions(_assertThisInitialized(_this), opts);
      _this.secure = null != opts.secure ? opts.secure : typeof location !== "undefined" && "https:" === location.protocol;

      if (opts.hostname && !opts.port) {
        // if no port is specified manually, use the protocol default
        opts.port = _this.secure ? "443" : "80";
      }

      _this.hostname = opts.hostname || (typeof location !== "undefined" ? location.hostname : "localhost");
      _this.port = opts.port || (typeof location !== "undefined" && location.port ? location.port : _this.secure ? "443" : "80");
      _this.transports = opts.transports || ["polling", "websocket"];
      _this.readyState = "";
      _this.writeBuffer = [];
      _this.prevBufferLen = 0;
      _this.opts = _extends({
        path: "/engine.io",
        agent: false,
        withCredentials: false,
        upgrade: true,
        timestampParam: "t",
        rememberUpgrade: false,
        rejectUnauthorized: true,
        perMessageDeflate: {
          threshold: 1024
        },
        transportOptions: {},
        closeOnBeforeunload: true
      }, opts);
      _this.opts.path = _this.opts.path.replace(/\/$/, "") + "/";

      if (typeof _this.opts.query === "string") {
        _this.opts.query = parseqs.decode(_this.opts.query);
      } // set on handshake


      _this.id = null;
      _this.upgrades = null;
      _this.pingInterval = null;
      _this.pingTimeout = null; // set on heartbeat

      _this.pingTimeoutTimer = null;

      if (typeof addEventListener === "function") {
        if (_this.opts.closeOnBeforeunload) {
          // Firefox closes the connection when the "beforeunload" event is emitted but not Chrome. This event listener
          // ensures every browser behaves the same (no "disconnect" event at the Socket.IO level when the page is
          // closed/reloaded)
          addEventListener("beforeunload", function () {
            if (_this.transport) {
              // silently close the transport
              _this.transport.removeAllListeners();

              _this.transport.close();
            }
          }, false);
        }

        if (_this.hostname !== "localhost") {
          _this.offlineEventListener = function () {
            _this.onClose("transport close");
          };

          addEventListener("offline", _this.offlineEventListener, false);
        }
      }

      _this.open();

      return _this;
    }
    /**
     * Creates transport of the given type.
     *
     * @param {String} transport name
     * @return {Transport}
     * @api private
     */


    _createClass(Socket, [{
      key: "createTransport",
      value: function createTransport(name) {
        var query = clone(this.opts.query); // append engine.io protocol identifier

        query.EIO = protocol$1; // transport name

        query.transport = name; // session id if we already have one

        if (this.id) query.sid = this.id;

        var opts = _extends({}, this.opts.transportOptions[name], this.opts, {
          query: query,
          socket: this,
          hostname: this.hostname,
          secure: this.secure,
          port: this.port
        });

        return new transports[name](opts);
      }
      /**
       * Initializes transport to use and starts probe.
       *
       * @api private
       */

    }, {
      key: "open",
      value: function open() {
        var _this2 = this;

        var transport;

        if (this.opts.rememberUpgrade && Socket.priorWebsocketSuccess && this.transports.indexOf("websocket") !== -1) {
          transport = "websocket";
        } else if (0 === this.transports.length) {
          // Emit error on next tick so it can be listened to
          this.setTimeoutFn(function () {
            _this2.emitReserved("error", "No transports available");
          }, 0);
          return;
        } else {
          transport = this.transports[0];
        }

        this.readyState = "opening"; // Retry with the next transport if the transport is disabled (jsonp: false)

        try {
          transport = this.createTransport(transport);
        } catch (e) {
          this.transports.shift();
          this.open();
          return;
        }

        transport.open();
        this.setTransport(transport);
      }
      /**
       * Sets the current transport. Disables the existing one (if any).
       *
       * @api private
       */

    }, {
      key: "setTransport",
      value: function setTransport(transport) {
        var _this3 = this;

        if (this.transport) {
          this.transport.removeAllListeners();
        } // set up transport


        this.transport = transport; // set up transport listeners

        transport.on("drain", this.onDrain.bind(this)).on("packet", this.onPacket.bind(this)).on("error", this.onError.bind(this)).on("close", function () {
          _this3.onClose("transport close");
        });
      }
      /**
       * Probes a transport.
       *
       * @param {String} transport name
       * @api private
       */

    }, {
      key: "probe",
      value: function probe(name) {
        var _this4 = this;

        var transport = this.createTransport(name);
        var failed = false;
        Socket.priorWebsocketSuccess = false;

        var onTransportOpen = function onTransportOpen() {
          if (failed) return;
          transport.send([{
            type: "ping",
            data: "probe"
          }]);
          transport.once("packet", function (msg) {
            if (failed) return;

            if ("pong" === msg.type && "probe" === msg.data) {
              _this4.upgrading = true;

              _this4.emitReserved("upgrading", transport);

              if (!transport) return;
              Socket.priorWebsocketSuccess = "websocket" === transport.name;

              _this4.transport.pause(function () {
                if (failed) return;
                if ("closed" === _this4.readyState) return;
                cleanup();

                _this4.setTransport(transport);

                transport.send([{
                  type: "upgrade"
                }]);

                _this4.emitReserved("upgrade", transport);

                transport = null;
                _this4.upgrading = false;

                _this4.flush();
              });
            } else {
              var err = new Error("probe error"); // @ts-ignore

              err.transport = transport.name;

              _this4.emitReserved("upgradeError", err);
            }
          });
        };

        function freezeTransport() {
          if (failed) return; // Any callback called by transport should be ignored since now

          failed = true;
          cleanup();
          transport.close();
          transport = null;
        } // Handle any error that happens while probing


        var onerror = function onerror(err) {
          var error = new Error("probe error: " + err); // @ts-ignore

          error.transport = transport.name;
          freezeTransport();

          _this4.emitReserved("upgradeError", error);
        };

        function onTransportClose() {
          onerror("transport closed");
        } // When the socket is closed while we're probing


        function onclose() {
          onerror("socket closed");
        } // When the socket is upgraded while we're probing


        function onupgrade(to) {
          if (transport && to.name !== transport.name) {
            freezeTransport();
          }
        } // Remove all listeners on the transport and on self


        var cleanup = function cleanup() {
          transport.removeListener("open", onTransportOpen);
          transport.removeListener("error", onerror);
          transport.removeListener("close", onTransportClose);

          _this4.off("close", onclose);

          _this4.off("upgrading", onupgrade);
        };

        transport.once("open", onTransportOpen);
        transport.once("error", onerror);
        transport.once("close", onTransportClose);
        this.once("close", onclose);
        this.once("upgrading", onupgrade);
        transport.open();
      }
      /**
       * Called when connection is deemed open.
       *
       * @api private
       */

    }, {
      key: "onOpen",
      value: function onOpen() {
        this.readyState = "open";
        Socket.priorWebsocketSuccess = "websocket" === this.transport.name;
        this.emitReserved("open");
        this.flush(); // we check for `readyState` in case an `open`
        // listener already closed the socket

        if ("open" === this.readyState && this.opts.upgrade && this.transport.pause) {
          var i = 0;
          var l = this.upgrades.length;

          for (; i < l; i++) {
            this.probe(this.upgrades[i]);
          }
        }
      }
      /**
       * Handles a packet.
       *
       * @api private
       */

    }, {
      key: "onPacket",
      value: function onPacket(packet) {
        if ("opening" === this.readyState || "open" === this.readyState || "closing" === this.readyState) {
          this.emitReserved("packet", packet); // Socket is live - any packet counts

          this.emitReserved("heartbeat");

          switch (packet.type) {
            case "open":
              this.onHandshake(JSON.parse(packet.data));
              break;

            case "ping":
              this.resetPingTimeout();
              this.sendPacket("pong");
              this.emitReserved("ping");
              this.emitReserved("pong");
              break;

            case "error":
              var err = new Error("server error"); // @ts-ignore

              err.code = packet.data;
              this.onError(err);
              break;

            case "message":
              this.emitReserved("data", packet.data);
              this.emitReserved("message", packet.data);
              break;
          }
        }
      }
      /**
       * Called upon handshake completion.
       *
       * @param {Object} data - handshake obj
       * @api private
       */

    }, {
      key: "onHandshake",
      value: function onHandshake(data) {
        this.emitReserved("handshake", data);
        this.id = data.sid;
        this.transport.query.sid = data.sid;
        this.upgrades = this.filterUpgrades(data.upgrades);
        this.pingInterval = data.pingInterval;
        this.pingTimeout = data.pingTimeout;
        this.onOpen(); // In case open handler closes socket

        if ("closed" === this.readyState) return;
        this.resetPingTimeout();
      }
      /**
       * Sets and resets ping timeout timer based on server pings.
       *
       * @api private
       */

    }, {
      key: "resetPingTimeout",
      value: function resetPingTimeout() {
        var _this5 = this;

        this.clearTimeoutFn(this.pingTimeoutTimer);
        this.pingTimeoutTimer = this.setTimeoutFn(function () {
          _this5.onClose("ping timeout");
        }, this.pingInterval + this.pingTimeout);

        if (this.opts.autoUnref) {
          this.pingTimeoutTimer.unref();
        }
      }
      /**
       * Called on `drain` event
       *
       * @api private
       */

    }, {
      key: "onDrain",
      value: function onDrain() {
        this.writeBuffer.splice(0, this.prevBufferLen); // setting prevBufferLen = 0 is very important
        // for example, when upgrading, upgrade packet is sent over,
        // and a nonzero prevBufferLen could cause problems on `drain`

        this.prevBufferLen = 0;

        if (0 === this.writeBuffer.length) {
          this.emitReserved("drain");
        } else {
          this.flush();
        }
      }
      /**
       * Flush write buffers.
       *
       * @api private
       */

    }, {
      key: "flush",
      value: function flush() {
        if ("closed" !== this.readyState && this.transport.writable && !this.upgrading && this.writeBuffer.length) {
          this.transport.send(this.writeBuffer); // keep track of current length of writeBuffer
          // splice writeBuffer and callbackBuffer on `drain`

          this.prevBufferLen = this.writeBuffer.length;
          this.emitReserved("flush");
        }
      }
      /**
       * Sends a message.
       *
       * @param {String} message.
       * @param {Function} callback function.
       * @param {Object} options.
       * @return {Socket} for chaining.
       * @api public
       */

    }, {
      key: "write",
      value: function write(msg, options, fn) {
        this.sendPacket("message", msg, options, fn);
        return this;
      }
    }, {
      key: "send",
      value: function send(msg, options, fn) {
        this.sendPacket("message", msg, options, fn);
        return this;
      }
      /**
       * Sends a packet.
       *
       * @param {String} packet type.
       * @param {String} data.
       * @param {Object} options.
       * @param {Function} callback function.
       * @api private
       */

    }, {
      key: "sendPacket",
      value: function sendPacket(type, data, options, fn) {
        if ("function" === typeof data) {
          fn = data;
          data = undefined;
        }

        if ("function" === typeof options) {
          fn = options;
          options = null;
        }

        if ("closing" === this.readyState || "closed" === this.readyState) {
          return;
        }

        options = options || {};
        options.compress = false !== options.compress;
        var packet = {
          type: type,
          data: data,
          options: options
        };
        this.emitReserved("packetCreate", packet);
        this.writeBuffer.push(packet);
        if (fn) this.once("flush", fn);
        this.flush();
      }
      /**
       * Closes the connection.
       *
       * @api public
       */

    }, {
      key: "close",
      value: function close() {
        var _this6 = this;

        var close = function close() {
          _this6.onClose("forced close");

          _this6.transport.close();
        };

        var cleanupAndClose = function cleanupAndClose() {
          _this6.off("upgrade", cleanupAndClose);

          _this6.off("upgradeError", cleanupAndClose);

          close();
        };

        var waitForUpgrade = function waitForUpgrade() {
          // wait for upgrade to finish since we can't send packets while pausing a transport
          _this6.once("upgrade", cleanupAndClose);

          _this6.once("upgradeError", cleanupAndClose);
        };

        if ("opening" === this.readyState || "open" === this.readyState) {
          this.readyState = "closing";

          if (this.writeBuffer.length) {
            this.once("drain", function () {
              if (_this6.upgrading) {
                waitForUpgrade();
              } else {
                close();
              }
            });
          } else if (this.upgrading) {
            waitForUpgrade();
          } else {
            close();
          }
        }

        return this;
      }
      /**
       * Called upon transport error
       *
       * @api private
       */

    }, {
      key: "onError",
      value: function onError(err) {
        Socket.priorWebsocketSuccess = false;
        this.emitReserved("error", err);
        this.onClose("transport error", err);
      }
      /**
       * Called upon transport close.
       *
       * @api private
       */

    }, {
      key: "onClose",
      value: function onClose(reason, desc) {
        if ("opening" === this.readyState || "open" === this.readyState || "closing" === this.readyState) {
          // clear timers
          this.clearTimeoutFn(this.pingTimeoutTimer); // stop event from firing again for transport

          this.transport.removeAllListeners("close"); // ensure transport won't stay open

          this.transport.close(); // ignore further transport communication

          this.transport.removeAllListeners();

          if (typeof removeEventListener === "function") {
            removeEventListener("offline", this.offlineEventListener, false);
          } // set ready state


          this.readyState = "closed"; // clear session id

          this.id = null; // emit close event

          this.emitReserved("close", reason, desc); // clean buffers after, so users can still
          // grab the buffers on `close` event

          this.writeBuffer = [];
          this.prevBufferLen = 0;
        }
      }
      /**
       * Filters upgrades, returning only those matching client transports.
       *
       * @param {Array} server upgrades
       * @api private
       *
       */

    }, {
      key: "filterUpgrades",
      value: function filterUpgrades(upgrades) {
        var filteredUpgrades = [];
        var i = 0;
        var j = upgrades.length;

        for (; i < j; i++) {
          if (~this.transports.indexOf(upgrades[i])) filteredUpgrades.push(upgrades[i]);
        }

        return filteredUpgrades;
      }
    }]);

    return Socket;
  }(Emitter_1);
  Socket$1.protocol = protocol$1;

  function clone(obj) {
    var o = {};

    for (var i in obj) {
      if (obj.hasOwnProperty(i)) {
        o[i] = obj[i];
      }
    }

    return o;
  }

  var withNativeArrayBuffer = typeof ArrayBuffer === "function";

  var isView = function isView(obj) {
    return typeof ArrayBuffer.isView === "function" ? ArrayBuffer.isView(obj) : obj.buffer instanceof ArrayBuffer;
  };

  var toString = Object.prototype.toString;
  var withNativeBlob = typeof Blob === "function" || typeof Blob !== "undefined" && toString.call(Blob) === "[object BlobConstructor]";
  var withNativeFile = typeof File === "function" || typeof File !== "undefined" && toString.call(File) === "[object FileConstructor]";
  /**
   * Returns true if obj is a Buffer, an ArrayBuffer, a Blob or a File.
   *
   * @private
   */

  function isBinary(obj) {
    return withNativeArrayBuffer && (obj instanceof ArrayBuffer || isView(obj)) || withNativeBlob && obj instanceof Blob || withNativeFile && obj instanceof File;
  }
  function hasBinary(obj, toJSON) {
    if (!obj || _typeof(obj) !== "object") {
      return false;
    }

    if (Array.isArray(obj)) {
      for (var i = 0, l = obj.length; i < l; i++) {
        if (hasBinary(obj[i])) {
          return true;
        }
      }

      return false;
    }

    if (isBinary(obj)) {
      return true;
    }

    if (obj.toJSON && typeof obj.toJSON === "function" && arguments.length === 1) {
      return hasBinary(obj.toJSON(), true);
    }

    for (var key in obj) {
      if (Object.prototype.hasOwnProperty.call(obj, key) && hasBinary(obj[key])) {
        return true;
      }
    }

    return false;
  }

  /**
   * Replaces every Buffer | ArrayBuffer | Blob | File in packet with a numbered placeholder.
   *
   * @param {Object} packet - socket.io event packet
   * @return {Object} with deconstructed packet and list of buffers
   * @public
   */

  function deconstructPacket(packet) {
    var buffers = [];
    var packetData = packet.data;
    var pack = packet;
    pack.data = _deconstructPacket(packetData, buffers);
    pack.attachments = buffers.length; // number of binary 'attachments'

    return {
      packet: pack,
      buffers: buffers
    };
  }

  function _deconstructPacket(data, buffers) {
    if (!data) return data;

    if (isBinary(data)) {
      var placeholder = {
        _placeholder: true,
        num: buffers.length
      };
      buffers.push(data);
      return placeholder;
    } else if (Array.isArray(data)) {
      var newData = new Array(data.length);

      for (var i = 0; i < data.length; i++) {
        newData[i] = _deconstructPacket(data[i], buffers);
      }

      return newData;
    } else if (_typeof(data) === "object" && !(data instanceof Date)) {
      var _newData = {};

      for (var key in data) {
        if (data.hasOwnProperty(key)) {
          _newData[key] = _deconstructPacket(data[key], buffers);
        }
      }

      return _newData;
    }

    return data;
  }
  /**
   * Reconstructs a binary packet from its placeholder packet and buffers
   *
   * @param {Object} packet - event packet with placeholders
   * @param {Array} buffers - binary buffers to put in placeholder positions
   * @return {Object} reconstructed packet
   * @public
   */


  function reconstructPacket(packet, buffers) {
    packet.data = _reconstructPacket(packet.data, buffers);
    packet.attachments = undefined; // no longer useful

    return packet;
  }

  function _reconstructPacket(data, buffers) {
    if (!data) return data;

    if (data && data._placeholder) {
      return buffers[data.num]; // appropriate buffer (should be natural order anyway)
    } else if (Array.isArray(data)) {
      for (var i = 0; i < data.length; i++) {
        data[i] = _reconstructPacket(data[i], buffers);
      }
    } else if (_typeof(data) === "object") {
      for (var key in data) {
        if (data.hasOwnProperty(key)) {
          data[key] = _reconstructPacket(data[key], buffers);
        }
      }
    }

    return data;
  }

  /**
   * Protocol version.
   *
   * @public
   */

  var protocol = 5;
  var PacketType;

  (function (PacketType) {
    PacketType[PacketType["CONNECT"] = 0] = "CONNECT";
    PacketType[PacketType["DISCONNECT"] = 1] = "DISCONNECT";
    PacketType[PacketType["EVENT"] = 2] = "EVENT";
    PacketType[PacketType["ACK"] = 3] = "ACK";
    PacketType[PacketType["CONNECT_ERROR"] = 4] = "CONNECT_ERROR";
    PacketType[PacketType["BINARY_EVENT"] = 5] = "BINARY_EVENT";
    PacketType[PacketType["BINARY_ACK"] = 6] = "BINARY_ACK";
  })(PacketType || (PacketType = {}));
  /**
   * A socket.io Encoder instance
   */


  var Encoder = /*#__PURE__*/function () {
    function Encoder() {
      _classCallCheck(this, Encoder);
    }

    _createClass(Encoder, [{
      key: "encode",
      value:
      /**
       * Encode a packet as a single string if non-binary, or as a
       * buffer sequence, depending on packet type.
       *
       * @param {Object} obj - packet object
       */
      function encode(obj) {
        if (obj.type === PacketType.EVENT || obj.type === PacketType.ACK) {
          if (hasBinary(obj)) {
            obj.type = obj.type === PacketType.EVENT ? PacketType.BINARY_EVENT : PacketType.BINARY_ACK;
            return this.encodeAsBinary(obj);
          }
        }

        return [this.encodeAsString(obj)];
      }
      /**
       * Encode packet as string.
       */

    }, {
      key: "encodeAsString",
      value: function encodeAsString(obj) {
        // first is type
        var str = "" + obj.type; // attachments if we have them

        if (obj.type === PacketType.BINARY_EVENT || obj.type === PacketType.BINARY_ACK) {
          str += obj.attachments + "-";
        } // if we have a namespace other than `/`
        // we append it followed by a comma `,`


        if (obj.nsp && "/" !== obj.nsp) {
          str += obj.nsp + ",";
        } // immediately followed by the id


        if (null != obj.id) {
          str += obj.id;
        } // json data


        if (null != obj.data) {
          str += JSON.stringify(obj.data);
        }

        return str;
      }
      /**
       * Encode packet as 'buffer sequence' by removing blobs, and
       * deconstructing packet into object with placeholders and
       * a list of buffers.
       */

    }, {
      key: "encodeAsBinary",
      value: function encodeAsBinary(obj) {
        var deconstruction = deconstructPacket(obj);
        var pack = this.encodeAsString(deconstruction.packet);
        var buffers = deconstruction.buffers;
        buffers.unshift(pack); // add packet info to beginning of data list

        return buffers; // write all the buffers
      }
    }]);

    return Encoder;
  }();
  /**
   * A socket.io Decoder instance
   *
   * @return {Object} decoder
   */

  var Decoder = /*#__PURE__*/function (_Emitter) {
    _inherits(Decoder, _Emitter);

    var _super = _createSuper(Decoder);

    function Decoder() {
      _classCallCheck(this, Decoder);

      return _super.call(this);
    }
    /**
     * Decodes an encoded packet string into packet JSON.
     *
     * @param {String} obj - encoded packet
     */


    _createClass(Decoder, [{
      key: "add",
      value: function add(obj) {
        var packet;

        if (typeof obj === "string") {
          packet = this.decodeString(obj);

          if (packet.type === PacketType.BINARY_EVENT || packet.type === PacketType.BINARY_ACK) {
            // binary packet's json
            this.reconstructor = new BinaryReconstructor(packet); // no attachments, labeled binary but no binary data to follow

            if (packet.attachments === 0) {
              _get(_getPrototypeOf(Decoder.prototype), "emitReserved", this).call(this, "decoded", packet);
            }
          } else {
            // non-binary full packet
            _get(_getPrototypeOf(Decoder.prototype), "emitReserved", this).call(this, "decoded", packet);
          }
        } else if (isBinary(obj) || obj.base64) {
          // raw binary data
          if (!this.reconstructor) {
            throw new Error("got binary data when not reconstructing a packet");
          } else {
            packet = this.reconstructor.takeBinaryData(obj);

            if (packet) {
              // received final buffer
              this.reconstructor = null;

              _get(_getPrototypeOf(Decoder.prototype), "emitReserved", this).call(this, "decoded", packet);
            }
          }
        } else {
          throw new Error("Unknown type: " + obj);
        }
      }
      /**
       * Decode a packet String (JSON data)
       *
       * @param {String} str
       * @return {Object} packet
       */

    }, {
      key: "decodeString",
      value: function decodeString(str) {
        var i = 0; // look up type

        var p = {
          type: Number(str.charAt(0))
        };

        if (PacketType[p.type] === undefined) {
          throw new Error("unknown packet type " + p.type);
        } // look up attachments if type binary


        if (p.type === PacketType.BINARY_EVENT || p.type === PacketType.BINARY_ACK) {
          var start = i + 1;

          while (str.charAt(++i) !== "-" && i != str.length) {}

          var buf = str.substring(start, i);

          if (buf != Number(buf) || str.charAt(i) !== "-") {
            throw new Error("Illegal attachments");
          }

          p.attachments = Number(buf);
        } // look up namespace (if any)


        if ("/" === str.charAt(i + 1)) {
          var _start = i + 1;

          while (++i) {
            var c = str.charAt(i);
            if ("," === c) break;
            if (i === str.length) break;
          }

          p.nsp = str.substring(_start, i);
        } else {
          p.nsp = "/";
        } // look up id


        var next = str.charAt(i + 1);

        if ("" !== next && Number(next) == next) {
          var _start2 = i + 1;

          while (++i) {
            var _c = str.charAt(i);

            if (null == _c || Number(_c) != _c) {
              --i;
              break;
            }

            if (i === str.length) break;
          }

          p.id = Number(str.substring(_start2, i + 1));
        } // look up json data


        if (str.charAt(++i)) {
          var payload = tryParse(str.substr(i));

          if (Decoder.isPayloadValid(p.type, payload)) {
            p.data = payload;
          } else {
            throw new Error("invalid payload");
          }
        }

        return p;
      }
    }, {
      key: "destroy",
      value:
      /**
       * Deallocates a parser's resources
       */
      function destroy() {
        if (this.reconstructor) {
          this.reconstructor.finishedReconstruction();
        }
      }
    }], [{
      key: "isPayloadValid",
      value: function isPayloadValid(type, payload) {
        switch (type) {
          case PacketType.CONNECT:
            return _typeof(payload) === "object";

          case PacketType.DISCONNECT:
            return payload === undefined;

          case PacketType.CONNECT_ERROR:
            return typeof payload === "string" || _typeof(payload) === "object";

          case PacketType.EVENT:
          case PacketType.BINARY_EVENT:
            return Array.isArray(payload) && payload.length > 0;

          case PacketType.ACK:
          case PacketType.BINARY_ACK:
            return Array.isArray(payload);
        }
      }
    }]);

    return Decoder;
  }(Emitter_1);

  function tryParse(str) {
    try {
      return JSON.parse(str);
    } catch (e) {
      return false;
    }
  }
  /**
   * A manager of a binary event's 'buffer sequence'. Should
   * be constructed whenever a packet of type BINARY_EVENT is
   * decoded.
   *
   * @param {Object} packet
   * @return {BinaryReconstructor} initialized reconstructor
   */


  var BinaryReconstructor = /*#__PURE__*/function () {
    function BinaryReconstructor(packet) {
      _classCallCheck(this, BinaryReconstructor);

      this.packet = packet;
      this.buffers = [];
      this.reconPack = packet;
    }
    /**
     * Method to be called when binary data received from connection
     * after a BINARY_EVENT packet.
     *
     * @param {Buffer | ArrayBuffer} binData - the raw binary data received
     * @return {null | Object} returns null if more binary data is expected or
     *   a reconstructed packet object if all buffers have been received.
     */


    _createClass(BinaryReconstructor, [{
      key: "takeBinaryData",
      value: function takeBinaryData(binData) {
        this.buffers.push(binData);

        if (this.buffers.length === this.reconPack.attachments) {
          // done with buffer list
          var packet = reconstructPacket(this.reconPack, this.buffers);
          this.finishedReconstruction();
          return packet;
        }

        return null;
      }
      /**
       * Cleans up binary packet reconstruction variables.
       */

    }, {
      key: "finishedReconstruction",
      value: function finishedReconstruction() {
        this.reconPack = null;
        this.buffers = [];
      }
    }]);

    return BinaryReconstructor;
  }();

  var parser = /*#__PURE__*/Object.freeze({
    __proto__: null,
    protocol: protocol,
    get PacketType () { return PacketType; },
    Encoder: Encoder,
    Decoder: Decoder
  });

  function on(obj, ev, fn) {
    obj.on(ev, fn);
    return function subDestroy() {
      obj.off(ev, fn);
    };
  }

  /**
   * Internal events.
   * These events can't be emitted by the user.
   */

  var RESERVED_EVENTS = Object.freeze({
    connect: 1,
    connect_error: 1,
    disconnect: 1,
    disconnecting: 1,
    // EventEmitter reserved events: https://nodejs.org/api/events.html#events_event_newlistener
    newListener: 1,
    removeListener: 1
  });
  var Socket = /*#__PURE__*/function (_Emitter) {
    _inherits(Socket, _Emitter);

    var _super = _createSuper(Socket);

    /**
     * `Socket` constructor.
     *
     * @public
     */
    function Socket(io, nsp, opts) {
      var _this;

      _classCallCheck(this, Socket);

      _this = _super.call(this);
      _this.connected = false;
      _this.disconnected = true;
      _this.receiveBuffer = [];
      _this.sendBuffer = [];
      _this.ids = 0;
      _this.acks = {};
      _this.flags = {};
      _this.io = io;
      _this.nsp = nsp;

      if (opts && opts.auth) {
        _this.auth = opts.auth;
      }

      if (_this.io._autoConnect) _this.open();
      return _this;
    }
    /**
     * Subscribe to open, close and packet events
     *
     * @private
     */


    _createClass(Socket, [{
      key: "subEvents",
      value: function subEvents() {
        if (this.subs) return;
        var io = this.io;
        this.subs = [on(io, "open", this.onopen.bind(this)), on(io, "packet", this.onpacket.bind(this)), on(io, "error", this.onerror.bind(this)), on(io, "close", this.onclose.bind(this))];
      }
      /**
       * Whether the Socket will try to reconnect when its Manager connects or reconnects
       */

    }, {
      key: "active",
      get: function get() {
        return !!this.subs;
      }
      /**
       * "Opens" the socket.
       *
       * @public
       */

    }, {
      key: "connect",
      value: function connect() {
        if (this.connected) return this;
        this.subEvents();
        if (!this.io["_reconnecting"]) this.io.open(); // ensure open

        if ("open" === this.io._readyState) this.onopen();
        return this;
      }
      /**
       * Alias for connect()
       */

    }, {
      key: "open",
      value: function open() {
        return this.connect();
      }
      /**
       * Sends a `message` event.
       *
       * @return self
       * @public
       */

    }, {
      key: "send",
      value: function send() {
        for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
          args[_key] = arguments[_key];
        }

        args.unshift("message");
        this.emit.apply(this, args);
        return this;
      }
      /**
       * Override `emit`.
       * If the event is in `events`, it's emitted normally.
       *
       * @return self
       * @public
       */

    }, {
      key: "emit",
      value: function emit(ev) {
        if (RESERVED_EVENTS.hasOwnProperty(ev)) {
          throw new Error('"' + ev + '" is a reserved event name');
        }

        for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
          args[_key2 - 1] = arguments[_key2];
        }

        args.unshift(ev);
        var packet = {
          type: PacketType.EVENT,
          data: args
        };
        packet.options = {};
        packet.options.compress = this.flags.compress !== false; // event ack callback

        if ("function" === typeof args[args.length - 1]) {
          var id = this.ids++;
          var ack = args.pop();

          this._registerAckCallback(id, ack);

          packet.id = id;
        }

        var isTransportWritable = this.io.engine && this.io.engine.transport && this.io.engine.transport.writable;
        var discardPacket = this.flags["volatile"] && (!isTransportWritable || !this.connected);

        if (discardPacket) ; else if (this.connected) {
          this.packet(packet);
        } else {
          this.sendBuffer.push(packet);
        }

        this.flags = {};
        return this;
      }
      /**
       * @private
       */

    }, {
      key: "_registerAckCallback",
      value: function _registerAckCallback(id, ack) {
        var _this2 = this;

        var timeout = this.flags.timeout;

        if (timeout === undefined) {
          this.acks[id] = ack;
          return;
        } // @ts-ignore


        var timer = this.io.setTimeoutFn(function () {
          delete _this2.acks[id];

          for (var i = 0; i < _this2.sendBuffer.length; i++) {
            if (_this2.sendBuffer[i].id === id) {
              _this2.sendBuffer.splice(i, 1);
            }
          }

          ack.call(_this2, new Error("operation has timed out"));
        }, timeout);

        this.acks[id] = function () {
          // @ts-ignore
          _this2.io.clearTimeoutFn(timer);

          for (var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
            args[_key3] = arguments[_key3];
          }

          ack.apply(_this2, [null].concat(args));
        };
      }
      /**
       * Sends a packet.
       *
       * @param packet
       * @private
       */

    }, {
      key: "packet",
      value: function packet(_packet) {
        _packet.nsp = this.nsp;

        this.io._packet(_packet);
      }
      /**
       * Called upon engine `open`.
       *
       * @private
       */

    }, {
      key: "onopen",
      value: function onopen() {
        var _this3 = this;

        if (typeof this.auth == "function") {
          this.auth(function (data) {
            _this3.packet({
              type: PacketType.CONNECT,
              data: data
            });
          });
        } else {
          this.packet({
            type: PacketType.CONNECT,
            data: this.auth
          });
        }
      }
      /**
       * Called upon engine or manager `error`.
       *
       * @param err
       * @private
       */

    }, {
      key: "onerror",
      value: function onerror(err) {
        if (!this.connected) {
          this.emitReserved("connect_error", err);
        }
      }
      /**
       * Called upon engine `close`.
       *
       * @param reason
       * @private
       */

    }, {
      key: "onclose",
      value: function onclose(reason) {
        this.connected = false;
        this.disconnected = true;
        delete this.id;
        this.emitReserved("disconnect", reason);
      }
      /**
       * Called with socket packet.
       *
       * @param packet
       * @private
       */

    }, {
      key: "onpacket",
      value: function onpacket(packet) {
        var sameNamespace = packet.nsp === this.nsp;
        if (!sameNamespace) return;

        switch (packet.type) {
          case PacketType.CONNECT:
            if (packet.data && packet.data.sid) {
              var id = packet.data.sid;
              this.onconnect(id);
            } else {
              this.emitReserved("connect_error", new Error("It seems you are trying to reach a Socket.IO server in v2.x with a v3.x client, but they are not compatible (more information here: https://socket.io/docs/v3/migrating-from-2-x-to-3-0/)"));
            }

            break;

          case PacketType.EVENT:
            this.onevent(packet);
            break;

          case PacketType.BINARY_EVENT:
            this.onevent(packet);
            break;

          case PacketType.ACK:
            this.onack(packet);
            break;

          case PacketType.BINARY_ACK:
            this.onack(packet);
            break;

          case PacketType.DISCONNECT:
            this.ondisconnect();
            break;

          case PacketType.CONNECT_ERROR:
            this.destroy();
            var err = new Error(packet.data.message); // @ts-ignore

            err.data = packet.data.data;
            this.emitReserved("connect_error", err);
            break;
        }
      }
      /**
       * Called upon a server event.
       *
       * @param packet
       * @private
       */

    }, {
      key: "onevent",
      value: function onevent(packet) {
        var args = packet.data || [];

        if (null != packet.id) {
          args.push(this.ack(packet.id));
        }

        if (this.connected) {
          this.emitEvent(args);
        } else {
          this.receiveBuffer.push(Object.freeze(args));
        }
      }
    }, {
      key: "emitEvent",
      value: function emitEvent(args) {
        if (this._anyListeners && this._anyListeners.length) {
          var listeners = this._anyListeners.slice();

          var _iterator = _createForOfIteratorHelper(listeners),
              _step;

          try {
            for (_iterator.s(); !(_step = _iterator.n()).done;) {
              var listener = _step.value;
              listener.apply(this, args);
            }
          } catch (err) {
            _iterator.e(err);
          } finally {
            _iterator.f();
          }
        }

        _get(_getPrototypeOf(Socket.prototype), "emit", this).apply(this, args);
      }
      /**
       * Produces an ack callback to emit with an event.
       *
       * @private
       */

    }, {
      key: "ack",
      value: function ack(id) {
        var self = this;
        var sent = false;
        return function () {
          // prevent double callbacks
          if (sent) return;
          sent = true;

          for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) {
            args[_key4] = arguments[_key4];
          }

          self.packet({
            type: PacketType.ACK,
            id: id,
            data: args
          });
        };
      }
      /**
       * Called upon a server acknowlegement.
       *
       * @param packet
       * @private
       */

    }, {
      key: "onack",
      value: function onack(packet) {
        var ack = this.acks[packet.id];

        if ("function" === typeof ack) {
          ack.apply(this, packet.data);
          delete this.acks[packet.id];
        }
      }
      /**
       * Called upon server connect.
       *
       * @private
       */

    }, {
      key: "onconnect",
      value: function onconnect(id) {
        this.id = id;
        this.connected = true;
        this.disconnected = false;
        this.emitBuffered();
        this.emitReserved("connect");
      }
      /**
       * Emit buffered events (received and emitted).
       *
       * @private
       */

    }, {
      key: "emitBuffered",
      value: function emitBuffered() {
        var _this4 = this;

        this.receiveBuffer.forEach(function (args) {
          return _this4.emitEvent(args);
        });
        this.receiveBuffer = [];
        this.sendBuffer.forEach(function (packet) {
          return _this4.packet(packet);
        });
        this.sendBuffer = [];
      }
      /**
       * Called upon server disconnect.
       *
       * @private
       */

    }, {
      key: "ondisconnect",
      value: function ondisconnect() {
        this.destroy();
        this.onclose("io server disconnect");
      }
      /**
       * Called upon forced client/server side disconnections,
       * this method ensures the manager stops tracking us and
       * that reconnections don't get triggered for this.
       *
       * @private
       */

    }, {
      key: "destroy",
      value: function destroy() {
        if (this.subs) {
          // clean subscriptions to avoid reconnections
          this.subs.forEach(function (subDestroy) {
            return subDestroy();
          });
          this.subs = undefined;
        }

        this.io["_destroy"](this);
      }
      /**
       * Disconnects the socket manually.
       *
       * @return self
       * @public
       */

    }, {
      key: "disconnect",
      value: function disconnect() {
        if (this.connected) {
          this.packet({
            type: PacketType.DISCONNECT
          });
        } // remove socket from pool


        this.destroy();

        if (this.connected) {
          // fire events
          this.onclose("io client disconnect");
        }

        return this;
      }
      /**
       * Alias for disconnect()
       *
       * @return self
       * @public
       */

    }, {
      key: "close",
      value: function close() {
        return this.disconnect();
      }
      /**
       * Sets the compress flag.
       *
       * @param compress - if `true`, compresses the sending data
       * @return self
       * @public
       */

    }, {
      key: "compress",
      value: function compress(_compress) {
        this.flags.compress = _compress;
        return this;
      }
      /**
       * Sets a modifier for a subsequent event emission that the event message will be dropped when this socket is not
       * ready to send messages.
       *
       * @returns self
       * @public
       */

    }, {
      key: "volatile",
      get: function get() {
        this.flags["volatile"] = true;
        return this;
      }
      /**
       * Sets a modifier for a subsequent event emission that the callback will be called with an error when the
       * given number of milliseconds have elapsed without an acknowledgement from the server:
       *
       * ```
       * socket.timeout(5000).emit("my-event", (err) => {
       *   if (err) {
       *     // the server did not acknowledge the event in the given delay
       *   }
       * });
       * ```
       *
       * @returns self
       * @public
       */

    }, {
      key: "timeout",
      value: function timeout(_timeout) {
        this.flags.timeout = _timeout;
        return this;
      }
      /**
       * Adds a listener that will be fired when any event is emitted. The event name is passed as the first argument to the
       * callback.
       *
       * @param listener
       * @public
       */

    }, {
      key: "onAny",
      value: function onAny(listener) {
        this._anyListeners = this._anyListeners || [];

        this._anyListeners.push(listener);

        return this;
      }
      /**
       * Adds a listener that will be fired when any event is emitted. The event name is passed as the first argument to the
       * callback. The listener is added to the beginning of the listeners array.
       *
       * @param listener
       * @public
       */

    }, {
      key: "prependAny",
      value: function prependAny(listener) {
        this._anyListeners = this._anyListeners || [];

        this._anyListeners.unshift(listener);

        return this;
      }
      /**
       * Removes the listener that will be fired when any event is emitted.
       *
       * @param listener
       * @public
       */

    }, {
      key: "offAny",
      value: function offAny(listener) {
        if (!this._anyListeners) {
          return this;
        }

        if (listener) {
          var listeners = this._anyListeners;

          for (var i = 0; i < listeners.length; i++) {
            if (listener === listeners[i]) {
              listeners.splice(i, 1);
              return this;
            }
          }
        } else {
          this._anyListeners = [];
        }

        return this;
      }
      /**
       * Returns an array of listeners that are listening for any event that is specified. This array can be manipulated,
       * e.g. to remove listeners.
       *
       * @public
       */

    }, {
      key: "listenersAny",
      value: function listenersAny() {
        return this._anyListeners || [];
      }
    }]);

    return Socket;
  }(Emitter_1);

  /**
   * Expose `Backoff`.
   */

  var backo2 = Backoff;
  /**
   * Initialize backoff timer with `opts`.
   *
   * - `min` initial timeout in milliseconds [100]
   * - `max` max timeout [10000]
   * - `jitter` [0]
   * - `factor` [2]
   *
   * @param {Object} opts
   * @api public
   */

  function Backoff(opts) {
    opts = opts || {};
    this.ms = opts.min || 100;
    this.max = opts.max || 10000;
    this.factor = opts.factor || 2;
    this.jitter = opts.jitter > 0 && opts.jitter <= 1 ? opts.jitter : 0;
    this.attempts = 0;
  }
  /**
   * Return the backoff duration.
   *
   * @return {Number}
   * @api public
   */


  Backoff.prototype.duration = function () {
    var ms = this.ms * Math.pow(this.factor, this.attempts++);

    if (this.jitter) {
      var rand = Math.random();
      var deviation = Math.floor(rand * this.jitter * ms);
      ms = (Math.floor(rand * 10) & 1) == 0 ? ms - deviation : ms + deviation;
    }

    return Math.min(ms, this.max) | 0;
  };
  /**
   * Reset the number of attempts.
   *
   * @api public
   */


  Backoff.prototype.reset = function () {
    this.attempts = 0;
  };
  /**
   * Set the minimum duration
   *
   * @api public
   */


  Backoff.prototype.setMin = function (min) {
    this.ms = min;
  };
  /**
   * Set the maximum duration
   *
   * @api public
   */


  Backoff.prototype.setMax = function (max) {
    this.max = max;
  };
  /**
   * Set the jitter
   *
   * @api public
   */


  Backoff.prototype.setJitter = function (jitter) {
    this.jitter = jitter;
  };

  var Manager = /*#__PURE__*/function (_Emitter) {
    _inherits(Manager, _Emitter);

    var _super = _createSuper(Manager);

    function Manager(uri, opts) {
      var _this;

      _classCallCheck(this, Manager);

      var _a;

      _this = _super.call(this);
      _this.nsps = {};
      _this.subs = [];

      if (uri && "object" === _typeof(uri)) {
        opts = uri;
        uri = undefined;
      }

      opts = opts || {};
      opts.path = opts.path || "/socket.io";
      _this.opts = opts;
      installTimerFunctions(_assertThisInitialized(_this), opts);

      _this.reconnection(opts.reconnection !== false);

      _this.reconnectionAttempts(opts.reconnectionAttempts || Infinity);

      _this.reconnectionDelay(opts.reconnectionDelay || 1000);

      _this.reconnectionDelayMax(opts.reconnectionDelayMax || 5000);

      _this.randomizationFactor((_a = opts.randomizationFactor) !== null && _a !== void 0 ? _a : 0.5);

      _this.backoff = new backo2({
        min: _this.reconnectionDelay(),
        max: _this.reconnectionDelayMax(),
        jitter: _this.randomizationFactor()
      });

      _this.timeout(null == opts.timeout ? 20000 : opts.timeout);

      _this._readyState = "closed";
      _this.uri = uri;

      var _parser = opts.parser || parser;

      _this.encoder = new _parser.Encoder();
      _this.decoder = new _parser.Decoder();
      _this._autoConnect = opts.autoConnect !== false;
      if (_this._autoConnect) _this.open();
      return _this;
    }

    _createClass(Manager, [{
      key: "reconnection",
      value: function reconnection(v) {
        if (!arguments.length) return this._reconnection;
        this._reconnection = !!v;
        return this;
      }
    }, {
      key: "reconnectionAttempts",
      value: function reconnectionAttempts(v) {
        if (v === undefined) return this._reconnectionAttempts;
        this._reconnectionAttempts = v;
        return this;
      }
    }, {
      key: "reconnectionDelay",
      value: function reconnectionDelay(v) {
        var _a;

        if (v === undefined) return this._reconnectionDelay;
        this._reconnectionDelay = v;
        (_a = this.backoff) === null || _a === void 0 ? void 0 : _a.setMin(v);
        return this;
      }
    }, {
      key: "randomizationFactor",
      value: function randomizationFactor(v) {
        var _a;

        if (v === undefined) return this._randomizationFactor;
        this._randomizationFactor = v;
        (_a = this.backoff) === null || _a === void 0 ? void 0 : _a.setJitter(v);
        return this;
      }
    }, {
      key: "reconnectionDelayMax",
      value: function reconnectionDelayMax(v) {
        var _a;

        if (v === undefined) return this._reconnectionDelayMax;
        this._reconnectionDelayMax = v;
        (_a = this.backoff) === null || _a === void 0 ? void 0 : _a.setMax(v);
        return this;
      }
    }, {
      key: "timeout",
      value: function timeout(v) {
        if (!arguments.length) return this._timeout;
        this._timeout = v;
        return this;
      }
      /**
       * Starts trying to reconnect if reconnection is enabled and we have not
       * started reconnecting yet
       *
       * @private
       */

    }, {
      key: "maybeReconnectOnOpen",
      value: function maybeReconnectOnOpen() {
        // Only try to reconnect if it's the first time we're connecting
        if (!this._reconnecting && this._reconnection && this.backoff.attempts === 0) {
          // keeps reconnection from firing twice for the same reconnection loop
          this.reconnect();
        }
      }
      /**
       * Sets the current transport `socket`.
       *
       * @param {Function} fn - optional, callback
       * @return self
       * @public
       */

    }, {
      key: "open",
      value: function open(fn) {
        var _this2 = this;

        if (~this._readyState.indexOf("open")) return this;
        this.engine = new Socket$1(this.uri, this.opts);
        var socket = this.engine;
        var self = this;
        this._readyState = "opening";
        this.skipReconnect = false; // emit `open`

        var openSubDestroy = on(socket, "open", function () {
          self.onopen();
          fn && fn();
        }); // emit `error`

        var errorSub = on(socket, "error", function (err) {
          self.cleanup();
          self._readyState = "closed";

          _this2.emitReserved("error", err);

          if (fn) {
            fn(err);
          } else {
            // Only do this if there is no fn to handle the error
            self.maybeReconnectOnOpen();
          }
        });

        if (false !== this._timeout) {
          var timeout = this._timeout;

          if (timeout === 0) {
            openSubDestroy(); // prevents a race condition with the 'open' event
          } // set timer


          var timer = this.setTimeoutFn(function () {
            openSubDestroy();
            socket.close(); // @ts-ignore

            socket.emit("error", new Error("timeout"));
          }, timeout);

          if (this.opts.autoUnref) {
            timer.unref();
          }

          this.subs.push(function subDestroy() {
            clearTimeout(timer);
          });
        }

        this.subs.push(openSubDestroy);
        this.subs.push(errorSub);
        return this;
      }
      /**
       * Alias for open()
       *
       * @return self
       * @public
       */

    }, {
      key: "connect",
      value: function connect(fn) {
        return this.open(fn);
      }
      /**
       * Called upon transport open.
       *
       * @private
       */

    }, {
      key: "onopen",
      value: function onopen() {
        // clear old subs
        this.cleanup(); // mark as open

        this._readyState = "open";
        this.emitReserved("open"); // add new subs

        var socket = this.engine;
        this.subs.push(on(socket, "ping", this.onping.bind(this)), on(socket, "data", this.ondata.bind(this)), on(socket, "error", this.onerror.bind(this)), on(socket, "close", this.onclose.bind(this)), on(this.decoder, "decoded", this.ondecoded.bind(this)));
      }
      /**
       * Called upon a ping.
       *
       * @private
       */

    }, {
      key: "onping",
      value: function onping() {
        this.emitReserved("ping");
      }
      /**
       * Called with data.
       *
       * @private
       */

    }, {
      key: "ondata",
      value: function ondata(data) {
        this.decoder.add(data);
      }
      /**
       * Called when parser fully decodes a packet.
       *
       * @private
       */

    }, {
      key: "ondecoded",
      value: function ondecoded(packet) {
        this.emitReserved("packet", packet);
      }
      /**
       * Called upon socket error.
       *
       * @private
       */

    }, {
      key: "onerror",
      value: function onerror(err) {
        this.emitReserved("error", err);
      }
      /**
       * Creates a new socket for the given `nsp`.
       *
       * @return {Socket}
       * @public
       */

    }, {
      key: "socket",
      value: function socket(nsp, opts) {
        var socket = this.nsps[nsp];

        if (!socket) {
          socket = new Socket(this, nsp, opts);
          this.nsps[nsp] = socket;
        }

        return socket;
      }
      /**
       * Called upon a socket close.
       *
       * @param socket
       * @private
       */

    }, {
      key: "_destroy",
      value: function _destroy(socket) {
        var nsps = Object.keys(this.nsps);

        for (var _i = 0, _nsps = nsps; _i < _nsps.length; _i++) {
          var nsp = _nsps[_i];
          var _socket = this.nsps[nsp];

          if (_socket.active) {
            return;
          }
        }

        this._close();
      }
      /**
       * Writes a packet.
       *
       * @param packet
       * @private
       */

    }, {
      key: "_packet",
      value: function _packet(packet) {
        var encodedPackets = this.encoder.encode(packet);

        for (var i = 0; i < encodedPackets.length; i++) {
          this.engine.write(encodedPackets[i], packet.options);
        }
      }
      /**
       * Clean up transport subscriptions and packet buffer.
       *
       * @private
       */

    }, {
      key: "cleanup",
      value: function cleanup() {
        this.subs.forEach(function (subDestroy) {
          return subDestroy();
        });
        this.subs.length = 0;
        this.decoder.destroy();
      }
      /**
       * Close the current socket.
       *
       * @private
       */

    }, {
      key: "_close",
      value: function _close() {
        this.skipReconnect = true;
        this._reconnecting = false;
        this.onclose("forced close");
        if (this.engine) this.engine.close();
      }
      /**
       * Alias for close()
       *
       * @private
       */

    }, {
      key: "disconnect",
      value: function disconnect() {
        return this._close();
      }
      /**
       * Called upon engine close.
       *
       * @private
       */

    }, {
      key: "onclose",
      value: function onclose(reason) {
        this.cleanup();
        this.backoff.reset();
        this._readyState = "closed";
        this.emitReserved("close", reason);

        if (this._reconnection && !this.skipReconnect) {
          this.reconnect();
        }
      }
      /**
       * Attempt a reconnection.
       *
       * @private
       */

    }, {
      key: "reconnect",
      value: function reconnect() {
        var _this3 = this;

        if (this._reconnecting || this.skipReconnect) return this;
        var self = this;

        if (this.backoff.attempts >= this._reconnectionAttempts) {
          this.backoff.reset();
          this.emitReserved("reconnect_failed");
          this._reconnecting = false;
        } else {
          var delay = this.backoff.duration();
          this._reconnecting = true;
          var timer = this.setTimeoutFn(function () {
            if (self.skipReconnect) return;

            _this3.emitReserved("reconnect_attempt", self.backoff.attempts); // check again for the case socket closed in above events


            if (self.skipReconnect) return;
            self.open(function (err) {
              if (err) {
                self._reconnecting = false;
                self.reconnect();

                _this3.emitReserved("reconnect_error", err);
              } else {
                self.onreconnect();
              }
            });
          }, delay);

          if (this.opts.autoUnref) {
            timer.unref();
          }

          this.subs.push(function subDestroy() {
            clearTimeout(timer);
          });
        }
      }
      /**
       * Called upon successful reconnect.
       *
       * @private
       */

    }, {
      key: "onreconnect",
      value: function onreconnect() {
        var attempt = this.backoff.attempts;
        this._reconnecting = false;
        this.backoff.reset();
        this.emitReserved("reconnect", attempt);
      }
    }]);

    return Manager;
  }(Emitter_1);

  /**
   * Managers cache.
   */

  var cache = {};

  function lookup(uri, opts) {
    if (_typeof(uri) === "object") {
      opts = uri;
      uri = undefined;
    }

    opts = opts || {};
    var parsed = url(uri, opts.path || "/socket.io");
    var source = parsed.source;
    var id = parsed.id;
    var path = parsed.path;
    var sameNamespace = cache[id] && path in cache[id]["nsps"];
    var newConnection = opts.forceNew || opts["force new connection"] || false === opts.multiplex || sameNamespace;
    var io;

    if (newConnection) {
      io = new Manager(source, opts);
    } else {
      if (!cache[id]) {
        cache[id] = new Manager(source, opts);
      }

      io = cache[id];
    }

    if (parsed.query && !opts.query) {
      opts.query = parsed.queryKey;
    }

    return io.socket(parsed.path, opts);
  } // so that "lookup" can be used both as a function (e.g. `io(...)`) and as a
  // namespace (e.g. `io.connect(...)`), for backward compatibility


  _extends(lookup, {
    Manager: Manager,
    Socket: Socket,
    io: lookup,
    connect: lookup
  });

  return lookup;

}));
//# sourceMappingURL=socket.io.js.map
;
/**
 * @license RequireJS domReady 2.0.1 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
 * Available via the MIT or new BSD license.
 * see: http://github.com/requirejs/domReady for details
 */
/*jslint */
/*global require: false, define: false, requirejs: false,
  window: false, clearInterval: false, document: false,
  self: false, setInterval: false */


define('requirejs/domReady',[],function () {
    'use strict';

    var isTop, testDiv, scrollIntervalId,
        isBrowser = typeof window !== "undefined" && window.document,
        isPageLoaded = !isBrowser,
        doc = isBrowser ? document : null,
        readyCalls = [];

    function runCallbacks(callbacks) {
        var i;
        for (i = 0; i < callbacks.length; i += 1) {
            callbacks[i](doc);
        }
    }

    function callReady() {
        var callbacks = readyCalls;

        if (isPageLoaded) {
            //Call the DOM ready callbacks
            if (callbacks.length) {
                readyCalls = [];
                runCallbacks(callbacks);
            }
        }
    }

    /**
     * Sets the page as loaded.
     */
    function pageLoaded() {
        if (!isPageLoaded) {
            isPageLoaded = true;
            if (scrollIntervalId) {
                clearInterval(scrollIntervalId);
            }

            callReady();
        }
    }

    if (isBrowser) {
        if (document.addEventListener) {
            //Standards. Hooray! Assumption here that if standards based,
            //it knows about DOMContentLoaded.
            document.addEventListener("DOMContentLoaded", pageLoaded, false);
            window.addEventListener("load", pageLoaded, false);
        } else if (window.attachEvent) {
            window.attachEvent("onload", pageLoaded);

            testDiv = document.createElement('div');
            try {
                isTop = window.frameElement === null;
            } catch (e) {}

            //DOMContentLoaded approximation that uses a doScroll, as found by
            //Diego Perini: http://javascript.nwbox.com/IEContentLoaded/,
            //but modified by other contributors, including jdalton
            if (testDiv.doScroll && isTop && window.external) {
                scrollIntervalId = setInterval(function () {
                    try {
                        testDiv.doScroll();
                        pageLoaded();
                    } catch (e) {}
                }, 30);
            }
        }

        //Check if document already complete, and if so, just trigger page load
        //listeners. Latest webkit browsers also use "interactive", and
        //will fire the onDOMContentLoaded before "interactive" but not after
        //entering "interactive" or "complete". More details:
        //http://dev.w3.org/html5/spec/the-end.html#the-end
        //http://stackoverflow.com/questions/3665561/document-readystate-of-interactive-vs-ondomcontentloaded
        //Hmm, this is more complicated on further use, see "firing too early"
        //bug: https://github.com/requirejs/domReady/issues/1
        //so removing the || document.readyState === "interactive" test.
        //There is still a window.onload binding that should get fired if
        //DOMContentLoaded is missed.
        if (document.readyState === "complete") {
            pageLoaded();
        }
    }

    /** START OF PUBLIC API **/

    /**
     * Registers a callback for DOM ready. If DOM is already ready, the
     * callback is called immediately.
     * @param {Function} callback
     */
    function domReady(callback) {
        if (isPageLoaded) {
            callback(doc);
        } else {
            readyCalls.push(callback);
        }
        return domReady;
    }

    domReady.version = '2.0.1';

    /**
     * Loader Plugin API method
     */
    domReady.load = function (name, req, onLoad, config) {
        if (config.isBuild) {
            onLoad(null);
        } else {
            domReady(onLoad);
        }
    };

    /** END OF PUBLIC API **/

    return domReady;
});

/*******************************************************************************
 * @license
 * Copyright (c) 2012, 2019 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 * 
 * Contributors: Anton McConville - IBM Corporation - initial API and implementation
 ******************************************************************************/
/*eslint-env browser, amd*/
define('orion/widgets/input/DropDownMenu',['orion/objects', 'orion/webui/littlelib'], function(objects, lib) {

	/**
	 * Creates a dropdown menu for a node and its associated trigger node (button)
	 * @param {Object} parent The dom object or string id of the node that will contain the dropdown menu
	 * @param {Object} triggerNode The dom object or string id of the dom node that will trigger the dropdown menu appearance
	 * @param {Object} [options] options for the drop down menu.
	 * @param {String} [options.selectionClass] CSS class to be appended when the trigger node is selected.
	 * @param {String} [options.noClick] Do not add the click handler to the trigger node.
	 * @param {String} [options.onShow] Callback called when the menu is shown.
	 * @param {String} [options.onHide] Callback called when the menu is hidden.
	 */
	function DropDownMenu( parent, triggerNode, options ){
		var node = lib.node(parent);
		if (node) {
			this._parent = node;
		} else {
			throw new Error("Parent node of dropdown menu not found"); //$NON-NLS-0$
		}
		
		options = options || {};
		this.options = options;
		
		// Assign dynamic ids to the dropdown menu node to support multiple drop down menus in the same page
		this.navDropDownId = this._parent.id + '_navdropdown'; //$NON-NLS-0$
		this.selectionClass = options.selectionClass;
		
		// Create dropdown container and append to parent dom
		var dropDownContainer = document.createElement("div"); //$NON-NLS-0$
		dropDownContainer.classList.add("dropdownMenu"); //$NON-NLS-0$
		dropDownContainer.classList.add("dropdownMenuOpen"); //$NON-NLS-0$
		dropDownContainer.id = this.navDropDownId; 
		dropDownContainer.style.display = 'none'; //$NON-NLS-0$
		this._parent.appendChild(dropDownContainer);
		this._dropdownMenu = dropDownContainer;
		
		// Display trigger node and bind on click event
		triggerNode = lib.node(triggerNode);
		if (triggerNode) {
			this._triggerNode = triggerNode;
		} else {
			throw "Trigger node of dropdown menu not found"; //$NON-NLS-0$
		}
		if (this._triggerNode.style.visibility === 'hidden') { //$NON-NLS-0$
			this._triggerNode.style.visibility = 'visible'; //$NON-NLS-0$
		}
		
		if (!options.noClick) {
			this._triggerNode.onclick = this.click.bind(this);
		}
		this._dropdownMenu.addEventListener("keydown", function (e) { //$NON-NLS-0$
			if (e.keyCode === lib.KEY.ESCAPE) {
				this.clearPanel();
			}
		}.bind(this));
	}
	
	objects.mixin(DropDownMenu.prototype, {
		click: function() {
			if( this._dropdownMenu.style.display === 'none' ){ //$NON-NLS-0$
				this.updateContent ( this.getContentNode() , function () {
					this.previousActiveElement = document.activeElement;
					lib.setFramesEnabled(false);
					lib.trapTabs(this._dropdownMenu);
					this._dropdownMenu.style.display = '';
					this._positionDropdown();
					if (this.selectionClass) {
						this._triggerNode.classList.add(this.selectionClass);
					}
					this.handle = lib.addAutoDismiss( [ this._triggerNode, this._dropdownMenu], this.clearPanel.bind(this) );
					this.focus();
					if (this.options.onShow) {
						this.options.onShow();
					}
				}.bind(this));
			}else{
				this.clearPanel();
			}
		},
		
		clearPanel: function(){
			if (!this.isVisible()) { return; }
			lib.returnFocus(this._dropdownMenu, this.previousActiveElement, function() {
				this._dropdownMenu.style.display = 'none'; //$NON-NLS-0$
				lib.setFramesEnabled(true);
				if (this.selectionClass) {
					this._triggerNode.classList.remove(this.selectionClass);
				}
				if (this.options.onHide) {
					this.options.onHide();
				}
			}.bind(this));
		},
		
		// Add content to the dropdown container
		addContent: function( content ){
			lib.setSafeInnerHTML(this._dropdownMenu, content);
		},
		
		getContentNode: function(){
			return this._dropdownMenu;
		},
		
		updateContent: function( contentNode, callback ){
			// to be overridden to update the contents before showing
			// the callback needs to be called once the content is up to date
			callback();
		},

		_positionDropdown: function() {
			this._dropdownMenu.style.right = "";
			var bounds = lib.bounds(this._dropdownMenu);
			var bodyBounds = lib.bounds(document.body);
			if (bounds.left + bounds.width > (bodyBounds.left + bodyBounds.width)) {
				var totalBounds = lib.bounds(this._boundingNode(this._triggerNode));
				var triggerBounds = lib.bounds(this._triggerNode);
				this._dropdownMenu.style.right = (totalBounds.width - ((triggerBounds.left - totalBounds.left) + triggerBounds.width)) + "px"; //$NON-NLS-0$
			}
		},
		
		_boundingNode: function(node) {
			var style = window.getComputedStyle(node, null);
			if (style === null) {
				return node;
			}
			var position = style.getPropertyValue("position"); //$NON-NLS-0$
			if (position === "absolute" || !node.parentNode || node === document.body) { //$NON-NLS-0$
				return node;
			}
			return this._boundingNode(node.parentNode);
		},
		
		isDestroyed: function() {
			return !this._dropdownMenu.parentNode;
		},

		isVisible: function() {
			return this._dropdownMenu.style.display !== "none" && !this.isDestroyed(); //$NON-NLS-0$
		},

		focus: function() {
			this._dropdownMenu.focus();
		},

		destroy: function() {
			if (this._parent) {
				lib.setFramesEnabled(true);
				lib.empty(this._parent);
				this._parent = this.select = null;
			}
		}
	});
	
	return DropDownMenu;
});

/*******************************************************************************
 * @license
 * Copyright (c) 2012, 2019 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 * 
 * Contributors: Anton McConville - IBM Corporation - initial API and implementation
 ******************************************************************************/
/*eslint-env browser, amd*/
define('orion/widgets/input/Select',['orion/objects', 'orion/webui/littlelib'], function(objects, lib) {

	/**
	 * @param {Object[]} param.options Array of {value:Object, label:String, selected:Boolean(optional)}
	 */
	function Select( params, node ){
		objects.mixin(this, params);
		this.node = node || document.createElement("div"); //$NON-NLS-0$
		lib.setSafeInnerHTML(this.node, this.templateString);
		this.select = lib.$(".setting-control", this.node); //$NON-NLS-0$
	}
	objects.mixin(Select.prototype, {
		templateString: '<select class="setting-control" id="selection"></select>', //$NON-NLS-0$

		addOptions : function(item, index, ar){			
			var option = document.createElement("option"); //$NON-NLS-0$
			option.value = item.value;
			option.appendChild(document.createTextNode(typeof item.label === "string" ? item.label : item.value)); //$NON-NLS-0$
			if( item.selected  ){
				option.selected = 'selected'; //$NON-NLS-0$
			}
			this.select.appendChild(option);
		},

		show: function() {
			this.postCreate();
		},

		postCreate: function() {
			this.options.forEach( this.addOptions.bind(this) );
			this.select.addEventListener("change",  this.change.bind(this)); //$NON-NLS-0$
		},

		destroy: function() {
			if (this.node) {
				lib.empty(this.node);
				this.node = this.select = null;
			}
		},
		
		getSelected : function(){
			return this.select.value;
		},
	
		getSelectedIndex: function() {
			return this.select.selectedIndex;
		},
		
		setSelectedIndex : function setSelectedIndex(index) {
			this.select.selectedIndex = index;
		},
		
		getSelection: function(){
			return this.getSelected();
		},
		
		setSelection: function(value){
			for (var i = 0; i < this.options.length; i++) {
				if (this.options[i].value === value) {				
					this.setSelectedIndex(i);
					return;
				}
			}
			this.setSelectedIndex(0);
		},
	
		change : function change(){
			if (this.postChange) {
				this.postChange(this.select.value);
			}
		}
	});
	return Select;
});

/*******************************************************************************
 * @license
 * Copyright (c) 2012, 2014 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made
 * available under the terms of the Eclipse Public License v1.0
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html).
 *
 * Contributors: Anton McConville - IBM Corporation - initial API and implementation
 ******************************************************************************/
/*eslint-env browser, amd*/
define('orion/widgets/input/SettingsSelect',['orion/objects', 'orion/webui/littlelib', 'orion/widgets/input/Select'],  function(objects, lib, Select) {

	/**
	 * This is just an orion/widgets/input/Select with a label.
	 */
	function SettingsSelect( params, node ){
		makeLocalSelect(params);
		Select.apply(this, arguments);
		this.mylabel = lib.$(".setting-label", this.node); //$NON-NLS-0$
	}

 	objects.mixin(SettingsSelect.prototype, Select.prototype, makeSelect());

	function makeLocalSelect(params) {
		var newSelect = makeSelect();

		if (params.local) {
			newSelect.templateString =
			'<label>' + //$NON-NLS-0$
				'<span class="setting-label"></span>' + //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
				'<select class="setting-control"></select>' + //$NON-NLS-0$
			'</label>';  //$NON-NLS-0$

			objects.mixin(SettingsSelect.prototype, Select.prototype, newSelect);
		}
	}

	function makeSelect() {
		return {
			templateString :
			'<div>' +  //$NON-NLS-0$
				'<label>' + //$NON-NLS-0$
					'<span class="setting-label"></span>' + //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
					'<select class="setting-control"></select>' + //$NON-NLS-0$
				'</label>' +  //$NON-NLS-0$
			'</div>', //$NON-NLS-0$

			postCreate: function() {
				Select.prototype.postCreate.call(this);
				this.mylabel.textContent = this.fieldlabel;
			},

			destroy: function() {
				Select.prototype.destroy.call(this);
				if (this.mylabel) {
					this.mylabel = null;
				}
			}
		}
	}

	return SettingsSelect;
});
!function(e,t){if("object"==typeof exports&&"object"==typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define('xterm/xterm',[],t);else{var r=t();for(var i in r)("object"==typeof exports?exports:e)[i]=r[i]}}(self,(function(){return(()=>{"use strict";var e={4567:function(e,t,r){var i,n=this&&this.__extends||(i=function(e,t){return i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])},i(e,t)},function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function r(){this.constructor=e}i(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)});Object.defineProperty(t,"__esModule",{value:!0}),t.AccessibilityManager=void 0;var o=r(9042),s=r(6114),a=r(9924),c=r(3656),l=r(844),h=r(5596),u=r(9631),f=function(e){function t(t,r){var i=e.call(this)||this;i._terminal=t,i._renderService=r,i._liveRegionLineCount=0,i._charsToConsume=[],i._charsToAnnounce="",i._accessibilityTreeRoot=document.createElement("div"),i._accessibilityTreeRoot.setAttribute("role","document"),i._accessibilityTreeRoot.classList.add("xterm-accessibility"),i._accessibilityTreeRoot.tabIndex=0,i._rowContainer=document.createElement("div"),i._rowContainer.setAttribute("role","list"),i._rowContainer.classList.add("xterm-accessibility-tree"),i._rowElements=[];for(var n=0;n<i._terminal.rows;n++)i._rowElements[n]=i._createAccessibilityTreeNode(),i._rowContainer.appendChild(i._rowElements[n]);if(i._topBoundaryFocusListener=function(e){return i._onBoundaryFocus(e,0)},i._bottomBoundaryFocusListener=function(e){return i._onBoundaryFocus(e,1)},i._rowElements[0].addEventListener("focus",i._topBoundaryFocusListener),i._rowElements[i._rowElements.length-1].addEventListener("focus",i._bottomBoundaryFocusListener),i._refreshRowsDimensions(),i._accessibilityTreeRoot.appendChild(i._rowContainer),i._renderRowsDebouncer=new a.TimeBasedDebouncer(i._renderRows.bind(i)),i._refreshRows(),i._liveRegion=document.createElement("div"),i._liveRegion.classList.add("live-region"),i._liveRegion.setAttribute("aria-live","assertive"),i._accessibilityTreeRoot.appendChild(i._liveRegion),!i._terminal.element)throw new Error("Cannot enable accessibility before Terminal.open");return i._terminal.element.insertAdjacentElement("afterbegin",i._accessibilityTreeRoot),i.register(i._renderRowsDebouncer),i.register(i._terminal.onResize((function(e){return i._onResize(e.rows)}))),i.register(i._terminal.onRender((function(e){return i._refreshRows(e.start,e.end)}))),i.register(i._terminal.onScroll((function(){return i._refreshRows()}))),i.register(i._terminal.onA11yChar((function(e){return i._onChar(e)}))),i.register(i._terminal.onLineFeed((function(){return i._onChar("\n")}))),i.register(i._terminal.onA11yTab((function(e){return i._onTab(e)}))),i.register(i._terminal.onKey((function(e){return i._onKey(e.key)}))),i.register(i._terminal.onBlur((function(){return i._clearLiveRegion()}))),i.register(i._renderService.onDimensionsChange((function(){return i._refreshRowsDimensions()}))),i._screenDprMonitor=new h.ScreenDprMonitor,i.register(i._screenDprMonitor),i._screenDprMonitor.setListener((function(){return i._refreshRowsDimensions()})),i.register((0,c.addDisposableDomListener)(window,"resize",(function(){return i._refreshRowsDimensions()}))),i}return n(t,e),t.prototype.dispose=function(){e.prototype.dispose.call(this),(0,u.removeElementFromParent)(this._accessibilityTreeRoot),this._rowElements.length=0},t.prototype._onBoundaryFocus=function(e,t){var r=e.target,i=this._rowElements[0===t?1:this._rowElements.length-2];if(r.getAttribute("aria-posinset")!==(0===t?"1":""+this._terminal.buffer.lines.length)&&e.relatedTarget===i){var n,o;if(0===t?(n=r,o=this._rowElements.pop(),this._rowContainer.removeChild(o)):(n=this._rowElements.shift(),o=r,this._rowContainer.removeChild(n)),n.removeEventListener("focus",this._topBoundaryFocusListener),o.removeEventListener("focus",this._bottomBoundaryFocusListener),0===t){var s=this._createAccessibilityTreeNode();this._rowElements.unshift(s),this._rowContainer.insertAdjacentElement("afterbegin",s)}else s=this._createAccessibilityTreeNode(),this._rowElements.push(s),this._rowContainer.appendChild(s);this._rowElements[0].addEventListener("focus",this._topBoundaryFocusListener),this._rowElements[this._rowElements.length-1].addEventListener("focus",this._bottomBoundaryFocusListener),this._terminal.scrollLines(0===t?-1:1),this._rowElements[0===t?1:this._rowElements.length-2].focus(),e.preventDefault(),e.stopImmediatePropagation()}},t.prototype._onResize=function(e){this._rowElements[this._rowElements.length-1].removeEventListener("focus",this._bottomBoundaryFocusListener);for(var t=this._rowContainer.children.length;t<this._terminal.rows;t++)this._rowElements[t]=this._createAccessibilityTreeNode(),this._rowContainer.appendChild(this._rowElements[t]);for(;this._rowElements.length>e;)this._rowContainer.removeChild(this._rowElements.pop());this._rowElements[this._rowElements.length-1].addEventListener("focus",this._bottomBoundaryFocusListener),this._refreshRowsDimensions()},t.prototype._createAccessibilityTreeNode=function(){var e=document.createElement("div");return e.setAttribute("role","listitem"),e.tabIndex=-1,this._refreshRowDimensions(e),e},t.prototype._onTab=function(e){for(var t=0;t<e;t++)this._onChar(" ")},t.prototype._onChar=function(e){var t=this;this._liveRegionLineCount<21&&(this._charsToConsume.length>0?this._charsToConsume.shift()!==e&&(this._charsToAnnounce+=e):this._charsToAnnounce+=e,"\n"===e&&(this._liveRegionLineCount++,21===this._liveRegionLineCount&&(this._liveRegion.textContent+=o.tooMuchOutput)),s.isMac&&this._liveRegion.textContent&&this._liveRegion.textContent.length>0&&!this._liveRegion.parentNode&&setTimeout((function(){t._accessibilityTreeRoot.appendChild(t._liveRegion)}),0))},t.prototype._clearLiveRegion=function(){this._liveRegion.textContent="",this._liveRegionLineCount=0,s.isMac&&(0,u.removeElementFromParent)(this._liveRegion)},t.prototype._onKey=function(e){this._clearLiveRegion(),this._charsToConsume.push(e)},t.prototype._refreshRows=function(e,t){this._renderRowsDebouncer.refresh(e,t,this._terminal.rows)},t.prototype._renderRows=function(e,t){for(var r=this._terminal.buffer,i=r.lines.length.toString(),n=e;n<=t;n++){var o=r.translateBufferLineToString(r.ydisp+n,!0),s=(r.ydisp+n+1).toString(),a=this._rowElements[n];a&&(0===o.length?a.innerText=" ":a.textContent=o,a.setAttribute("aria-posinset",s),a.setAttribute("aria-setsize",i))}this._announceCharacters()},t.prototype._refreshRowsDimensions=function(){if(this._renderService.dimensions.actualCellHeight){this._rowElements.length!==this._terminal.rows&&this._onResize(this._terminal.rows);for(var e=0;e<this._terminal.rows;e++)this._refreshRowDimensions(this._rowElements[e])}},t.prototype._refreshRowDimensions=function(e){e.style.height=this._renderService.dimensions.actualCellHeight+"px"},t.prototype._announceCharacters=function(){0!==this._charsToAnnounce.length&&(this._liveRegion.textContent+=this._charsToAnnounce,this._charsToAnnounce="")},t}(l.Disposable);t.AccessibilityManager=f},3614:(e,t)=>{function r(e){return e.replace(/\r?\n/g,"\r")}function i(e,t){return t?"[200~"+e+"[201~":e}function n(e,t,n){e=i(e=r(e),n.decPrivateModes.bracketedPasteMode),n.triggerDataEvent(e,!0),t.value=""}function o(e,t,r){var i=r.getBoundingClientRect(),n=e.clientX-i.left-10,o=e.clientY-i.top-10;t.style.width="20px",t.style.height="20px",t.style.left=n+"px",t.style.top=o+"px",t.style.zIndex="1000",t.focus()}Object.defineProperty(t,"__esModule",{value:!0}),t.rightClickHandler=t.moveTextAreaUnderMouseCursor=t.paste=t.handlePasteEvent=t.copyHandler=t.bracketTextForPaste=t.prepareTextForTerminal=void 0,t.prepareTextForTerminal=r,t.bracketTextForPaste=i,t.copyHandler=function(e,t){e.clipboardData&&e.clipboardData.setData("text/plain",t.selectionText),e.preventDefault()},t.handlePasteEvent=function(e,t,r){e.stopPropagation(),e.clipboardData&&n(e.clipboardData.getData("text/plain"),t,r)},t.paste=n,t.moveTextAreaUnderMouseCursor=o,t.rightClickHandler=function(e,t,r,i,n){o(e,t,r),n&&i.rightClickSelect(e),t.value=i.selectionText,t.select()}},4774:(e,t)=>{var r,i,n,o;function s(e){var t=e.toString(16);return t.length<2?"0"+t:t}function a(e,t){return e<t?(t+.05)/(e+.05):(e+.05)/(t+.05)}Object.defineProperty(t,"__esModule",{value:!0}),t.contrastRatio=t.toPaddedHex=t.rgba=t.rgb=t.css=t.color=t.channels=void 0,function(e){e.toCss=function(e,t,r,i){return void 0!==i?"#"+s(e)+s(t)+s(r)+s(i):"#"+s(e)+s(t)+s(r)},e.toRgba=function(e,t,r,i){return void 0===i&&(i=255),(e<<24|t<<16|r<<8|i)>>>0}}(r=t.channels||(t.channels={})),(i=t.color||(t.color={})).blend=function(e,t){var i=(255&t.rgba)/255;if(1===i)return{css:t.css,rgba:t.rgba};var n=t.rgba>>24&255,o=t.rgba>>16&255,s=t.rgba>>8&255,a=e.rgba>>24&255,c=e.rgba>>16&255,l=e.rgba>>8&255,h=a+Math.round((n-a)*i),u=c+Math.round((o-c)*i),f=l+Math.round((s-l)*i);return{css:r.toCss(h,u,f),rgba:r.toRgba(h,u,f)}},i.isOpaque=function(e){return 255==(255&e.rgba)},i.ensureContrastRatio=function(e,t,r){var i=o.ensureContrastRatio(e.rgba,t.rgba,r);if(i)return o.toColor(i>>24&255,i>>16&255,i>>8&255)},i.opaque=function(e){var t=(255|e.rgba)>>>0,i=o.toChannels(t),n=i[0],s=i[1],a=i[2];return{css:r.toCss(n,s,a),rgba:t}},i.opacity=function(e,t){var i=Math.round(255*t),n=o.toChannels(e.rgba),s=n[0],a=n[1],c=n[2];return{css:r.toCss(s,a,c,i),rgba:r.toRgba(s,a,c,i)}},i.toColorRGB=function(e){return[e.rgba>>24&255,e.rgba>>16&255,e.rgba>>8&255]},(t.css||(t.css={})).toColor=function(e){switch(e.length){case 7:return{css:e,rgba:(parseInt(e.slice(1),16)<<8|255)>>>0};case 9:return{css:e,rgba:parseInt(e.slice(1),16)>>>0}}throw new Error("css.toColor: Unsupported css format")},function(e){function t(e,t,r){var i=e/255,n=t/255,o=r/255;return.2126*(i<=.03928?i/12.92:Math.pow((i+.055)/1.055,2.4))+.7152*(n<=.03928?n/12.92:Math.pow((n+.055)/1.055,2.4))+.0722*(o<=.03928?o/12.92:Math.pow((o+.055)/1.055,2.4))}e.relativeLuminance=function(e){return t(e>>16&255,e>>8&255,255&e)},e.relativeLuminance2=t}(n=t.rgb||(t.rgb={})),function(e){function t(e,t,r){for(var i=e>>24&255,o=e>>16&255,s=e>>8&255,c=t>>24&255,l=t>>16&255,h=t>>8&255,u=a(n.relativeLuminance2(c,h,l),n.relativeLuminance2(i,o,s));u<r&&(c>0||l>0||h>0);)c-=Math.max(0,Math.ceil(.1*c)),l-=Math.max(0,Math.ceil(.1*l)),h-=Math.max(0,Math.ceil(.1*h)),u=a(n.relativeLuminance2(c,h,l),n.relativeLuminance2(i,o,s));return(c<<24|l<<16|h<<8|255)>>>0}function i(e,t,r){for(var i=e>>24&255,o=e>>16&255,s=e>>8&255,c=t>>24&255,l=t>>16&255,h=t>>8&255,u=a(n.relativeLuminance2(c,h,l),n.relativeLuminance2(i,o,s));u<r&&(c<255||l<255||h<255);)c=Math.min(255,c+Math.ceil(.1*(255-c))),l=Math.min(255,l+Math.ceil(.1*(255-l))),h=Math.min(255,h+Math.ceil(.1*(255-h))),u=a(n.relativeLuminance2(c,h,l),n.relativeLuminance2(i,o,s));return(c<<24|l<<16|h<<8|255)>>>0}e.ensureContrastRatio=function(e,r,o){var s=n.relativeLuminance(e>>8),c=n.relativeLuminance(r>>8);if(a(s,c)<o)return c<s?t(e,r,o):i(e,r,o)},e.reduceLuminance=t,e.increaseLuminance=i,e.toChannels=function(e){return[e>>24&255,e>>16&255,e>>8&255,255&e]},e.toColor=function(e,t,i){return{css:r.toCss(e,t,i),rgba:r.toRgba(e,t,i)}}}(o=t.rgba||(t.rgba={})),t.toPaddedHex=s,t.contrastRatio=a},7239:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ColorContrastCache=void 0;var r=function(){function e(){this._color={},this._rgba={}}return e.prototype.clear=function(){this._color={},this._rgba={}},e.prototype.setCss=function(e,t,r){this._rgba[e]||(this._rgba[e]={}),this._rgba[e][t]=r},e.prototype.getCss=function(e,t){return this._rgba[e]?this._rgba[e][t]:void 0},e.prototype.setColor=function(e,t,r){this._color[e]||(this._color[e]={}),this._color[e][t]=r},e.prototype.getColor=function(e,t){return this._color[e]?this._color[e][t]:void 0},e}();t.ColorContrastCache=r},5680:function(e,t,r){var i=this&&this.__spreadArray||function(e,t,r){if(r||2===arguments.length)for(var i,n=0,o=t.length;n<o;n++)!i&&n in t||(i||(i=Array.prototype.slice.call(t,0,n)),i[n]=t[n]);return e.concat(i||Array.prototype.slice.call(t))};Object.defineProperty(t,"__esModule",{value:!0}),t.ColorManager=t.DEFAULT_ANSI_COLORS=void 0;var n=r(4774),o=r(7239),s=n.css.toColor("#ffffff"),a=n.css.toColor("#000000"),c=n.css.toColor("#ffffff"),l=n.css.toColor("#000000"),h={css:"rgba(255, 255, 255, 0.3)",rgba:4294967117};t.DEFAULT_ANSI_COLORS=Object.freeze(function(){for(var e=[n.css.toColor("#2e3436"),n.css.toColor("#cc0000"),n.css.toColor("#4e9a06"),n.css.toColor("#c4a000"),n.css.toColor("#3465a4"),n.css.toColor("#75507b"),n.css.toColor("#06989a"),n.css.toColor("#d3d7cf"),n.css.toColor("#555753"),n.css.toColor("#ef2929"),n.css.toColor("#8ae234"),n.css.toColor("#fce94f"),n.css.toColor("#729fcf"),n.css.toColor("#ad7fa8"),n.css.toColor("#34e2e2"),n.css.toColor("#eeeeec")],t=[0,95,135,175,215,255],r=0;r<216;r++){var i=t[r/36%6|0],o=t[r/6%6|0],s=t[r%6];e.push({css:n.channels.toCss(i,o,s),rgba:n.channels.toRgba(i,o,s)})}for(r=0;r<24;r++){var a=8+10*r;e.push({css:n.channels.toCss(a,a,a),rgba:n.channels.toRgba(a,a,a)})}return e}());var u=function(){function e(e,r){this.allowTransparency=r;var i=e.createElement("canvas");i.width=1,i.height=1;var u=i.getContext("2d");if(!u)throw new Error("Could not get rendering context");this._ctx=u,this._ctx.globalCompositeOperation="copy",this._litmusColor=this._ctx.createLinearGradient(0,0,1,1),this._contrastCache=new o.ColorContrastCache,this.colors={foreground:s,background:a,cursor:c,cursorAccent:l,selectionTransparent:h,selectionOpaque:n.color.blend(a,h),ansi:t.DEFAULT_ANSI_COLORS.slice(),contrastCache:this._contrastCache},this._updateRestoreColors()}return e.prototype.onOptionsChange=function(e){"minimumContrastRatio"===e&&this._contrastCache.clear()},e.prototype.setTheme=function(e){void 0===e&&(e={}),this.colors.foreground=this._parseColor(e.foreground,s),this.colors.background=this._parseColor(e.background,a),this.colors.cursor=this._parseColor(e.cursor,c,!0),this.colors.cursorAccent=this._parseColor(e.cursorAccent,l,!0),this.colors.selectionTransparent=this._parseColor(e.selection,h,!0),this.colors.selectionOpaque=n.color.blend(this.colors.background,this.colors.selectionTransparent),n.color.isOpaque(this.colors.selectionTransparent)&&(this.colors.selectionTransparent=n.color.opacity(this.colors.selectionTransparent,.3)),this.colors.ansi[0]=this._parseColor(e.black,t.DEFAULT_ANSI_COLORS[0]),this.colors.ansi[1]=this._parseColor(e.red,t.DEFAULT_ANSI_COLORS[1]),this.colors.ansi[2]=this._parseColor(e.green,t.DEFAULT_ANSI_COLORS[2]),this.colors.ansi[3]=this._parseColor(e.yellow,t.DEFAULT_ANSI_COLORS[3]),this.colors.ansi[4]=this._parseColor(e.blue,t.DEFAULT_ANSI_COLORS[4]),this.colors.ansi[5]=this._parseColor(e.magenta,t.DEFAULT_ANSI_COLORS[5]),this.colors.ansi[6]=this._parseColor(e.cyan,t.DEFAULT_ANSI_COLORS[6]),this.colors.ansi[7]=this._parseColor(e.white,t.DEFAULT_ANSI_COLORS[7]),this.colors.ansi[8]=this._parseColor(e.brightBlack,t.DEFAULT_ANSI_COLORS[8]),this.colors.ansi[9]=this._parseColor(e.brightRed,t.DEFAULT_ANSI_COLORS[9]),this.colors.ansi[10]=this._parseColor(e.brightGreen,t.DEFAULT_ANSI_COLORS[10]),this.colors.ansi[11]=this._parseColor(e.brightYellow,t.DEFAULT_ANSI_COLORS[11]),this.colors.ansi[12]=this._parseColor(e.brightBlue,t.DEFAULT_ANSI_COLORS[12]),this.colors.ansi[13]=this._parseColor(e.brightMagenta,t.DEFAULT_ANSI_COLORS[13]),this.colors.ansi[14]=this._parseColor(e.brightCyan,t.DEFAULT_ANSI_COLORS[14]),this.colors.ansi[15]=this._parseColor(e.brightWhite,t.DEFAULT_ANSI_COLORS[15]),this._contrastCache.clear(),this._updateRestoreColors()},e.prototype.restoreColor=function(e){if(void 0!==e)switch(e){case 256:this.colors.foreground=this._restoreColors.foreground;break;case 257:this.colors.background=this._restoreColors.background;break;case 258:this.colors.cursor=this._restoreColors.cursor;break;default:this.colors.ansi[e]=this._restoreColors.ansi[e]}else for(var t=0;t<this._restoreColors.ansi.length;++t)this.colors.ansi[t]=this._restoreColors.ansi[t]},e.prototype._updateRestoreColors=function(){this._restoreColors={foreground:this.colors.foreground,background:this.colors.background,cursor:this.colors.cursor,ansi:i([],this.colors.ansi,!0)}},e.prototype._parseColor=function(e,t,r){if(void 0===r&&(r=this.allowTransparency),void 0===e)return t;if(this._ctx.fillStyle=this._litmusColor,this._ctx.fillStyle=e,"string"!=typeof this._ctx.fillStyle)return console.warn("Color: "+e+" is invalid using fallback "+t.css),t;this._ctx.fillRect(0,0,1,1);var i=this._ctx.getImageData(0,0,1,1).data;if(255!==i[3]){if(!r)return console.warn("Color: "+e+" is using transparency, but allowTransparency is false. Using fallback "+t.css+"."),t;var o=this._ctx.fillStyle.substring(5,this._ctx.fillStyle.length-1).split(",").map((function(e){return Number(e)})),s=o[0],a=o[1],c=o[2],l=o[3],h=Math.round(255*l);return{rgba:n.channels.toRgba(s,a,c,h),css:e}}return{css:this._ctx.fillStyle,rgba:n.channels.toRgba(i[0],i[1],i[2],i[3])}},e}();t.ColorManager=u},9631:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.removeElementFromParent=void 0,t.removeElementFromParent=function(){for(var e,t=[],r=0;r<arguments.length;r++)t[r]=arguments[r];for(var i=0,n=t;i<n.length;i++){var o=n[i];null===(e=null==o?void 0:o.parentElement)||void 0===e||e.removeChild(o)}}},3656:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.addDisposableDomListener=void 0,t.addDisposableDomListener=function(e,t,r,i){e.addEventListener(t,r,i);var n=!1;return{dispose:function(){n||(n=!0,e.removeEventListener(t,r,i))}}}},3551:function(e,t,r){var i=this&&this.__decorate||function(e,t,r,i){var n,o=arguments.length,s=o<3?t:null===i?i=Object.getOwnPropertyDescriptor(t,r):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)s=Reflect.decorate(e,t,r,i);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(s=(o<3?n(s):o>3?n(t,r,s):n(t,r))||s);return o>3&&s&&Object.defineProperty(t,r,s),s},n=this&&this.__param||function(e,t){return function(r,i){t(r,i,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.MouseZone=t.Linkifier=void 0;var o=r(8460),s=r(2585),a=function(){function e(e,t,r){this._bufferService=e,this._logService=t,this._unicodeService=r,this._linkMatchers=[],this._nextLinkMatcherId=0,this._onShowLinkUnderline=new o.EventEmitter,this._onHideLinkUnderline=new o.EventEmitter,this._onLinkTooltip=new o.EventEmitter,this._rowsToLinkify={start:void 0,end:void 0}}return Object.defineProperty(e.prototype,"onShowLinkUnderline",{get:function(){return this._onShowLinkUnderline.event},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"onHideLinkUnderline",{get:function(){return this._onHideLinkUnderline.event},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"onLinkTooltip",{get:function(){return this._onLinkTooltip.event},enumerable:!1,configurable:!0}),e.prototype.attachToDom=function(e,t){this._element=e,this._mouseZoneManager=t},e.prototype.linkifyRows=function(t,r){var i=this;this._mouseZoneManager&&(void 0===this._rowsToLinkify.start||void 0===this._rowsToLinkify.end?(this._rowsToLinkify.start=t,this._rowsToLinkify.end=r):(this._rowsToLinkify.start=Math.min(this._rowsToLinkify.start,t),this._rowsToLinkify.end=Math.max(this._rowsToLinkify.end,r)),this._mouseZoneManager.clearAll(t,r),this._rowsTimeoutId&&clearTimeout(this._rowsTimeoutId),this._rowsTimeoutId=setTimeout((function(){return i._linkifyRows()}),e._timeBeforeLatency))},e.prototype._linkifyRows=function(){this._rowsTimeoutId=void 0;var e=this._bufferService.buffer;if(void 0!==this._rowsToLinkify.start&&void 0!==this._rowsToLinkify.end){var t=e.ydisp+this._rowsToLinkify.start;if(!(t>=e.lines.length)){for(var r=e.ydisp+Math.min(this._rowsToLinkify.end,this._bufferService.rows)+1,i=Math.ceil(2e3/this._bufferService.cols),n=this._bufferService.buffer.iterator(!1,t,r,i,i);n.hasNext();)for(var o=n.next(),s=0;s<this._linkMatchers.length;s++)this._doLinkifyRow(o.range.first,o.content,this._linkMatchers[s]);this._rowsToLinkify.start=void 0,this._rowsToLinkify.end=void 0}}else this._logService.debug("_rowToLinkify was unset before _linkifyRows was called")},e.prototype.registerLinkMatcher=function(e,t,r){if(void 0===r&&(r={}),!t)throw new Error("handler must be defined");var i={id:this._nextLinkMatcherId++,regex:e,handler:t,matchIndex:r.matchIndex,validationCallback:r.validationCallback,hoverTooltipCallback:r.tooltipCallback,hoverLeaveCallback:r.leaveCallback,willLinkActivate:r.willLinkActivate,priority:r.priority||0};return this._addLinkMatcherToList(i),i.id},e.prototype._addLinkMatcherToList=function(e){if(0!==this._linkMatchers.length){for(var t=this._linkMatchers.length-1;t>=0;t--)if(e.priority<=this._linkMatchers[t].priority)return void this._linkMatchers.splice(t+1,0,e);this._linkMatchers.splice(0,0,e)}else this._linkMatchers.push(e)},e.prototype.deregisterLinkMatcher=function(e){for(var t=0;t<this._linkMatchers.length;t++)if(this._linkMatchers[t].id===e)return this._linkMatchers.splice(t,1),!0;return!1},e.prototype._doLinkifyRow=function(e,t,r){for(var i,n=this,o=new RegExp(r.regex.source,(r.regex.flags||"")+"g"),s=-1,a=function(){var a=i["number"!=typeof r.matchIndex?0:r.matchIndex];if(!a)return c._logService.debug("match found without corresponding matchIndex",i,r),"break";if(s=t.indexOf(a,s+1),o.lastIndex=s+a.length,s<0)return"break";var l=c._bufferService.buffer.stringIndexToBufferIndex(e,s);if(l[0]<0)return"break";var h=c._bufferService.buffer.lines.get(l[0]);if(!h)return"break";var u=h.getFg(l[1]),f=u?u>>9&511:void 0;r.validationCallback?r.validationCallback(a,(function(e){n._rowsTimeoutId||e&&n._addLink(l[1],l[0]-n._bufferService.buffer.ydisp,a,r,f)})):c._addLink(l[1],l[0]-c._bufferService.buffer.ydisp,a,r,f)},c=this;null!==(i=o.exec(t))&&"break"!==a(););},e.prototype._addLink=function(e,t,r,i,n){var o=this;if(this._mouseZoneManager&&this._element){var s=this._unicodeService.getStringCellWidth(r),a=e%this._bufferService.cols,l=t+Math.floor(e/this._bufferService.cols),h=(a+s)%this._bufferService.cols,u=l+Math.floor((a+s)/this._bufferService.cols);0===h&&(h=this._bufferService.cols,u--),this._mouseZoneManager.add(new c(a+1,l+1,h+1,u+1,(function(e){if(i.handler)return i.handler(e,r);var t=window.open();t?(t.opener=null,t.location.href=r):console.warn("Opening link blocked as opener could not be cleared")}),(function(){o._onShowLinkUnderline.fire(o._createLinkHoverEvent(a,l,h,u,n)),o._element.classList.add("xterm-cursor-pointer")}),(function(e){o._onLinkTooltip.fire(o._createLinkHoverEvent(a,l,h,u,n)),i.hoverTooltipCallback&&i.hoverTooltipCallback(e,r,{start:{x:a,y:l},end:{x:h,y:u}})}),(function(){o._onHideLinkUnderline.fire(o._createLinkHoverEvent(a,l,h,u,n)),o._element.classList.remove("xterm-cursor-pointer"),i.hoverLeaveCallback&&i.hoverLeaveCallback()}),(function(e){return!i.willLinkActivate||i.willLinkActivate(e,r)})))}},e.prototype._createLinkHoverEvent=function(e,t,r,i,n){return{x1:e,y1:t,x2:r,y2:i,cols:this._bufferService.cols,fg:n}},e._timeBeforeLatency=200,e=i([n(0,s.IBufferService),n(1,s.ILogService),n(2,s.IUnicodeService)],e)}();t.Linkifier=a;var c=function(e,t,r,i,n,o,s,a,c){this.x1=e,this.y1=t,this.x2=r,this.y2=i,this.clickCallback=n,this.hoverCallback=o,this.tooltipCallback=s,this.leaveCallback=a,this.willLinkActivate=c};t.MouseZone=c},6465:function(e,t,r){var i,n=this&&this.__extends||(i=function(e,t){return i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])},i(e,t)},function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function r(){this.constructor=e}i(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)}),o=this&&this.__decorate||function(e,t,r,i){var n,o=arguments.length,s=o<3?t:null===i?i=Object.getOwnPropertyDescriptor(t,r):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)s=Reflect.decorate(e,t,r,i);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(s=(o<3?n(s):o>3?n(t,r,s):n(t,r))||s);return o>3&&s&&Object.defineProperty(t,r,s),s},s=this&&this.__param||function(e,t){return function(r,i){t(r,i,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.Linkifier2=void 0;var a=r(2585),c=r(8460),l=r(844),h=r(3656),u=function(e){function t(t){var r=e.call(this)||this;return r._bufferService=t,r._linkProviders=[],r._linkCacheDisposables=[],r._isMouseOut=!0,r._activeLine=-1,r._onShowLinkUnderline=r.register(new c.EventEmitter),r._onHideLinkUnderline=r.register(new c.EventEmitter),r.register((0,l.getDisposeArrayDisposable)(r._linkCacheDisposables)),r}return n(t,e),Object.defineProperty(t.prototype,"currentLink",{get:function(){return this._currentLink},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"onShowLinkUnderline",{get:function(){return this._onShowLinkUnderline.event},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"onHideLinkUnderline",{get:function(){return this._onHideLinkUnderline.event},enumerable:!1,configurable:!0}),t.prototype.registerLinkProvider=function(e){var t=this;return this._linkProviders.push(e),{dispose:function(){var r=t._linkProviders.indexOf(e);-1!==r&&t._linkProviders.splice(r,1)}}},t.prototype.attachToDom=function(e,t,r){var i=this;this._element=e,this._mouseService=t,this._renderService=r,this.register((0,h.addDisposableDomListener)(this._element,"mouseleave",(function(){i._isMouseOut=!0,i._clearCurrentLink()}))),this.register((0,h.addDisposableDomListener)(this._element,"mousemove",this._onMouseMove.bind(this))),this.register((0,h.addDisposableDomListener)(this._element,"click",this._onClick.bind(this)))},t.prototype._onMouseMove=function(e){if(this._lastMouseEvent=e,this._element&&this._mouseService){var t=this._positionFromMouseEvent(e,this._element,this._mouseService);if(t){this._isMouseOut=!1;for(var r=e.composedPath(),i=0;i<r.length;i++){var n=r[i];if(n.classList.contains("xterm"))break;if(n.classList.contains("xterm-hover"))return}this._lastBufferCell&&t.x===this._lastBufferCell.x&&t.y===this._lastBufferCell.y||(this._onHover(t),this._lastBufferCell=t)}}},t.prototype._onHover=function(e){if(this._activeLine!==e.y)return this._clearCurrentLink(),void this._askForLink(e,!1);this._currentLink&&this._linkAtPosition(this._currentLink.link,e)||(this._clearCurrentLink(),this._askForLink(e,!0))},t.prototype._askForLink=function(e,t){var r,i=this;this._activeProviderReplies&&t||(null===(r=this._activeProviderReplies)||void 0===r||r.forEach((function(e){null==e||e.forEach((function(e){e.link.dispose&&e.link.dispose()}))})),this._activeProviderReplies=new Map,this._activeLine=e.y);var n=!1;this._linkProviders.forEach((function(r,o){var s;t?(null===(s=i._activeProviderReplies)||void 0===s?void 0:s.get(o))&&(n=i._checkLinkProviderResult(o,e,n)):r.provideLinks(e.y,(function(t){var r,s;if(!i._isMouseOut){var a=null==t?void 0:t.map((function(e){return{link:e}}));null===(r=i._activeProviderReplies)||void 0===r||r.set(o,a),n=i._checkLinkProviderResult(o,e,n),(null===(s=i._activeProviderReplies)||void 0===s?void 0:s.size)===i._linkProviders.length&&i._removeIntersectingLinks(e.y,i._activeProviderReplies)}}))}))},t.prototype._removeIntersectingLinks=function(e,t){for(var r=new Set,i=0;i<t.size;i++){var n=t.get(i);if(n)for(var o=0;o<n.length;o++)for(var s=n[o],a=s.link.range.start.y<e?0:s.link.range.start.x,c=s.link.range.end.y>e?this._bufferService.cols:s.link.range.end.x,l=a;l<=c;l++){if(r.has(l)){n.splice(o--,1);break}r.add(l)}}},t.prototype._checkLinkProviderResult=function(e,t,r){var i,n=this;if(!this._activeProviderReplies)return r;for(var o=this._activeProviderReplies.get(e),s=!1,a=0;a<e;a++)this._activeProviderReplies.has(a)&&!this._activeProviderReplies.get(a)||(s=!0);if(!s&&o){var c=o.find((function(e){return n._linkAtPosition(e.link,t)}));c&&(r=!0,this._handleNewLink(c))}if(this._activeProviderReplies.size===this._linkProviders.length&&!r)for(a=0;a<this._activeProviderReplies.size;a++){var l=null===(i=this._activeProviderReplies.get(a))||void 0===i?void 0:i.find((function(e){return n._linkAtPosition(e.link,t)}));if(l){r=!0,this._handleNewLink(l);break}}return r},t.prototype._onClick=function(e){if(this._element&&this._mouseService&&this._currentLink){var t=this._positionFromMouseEvent(e,this._element,this._mouseService);t&&this._linkAtPosition(this._currentLink.link,t)&&this._currentLink.link.activate(e,this._currentLink.link.text)}},t.prototype._clearCurrentLink=function(e,t){this._element&&this._currentLink&&this._lastMouseEvent&&(!e||!t||this._currentLink.link.range.start.y>=e&&this._currentLink.link.range.end.y<=t)&&(this._linkLeave(this._element,this._currentLink.link,this._lastMouseEvent),this._currentLink=void 0,(0,l.disposeArray)(this._linkCacheDisposables))},t.prototype._handleNewLink=function(e){var t=this;if(this._element&&this._lastMouseEvent&&this._mouseService){var r=this._positionFromMouseEvent(this._lastMouseEvent,this._element,this._mouseService);r&&this._linkAtPosition(e.link,r)&&(this._currentLink=e,this._currentLink.state={decorations:{underline:void 0===e.link.decorations||e.link.decorations.underline,pointerCursor:void 0===e.link.decorations||e.link.decorations.pointerCursor},isHovered:!0},this._linkHover(this._element,e.link,this._lastMouseEvent),e.link.decorations={},Object.defineProperties(e.link.decorations,{pointerCursor:{get:function(){var e,r;return null===(r=null===(e=t._currentLink)||void 0===e?void 0:e.state)||void 0===r?void 0:r.decorations.pointerCursor},set:function(e){var r,i;(null===(r=t._currentLink)||void 0===r?void 0:r.state)&&t._currentLink.state.decorations.pointerCursor!==e&&(t._currentLink.state.decorations.pointerCursor=e,t._currentLink.state.isHovered&&(null===(i=t._element)||void 0===i||i.classList.toggle("xterm-cursor-pointer",e)))}},underline:{get:function(){var e,r;return null===(r=null===(e=t._currentLink)||void 0===e?void 0:e.state)||void 0===r?void 0:r.decorations.underline},set:function(r){var i,n,o;(null===(i=t._currentLink)||void 0===i?void 0:i.state)&&(null===(o=null===(n=t._currentLink)||void 0===n?void 0:n.state)||void 0===o?void 0:o.decorations.underline)!==r&&(t._currentLink.state.decorations.underline=r,t._currentLink.state.isHovered&&t._fireUnderlineEvent(e.link,r))}}}),this._renderService&&this._linkCacheDisposables.push(this._renderService.onRenderedBufferChange((function(e){var r=0===e.start?0:e.start+1+t._bufferService.buffer.ydisp;t._clearCurrentLink(r,e.end+1+t._bufferService.buffer.ydisp)}))))}},t.prototype._linkHover=function(e,t,r){var i;(null===(i=this._currentLink)||void 0===i?void 0:i.state)&&(this._currentLink.state.isHovered=!0,this._currentLink.state.decorations.underline&&this._fireUnderlineEvent(t,!0),this._currentLink.state.decorations.pointerCursor&&e.classList.add("xterm-cursor-pointer")),t.hover&&t.hover(r,t.text)},t.prototype._fireUnderlineEvent=function(e,t){var r=e.range,i=this._bufferService.buffer.ydisp,n=this._createLinkUnderlineEvent(r.start.x-1,r.start.y-i-1,r.end.x,r.end.y-i-1,void 0);(t?this._onShowLinkUnderline:this._onHideLinkUnderline).fire(n)},t.prototype._linkLeave=function(e,t,r){var i;(null===(i=this._currentLink)||void 0===i?void 0:i.state)&&(this._currentLink.state.isHovered=!1,this._currentLink.state.decorations.underline&&this._fireUnderlineEvent(t,!1),this._currentLink.state.decorations.pointerCursor&&e.classList.remove("xterm-cursor-pointer")),t.leave&&t.leave(r,t.text)},t.prototype._linkAtPosition=function(e,t){var r=e.range.start.y===e.range.end.y,i=e.range.start.y<t.y,n=e.range.end.y>t.y;return(r&&e.range.start.x<=t.x&&e.range.end.x>=t.x||i&&e.range.end.x>=t.x||n&&e.range.start.x<=t.x||i&&n)&&e.range.start.y<=t.y&&e.range.end.y>=t.y},t.prototype._positionFromMouseEvent=function(e,t,r){var i=r.getCoords(e,t,this._bufferService.cols,this._bufferService.rows);if(i)return{x:i[0],y:i[1]+this._bufferService.buffer.ydisp}},t.prototype._createLinkUnderlineEvent=function(e,t,r,i,n){return{x1:e,y1:t,x2:r,y2:i,cols:this._bufferService.cols,fg:n}},o([s(0,a.IBufferService)],t)}(l.Disposable);t.Linkifier2=u},9042:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.tooMuchOutput=t.promptLabel=void 0,t.promptLabel="Terminal input",t.tooMuchOutput="Too much output to announce, navigate to rows manually to read"},6954:function(e,t,r){var i,n=this&&this.__extends||(i=function(e,t){return i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])},i(e,t)},function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function r(){this.constructor=e}i(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)}),o=this&&this.__decorate||function(e,t,r,i){var n,o=arguments.length,s=o<3?t:null===i?i=Object.getOwnPropertyDescriptor(t,r):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)s=Reflect.decorate(e,t,r,i);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(s=(o<3?n(s):o>3?n(t,r,s):n(t,r))||s);return o>3&&s&&Object.defineProperty(t,r,s),s},s=this&&this.__param||function(e,t){return function(r,i){t(r,i,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.MouseZoneManager=void 0;var a=r(844),c=r(3656),l=r(4725),h=r(2585),u=function(e){function t(t,r,i,n,o,s){var a=e.call(this)||this;return a._element=t,a._screenElement=r,a._bufferService=i,a._mouseService=n,a._selectionService=o,a._optionsService=s,a._zones=[],a._areZonesActive=!1,a._lastHoverCoords=[void 0,void 0],a._initialSelectionLength=0,a.register((0,c.addDisposableDomListener)(a._element,"mousedown",(function(e){return a._onMouseDown(e)}))),a._mouseMoveListener=function(e){return a._onMouseMove(e)},a._mouseLeaveListener=function(e){return a._onMouseLeave(e)},a._clickListener=function(e){return a._onClick(e)},a}return n(t,e),t.prototype.dispose=function(){e.prototype.dispose.call(this),this._deactivate()},t.prototype.add=function(e){this._zones.push(e),1===this._zones.length&&this._activate()},t.prototype.clearAll=function(e,t){if(0!==this._zones.length){e&&t||(e=0,t=this._bufferService.rows-1);for(var r=0;r<this._zones.length;r++){var i=this._zones[r];(i.y1>e&&i.y1<=t+1||i.y2>e&&i.y2<=t+1||i.y1<e&&i.y2>t+1)&&(this._currentZone&&this._currentZone===i&&(this._currentZone.leaveCallback(),this._currentZone=void 0),this._zones.splice(r--,1))}0===this._zones.length&&this._deactivate()}},t.prototype._activate=function(){this._areZonesActive||(this._areZonesActive=!0,this._element.addEventListener("mousemove",this._mouseMoveListener),this._element.addEventListener("mouseleave",this._mouseLeaveListener),this._element.addEventListener("click",this._clickListener))},t.prototype._deactivate=function(){this._areZonesActive&&(this._areZonesActive=!1,this._element.removeEventListener("mousemove",this._mouseMoveListener),this._element.removeEventListener("mouseleave",this._mouseLeaveListener),this._element.removeEventListener("click",this._clickListener))},t.prototype._onMouseMove=function(e){this._lastHoverCoords[0]===e.pageX&&this._lastHoverCoords[1]===e.pageY||(this._onHover(e),this._lastHoverCoords=[e.pageX,e.pageY])},t.prototype._onHover=function(e){var t=this,r=this._findZoneEventAt(e);r!==this._currentZone&&(this._currentZone&&(this._currentZone.leaveCallback(),this._currentZone=void 0,this._tooltipTimeout&&clearTimeout(this._tooltipTimeout)),r&&(this._currentZone=r,r.hoverCallback&&r.hoverCallback(e),this._tooltipTimeout=window.setTimeout((function(){return t._onTooltip(e)}),this._optionsService.options.linkTooltipHoverDuration)))},t.prototype._onTooltip=function(e){this._tooltipTimeout=void 0;var t=this._findZoneEventAt(e);null==t||t.tooltipCallback(e)},t.prototype._onMouseDown=function(e){if(this._initialSelectionLength=this._getSelectionLength(),this._areZonesActive){var t=this._findZoneEventAt(e);(null==t?void 0:t.willLinkActivate(e))&&(e.preventDefault(),e.stopImmediatePropagation())}},t.prototype._onMouseLeave=function(e){this._currentZone&&(this._currentZone.leaveCallback(),this._currentZone=void 0,this._tooltipTimeout&&clearTimeout(this._tooltipTimeout))},t.prototype._onClick=function(e){var t=this._findZoneEventAt(e),r=this._getSelectionLength();t&&r===this._initialSelectionLength&&(t.clickCallback(e),e.preventDefault(),e.stopImmediatePropagation())},t.prototype._getSelectionLength=function(){var e=this._selectionService.selectionText;return e?e.length:0},t.prototype._findZoneEventAt=function(e){var t=this._mouseService.getCoords(e,this._screenElement,this._bufferService.cols,this._bufferService.rows);if(t)for(var r=t[0],i=t[1],n=0;n<this._zones.length;n++){var o=this._zones[n];if(o.y1===o.y2){if(i===o.y1&&r>=o.x1&&r<o.x2)return o}else if(i===o.y1&&r>=o.x1||i===o.y2&&r<o.x2||i>o.y1&&i<o.y2)return o}},o([s(2,h.IBufferService),s(3,l.IMouseService),s(4,l.ISelectionService),s(5,h.IOptionsService)],t)}(a.Disposable);t.MouseZoneManager=u},6193:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.RenderDebouncer=void 0;var r=function(){function e(e){this._renderCallback=e}return e.prototype.dispose=function(){this._animationFrame&&(window.cancelAnimationFrame(this._animationFrame),this._animationFrame=void 0)},e.prototype.refresh=function(e,t,r){var i=this;this._rowCount=r,e=void 0!==e?e:0,t=void 0!==t?t:this._rowCount-1,this._rowStart=void 0!==this._rowStart?Math.min(this._rowStart,e):e,this._rowEnd=void 0!==this._rowEnd?Math.max(this._rowEnd,t):t,this._animationFrame||(this._animationFrame=window.requestAnimationFrame((function(){return i._innerRefresh()})))},e.prototype._innerRefresh=function(){if(void 0!==this._rowStart&&void 0!==this._rowEnd&&void 0!==this._rowCount){var e=Math.max(this._rowStart,0),t=Math.min(this._rowEnd,this._rowCount-1);this._rowStart=void 0,this._rowEnd=void 0,this._animationFrame=void 0,this._renderCallback(e,t)}},e}();t.RenderDebouncer=r},5596:function(e,t,r){var i,n=this&&this.__extends||(i=function(e,t){return i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])},i(e,t)},function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function r(){this.constructor=e}i(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)});Object.defineProperty(t,"__esModule",{value:!0}),t.ScreenDprMonitor=void 0;var o=function(e){function t(){var t=null!==e&&e.apply(this,arguments)||this;return t._currentDevicePixelRatio=window.devicePixelRatio,t}return n(t,e),t.prototype.setListener=function(e){var t=this;this._listener&&this.clearListener(),this._listener=e,this._outerListener=function(){t._listener&&(t._listener(window.devicePixelRatio,t._currentDevicePixelRatio),t._updateDpr())},this._updateDpr()},t.prototype.dispose=function(){e.prototype.dispose.call(this),this.clearListener()},t.prototype._updateDpr=function(){var e;this._outerListener&&(null===(e=this._resolutionMediaMatchList)||void 0===e||e.removeListener(this._outerListener),this._currentDevicePixelRatio=window.devicePixelRatio,this._resolutionMediaMatchList=window.matchMedia("screen and (resolution: "+window.devicePixelRatio+"dppx)"),this._resolutionMediaMatchList.addListener(this._outerListener))},t.prototype.clearListener=function(){this._resolutionMediaMatchList&&this._listener&&this._outerListener&&(this._resolutionMediaMatchList.removeListener(this._outerListener),this._resolutionMediaMatchList=void 0,this._listener=void 0,this._outerListener=void 0)},t}(r(844).Disposable);t.ScreenDprMonitor=o},3236:function(e,t,r){var i,n=this&&this.__extends||(i=function(e,t){return i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])},i(e,t)},function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function r(){this.constructor=e}i(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)});Object.defineProperty(t,"__esModule",{value:!0}),t.Terminal=void 0;var o=r(2950),s=r(1680),a=r(3614),c=r(2584),l=r(5435),h=r(3525),u=r(3551),f=r(9312),_=r(6114),d=r(3656),p=r(9042),v=r(357),g=r(6954),y=r(4567),m=r(1296),S=r(7399),C=r(8460),b=r(8437),w=r(5680),L=r(3230),E=r(4725),x=r(428),M=r(8934),k=r(6465),A=r(5114),R=r(8969),T=r(4774),B=r(4269),O=r(5941),D="undefined"!=typeof window?window.document:null,P=function(e){function t(t){void 0===t&&(t={});var r=e.call(this,t)||this;return r.browser=_,r._keyDownHandled=!1,r._keyPressHandled=!1,r._unprocessedDeadKey=!1,r._onCursorMove=new C.EventEmitter,r._onKey=new C.EventEmitter,r._onRender=new C.EventEmitter,r._onSelectionChange=new C.EventEmitter,r._onTitleChange=new C.EventEmitter,r._onBell=new C.EventEmitter,r._onFocus=new C.EventEmitter,r._onBlur=new C.EventEmitter,r._onA11yCharEmitter=new C.EventEmitter,r._onA11yTabEmitter=new C.EventEmitter,r._setup(),r.linkifier=r._instantiationService.createInstance(u.Linkifier),r.linkifier2=r.register(r._instantiationService.createInstance(k.Linkifier2)),r.register(r._inputHandler.onRequestBell((function(){return r.bell()}))),r.register(r._inputHandler.onRequestRefreshRows((function(e,t){return r.refresh(e,t)}))),r.register(r._inputHandler.onRequestSendFocus((function(){return r._reportFocus()}))),r.register(r._inputHandler.onRequestReset((function(){return r.reset()}))),r.register(r._inputHandler.onRequestWindowsOptionsReport((function(e){return r._reportWindowsOptions(e)}))),r.register(r._inputHandler.onColor((function(e){return r._handleColorEvent(e)}))),r.register((0,C.forwardEvent)(r._inputHandler.onCursorMove,r._onCursorMove)),r.register((0,C.forwardEvent)(r._inputHandler.onTitleChange,r._onTitleChange)),r.register((0,C.forwardEvent)(r._inputHandler.onA11yChar,r._onA11yCharEmitter)),r.register((0,C.forwardEvent)(r._inputHandler.onA11yTab,r._onA11yTabEmitter)),r.register(r._bufferService.onResize((function(e){return r._afterResize(e.cols,e.rows)}))),r}return n(t,e),Object.defineProperty(t.prototype,"onCursorMove",{get:function(){return this._onCursorMove.event},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"onKey",{get:function(){return this._onKey.event},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"onRender",{get:function(){return this._onRender.event},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"onSelectionChange",{get:function(){return this._onSelectionChange.event},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"onTitleChange",{get:function(){return this._onTitleChange.event},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"onBell",{get:function(){return this._onBell.event},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"onFocus",{get:function(){return this._onFocus.event},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"onBlur",{get:function(){return this._onBlur.event},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"onA11yChar",{get:function(){return this._onA11yCharEmitter.event},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"onA11yTab",{get:function(){return this._onA11yTabEmitter.event},enumerable:!1,configurable:!0}),t.prototype._handleColorEvent=function(e){var t,r;if(this._colorManager){for(var i=0,n=e;i<n.length;i++){var o=n[i],s=void 0,a="";switch(o.index){case 256:s="foreground",a="10";break;case 257:s="background",a="11";break;case 258:s="cursor",a="12";break;default:s="ansi",a="4;"+o.index}if(s)switch(o.type){case 0:var l=T.color.toColorRGB("ansi"===s?this._colorManager.colors.ansi[o.index]:this._colorManager.colors[s]);this.coreService.triggerDataEvent(c.C0.ESC+"]"+a+";"+(0,O.toRgbString)(l)+c.C0.BEL);break;case 1:"ansi"===s?this._colorManager.colors.ansi[o.index]=T.rgba.toColor.apply(T.rgba,o.color):this._colorManager.colors[s]=T.rgba.toColor.apply(T.rgba,o.color);break;case 2:this._colorManager.restoreColor(o.index)}}null===(t=this._renderService)||void 0===t||t.setColors(this._colorManager.colors),null===(r=this.viewport)||void 0===r||r.onThemeChange(this._colorManager.colors)}},t.prototype.dispose=function(){var t,r,i;this._isDisposed||(e.prototype.dispose.call(this),null===(t=this._renderService)||void 0===t||t.dispose(),this._customKeyEventHandler=void 0,this.write=function(){},null===(i=null===(r=this.element)||void 0===r?void 0:r.parentNode)||void 0===i||i.removeChild(this.element))},t.prototype._setup=function(){e.prototype._setup.call(this),this._customKeyEventHandler=void 0},Object.defineProperty(t.prototype,"buffer",{get:function(){return this.buffers.active},enumerable:!1,configurable:!0}),t.prototype.focus=function(){this.textarea&&this.textarea.focus({preventScroll:!0})},t.prototype._updateOptions=function(t){var r,i,n,o;switch(e.prototype._updateOptions.call(this,t),t){case"fontFamily":case"fontSize":null===(r=this._renderService)||void 0===r||r.clear(),null===(i=this._charSizeService)||void 0===i||i.measure();break;case"cursorBlink":case"cursorStyle":this.refresh(this.buffer.y,this.buffer.y);break;case"customGlyphs":case"drawBoldTextInBrightColors":case"letterSpacing":case"lineHeight":case"fontWeight":case"fontWeightBold":case"minimumContrastRatio":this._renderService&&(this._renderService.clear(),this._renderService.onResize(this.cols,this.rows),this.refresh(0,this.rows-1));break;case"rendererType":this._renderService&&(this._renderService.setRenderer(this._createRenderer()),this._renderService.onResize(this.cols,this.rows));break;case"scrollback":null===(n=this.viewport)||void 0===n||n.syncScrollArea();break;case"screenReaderMode":this.optionsService.options.screenReaderMode?!this._accessibilityManager&&this._renderService&&(this._accessibilityManager=new y.AccessibilityManager(this,this._renderService)):(null===(o=this._accessibilityManager)||void 0===o||o.dispose(),this._accessibilityManager=void 0);break;case"tabStopWidth":this.buffers.setupTabStops();break;case"theme":this._setTheme(this.optionsService.options.theme)}},t.prototype._onTextAreaFocus=function(e){this.coreService.decPrivateModes.sendFocus&&this.coreService.triggerDataEvent(c.C0.ESC+"[I"),this.updateCursorStyle(e),this.element.classList.add("focus"),this._showCursor(),this._onFocus.fire()},t.prototype.blur=function(){var e;return null===(e=this.textarea)||void 0===e?void 0:e.blur()},t.prototype._onTextAreaBlur=function(){this.textarea.value="",this.refresh(this.buffer.y,this.buffer.y),this.coreService.decPrivateModes.sendFocus&&this.coreService.triggerDataEvent(c.C0.ESC+"[O"),this.element.classList.remove("focus"),this._onBlur.fire()},t.prototype._syncTextArea=function(){if(this.textarea&&this.buffer.isCursorInViewport&&!this._compositionHelper.isComposing&&this._renderService){var e=this.buffer.ybase+this.buffer.y,t=this.buffer.lines.get(e);if(t){var r=Math.min(this.buffer.x,this.cols-1),i=this._renderService.dimensions.actualCellHeight,n=t.getWidth(r),o=this._renderService.dimensions.actualCellWidth*n,s=this.buffer.y*this._renderService.dimensions.actualCellHeight,a=r*this._renderService.dimensions.actualCellWidth;this.textarea.style.left=a+"px",this.textarea.style.top=s+"px",this.textarea.style.width=o+"px",this.textarea.style.height=i+"px",this.textarea.style.lineHeight=i+"px",this.textarea.style.zIndex="-5"}}},t.prototype._initGlobal=function(){var e=this;this._bindKeys(),this.register((0,d.addDisposableDomListener)(this.element,"copy",(function(t){e.hasSelection()&&(0,a.copyHandler)(t,e._selectionService)})));var t=function(t){return(0,a.handlePasteEvent)(t,e.textarea,e.coreService)};this.register((0,d.addDisposableDomListener)(this.textarea,"paste",t)),this.register((0,d.addDisposableDomListener)(this.element,"paste",t)),_.isFirefox?this.register((0,d.addDisposableDomListener)(this.element,"mousedown",(function(t){2===t.button&&(0,a.rightClickHandler)(t,e.textarea,e.screenElement,e._selectionService,e.options.rightClickSelectsWord)}))):this.register((0,d.addDisposableDomListener)(this.element,"contextmenu",(function(t){(0,a.rightClickHandler)(t,e.textarea,e.screenElement,e._selectionService,e.options.rightClickSelectsWord)}))),_.isLinux&&this.register((0,d.addDisposableDomListener)(this.element,"auxclick",(function(t){1===t.button&&(0,a.moveTextAreaUnderMouseCursor)(t,e.textarea,e.screenElement)})))},t.prototype._bindKeys=function(){var e=this;this.register((0,d.addDisposableDomListener)(this.textarea,"keyup",(function(t){return e._keyUp(t)}),!0)),this.register((0,d.addDisposableDomListener)(this.textarea,"keydown",(function(t){return e._keyDown(t)}),!0)),this.register((0,d.addDisposableDomListener)(this.textarea,"keypress",(function(t){return e._keyPress(t)}),!0)),this.register((0,d.addDisposableDomListener)(this.textarea,"compositionstart",(function(){return e._compositionHelper.compositionstart()}))),this.register((0,d.addDisposableDomListener)(this.textarea,"compositionupdate",(function(t){return e._compositionHelper.compositionupdate(t)}))),this.register((0,d.addDisposableDomListener)(this.textarea,"compositionend",(function(){return e._compositionHelper.compositionend()}))),this.register((0,d.addDisposableDomListener)(this.textarea,"input",(function(t){return e._inputEvent(t)}),!0)),this.register(this.onRender((function(){return e._compositionHelper.updateCompositionElements()}))),this.register(this.onRender((function(t){return e._queueLinkification(t.start,t.end)})))},t.prototype.open=function(e){var t=this;if(!e)throw new Error("Terminal requires a parent element.");e.isConnected||this._logService.debug("Terminal.open was called on an element that was not attached to the DOM"),this._document=e.ownerDocument,this.element=this._document.createElement("div"),this.element.dir="ltr",this.element.classList.add("terminal"),this.element.classList.add("xterm"),this.element.setAttribute("tabindex","0"),e.appendChild(this.element);var r=D.createDocumentFragment();this._viewportElement=D.createElement("div"),this._viewportElement.classList.add("xterm-viewport"),r.appendChild(this._viewportElement),this._viewportScrollArea=D.createElement("div"),this._viewportScrollArea.classList.add("xterm-scroll-area"),this._viewportElement.appendChild(this._viewportScrollArea),this.screenElement=D.createElement("div"),this.screenElement.classList.add("xterm-screen"),this._helperContainer=D.createElement("div"),this._helperContainer.classList.add("xterm-helpers"),this.screenElement.appendChild(this._helperContainer),r.appendChild(this.screenElement),this.textarea=D.createElement("textarea"),this.textarea.classList.add("xterm-helper-textarea"),this.textarea.setAttribute("aria-label",p.promptLabel),this.textarea.setAttribute("aria-multiline","false"),this.textarea.setAttribute("autocorrect","off"),this.textarea.setAttribute("autocapitalize","off"),this.textarea.setAttribute("spellcheck","false"),this.textarea.tabIndex=0,this.register((0,d.addDisposableDomListener)(this.textarea,"focus",(function(e){return t._onTextAreaFocus(e)}))),this.register((0,d.addDisposableDomListener)(this.textarea,"blur",(function(){return t._onTextAreaBlur()}))),this._helperContainer.appendChild(this.textarea);var i=this._instantiationService.createInstance(A.CoreBrowserService,this.textarea);this._instantiationService.setService(E.ICoreBrowserService,i),this._charSizeService=this._instantiationService.createInstance(x.CharSizeService,this._document,this._helperContainer),this._instantiationService.setService(E.ICharSizeService,this._charSizeService),this._theme=this.options.theme||this._theme,this._colorManager=new w.ColorManager(D,this.options.allowTransparency),this.register(this.optionsService.onOptionChange((function(e){return t._colorManager.onOptionsChange(e)}))),this._colorManager.setTheme(this._theme),this._characterJoinerService=this._instantiationService.createInstance(B.CharacterJoinerService),this._instantiationService.setService(E.ICharacterJoinerService,this._characterJoinerService);var n=this._createRenderer();this._renderService=this.register(this._instantiationService.createInstance(L.RenderService,n,this.rows,this.screenElement)),this._instantiationService.setService(E.IRenderService,this._renderService),this.register(this._renderService.onRenderedBufferChange((function(e){return t._onRender.fire(e)}))),this.onResize((function(e){return t._renderService.resize(e.cols,e.rows)})),this._compositionView=D.createElement("div"),this._compositionView.classList.add("composition-view"),this._compositionHelper=this._instantiationService.createInstance(o.CompositionHelper,this.textarea,this._compositionView),this._helperContainer.appendChild(this._compositionView),this.element.appendChild(r),this._soundService=this._instantiationService.createInstance(v.SoundService),this._instantiationService.setService(E.ISoundService,this._soundService),this._mouseService=this._instantiationService.createInstance(M.MouseService),this._instantiationService.setService(E.IMouseService,this._mouseService),this.viewport=this._instantiationService.createInstance(s.Viewport,(function(e){return t.scrollLines(e,!0,1)}),this._viewportElement,this._viewportScrollArea,this.element),this.viewport.onThemeChange(this._colorManager.colors),this.register(this._inputHandler.onRequestSyncScrollBar((function(){return t.viewport.syncScrollArea()}))),this.register(this.viewport),this.register(this.onCursorMove((function(){t._renderService.onCursorMove(),t._syncTextArea()}))),this.register(this.onResize((function(){return t._renderService.onResize(t.cols,t.rows)}))),this.register(this.onBlur((function(){return t._renderService.onBlur()}))),this.register(this.onFocus((function(){return t._renderService.onFocus()}))),this.register(this._renderService.onDimensionsChange((function(){return t.viewport.syncScrollArea()}))),this._selectionService=this.register(this._instantiationService.createInstance(f.SelectionService,this.element,this.screenElement,this.linkifier2)),this._instantiationService.setService(E.ISelectionService,this._selectionService),this.register(this._selectionService.onRequestScrollLines((function(e){return t.scrollLines(e.amount,e.suppressScrollEvent)}))),this.register(this._selectionService.onSelectionChange((function(){return t._onSelectionChange.fire()}))),this.register(this._selectionService.onRequestRedraw((function(e){return t._renderService.onSelectionChanged(e.start,e.end,e.columnSelectMode)}))),this.register(this._selectionService.onLinuxMouseSelection((function(e){t.textarea.value=e,t.textarea.focus(),t.textarea.select()}))),this.register(this._onScroll.event((function(e){t.viewport.syncScrollArea(),t._selectionService.refresh()}))),this.register((0,d.addDisposableDomListener)(this._viewportElement,"scroll",(function(){return t._selectionService.refresh()}))),this._mouseZoneManager=this._instantiationService.createInstance(g.MouseZoneManager,this.element,this.screenElement),this.register(this._mouseZoneManager),this.register(this.onScroll((function(){return t._mouseZoneManager.clearAll()}))),this.linkifier.attachToDom(this.element,this._mouseZoneManager),this.linkifier2.attachToDom(this.screenElement,this._mouseService,this._renderService),this.register((0,d.addDisposableDomListener)(this.element,"mousedown",(function(e){return t._selectionService.onMouseDown(e)}))),this.coreMouseService.areMouseEventsActive?(this._selectionService.disable(),this.element.classList.add("enable-mouse-events")):this._selectionService.enable(),this.options.screenReaderMode&&(this._accessibilityManager=new y.AccessibilityManager(this,this._renderService)),this._charSizeService.measure(),this.refresh(0,this.rows-1),this._initGlobal(),this.bindMouse()},t.prototype._createRenderer=function(){switch(this.options.rendererType){case"canvas":return this._instantiationService.createInstance(h.Renderer,this._colorManager.colors,this.screenElement,this.linkifier,this.linkifier2);case"dom":return this._instantiationService.createInstance(m.DomRenderer,this._colorManager.colors,this.element,this.screenElement,this._viewportElement,this.linkifier,this.linkifier2);default:throw new Error('Unrecognized rendererType "'+this.options.rendererType+'"')}},t.prototype._setTheme=function(e){var t,r,i;this._theme=e,null===(t=this._colorManager)||void 0===t||t.setTheme(e),null===(r=this._renderService)||void 0===r||r.setColors(this._colorManager.colors),null===(i=this.viewport)||void 0===i||i.onThemeChange(this._colorManager.colors)},t.prototype.bindMouse=function(){var e=this,t=this,r=this.element;function i(e){var r,i,n=t._mouseService.getRawByteCoords(e,t.screenElement,t.cols,t.rows);if(!n)return!1;switch(e.overrideType||e.type){case"mousemove":i=32,void 0===e.buttons?(r=3,void 0!==e.button&&(r=e.button<3?e.button:3)):r=1&e.buttons?0:4&e.buttons?1:2&e.buttons?2:3;break;case"mouseup":i=0,r=e.button<3?e.button:3;break;case"mousedown":i=1,r=e.button<3?e.button:3;break;case"wheel":0!==e.deltaY&&(i=e.deltaY<0?0:1),r=4;break;default:return!1}return!(void 0===i||void 0===r||r>4)&&t.coreMouseService.triggerMouseEvent({col:n.x-33,row:n.y-33,button:r,action:i,ctrl:e.ctrlKey,alt:e.altKey,shift:e.shiftKey})}var n={mouseup:null,wheel:null,mousedrag:null,mousemove:null},o=function(t){return i(t),t.buttons||(e._document.removeEventListener("mouseup",n.mouseup),n.mousedrag&&e._document.removeEventListener("mousemove",n.mousedrag)),e.cancel(t)},s=function(t){return i(t),e.cancel(t,!0)},a=function(e){e.buttons&&i(e)},l=function(e){e.buttons||i(e)};this.register(this.coreMouseService.onProtocolChange((function(t){t?("debug"===e.optionsService.options.logLevel&&e._logService.debug("Binding to mouse events:",e.coreMouseService.explainEvents(t)),e.element.classList.add("enable-mouse-events"),e._selectionService.disable()):(e._logService.debug("Unbinding from mouse events."),e.element.classList.remove("enable-mouse-events"),e._selectionService.enable()),8&t?n.mousemove||(r.addEventListener("mousemove",l),n.mousemove=l):(r.removeEventListener("mousemove",n.mousemove),n.mousemove=null),16&t?n.wheel||(r.addEventListener("wheel",s,{passive:!1}),n.wheel=s):(r.removeEventListener("wheel",n.wheel),n.wheel=null),2&t?n.mouseup||(n.mouseup=o):(e._document.removeEventListener("mouseup",n.mouseup),n.mouseup=null),4&t?n.mousedrag||(n.mousedrag=a):(e._document.removeEventListener("mousemove",n.mousedrag),n.mousedrag=null)}))),this.coreMouseService.activeProtocol=this.coreMouseService.activeProtocol,this.register((0,d.addDisposableDomListener)(r,"mousedown",(function(t){if(t.preventDefault(),e.focus(),e.coreMouseService.areMouseEventsActive&&!e._selectionService.shouldForceSelection(t))return i(t),n.mouseup&&e._document.addEventListener("mouseup",n.mouseup),n.mousedrag&&e._document.addEventListener("mousemove",n.mousedrag),e.cancel(t)}))),this.register((0,d.addDisposableDomListener)(r,"wheel",(function(t){if(!n.wheel){if(!e.buffer.hasScrollback){var r=e.viewport.getLinesScrolled(t);if(0===r)return;for(var i=c.C0.ESC+(e.coreService.decPrivateModes.applicationCursorKeys?"O":"[")+(t.deltaY<0?"A":"B"),o="",s=0;s<Math.abs(r);s++)o+=i;return e.coreService.triggerDataEvent(o,!0),e.cancel(t,!0)}return e.viewport.onWheel(t)?e.cancel(t):void 0}}),{passive:!1})),this.register((0,d.addDisposableDomListener)(r,"touchstart",(function(t){if(!e.coreMouseService.areMouseEventsActive)return e.viewport.onTouchStart(t),e.cancel(t)}),{passive:!0})),this.register((0,d.addDisposableDomListener)(r,"touchmove",(function(t){if(!e.coreMouseService.areMouseEventsActive)return e.viewport.onTouchMove(t)?void 0:e.cancel(t)}),{passive:!1}))},t.prototype.refresh=function(e,t){var r;null===(r=this._renderService)||void 0===r||r.refreshRows(e,t)},t.prototype._queueLinkification=function(e,t){var r;null===(r=this.linkifier)||void 0===r||r.linkifyRows(e,t)},t.prototype.updateCursorStyle=function(e){var t;(null===(t=this._selectionService)||void 0===t?void 0:t.shouldColumnSelect(e))?this.element.classList.add("column-select"):this.element.classList.remove("column-select")},t.prototype._showCursor=function(){this.coreService.isCursorInitialized||(this.coreService.isCursorInitialized=!0,this.refresh(this.buffer.y,this.buffer.y))},t.prototype.scrollLines=function(t,r,i){void 0===i&&(i=0),e.prototype.scrollLines.call(this,t,r,i),this.refresh(0,this.rows-1)},t.prototype.paste=function(e){(0,a.paste)(e,this.textarea,this.coreService)},t.prototype.attachCustomKeyEventHandler=function(e){this._customKeyEventHandler=e},t.prototype.registerLinkMatcher=function(e,t,r){var i=this.linkifier.registerLinkMatcher(e,t,r);return this.refresh(0,this.rows-1),i},t.prototype.deregisterLinkMatcher=function(e){this.linkifier.deregisterLinkMatcher(e)&&this.refresh(0,this.rows-1)},t.prototype.registerLinkProvider=function(e){return this.linkifier2.registerLinkProvider(e)},t.prototype.registerCharacterJoiner=function(e){if(!this._characterJoinerService)throw new Error("Terminal must be opened first");var t=this._characterJoinerService.register(e);return this.refresh(0,this.rows-1),t},t.prototype.deregisterCharacterJoiner=function(e){if(!this._characterJoinerService)throw new Error("Terminal must be opened first");this._characterJoinerService.deregister(e)&&this.refresh(0,this.rows-1)},Object.defineProperty(t.prototype,"markers",{get:function(){return this.buffer.markers},enumerable:!1,configurable:!0}),t.prototype.addMarker=function(e){if(this.buffer===this.buffers.normal)return this.buffer.addMarker(this.buffer.ybase+this.buffer.y+e)},t.prototype.hasSelection=function(){return!!this._selectionService&&this._selectionService.hasSelection},t.prototype.select=function(e,t,r){this._selectionService.setSelection(e,t,r)},t.prototype.getSelection=function(){return this._selectionService?this._selectionService.selectionText:""},t.prototype.getSelectionPosition=function(){if(this._selectionService&&this._selectionService.hasSelection)return{startColumn:this._selectionService.selectionStart[0],startRow:this._selectionService.selectionStart[1],endColumn:this._selectionService.selectionEnd[0],endRow:this._selectionService.selectionEnd[1]}},t.prototype.clearSelection=function(){var e;null===(e=this._selectionService)||void 0===e||e.clearSelection()},t.prototype.selectAll=function(){var e;null===(e=this._selectionService)||void 0===e||e.selectAll()},t.prototype.selectLines=function(e,t){var r;null===(r=this._selectionService)||void 0===r||r.selectLines(e,t)},t.prototype._keyDown=function(e){if(this._keyDownHandled=!1,this._customKeyEventHandler&&!1===this._customKeyEventHandler(e))return!1;if(!this._compositionHelper.keydown(e))return this.buffer.ybase!==this.buffer.ydisp&&this._bufferService.scrollToBottom(),!1;"Dead"!==e.key&&"AltGraph"!==e.key||(this._unprocessedDeadKey=!0);var t=(0,S.evaluateKeyboardEvent)(e,this.coreService.decPrivateModes.applicationCursorKeys,this.browser.isMac,this.options.macOptionIsMeta);if(this.updateCursorStyle(e),3===t.type||2===t.type){var r=this.rows-1;return this.scrollLines(2===t.type?-r:r),this.cancel(e,!0)}return 1===t.type&&this.selectAll(),!!this._isThirdLevelShift(this.browser,e)||(t.cancel&&this.cancel(e,!0),!t.key||(this._unprocessedDeadKey?(this._unprocessedDeadKey=!1,!0):(t.key!==c.C0.ETX&&t.key!==c.C0.CR||(this.textarea.value=""),this._onKey.fire({key:t.key,domEvent:e}),this._showCursor(),this.coreService.triggerDataEvent(t.key,!0),this.optionsService.options.screenReaderMode?void(this._keyDownHandled=!0):this.cancel(e,!0))))},t.prototype._isThirdLevelShift=function(e,t){var r=e.isMac&&!this.options.macOptionIsMeta&&t.altKey&&!t.ctrlKey&&!t.metaKey||e.isWindows&&t.altKey&&t.ctrlKey&&!t.metaKey||e.isWindows&&t.getModifierState("AltGraph");return"keypress"===t.type?r:r&&(!t.keyCode||t.keyCode>47)},t.prototype._keyUp=function(e){this._customKeyEventHandler&&!1===this._customKeyEventHandler(e)||(function(e){return 16===e.keyCode||17===e.keyCode||18===e.keyCode}(e)||this.focus(),this.updateCursorStyle(e),this._keyPressHandled=!1)},t.prototype._keyPress=function(e){var t;if(this._keyPressHandled=!1,this._keyDownHandled)return!1;if(this._customKeyEventHandler&&!1===this._customKeyEventHandler(e))return!1;if(this.cancel(e),e.charCode)t=e.charCode;else if(null===e.which||void 0===e.which)t=e.keyCode;else{if(0===e.which||0===e.charCode)return!1;t=e.which}return!(!t||(e.altKey||e.ctrlKey||e.metaKey)&&!this._isThirdLevelShift(this.browser,e)||(t=String.fromCharCode(t),this._onKey.fire({key:t,domEvent:e}),this._showCursor(),this.coreService.triggerDataEvent(t,!0),this._keyPressHandled=!0,this._unprocessedDeadKey=!1,0))},t.prototype._inputEvent=function(e){if(e.data&&"insertText"===e.inputType&&!e.composed&&!this.optionsService.options.screenReaderMode){if(this._keyPressHandled)return!1;this._unprocessedDeadKey=!1;var t=e.data;return this.coreService.triggerDataEvent(t,!0),this.cancel(e),!0}return!1},t.prototype.bell=function(){var e;this._soundBell()&&(null===(e=this._soundService)||void 0===e||e.playBellSound()),this._onBell.fire()},t.prototype.resize=function(t,r){t!==this.cols||r!==this.rows?e.prototype.resize.call(this,t,r):this._charSizeService&&!this._charSizeService.hasValidSize&&this._charSizeService.measure()},t.prototype._afterResize=function(e,t){var r,i;null===(r=this._charSizeService)||void 0===r||r.measure(),null===(i=this.viewport)||void 0===i||i.syncScrollArea(!0)},t.prototype.clear=function(){if(0!==this.buffer.ybase||0!==this.buffer.y){this.buffer.lines.set(0,this.buffer.lines.get(this.buffer.ybase+this.buffer.y)),this.buffer.lines.length=1,this.buffer.ydisp=0,this.buffer.ybase=0,this.buffer.y=0;for(var e=1;e<this.rows;e++)this.buffer.lines.push(this.buffer.getBlankLine(b.DEFAULT_ATTR_DATA));this.refresh(0,this.rows-1),this._onScroll.fire({position:this.buffer.ydisp,source:0})}},t.prototype.reset=function(){var t,r;this.options.rows=this.rows,this.options.cols=this.cols;var i=this._customKeyEventHandler;this._setup(),e.prototype.reset.call(this),null===(t=this._selectionService)||void 0===t||t.reset(),this._customKeyEventHandler=i,this.refresh(0,this.rows-1),null===(r=this.viewport)||void 0===r||r.syncScrollArea()},t.prototype.clearTextureAtlas=function(){var e;null===(e=this._renderService)||void 0===e||e.clearTextureAtlas()},t.prototype._reportFocus=function(){var e;(null===(e=this.element)||void 0===e?void 0:e.classList.contains("focus"))?this.coreService.triggerDataEvent(c.C0.ESC+"[I"):this.coreService.triggerDataEvent(c.C0.ESC+"[O")},t.prototype._reportWindowsOptions=function(e){if(this._renderService)switch(e){case l.WindowsOptionsReportType.GET_WIN_SIZE_PIXELS:var t=this._renderService.dimensions.scaledCanvasWidth.toFixed(0),r=this._renderService.dimensions.scaledCanvasHeight.toFixed(0);this.coreService.triggerDataEvent(c.C0.ESC+"[4;"+r+";"+t+"t");break;case l.WindowsOptionsReportType.GET_CELL_SIZE_PIXELS:var i=this._renderService.dimensions.scaledCellWidth.toFixed(0),n=this._renderService.dimensions.scaledCellHeight.toFixed(0);this.coreService.triggerDataEvent(c.C0.ESC+"[6;"+n+";"+i+"t")}},t.prototype.cancel=function(e,t){if(this.options.cancelEvents||t)return e.preventDefault(),e.stopPropagation(),!1},t.prototype._visualBell=function(){return!1},t.prototype._soundBell=function(){return"sound"===this.options.bellStyle},t}(R.CoreTerminal);t.Terminal=P},9924:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.TimeBasedDebouncer=void 0;var r=function(){function e(e,t){void 0===t&&(t=1e3),this._renderCallback=e,this._debounceThresholdMS=t,this._lastRefreshMs=0,this._additionalRefreshRequested=!1}return e.prototype.dispose=function(){this._refreshTimeoutID&&clearTimeout(this._refreshTimeoutID)},e.prototype.refresh=function(e,t,r){var i=this;this._rowCount=r,e=void 0!==e?e:0,t=void 0!==t?t:this._rowCount-1,this._rowStart=void 0!==this._rowStart?Math.min(this._rowStart,e):e,this._rowEnd=void 0!==this._rowEnd?Math.max(this._rowEnd,t):t;var n=Date.now();if(n-this._lastRefreshMs>=this._debounceThresholdMS)this._lastRefreshMs=n,this._innerRefresh();else if(!this._additionalRefreshRequested){var o=n-this._lastRefreshMs,s=this._debounceThresholdMS-o;this._additionalRefreshRequested=!0,this._refreshTimeoutID=window.setTimeout((function(){i._lastRefreshMs=Date.now(),i._innerRefresh(),i._additionalRefreshRequested=!1,i._refreshTimeoutID=void 0}),s)}},e.prototype._innerRefresh=function(){if(void 0!==this._rowStart&&void 0!==this._rowEnd&&void 0!==this._rowCount){var e=Math.max(this._rowStart,0),t=Math.min(this._rowEnd,this._rowCount-1);this._rowStart=void 0,this._rowEnd=void 0,this._renderCallback(e,t)}},e}();t.TimeBasedDebouncer=r},1680:function(e,t,r){var i,n=this&&this.__extends||(i=function(e,t){return i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])},i(e,t)},function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function r(){this.constructor=e}i(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)}),o=this&&this.__decorate||function(e,t,r,i){var n,o=arguments.length,s=o<3?t:null===i?i=Object.getOwnPropertyDescriptor(t,r):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)s=Reflect.decorate(e,t,r,i);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(s=(o<3?n(s):o>3?n(t,r,s):n(t,r))||s);return o>3&&s&&Object.defineProperty(t,r,s),s},s=this&&this.__param||function(e,t){return function(r,i){t(r,i,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.Viewport=void 0;var a=r(844),c=r(3656),l=r(4725),h=r(2585),u=function(e){function t(t,r,i,n,o,s,a,l){var h=e.call(this)||this;return h._scrollLines=t,h._viewportElement=r,h._scrollArea=i,h._element=n,h._bufferService=o,h._optionsService=s,h._charSizeService=a,h._renderService=l,h.scrollBarWidth=0,h._currentRowHeight=0,h._currentScaledCellHeight=0,h._lastRecordedBufferLength=0,h._lastRecordedViewportHeight=0,h._lastRecordedBufferHeight=0,h._lastTouchY=0,h._lastScrollTop=0,h._lastHadScrollBar=!1,h._wheelPartialScroll=0,h._refreshAnimationFrame=null,h._ignoreNextScrollEvent=!1,h.scrollBarWidth=h._viewportElement.offsetWidth-h._scrollArea.offsetWidth||15,h._lastHadScrollBar=!0,h.register((0,c.addDisposableDomListener)(h._viewportElement,"scroll",h._onScroll.bind(h))),h._activeBuffer=h._bufferService.buffer,h.register(h._bufferService.buffers.onBufferActivate((function(e){return h._activeBuffer=e.activeBuffer}))),h._renderDimensions=h._renderService.dimensions,h.register(h._renderService.onDimensionsChange((function(e){return h._renderDimensions=e}))),setTimeout((function(){return h.syncScrollArea()}),0),h}return n(t,e),t.prototype.onThemeChange=function(e){this._viewportElement.style.backgroundColor=e.background.css},t.prototype._refresh=function(e){var t=this;if(e)return this._innerRefresh(),void(null!==this._refreshAnimationFrame&&cancelAnimationFrame(this._refreshAnimationFrame));null===this._refreshAnimationFrame&&(this._refreshAnimationFrame=requestAnimationFrame((function(){return t._innerRefresh()})))},t.prototype._innerRefresh=function(){if(this._charSizeService.height>0){this._currentRowHeight=this._renderService.dimensions.scaledCellHeight/window.devicePixelRatio,this._currentScaledCellHeight=this._renderService.dimensions.scaledCellHeight,this._lastRecordedViewportHeight=this._viewportElement.offsetHeight;var e=Math.round(this._currentRowHeight*this._lastRecordedBufferLength)+(this._lastRecordedViewportHeight-this._renderService.dimensions.canvasHeight);this._lastRecordedBufferHeight!==e&&(this._lastRecordedBufferHeight=e,this._scrollArea.style.height=this._lastRecordedBufferHeight+"px")}var t=this._bufferService.buffer.ydisp*this._currentRowHeight;this._viewportElement.scrollTop!==t&&(this._ignoreNextScrollEvent=!0,this._viewportElement.scrollTop=t),0===this._optionsService.options.scrollback?this.scrollBarWidth=0:this.scrollBarWidth=this._viewportElement.offsetWidth-this._scrollArea.offsetWidth||15,this._lastHadScrollBar=this.scrollBarWidth>0;var r=window.getComputedStyle(this._element),i=parseInt(r.paddingLeft)+parseInt(r.paddingRight);this._viewportElement.style.width=(this._renderService.dimensions.actualCellWidth*this._bufferService.cols+this.scrollBarWidth+(this._lastHadScrollBar?i:0)).toString()+"px",this._refreshAnimationFrame=null},t.prototype.syncScrollArea=function(e){if(void 0===e&&(e=!1),this._lastRecordedBufferLength!==this._bufferService.buffer.lines.length)return this._lastRecordedBufferLength=this._bufferService.buffer.lines.length,void this._refresh(e);this._lastRecordedViewportHeight===this._renderService.dimensions.canvasHeight&&this._lastScrollTop===this._activeBuffer.ydisp*this._currentRowHeight&&this._renderDimensions.scaledCellHeight===this._currentScaledCellHeight?this._lastHadScrollBar!==this._optionsService.options.scrollback>0&&this._refresh(e):this._refresh(e)},t.prototype._onScroll=function(e){if(this._lastScrollTop=this._viewportElement.scrollTop,this._viewportElement.offsetParent){if(this._ignoreNextScrollEvent)return this._ignoreNextScrollEvent=!1,void this._scrollLines(0);var t=Math.round(this._lastScrollTop/this._currentRowHeight)-this._bufferService.buffer.ydisp;this._scrollLines(t)}},t.prototype._bubbleScroll=function(e,t){var r=this._viewportElement.scrollTop+this._lastRecordedViewportHeight;return!(t<0&&0!==this._viewportElement.scrollTop||t>0&&r<this._lastRecordedBufferHeight)||(e.cancelable&&e.preventDefault(),!1)},t.prototype.onWheel=function(e){var t=this._getPixelsScrolled(e);return 0!==t&&(this._viewportElement.scrollTop+=t,this._bubbleScroll(e,t))},t.prototype._getPixelsScrolled=function(e){if(0===e.deltaY||e.shiftKey)return 0;var t=this._applyScrollModifier(e.deltaY,e);return e.deltaMode===WheelEvent.DOM_DELTA_LINE?t*=this._currentRowHeight:e.deltaMode===WheelEvent.DOM_DELTA_PAGE&&(t*=this._currentRowHeight*this._bufferService.rows),t},t.prototype.getLinesScrolled=function(e){if(0===e.deltaY||e.shiftKey)return 0;var t=this._applyScrollModifier(e.deltaY,e);return e.deltaMode===WheelEvent.DOM_DELTA_PIXEL?(t/=this._currentRowHeight+0,this._wheelPartialScroll+=t,t=Math.floor(Math.abs(this._wheelPartialScroll))*(this._wheelPartialScroll>0?1:-1),this._wheelPartialScroll%=1):e.deltaMode===WheelEvent.DOM_DELTA_PAGE&&(t*=this._bufferService.rows),t},t.prototype._applyScrollModifier=function(e,t){var r=this._optionsService.options.fastScrollModifier;return"alt"===r&&t.altKey||"ctrl"===r&&t.ctrlKey||"shift"===r&&t.shiftKey?e*this._optionsService.options.fastScrollSensitivity*this._optionsService.options.scrollSensitivity:e*this._optionsService.options.scrollSensitivity},t.prototype.onTouchStart=function(e){this._lastTouchY=e.touches[0].pageY},t.prototype.onTouchMove=function(e){var t=this._lastTouchY-e.touches[0].pageY;return this._lastTouchY=e.touches[0].pageY,0!==t&&(this._viewportElement.scrollTop+=t,this._bubbleScroll(e,t))},o([s(4,h.IBufferService),s(5,h.IOptionsService),s(6,l.ICharSizeService),s(7,l.IRenderService)],t)}(a.Disposable);t.Viewport=u},2950:function(e,t,r){var i=this&&this.__decorate||function(e,t,r,i){var n,o=arguments.length,s=o<3?t:null===i?i=Object.getOwnPropertyDescriptor(t,r):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)s=Reflect.decorate(e,t,r,i);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(s=(o<3?n(s):o>3?n(t,r,s):n(t,r))||s);return o>3&&s&&Object.defineProperty(t,r,s),s},n=this&&this.__param||function(e,t){return function(r,i){t(r,i,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.CompositionHelper=void 0;var o=r(4725),s=r(2585),a=function(){function e(e,t,r,i,n,o){this._textarea=e,this._compositionView=t,this._bufferService=r,this._optionsService=i,this._coreService=n,this._renderService=o,this._isComposing=!1,this._isSendingComposition=!1,this._compositionPosition={start:0,end:0},this._dataAlreadySent=""}return Object.defineProperty(e.prototype,"isComposing",{get:function(){return this._isComposing},enumerable:!1,configurable:!0}),e.prototype.compositionstart=function(){this._isComposing=!0,this._compositionPosition.start=this._textarea.value.length,this._compositionView.textContent="",this._dataAlreadySent="",this._compositionView.classList.add("active")},e.prototype.compositionupdate=function(e){var t=this;this._compositionView.textContent=e.data,this.updateCompositionElements(),setTimeout((function(){t._compositionPosition.end=t._textarea.value.length}),0)},e.prototype.compositionend=function(){this._finalizeComposition(!0)},e.prototype.keydown=function(e){if(this._isComposing||this._isSendingComposition){if(229===e.keyCode)return!1;if(16===e.keyCode||17===e.keyCode||18===e.keyCode)return!1;this._finalizeComposition(!1)}return 229!==e.keyCode||(this._handleAnyTextareaChanges(),!1)},e.prototype._finalizeComposition=function(e){var t=this;if(this._compositionView.classList.remove("active"),this._isComposing=!1,e){var r={start:this._compositionPosition.start,end:this._compositionPosition.end};this._isSendingComposition=!0,setTimeout((function(){if(t._isSendingComposition){t._isSendingComposition=!1;var e;r.start+=t._dataAlreadySent.length,(e=t._isComposing?t._textarea.value.substring(r.start,r.end):t._textarea.value.substring(r.start)).length>0&&t._coreService.triggerDataEvent(e,!0)}}),0)}else{this._isSendingComposition=!1;var i=this._textarea.value.substring(this._compositionPosition.start,this._compositionPosition.end);this._coreService.triggerDataEvent(i,!0)}},e.prototype._handleAnyTextareaChanges=function(){var e=this,t=this._textarea.value;setTimeout((function(){if(!e._isComposing){var r=e._textarea.value.replace(t,"");r.length>0&&(e._dataAlreadySent=r,e._coreService.triggerDataEvent(r,!0))}}),0)},e.prototype.updateCompositionElements=function(e){var t=this;if(this._isComposing){if(this._bufferService.buffer.isCursorInViewport){var r=Math.min(this._bufferService.buffer.x,this._bufferService.cols-1),i=this._renderService.dimensions.actualCellHeight,n=this._bufferService.buffer.y*this._renderService.dimensions.actualCellHeight,o=r*this._renderService.dimensions.actualCellWidth;this._compositionView.style.left=o+"px",this._compositionView.style.top=n+"px",this._compositionView.style.height=i+"px",this._compositionView.style.lineHeight=i+"px",this._compositionView.style.fontFamily=this._optionsService.options.fontFamily,this._compositionView.style.fontSize=this._optionsService.options.fontSize+"px";var s=this._compositionView.getBoundingClientRect();this._textarea.style.left=o+"px",this._textarea.style.top=n+"px",this._textarea.style.width=Math.max(s.width,1)+"px",this._textarea.style.height=Math.max(s.height,1)+"px",this._textarea.style.lineHeight=s.height+"px"}e||setTimeout((function(){return t.updateCompositionElements(!0)}),0)}},i([n(2,s.IBufferService),n(3,s.IOptionsService),n(4,s.ICoreService),n(5,o.IRenderService)],e)}();t.CompositionHelper=a},9806:(e,t)=>{function r(e,t){var r=t.getBoundingClientRect();return[e.clientX-r.left,e.clientY-r.top]}Object.defineProperty(t,"__esModule",{value:!0}),t.getRawByteCoords=t.getCoords=t.getCoordsRelativeToElement=void 0,t.getCoordsRelativeToElement=r,t.getCoords=function(e,t,i,n,o,s,a,c){if(o){var l=r(e,t);if(l)return l[0]=Math.ceil((l[0]+(c?s/2:0))/s),l[1]=Math.ceil(l[1]/a),l[0]=Math.min(Math.max(l[0],1),i+(c?1:0)),l[1]=Math.min(Math.max(l[1],1),n),l}},t.getRawByteCoords=function(e){if(e)return{x:e[0]+32,y:e[1]+32}}},9504:(e,t,r)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.moveToCellSequence=void 0;var i=r(2584);function n(e,t,r,i){var n=e-o(r,e),a=t-o(r,t),h=Math.abs(n-a)-function(e,t,r){for(var i=0,n=e-o(r,e),a=t-o(r,t),c=0;c<Math.abs(n-a);c++){var l="A"===s(e,t)?-1:1,h=r.buffer.lines.get(n+l*c);(null==h?void 0:h.isWrapped)&&i++}return i}(e,t,r);return l(h,c(s(e,t),i))}function o(e,t){for(var r=0,i=e.buffer.lines.get(t),n=null==i?void 0:i.isWrapped;n&&t>=0&&t<e.rows;)r++,n=null==(i=e.buffer.lines.get(--t))?void 0:i.isWrapped;return r}function s(e,t){return e>t?"A":"B"}function a(e,t,r,i,n,o){for(var s=e,a=t,c="";s!==r||a!==i;)s+=n?1:-1,n&&s>o.cols-1?(c+=o.buffer.translateBufferLineToString(a,!1,e,s),s=0,e=0,a++):!n&&s<0&&(c+=o.buffer.translateBufferLineToString(a,!1,0,e+1),e=s=o.cols-1,a--);return c+o.buffer.translateBufferLineToString(a,!1,e,s)}function c(e,t){var r=t?"O":"[";return i.C0.ESC+r+e}function l(e,t){e=Math.floor(e);for(var r="",i=0;i<e;i++)r+=t;return r}t.moveToCellSequence=function(e,t,r,i){var s,h=r.buffer.x,u=r.buffer.y;if(!r.buffer.hasScrollback)return function(e,t,r,i,s,h){return 0===n(t,i,s,h).length?"":l(a(e,t,e,t-o(s,t),!1,s).length,c("D",h))}(h,u,0,t,r,i)+n(u,t,r,i)+function(e,t,r,i,s,h){var u;u=n(t,i,s,h).length>0?i-o(s,i):t;var f=i,_=function(e,t,r,i,s,a){var c;return c=n(r,i,s,a).length>0?i-o(s,i):t,e<r&&c<=i||e>=r&&c<i?"C":"D"}(e,t,r,i,s,h);return l(a(e,u,r,f,"C"===_,s).length,c(_,h))}(h,u,e,t,r,i);if(u===t)return s=h>e?"D":"C",l(Math.abs(h-e),c(s,i));s=u>t?"D":"C";var f=Math.abs(u-t);return l(function(e,t){return t.cols-e}(u>t?e:h,r)+(f-1)*r.cols+1+((u>t?h:e)-1),c(s,i))}},1546:(e,t,r)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.BaseRenderLayer=void 0;var i=r(643),n=r(8803),o=r(1420),s=r(3734),a=r(1752),c=r(4774),l=r(9631),h=r(8978),u=function(){function e(e,t,r,i,n,o,s,a){this._container=e,this._alpha=i,this._colors=n,this._rendererId=o,this._bufferService=s,this._optionsService=a,this._scaledCharWidth=0,this._scaledCharHeight=0,this._scaledCellWidth=0,this._scaledCellHeight=0,this._scaledCharLeft=0,this._scaledCharTop=0,this._currentGlyphIdentifier={chars:"",code:0,bg:0,fg:0,bold:!1,dim:!1,italic:!1},this._canvas=document.createElement("canvas"),this._canvas.classList.add("xterm-"+t+"-layer"),this._canvas.style.zIndex=r.toString(),this._initCanvas(),this._container.appendChild(this._canvas)}return e.prototype.dispose=function(){var e;(0,l.removeElementFromParent)(this._canvas),null===(e=this._charAtlas)||void 0===e||e.dispose()},e.prototype._initCanvas=function(){this._ctx=(0,a.throwIfFalsy)(this._canvas.getContext("2d",{alpha:this._alpha})),this._alpha||this._clearAll()},e.prototype.onOptionsChanged=function(){},e.prototype.onBlur=function(){},e.prototype.onFocus=function(){},e.prototype.onCursorMove=function(){},e.prototype.onGridChanged=function(e,t){},e.prototype.onSelectionChanged=function(e,t,r){void 0===r&&(r=!1)},e.prototype.setColors=function(e){this._refreshCharAtlas(e)},e.prototype._setTransparency=function(e){if(e!==this._alpha){var t=this._canvas;this._alpha=e,this._canvas=this._canvas.cloneNode(),this._initCanvas(),this._container.replaceChild(this._canvas,t),this._refreshCharAtlas(this._colors),this.onGridChanged(0,this._bufferService.rows-1)}},e.prototype._refreshCharAtlas=function(e){this._scaledCharWidth<=0&&this._scaledCharHeight<=0||(this._charAtlas=(0,o.acquireCharAtlas)(this._optionsService.options,this._rendererId,e,this._scaledCharWidth,this._scaledCharHeight),this._charAtlas.warmUp())},e.prototype.resize=function(e){this._scaledCellWidth=e.scaledCellWidth,this._scaledCellHeight=e.scaledCellHeight,this._scaledCharWidth=e.scaledCharWidth,this._scaledCharHeight=e.scaledCharHeight,this._scaledCharLeft=e.scaledCharLeft,this._scaledCharTop=e.scaledCharTop,this._canvas.width=e.scaledCanvasWidth,this._canvas.height=e.scaledCanvasHeight,this._canvas.style.width=e.canvasWidth+"px",this._canvas.style.height=e.canvasHeight+"px",this._alpha||this._clearAll(),this._refreshCharAtlas(this._colors)},e.prototype.clearTextureAtlas=function(){var e;null===(e=this._charAtlas)||void 0===e||e.clear()},e.prototype._fillCells=function(e,t,r,i){this._ctx.fillRect(e*this._scaledCellWidth,t*this._scaledCellHeight,r*this._scaledCellWidth,i*this._scaledCellHeight)},e.prototype._fillMiddleLineAtCells=function(e,t,r){void 0===r&&(r=1);var i=Math.ceil(.5*this._scaledCellHeight);this._ctx.fillRect(e*this._scaledCellWidth,(t+1)*this._scaledCellHeight-i-window.devicePixelRatio,r*this._scaledCellWidth,window.devicePixelRatio)},e.prototype._fillBottomLineAtCells=function(e,t,r){void 0===r&&(r=1),this._ctx.fillRect(e*this._scaledCellWidth,(t+1)*this._scaledCellHeight-window.devicePixelRatio-1,r*this._scaledCellWidth,window.devicePixelRatio)},e.prototype._fillLeftLineAtCell=function(e,t,r){this._ctx.fillRect(e*this._scaledCellWidth,t*this._scaledCellHeight,window.devicePixelRatio*r,this._scaledCellHeight)},e.prototype._strokeRectAtCell=function(e,t,r,i){this._ctx.lineWidth=window.devicePixelRatio,this._ctx.strokeRect(e*this._scaledCellWidth+window.devicePixelRatio/2,t*this._scaledCellHeight+window.devicePixelRatio/2,r*this._scaledCellWidth-window.devicePixelRatio,i*this._scaledCellHeight-window.devicePixelRatio)},e.prototype._clearAll=function(){this._alpha?this._ctx.clearRect(0,0,this._canvas.width,this._canvas.height):(this._ctx.fillStyle=this._colors.background.css,this._ctx.fillRect(0,0,this._canvas.width,this._canvas.height))},e.prototype._clearCells=function(e,t,r,i){this._alpha?this._ctx.clearRect(e*this._scaledCellWidth,t*this._scaledCellHeight,r*this._scaledCellWidth,i*this._scaledCellHeight):(this._ctx.fillStyle=this._colors.background.css,this._ctx.fillRect(e*this._scaledCellWidth,t*this._scaledCellHeight,r*this._scaledCellWidth,i*this._scaledCellHeight))},e.prototype._fillCharTrueColor=function(e,t,r){this._ctx.font=this._getFont(!1,!1),this._ctx.textBaseline=n.TEXT_BASELINE,this._clipRow(r);var i=!1;!1!==this._optionsService.options.customGlyphs&&(i=(0,h.tryDrawCustomChar)(this._ctx,e.getChars(),t*this._scaledCellWidth,r*this._scaledCellHeight,this._scaledCellWidth,this._scaledCellHeight)),i||this._ctx.fillText(e.getChars(),t*this._scaledCellWidth+this._scaledCharLeft,r*this._scaledCellHeight+this._scaledCharTop+this._scaledCharHeight)},e.prototype._drawChars=function(e,t,r){var o,s,a,c=this._getContrastColor(e);c||e.isFgRGB()||e.isBgRGB()?this._drawUncachedChars(e,t,r,c):(e.isInverse()?(s=e.isBgDefault()?n.INVERTED_DEFAULT_COLOR:e.getBgColor(),a=e.isFgDefault()?n.INVERTED_DEFAULT_COLOR:e.getFgColor()):(a=e.isBgDefault()?i.DEFAULT_COLOR:e.getBgColor(),s=e.isFgDefault()?i.DEFAULT_COLOR:e.getFgColor()),s+=this._optionsService.options.drawBoldTextInBrightColors&&e.isBold()&&s<8?8:0,this._currentGlyphIdentifier.chars=e.getChars()||i.WHITESPACE_CELL_CHAR,this._currentGlyphIdentifier.code=e.getCode()||i.WHITESPACE_CELL_CODE,this._currentGlyphIdentifier.bg=a,this._currentGlyphIdentifier.fg=s,this._currentGlyphIdentifier.bold=!!e.isBold(),this._currentGlyphIdentifier.dim=!!e.isDim(),this._currentGlyphIdentifier.italic=!!e.isItalic(),(null===(o=this._charAtlas)||void 0===o?void 0:o.draw(this._ctx,this._currentGlyphIdentifier,t*this._scaledCellWidth+this._scaledCharLeft,r*this._scaledCellHeight+this._scaledCharTop))||this._drawUncachedChars(e,t,r))},e.prototype._drawUncachedChars=function(e,t,r,i){if(this._ctx.save(),this._ctx.font=this._getFont(!!e.isBold(),!!e.isItalic()),this._ctx.textBaseline=n.TEXT_BASELINE,e.isInverse())if(i)this._ctx.fillStyle=i.css;else if(e.isBgDefault())this._ctx.fillStyle=c.color.opaque(this._colors.background).css;else if(e.isBgRGB())this._ctx.fillStyle="rgb("+s.AttributeData.toColorRGB(e.getBgColor()).join(",")+")";else{var o=e.getBgColor();this._optionsService.options.drawBoldTextInBrightColors&&e.isBold()&&o<8&&(o+=8),this._ctx.fillStyle=this._colors.ansi[o].css}else if(i)this._ctx.fillStyle=i.css;else if(e.isFgDefault())this._ctx.fillStyle=this._colors.foreground.css;else if(e.isFgRGB())this._ctx.fillStyle="rgb("+s.AttributeData.toColorRGB(e.getFgColor()).join(",")+")";else{var a=e.getFgColor();this._optionsService.options.drawBoldTextInBrightColors&&e.isBold()&&a<8&&(a+=8),this._ctx.fillStyle=this._colors.ansi[a].css}this._clipRow(r),e.isDim()&&(this._ctx.globalAlpha=n.DIM_OPACITY);var l=!1;!1!==this._optionsService.options.customGlyphs&&(l=(0,h.tryDrawCustomChar)(this._ctx,e.getChars(),t*this._scaledCellWidth,r*this._scaledCellHeight,this._scaledCellWidth,this._scaledCellHeight)),l||this._ctx.fillText(e.getChars(),t*this._scaledCellWidth+this._scaledCharLeft,r*this._scaledCellHeight+this._scaledCharTop+this._scaledCharHeight),this._ctx.restore()},e.prototype._clipRow=function(e){this._ctx.beginPath(),this._ctx.rect(0,e*this._scaledCellHeight,this._bufferService.cols*this._scaledCellWidth,this._scaledCellHeight),this._ctx.clip()},e.prototype._getFont=function(e,t){return(t?"italic":"")+" "+(e?this._optionsService.options.fontWeightBold:this._optionsService.options.fontWeight)+" "+this._optionsService.options.fontSize*window.devicePixelRatio+"px "+this._optionsService.options.fontFamily},e.prototype._getContrastColor=function(e){if(1!==this._optionsService.options.minimumContrastRatio){var t=this._colors.contrastCache.getColor(e.bg,e.fg);if(void 0!==t)return t||void 0;var r=e.getFgColor(),i=e.getFgColorMode(),n=e.getBgColor(),o=e.getBgColorMode(),s=!!e.isInverse(),a=!!e.isInverse();if(s){var l=r;r=n,n=l;var h=i;i=o,o=h}var u=this._resolveBackgroundRgba(o,n,s),f=this._resolveForegroundRgba(i,r,s,a),_=c.rgba.ensureContrastRatio(u,f,this._optionsService.options.minimumContrastRatio);if(_){var d={css:c.channels.toCss(_>>24&255,_>>16&255,_>>8&255),rgba:_};return this._colors.contrastCache.setColor(e.bg,e.fg,d),d}this._colors.contrastCache.setColor(e.bg,e.fg,null)}},e.prototype._resolveBackgroundRgba=function(e,t,r){switch(e){case 16777216:case 33554432:return this._colors.ansi[t].rgba;case 50331648:return t<<8;default:return r?this._colors.foreground.rgba:this._colors.background.rgba}},e.prototype._resolveForegroundRgba=function(e,t,r,i){switch(e){case 16777216:case 33554432:return this._optionsService.options.drawBoldTextInBrightColors&&i&&t<8&&(t+=8),this._colors.ansi[t].rgba;case 50331648:return t<<8;default:return r?this._colors.background.rgba:this._colors.foreground.rgba}},e}();t.BaseRenderLayer=u},2512:function(e,t,r){var i,n=this&&this.__extends||(i=function(e,t){return i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])},i(e,t)},function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function r(){this.constructor=e}i(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)}),o=this&&this.__decorate||function(e,t,r,i){var n,o=arguments.length,s=o<3?t:null===i?i=Object.getOwnPropertyDescriptor(t,r):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)s=Reflect.decorate(e,t,r,i);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(s=(o<3?n(s):o>3?n(t,r,s):n(t,r))||s);return o>3&&s&&Object.defineProperty(t,r,s),s},s=this&&this.__param||function(e,t){return function(r,i){t(r,i,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.CursorRenderLayer=void 0;var a=r(1546),c=r(511),l=r(2585),h=r(4725),u=600,f=function(e){function t(t,r,i,n,o,s,a,l,h){var u=e.call(this,t,"cursor",r,!0,i,n,s,a)||this;return u._onRequestRedraw=o,u._coreService=l,u._coreBrowserService=h,u._cell=new c.CellData,u._state={x:0,y:0,isFocused:!1,style:"",width:0},u._cursorRenderers={bar:u._renderBarCursor.bind(u),block:u._renderBlockCursor.bind(u),underline:u._renderUnderlineCursor.bind(u)},u}return n(t,e),t.prototype.dispose=function(){this._cursorBlinkStateManager&&(this._cursorBlinkStateManager.dispose(),this._cursorBlinkStateManager=void 0),e.prototype.dispose.call(this)},t.prototype.resize=function(t){e.prototype.resize.call(this,t),this._state={x:0,y:0,isFocused:!1,style:"",width:0}},t.prototype.reset=function(){var e;this._clearCursor(),null===(e=this._cursorBlinkStateManager)||void 0===e||e.restartBlinkAnimation(),this.onOptionsChanged()},t.prototype.onBlur=function(){var e;null===(e=this._cursorBlinkStateManager)||void 0===e||e.pause(),this._onRequestRedraw.fire({start:this._bufferService.buffer.y,end:this._bufferService.buffer.y})},t.prototype.onFocus=function(){var e;null===(e=this._cursorBlinkStateManager)||void 0===e||e.resume(),this._onRequestRedraw.fire({start:this._bufferService.buffer.y,end:this._bufferService.buffer.y})},t.prototype.onOptionsChanged=function(){var e,t=this;this._optionsService.options.cursorBlink?this._cursorBlinkStateManager||(this._cursorBlinkStateManager=new _(this._coreBrowserService.isFocused,(function(){t._render(!0)}))):(null===(e=this._cursorBlinkStateManager)||void 0===e||e.dispose(),this._cursorBlinkStateManager=void 0),this._onRequestRedraw.fire({start:this._bufferService.buffer.y,end:this._bufferService.buffer.y})},t.prototype.onCursorMove=function(){var e;null===(e=this._cursorBlinkStateManager)||void 0===e||e.restartBlinkAnimation()},t.prototype.onGridChanged=function(e,t){!this._cursorBlinkStateManager||this._cursorBlinkStateManager.isPaused?this._render(!1):this._cursorBlinkStateManager.restartBlinkAnimation()},t.prototype._render=function(e){if(this._coreService.isCursorInitialized&&!this._coreService.isCursorHidden){var t=this._bufferService.buffer.ybase+this._bufferService.buffer.y,r=t-this._bufferService.buffer.ydisp;if(r<0||r>=this._bufferService.rows)this._clearCursor();else{var i=Math.min(this._bufferService.buffer.x,this._bufferService.cols-1);if(this._bufferService.buffer.lines.get(t).loadCell(i,this._cell),void 0!==this._cell.content){if(!this._coreBrowserService.isFocused){this._clearCursor(),this._ctx.save(),this._ctx.fillStyle=this._colors.cursor.css;var n=this._optionsService.options.cursorStyle;return n&&"block"!==n?this._cursorRenderers[n](i,r,this._cell):this._renderBlurCursor(i,r,this._cell),this._ctx.restore(),this._state.x=i,this._state.y=r,this._state.isFocused=!1,this._state.style=n,void(this._state.width=this._cell.getWidth())}if(!this._cursorBlinkStateManager||this._cursorBlinkStateManager.isCursorVisible){if(this._state){if(this._state.x===i&&this._state.y===r&&this._state.isFocused===this._coreBrowserService.isFocused&&this._state.style===this._optionsService.options.cursorStyle&&this._state.width===this._cell.getWidth())return;this._clearCursor()}this._ctx.save(),this._cursorRenderers[this._optionsService.options.cursorStyle||"block"](i,r,this._cell),this._ctx.restore(),this._state.x=i,this._state.y=r,this._state.isFocused=!1,this._state.style=this._optionsService.options.cursorStyle,this._state.width=this._cell.getWidth()}else this._clearCursor()}}}else this._clearCursor()},t.prototype._clearCursor=function(){this._state&&(window.devicePixelRatio<1?this._clearAll():this._clearCells(this._state.x,this._state.y,this._state.width,1),this._state={x:0,y:0,isFocused:!1,style:"",width:0})},t.prototype._renderBarCursor=function(e,t,r){this._ctx.save(),this._ctx.fillStyle=this._colors.cursor.css,this._fillLeftLineAtCell(e,t,this._optionsService.options.cursorWidth),this._ctx.restore()},t.prototype._renderBlockCursor=function(e,t,r){this._ctx.save(),this._ctx.fillStyle=this._colors.cursor.css,this._fillCells(e,t,r.getWidth(),1),this._ctx.fillStyle=this._colors.cursorAccent.css,this._fillCharTrueColor(r,e,t),this._ctx.restore()},t.prototype._renderUnderlineCursor=function(e,t,r){this._ctx.save(),this._ctx.fillStyle=this._colors.cursor.css,this._fillBottomLineAtCells(e,t),this._ctx.restore()},t.prototype._renderBlurCursor=function(e,t,r){this._ctx.save(),this._ctx.strokeStyle=this._colors.cursor.css,this._strokeRectAtCell(e,t,r.getWidth(),1),this._ctx.restore()},o([s(5,l.IBufferService),s(6,l.IOptionsService),s(7,l.ICoreService),s(8,h.ICoreBrowserService)],t)}(a.BaseRenderLayer);t.CursorRenderLayer=f;var _=function(){function e(e,t){this._renderCallback=t,this.isCursorVisible=!0,e&&this._restartInterval()}return Object.defineProperty(e.prototype,"isPaused",{get:function(){return!(this._blinkStartTimeout||this._blinkInterval)},enumerable:!1,configurable:!0}),e.prototype.dispose=function(){this._blinkInterval&&(window.clearInterval(this._blinkInterval),this._blinkInterval=void 0),this._blinkStartTimeout&&(window.clearTimeout(this._blinkStartTimeout),this._blinkStartTimeout=void 0),this._animationFrame&&(window.cancelAnimationFrame(this._animationFrame),this._animationFrame=void 0)},e.prototype.restartBlinkAnimation=function(){var e=this;this.isPaused||(this._animationTimeRestarted=Date.now(),this.isCursorVisible=!0,this._animationFrame||(this._animationFrame=window.requestAnimationFrame((function(){e._renderCallback(),e._animationFrame=void 0}))))},e.prototype._restartInterval=function(e){var t=this;void 0===e&&(e=u),this._blinkInterval&&(window.clearInterval(this._blinkInterval),this._blinkInterval=void 0),this._blinkStartTimeout=window.setTimeout((function(){if(t._animationTimeRestarted){var e=u-(Date.now()-t._animationTimeRestarted);if(t._animationTimeRestarted=void 0,e>0)return void t._restartInterval(e)}t.isCursorVisible=!1,t._animationFrame=window.requestAnimationFrame((function(){t._renderCallback(),t._animationFrame=void 0})),t._blinkInterval=window.setInterval((function(){if(t._animationTimeRestarted){var e=u-(Date.now()-t._animationTimeRestarted);return t._animationTimeRestarted=void 0,void t._restartInterval(e)}t.isCursorVisible=!t.isCursorVisible,t._animationFrame=window.requestAnimationFrame((function(){t._renderCallback(),t._animationFrame=void 0}))}),u)}),e)},e.prototype.pause=function(){this.isCursorVisible=!0,this._blinkInterval&&(window.clearInterval(this._blinkInterval),this._blinkInterval=void 0),this._blinkStartTimeout&&(window.clearTimeout(this._blinkStartTimeout),this._blinkStartTimeout=void 0),this._animationFrame&&(window.cancelAnimationFrame(this._animationFrame),this._animationFrame=void 0)},e.prototype.resume=function(){this.pause(),this._animationTimeRestarted=void 0,this._restartInterval(),this.restartBlinkAnimation()},e}()},8978:(e,t,r)=>{var i,n,o,s,a,c,l,h,u,f,_,d,p,v,g,y,m,S,C,b,w,L,E,x,M,k,A,R,T,B,O,D,P,I,H,F,j,W,U,q,N,z,K,G,V,X,Y,Z,J,$,Q,ee,te,re,ie,ne,oe,se,ae,ce,le,he,ue,fe,_e,de,pe,ve,ge,ye,me,Se,Ce,be,we,Le,Ee,xe,Me,ke,Ae,Re,Te,Be,Oe,De,Pe,Ie,He,Fe,je,We,Ue,qe,Ne,ze,Ke,Ge,Ve,Xe,Ye,Ze,Je,$e,Qe,et,tt,rt,it,nt,ot,st,at,ct,lt,ht,ut,ft,_t,dt,pt,vt,gt,yt,mt,St,Ct,bt;Object.defineProperty(t,"__esModule",{value:!0}),t.tryDrawCustomChar=t.boxDrawingDefinitions=t.blockElementDefinitions=void 0;var wt=r(1752);t.blockElementDefinitions={"▀":[{x:0,y:0,w:8,h:4}],"▁":[{x:0,y:7,w:8,h:1}],"▂":[{x:0,y:6,w:8,h:2}],"▃":[{x:0,y:5,w:8,h:3}],"▄":[{x:0,y:4,w:8,h:4}],"▅":[{x:0,y:3,w:8,h:5}],"▆":[{x:0,y:2,w:8,h:6}],"▇":[{x:0,y:1,w:8,h:7}],"█":[{x:0,y:0,w:8,h:8}],"▉":[{x:0,y:0,w:7,h:8}],"▊":[{x:0,y:0,w:6,h:8}],"▋":[{x:0,y:0,w:5,h:8}],"▌":[{x:0,y:0,w:4,h:8}],"▍":[{x:0,y:0,w:3,h:8}],"▎":[{x:0,y:0,w:2,h:8}],"▏":[{x:0,y:0,w:1,h:8}],"▐":[{x:4,y:0,w:4,h:8}],"▔":[{x:0,y:0,w:9,h:1}],"▕":[{x:7,y:0,w:1,h:8}],"▖":[{x:0,y:4,w:4,h:4}],"▗":[{x:4,y:4,w:4,h:4}],"▘":[{x:0,y:0,w:4,h:4}],"▙":[{x:0,y:0,w:4,h:8},{x:0,y:4,w:8,h:4}],"▚":[{x:0,y:0,w:4,h:4},{x:4,y:4,w:4,h:4}],"▛":[{x:0,y:0,w:4,h:8},{x:0,y:0,w:4,h:8}],"▜":[{x:0,y:0,w:8,h:4},{x:4,y:0,w:4,h:8}],"▝":[{x:4,y:0,w:4,h:4}],"▞":[{x:4,y:0,w:4,h:4},{x:0,y:4,w:4,h:4}],"▟":[{x:4,y:0,w:4,h:8},{x:0,y:4,w:8,h:4}],"🭰":[{x:1,y:0,w:1,h:8}],"🭱":[{x:2,y:0,w:1,h:8}],"🭲":[{x:3,y:0,w:1,h:8}],"🭳":[{x:4,y:0,w:1,h:8}],"🭴":[{x:5,y:0,w:1,h:8}],"🭵":[{x:6,y:0,w:1,h:8}],"🭶":[{x:0,y:1,w:8,h:1}],"🭷":[{x:0,y:2,w:8,h:1}],"🭸":[{x:0,y:3,w:8,h:1}],"🭹":[{x:0,y:4,w:8,h:1}],"🭺":[{x:0,y:5,w:8,h:1}],"🭻":[{x:0,y:6,w:8,h:1}],"🭼":[{x:0,y:0,w:1,h:8},{x:0,y:7,w:8,h:1}],"🭽":[{x:0,y:0,w:1,h:8},{x:0,y:0,w:8,h:1}],"🭾":[{x:7,y:0,w:1,h:8},{x:0,y:0,w:8,h:1}],"🭿":[{x:7,y:0,w:1,h:8},{x:0,y:7,w:8,h:1}],"🮀":[{x:0,y:0,w:8,h:1},{x:0,y:7,w:8,h:1}],"🮁":[{x:0,y:0,w:8,h:1},{x:0,y:2,w:8,h:1},{x:0,y:4,w:8,h:1},{x:0,y:7,w:8,h:1}],"🮂":[{x:0,y:0,w:8,h:2}],"🮃":[{x:0,y:0,w:8,h:3}],"🮄":[{x:0,y:0,w:8,h:5}],"🮅":[{x:0,y:0,w:8,h:6}],"🮆":[{x:0,y:0,w:8,h:7}],"🮇":[{x:6,y:0,w:2,h:8}],"🮈":[{x:5,y:0,w:3,h:8}],"🮉":[{x:3,y:0,w:5,h:8}],"🮊":[{x:2,y:0,w:6,h:8}],"🮋":[{x:1,y:0,w:7,h:8}],"🮕":[{x:0,y:0,w:2,h:2},{x:4,y:0,w:2,h:2},{x:2,y:2,w:2,h:2},{x:6,y:2,w:2,h:2},{x:0,y:4,w:2,h:2},{x:4,y:4,w:2,h:2},{x:2,y:6,w:2,h:2},{x:6,y:6,w:2,h:2}],"🮖":[{x:2,y:0,w:2,h:2},{x:6,y:0,w:2,h:2},{x:0,y:2,w:2,h:2},{x:4,y:2,w:2,h:2},{x:2,y:4,w:2,h:2},{x:6,y:4,w:2,h:2},{x:0,y:6,w:2,h:2},{x:4,y:6,w:2,h:2}],"🮗":[{x:0,y:2,w:8,h:2},{x:0,y:6,w:8,h:2}]};var Lt={"░":[[1,0,0,0],[0,0,0,0],[0,0,1,0],[0,0,0,0]],"▒":[[1,0],[0,0],[0,1],[0,0]],"▓":[[0,1],[1,1],[1,0],[1,1]]};t.boxDrawingDefinitions={"─":(i={},i[1]="M0,.5 L1,.5",i),"━":(n={},n[3]="M0,.5 L1,.5",n),"│":(o={},o[1]="M.5,0 L.5,1",o),"┃":(s={},s[3]="M.5,0 L.5,1",s),"┌":(a={},a[1]="M0.5,1 L.5,.5 L1,.5",a),"┏":(c={},c[3]="M0.5,1 L.5,.5 L1,.5",c),"┐":(l={},l[1]="M0,.5 L.5,.5 L.5,1",l),"┓":(h={},h[3]="M0,.5 L.5,.5 L.5,1",h),"└":(u={},u[1]="M.5,0 L.5,.5 L1,.5",u),"┗":(f={},f[3]="M.5,0 L.5,.5 L1,.5",f),"┘":(_={},_[1]="M.5,0 L.5,.5 L0,.5",_),"┛":(d={},d[3]="M.5,0 L.5,.5 L0,.5",d),"├":(p={},p[1]="M.5,0 L.5,1 M.5,.5 L1,.5",p),"┣":(v={},v[3]="M.5,0 L.5,1 M.5,.5 L1,.5",v),"┤":(g={},g[1]="M.5,0 L.5,1 M.5,.5 L0,.5",g),"┫":(y={},y[3]="M.5,0 L.5,1 M.5,.5 L0,.5",y),"┬":(m={},m[1]="M0,.5 L1,.5 M.5,.5 L.5,1",m),"┳":(S={},S[3]="M0,.5 L1,.5 M.5,.5 L.5,1",S),"┴":(C={},C[1]="M0,.5 L1,.5 M.5,.5 L.5,0",C),"┻":(b={},b[3]="M0,.5 L1,.5 M.5,.5 L.5,0",b),"┼":(w={},w[1]="M0,.5 L1,.5 M.5,0 L.5,1",w),"╋":(L={},L[3]="M0,.5 L1,.5 M.5,0 L.5,1",L),"╴":(E={},E[1]="M.5,.5 L0,.5",E),"╸":(x={},x[3]="M.5,.5 L0,.5",x),"╵":(M={},M[1]="M.5,.5 L.5,0",M),"╹":(k={},k[3]="M.5,.5 L.5,0",k),"╶":(A={},A[1]="M.5,.5 L1,.5",A),"╺":(R={},R[3]="M.5,.5 L1,.5",R),"╷":(T={},T[1]="M.5,.5 L.5,1",T),"╻":(B={},B[3]="M.5,.5 L.5,1",B),"═":(O={},O[1]=function(e,t){return"M0,"+(.5-t)+" L1,"+(.5-t)+" M0,"+(.5+t)+" L1,"+(.5+t)},O),"║":(D={},D[1]=function(e,t){return"M"+(.5-e)+",0 L"+(.5-e)+",1 M"+(.5+e)+",0 L"+(.5+e)+",1"},D),"╒":(P={},P[1]=function(e,t){return"M.5,1 L.5,"+(.5-t)+" L1,"+(.5-t)+" M.5,"+(.5+t)+" L1,"+(.5+t)},P),"╓":(I={},I[1]=function(e,t){return"M"+(.5-e)+",1 L"+(.5-e)+",.5 L1,.5 M"+(.5+e)+",.5 L"+(.5+e)+",1"},I),"╔":(H={},H[1]=function(e,t){return"M1,"+(.5-t)+" L"+(.5-e)+","+(.5-t)+" L"+(.5-e)+",1 M1,"+(.5+t)+" L"+(.5+e)+","+(.5+t)+" L"+(.5+e)+",1"},H),"╕":(F={},F[1]=function(e,t){return"M0,"+(.5-t)+" L.5,"+(.5-t)+" L.5,1 M0,"+(.5+t)+" L.5,"+(.5+t)},F),"╖":(j={},j[1]=function(e,t){return"M"+(.5+e)+",1 L"+(.5+e)+",.5 L0,.5 M"+(.5-e)+",.5 L"+(.5-e)+",1"},j),"╗":(W={},W[1]=function(e,t){return"M0,"+(.5+t)+" L"+(.5-e)+","+(.5+t)+" L"+(.5-e)+",1 M0,"+(.5-t)+" L"+(.5+e)+","+(.5-t)+" L"+(.5+e)+",1"},W),"╘":(U={},U[1]=function(e,t){return"M.5,0 L.5,"+(.5+t)+" L1,"+(.5+t)+" M.5,"+(.5-t)+" L1,"+(.5-t)},U),"╙":(q={},q[1]=function(e,t){return"M1,.5 L"+(.5-e)+",.5 L"+(.5-e)+",0 M"+(.5+e)+",.5 L"+(.5+e)+",0"},q),"╚":(N={},N[1]=function(e,t){return"M1,"+(.5-t)+" L"+(.5+e)+","+(.5-t)+" L"+(.5+e)+",0 M1,"+(.5+t)+" L"+(.5-e)+","+(.5+t)+" L"+(.5-e)+",0"},N),"╛":(z={},z[1]=function(e,t){return"M0,"+(.5+t)+" L.5,"+(.5+t)+" L.5,0 M0,"+(.5-t)+" L.5,"+(.5-t)},z),"╜":(K={},K[1]=function(e,t){return"M0,.5 L"+(.5+e)+",.5 L"+(.5+e)+",0 M"+(.5-e)+",.5 L"+(.5-e)+",0"},K),"╝":(G={},G[1]=function(e,t){return"M0,"+(.5-t)+" L"+(.5-e)+","+(.5-t)+" L"+(.5-e)+",0 M0,"+(.5+t)+" L"+(.5+e)+","+(.5+t)+" L"+(.5+e)+",0"},G),"╞":(V={},V[1]=function(e,t){return"M.5,0 L.5,1 M.5,"+(.5-t)+" L1,"+(.5-t)+" M.5,"+(.5+t)+" L1,"+(.5+t)},V),"╟":(X={},X[1]=function(e,t){return"M"+(.5-e)+",0 L"+(.5-e)+",1 M"+(.5+e)+",0 L"+(.5+e)+",1 M"+(.5+e)+",.5 L1,.5"},X),"╠":(Y={},Y[1]=function(e,t){return"M"+(.5-e)+",0 L"+(.5-e)+",1 M1,"+(.5+t)+" L"+(.5+e)+","+(.5+t)+" L"+(.5+e)+",1 M1,"+(.5-t)+" L"+(.5+e)+","+(.5-t)+" L"+(.5+e)+",0"},Y),"╡":(Z={},Z[1]=function(e,t){return"M.5,0 L.5,1 M0,"+(.5-t)+" L.5,"+(.5-t)+" M0,"+(.5+t)+" L.5,"+(.5+t)},Z),"╢":(J={},J[1]=function(e,t){return"M0,.5 L"+(.5-e)+",.5 M"+(.5-e)+",0 L"+(.5-e)+",1 M"+(.5+e)+",0 L"+(.5+e)+",1"},J),"╣":($={},$[1]=function(e,t){return"M"+(.5+e)+",0 L"+(.5+e)+",1 M0,"+(.5+t)+" L"+(.5-e)+","+(.5+t)+" L"+(.5-e)+",1 M0,"+(.5-t)+" L"+(.5-e)+","+(.5-t)+" L"+(.5-e)+",0"},$),"╤":(Q={},Q[1]=function(e,t){return"M0,"+(.5-t)+" L1,"+(.5-t)+" M0,"+(.5+t)+" L1,"+(.5+t)+" M.5,"+(.5+t)+" L.5,1"},Q),"╥":(ee={},ee[1]=function(e,t){return"M0,.5 L1,.5 M"+(.5-e)+",.5 L"+(.5-e)+",1 M"+(.5+e)+",.5 L"+(.5+e)+",1"},ee),"╦":(te={},te[1]=function(e,t){return"M0,"+(.5-t)+" L1,"+(.5-t)+" M0,"+(.5+t)+" L"+(.5-e)+","+(.5+t)+" L"+(.5-e)+",1 M1,"+(.5+t)+" L"+(.5+e)+","+(.5+t)+" L"+(.5+e)+",1"},te),"╧":(re={},re[1]=function(e,t){return"M.5,0 L.5,"+(.5-t)+" M0,"+(.5-t)+" L1,"+(.5-t)+" M0,"+(.5+t)+" L1,"+(.5+t)},re),"╨":(ie={},ie[1]=function(e,t){return"M0,.5 L1,.5 M"+(.5-e)+",.5 L"+(.5-e)+",0 M"+(.5+e)+",.5 L"+(.5+e)+",0"},ie),"╩":(ne={},ne[1]=function(e,t){return"M0,"+(.5+t)+" L1,"+(.5+t)+" M0,"+(.5-t)+" L"+(.5-e)+","+(.5-t)+" L"+(.5-e)+",0 M1,"+(.5-t)+" L"+(.5+e)+","+(.5-t)+" L"+(.5+e)+",0"},ne),"╪":(oe={},oe[1]=function(e,t){return"M.5,0 L.5,1 M0,"+(.5-t)+" L1,"+(.5-t)+" M0,"+(.5+t)+" L1,"+(.5+t)},oe),"╫":(se={},se[1]=function(e,t){return"M0,.5 L1,.5 M"+(.5-e)+",0 L"+(.5-e)+",1 M"+(.5+e)+",0 L"+(.5+e)+",1"},se),"╬":(ae={},ae[1]=function(e,t){return"M0,"+(.5+t)+" L"+(.5-e)+","+(.5+t)+" L"+(.5-e)+",1 M1,"+(.5+t)+" L"+(.5+e)+","+(.5+t)+" L"+(.5+e)+",1 M0,"+(.5-t)+" L"+(.5-e)+","+(.5-t)+" L"+(.5-e)+",0 M1,"+(.5-t)+" L"+(.5+e)+","+(.5-t)+" L"+(.5+e)+",0"},ae),"╱":(ce={},ce[1]="M1,0 L0,1",ce),"╲":(le={},le[1]="M0,0 L1,1",le),"╳":(he={},he[1]="M1,0 L0,1 M0,0 L1,1",he),"╼":(ue={},ue[1]="M.5,.5 L0,.5",ue[3]="M.5,.5 L1,.5",ue),"╽":(fe={},fe[1]="M.5,.5 L.5,0",fe[3]="M.5,.5 L.5,1",fe),"╾":(_e={},_e[1]="M.5,.5 L1,.5",_e[3]="M.5,.5 L0,.5",_e),"╿":(de={},de[1]="M.5,.5 L.5,1",de[3]="M.5,.5 L.5,0",de),"┍":(pe={},pe[1]="M.5,.5 L.5,1",pe[3]="M.5,.5 L1,.5",pe),"┎":(ve={},ve[1]="M.5,.5 L1,.5",ve[3]="M.5,.5 L.5,1",ve),"┑":(ge={},ge[1]="M.5,.5 L.5,1",ge[3]="M.5,.5 L0,.5",ge),"┒":(ye={},ye[1]="M.5,.5 L0,.5",ye[3]="M.5,.5 L.5,1",ye),"┕":(me={},me[1]="M.5,.5 L.5,0",me[3]="M.5,.5 L1,.5",me),"┖":(Se={},Se[1]="M.5,.5 L1,.5",Se[3]="M.5,.5 L.5,0",Se),"┙":(Ce={},Ce[1]="M.5,.5 L.5,0",Ce[3]="M.5,.5 L0,.5",Ce),"┚":(be={},be[1]="M.5,.5 L0,.5",be[3]="M.5,.5 L.5,0",be),"┝":(we={},we[1]="M.5,0 L.5,1",we[3]="M.5,.5 L1,.5",we),"┞":(Le={},Le[1]="M0.5,1 L.5,.5 L1,.5",Le[3]="M.5,.5 L.5,0",Le),"┟":(Ee={},Ee[1]="M.5,0 L.5,.5 L1,.5",Ee[3]="M.5,.5 L.5,1",Ee),"┠":(xe={},xe[1]="M.5,.5 L1,.5",xe[3]="M.5,0 L.5,1",xe),"┡":(Me={},Me[1]="M.5,.5 L.5,1",Me[3]="M.5,0 L.5,.5 L1,.5",Me),"┢":(ke={},ke[1]="M.5,.5 L.5,0",ke[3]="M0.5,1 L.5,.5 L1,.5",ke),"┥":(Ae={},Ae[1]="M.5,0 L.5,1",Ae[3]="M.5,.5 L0,.5",Ae),"┦":(Re={},Re[1]="M0,.5 L.5,.5 L.5,1",Re[3]="M.5,.5 L.5,0",Re),"┧":(Te={},Te[1]="M.5,0 L.5,.5 L0,.5",Te[3]="M.5,.5 L.5,1",Te),"┨":(Be={},Be[1]="M.5,.5 L0,.5",Be[3]="M.5,0 L.5,1",Be),"┩":(Oe={},Oe[1]="M.5,.5 L.5,1",Oe[3]="M.5,0 L.5,.5 L0,.5",Oe),"┪":(De={},De[1]="M.5,.5 L.5,0",De[3]="M0,.5 L.5,.5 L.5,1",De),"┭":(Pe={},Pe[1]="M0.5,1 L.5,.5 L1,.5",Pe[3]="M.5,.5 L0,.5",Pe),"┮":(Ie={},Ie[1]="M0,.5 L.5,.5 L.5,1",Ie[3]="M.5,.5 L1,.5",Ie),"┯":(He={},He[1]="M.5,.5 L.5,1",He[3]="M0,.5 L1,.5",He),"┰":(Fe={},Fe[1]="M0,.5 L1,.5",Fe[3]="M.5,.5 L.5,1",Fe),"┱":(je={},je[1]="M.5,.5 L1,.5",je[3]="M0,.5 L.5,.5 L.5,1",je),"┲":(We={},We[1]="M.5,.5 L0,.5",We[3]="M0.5,1 L.5,.5 L1,.5",We),"┵":(Ue={},Ue[1]="M.5,0 L.5,.5 L1,.5",Ue[3]="M.5,.5 L0,.5",Ue),"┶":(qe={},qe[1]="M.5,0 L.5,.5 L0,.5",qe[3]="M.5,.5 L1,.5",qe),"┷":(Ne={},Ne[1]="M.5,.5 L.5,0",Ne[3]="M0,.5 L1,.5",Ne),"┸":(ze={},ze[1]="M0,.5 L1,.5",ze[3]="M.5,.5 L.5,0",ze),"┹":(Ke={},Ke[1]="M.5,.5 L1,.5",Ke[3]="M.5,0 L.5,.5 L0,.5",Ke),"┺":(Ge={},Ge[1]="M.5,.5 L0,.5",Ge[3]="M.5,0 L.5,.5 L1,.5",Ge),"┽":(Ve={},Ve[1]="M.5,0 L.5,1 M.5,.5 L1,.5",Ve[3]="M.5,.5 L0,.5",Ve),"┾":(Xe={},Xe[1]="M.5,0 L.5,1 M.5,.5 L0,.5",Xe[3]="M.5,.5 L1,.5",Xe),"┿":(Ye={},Ye[1]="M.5,0 L.5,1",Ye[3]="M0,.5 L1,.5",Ye),"╀":(Ze={},Ze[1]="M0,.5 L1,.5 M.5,.5 L.5,1",Ze[3]="M.5,.5 L.5,0",Ze),"╁":(Je={},Je[1]="M.5,.5 L.5,0 M0,.5 L1,.5",Je[3]="M.5,.5 L.5,1",Je),"╂":($e={},$e[1]="M0,.5 L1,.5",$e[3]="M.5,0 L.5,1",$e),"╃":(Qe={},Qe[1]="M0.5,1 L.5,.5 L1,.5",Qe[3]="M.5,0 L.5,.5 L0,.5",Qe),"╄":(et={},et[1]="M0,.5 L.5,.5 L.5,1",et[3]="M.5,0 L.5,.5 L1,.5",et),"╅":(tt={},tt[1]="M.5,0 L.5,.5 L1,.5",tt[3]="M0,.5 L.5,.5 L.5,1",tt),"╆":(rt={},rt[1]="M.5,0 L.5,.5 L0,.5",rt[3]="M0.5,1 L.5,.5 L1,.5",rt),"╇":(it={},it[1]="M.5,.5 L.5,1",it[3]="M.5,.5 L.5,0 M0,.5 L1,.5",it),"╈":(nt={},nt[1]="M.5,.5 L.5,0",nt[3]="M0,.5 L1,.5 M.5,.5 L.5,1",nt),"╉":(ot={},ot[1]="M.5,.5 L1,.5",ot[3]="M.5,0 L.5,1 M.5,.5 L0,.5",ot),"╊":(st={},st[1]="M.5,.5 L0,.5",st[3]="M.5,0 L.5,1 M.5,.5 L1,.5",st),"╌":(at={},at[1]="M.1,.5 L.4,.5 M.6,.5 L.9,.5",at),"╍":(ct={},ct[3]="M.1,.5 L.4,.5 M.6,.5 L.9,.5",ct),"┄":(lt={},lt[1]="M.0667,.5 L.2667,.5 M.4,.5 L.6,.5 M.7333,.5 L.9333,.5",lt),"┅":(ht={},ht[3]="M.0667,.5 L.2667,.5 M.4,.5 L.6,.5 M.7333,.5 L.9333,.5",ht),"┈":(ut={},ut[1]="M.05,.5 L.2,.5 M.3,.5 L.45,.5 M.55,.5 L.7,.5 M.8,.5 L.95,.5",ut),"┉":(ft={},ft[3]="M.05,.5 L.2,.5 M.3,.5 L.45,.5 M.55,.5 L.7,.5 M.8,.5 L.95,.5",ft),"╎":(_t={},_t[1]="M.5,.1 L.5,.4 M.5,.6 L.5,.9",_t),"╏":(dt={},dt[3]="M.5,.1 L.5,.4 M.5,.6 L.5,.9",dt),"┆":(pt={},pt[1]="M.5,.0667 L.5,.2667 M.5,.4 L.5,.6 M.5,.7333 L.5,.9333",pt),"┇":(vt={},vt[3]="M.5,.0667 L.5,.2667 M.5,.4 L.5,.6 M.5,.7333 L.5,.9333",vt),"┊":(gt={},gt[1]="M.5,.05 L.5,.2 M.5,.3 L.5,.45 L.5,.55 M.5,.7 L.5,.95",gt),"┋":(yt={},yt[3]="M.5,.05 L.5,.2 M.5,.3 L.5,.45 L.5,.55 M.5,.7 L.5,.95",yt),"╭":(mt={},mt[1]="C.5,1,.5,.5,1,.5",mt),"╮":(St={},St[1]="C.5,1,.5,.5,0,.5",St),"╯":(Ct={},Ct[1]="C.5,0,.5,.5,0,.5",Ct),"╰":(bt={},bt[1]="C.5,0,.5,.5,1,.5",bt)},t.tryDrawCustomChar=function(e,r,i,n,o,s){var a=t.blockElementDefinitions[r];if(a)return function(e,t,r,i,n,o){for(var s=0;s<t.length;s++){var a=t[s],c=n/8,l=o/8;e.fillRect(r+a.x*c,i+a.y*l,a.w*c,a.h*l)}}(e,a,i,n,o,s),!0;var c=Lt[r];if(c)return function(e,t,r,i,n,o){var s,a=Et.get(t);a||(a=new Map,Et.set(t,a));var c=e.fillStyle;if("string"!=typeof c)throw new Error('Unexpected fillStyle type "'+c+'"');var l=a.get(c);if(!l){var h=t[0].length,u=t.length,f=document.createElement("canvas");f.width=h,f.height=u;var _=(0,wt.throwIfFalsy)(f.getContext("2d")),d=new ImageData(h,u),p=void 0,v=void 0,g=void 0,y=void 0;if(c.startsWith("#"))p=parseInt(c.substr(1,2),16),v=parseInt(c.substr(3,2),16),g=parseInt(c.substr(5,2),16),y=c.length>7&&parseInt(c.substr(7,2),16)||1;else{if(!c.startsWith("rgba"))throw new Error('Unexpected fillStyle color format "'+c+'" when drawing pattern glyph');p=(s=c.substring(5,c.length-1).split(",").map((function(e){return parseFloat(e)})))[0],v=s[1],g=s[2],y=s[3]}for(var m=0;m<u;m++)for(var S=0;S<h;S++)d.data[4*(m*h+S)]=p,d.data[4*(m*h+S)+1]=v,d.data[4*(m*h+S)+2]=g,d.data[4*(m*h+S)+3]=t[m][S]*(255*y);_.putImageData(d,0,0),l=(0,wt.throwIfFalsy)(e.createPattern(f,null)),a.set(c,l)}e.fillStyle=l,e.fillRect(r,i,n,o)}(e,c,i,n,o,s),!0;var l=t.boxDrawingDefinitions[r];return!!l&&(function(e,t,r,i,n,o){e.strokeStyle=e.fillStyle;for(var s=0,a=Object.entries(t);s<a.length;s++){var c=a[s],l=c[0],h=c[1];e.beginPath(),e.lineWidth=window.devicePixelRatio*Number.parseInt(l);for(var u=0,f=("function"==typeof h?h(.15,.15/o*n):h).split(" ");u<f.length;u++){var _=f[u],d=_[0],p=Mt[d];if(p){var v=_.substring(1).split(",");v[0]&&v[1]&&p(e,kt(v,n,o,r,i))}else console.error('Could not find drawing instructions for "'+d+'"')}e.stroke(),e.closePath()}}(e,l,i,n,o,s),!0)};var Et=new Map;function xt(e,t,r){return void 0===r&&(r=0),Math.max(Math.min(e,t),r)}var Mt={C:function(e,t){return e.bezierCurveTo(t[0],t[1],t[2],t[3],t[4],t[5])},L:function(e,t){return e.lineTo(t[0],t[1])},M:function(e,t){return e.moveTo(t[0],t[1])}};function kt(e,t,r,i,n){var o=e.map((function(e){return parseFloat(e)||parseInt(e)}));if(o.length<2)throw new Error("Too few arguments for instruction");for(var s=0;s<o.length;s+=2)o[s]*=t,0!==o[s]&&(o[s]=xt(Math.round(o[s]+.5)-.5,t,0)),o[s]+=i;for(var a=1;a<o.length;a+=2)o[a]*=r,0!==o[a]&&(o[a]=xt(Math.round(o[a]+.5)-.5,r,0)),o[a]+=n;return o}},3700:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.GridCache=void 0;var r=function(){function e(){this.cache=[]}return e.prototype.resize=function(e,t){for(var r=0;r<e;r++){this.cache.length<=r&&this.cache.push([]);for(var i=this.cache[r].length;i<t;i++)this.cache[r].push(void 0);this.cache[r].length=t}this.cache.length=e},e.prototype.clear=function(){for(var e=0;e<this.cache.length;e++)for(var t=0;t<this.cache[e].length;t++)this.cache[e][t]=void 0},e}();t.GridCache=r},5098:function(e,t,r){var i,n=this&&this.__extends||(i=function(e,t){return i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])},i(e,t)},function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function r(){this.constructor=e}i(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)}),o=this&&this.__decorate||function(e,t,r,i){var n,o=arguments.length,s=o<3?t:null===i?i=Object.getOwnPropertyDescriptor(t,r):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)s=Reflect.decorate(e,t,r,i);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(s=(o<3?n(s):o>3?n(t,r,s):n(t,r))||s);return o>3&&s&&Object.defineProperty(t,r,s),s},s=this&&this.__param||function(e,t){return function(r,i){t(r,i,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.LinkRenderLayer=void 0;var a=r(1546),c=r(8803),l=r(2040),h=r(2585),u=function(e){function t(t,r,i,n,o,s,a,c){var l=e.call(this,t,"link",r,!0,i,n,a,c)||this;return o.onShowLinkUnderline((function(e){return l._onShowLinkUnderline(e)})),o.onHideLinkUnderline((function(e){return l._onHideLinkUnderline(e)})),s.onShowLinkUnderline((function(e){return l._onShowLinkUnderline(e)})),s.onHideLinkUnderline((function(e){return l._onHideLinkUnderline(e)})),l}return n(t,e),t.prototype.resize=function(t){e.prototype.resize.call(this,t),this._state=void 0},t.prototype.reset=function(){this._clearCurrentLink()},t.prototype._clearCurrentLink=function(){if(this._state){this._clearCells(this._state.x1,this._state.y1,this._state.cols-this._state.x1,1);var e=this._state.y2-this._state.y1-1;e>0&&this._clearCells(0,this._state.y1+1,this._state.cols,e),this._clearCells(0,this._state.y2,this._state.x2,1),this._state=void 0}},t.prototype._onShowLinkUnderline=function(e){if(e.fg===c.INVERTED_DEFAULT_COLOR?this._ctx.fillStyle=this._colors.background.css:e.fg&&(0,l.is256Color)(e.fg)?this._ctx.fillStyle=this._colors.ansi[e.fg].css:this._ctx.fillStyle=this._colors.foreground.css,e.y1===e.y2)this._fillBottomLineAtCells(e.x1,e.y1,e.x2-e.x1);else{this._fillBottomLineAtCells(e.x1,e.y1,e.cols-e.x1);for(var t=e.y1+1;t<e.y2;t++)this._fillBottomLineAtCells(0,t,e.cols);this._fillBottomLineAtCells(0,e.y2,e.x2)}this._state=e},t.prototype._onHideLinkUnderline=function(e){this._clearCurrentLink()},o([s(6,h.IBufferService),s(7,h.IOptionsService)],t)}(a.BaseRenderLayer);t.LinkRenderLayer=u},3525:function(e,t,r){var i,n=this&&this.__extends||(i=function(e,t){return i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])},i(e,t)},function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function r(){this.constructor=e}i(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)}),o=this&&this.__decorate||function(e,t,r,i){var n,o=arguments.length,s=o<3?t:null===i?i=Object.getOwnPropertyDescriptor(t,r):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)s=Reflect.decorate(e,t,r,i);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(s=(o<3?n(s):o>3?n(t,r,s):n(t,r))||s);return o>3&&s&&Object.defineProperty(t,r,s),s},s=this&&this.__param||function(e,t){return function(r,i){t(r,i,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.Renderer=void 0;var a=r(9596),c=r(4149),l=r(2512),h=r(5098),u=r(844),f=r(4725),_=r(2585),d=r(1420),p=r(8460),v=1,g=function(e){function t(t,r,i,n,o,s,u,f){var _=e.call(this)||this;_._colors=t,_._screenElement=r,_._bufferService=s,_._charSizeService=u,_._optionsService=f,_._id=v++,_._onRequestRedraw=new p.EventEmitter;var d=_._optionsService.options.allowTransparency;return _._renderLayers=[o.createInstance(a.TextRenderLayer,_._screenElement,0,_._colors,d,_._id),o.createInstance(c.SelectionRenderLayer,_._screenElement,1,_._colors,_._id),o.createInstance(h.LinkRenderLayer,_._screenElement,2,_._colors,_._id,i,n),o.createInstance(l.CursorRenderLayer,_._screenElement,3,_._colors,_._id,_._onRequestRedraw)],_.dimensions={scaledCharWidth:0,scaledCharHeight:0,scaledCellWidth:0,scaledCellHeight:0,scaledCharLeft:0,scaledCharTop:0,scaledCanvasWidth:0,scaledCanvasHeight:0,canvasWidth:0,canvasHeight:0,actualCellWidth:0,actualCellHeight:0},_._devicePixelRatio=window.devicePixelRatio,_._updateDimensions(),_.onOptionsChanged(),_}return n(t,e),Object.defineProperty(t.prototype,"onRequestRedraw",{get:function(){return this._onRequestRedraw.event},enumerable:!1,configurable:!0}),t.prototype.dispose=function(){for(var t=0,r=this._renderLayers;t<r.length;t++)r[t].dispose();e.prototype.dispose.call(this),(0,d.removeTerminalFromCache)(this._id)},t.prototype.onDevicePixelRatioChange=function(){this._devicePixelRatio!==window.devicePixelRatio&&(this._devicePixelRatio=window.devicePixelRatio,this.onResize(this._bufferService.cols,this._bufferService.rows))},t.prototype.setColors=function(e){this._colors=e;for(var t=0,r=this._renderLayers;t<r.length;t++){var i=r[t];i.setColors(this._colors),i.reset()}},t.prototype.onResize=function(e,t){this._updateDimensions();for(var r=0,i=this._renderLayers;r<i.length;r++)i[r].resize(this.dimensions);this._screenElement.style.width=this.dimensions.canvasWidth+"px",this._screenElement.style.height=this.dimensions.canvasHeight+"px"},t.prototype.onCharSizeChanged=function(){this.onResize(this._bufferService.cols,this._bufferService.rows)},t.prototype.onBlur=function(){this._runOperation((function(e){return e.onBlur()}))},t.prototype.onFocus=function(){this._runOperation((function(e){return e.onFocus()}))},t.prototype.onSelectionChanged=function(e,t,r){void 0===r&&(r=!1),this._runOperation((function(i){return i.onSelectionChanged(e,t,r)}))},t.prototype.onCursorMove=function(){this._runOperation((function(e){return e.onCursorMove()}))},t.prototype.onOptionsChanged=function(){this._runOperation((function(e){return e.onOptionsChanged()}))},t.prototype.clear=function(){this._runOperation((function(e){return e.reset()}))},t.prototype._runOperation=function(e){for(var t=0,r=this._renderLayers;t<r.length;t++)e(r[t])},t.prototype.renderRows=function(e,t){for(var r=0,i=this._renderLayers;r<i.length;r++)i[r].onGridChanged(e,t)},t.prototype.clearTextureAtlas=function(){for(var e=0,t=this._renderLayers;e<t.length;e++)t[e].clearTextureAtlas()},t.prototype._updateDimensions=function(){this._charSizeService.hasValidSize&&(this.dimensions.scaledCharWidth=Math.floor(this._charSizeService.width*window.devicePixelRatio),this.dimensions.scaledCharHeight=Math.ceil(this._charSizeService.height*window.devicePixelRatio),this.dimensions.scaledCellHeight=Math.floor(this.dimensions.scaledCharHeight*this._optionsService.options.lineHeight),this.dimensions.scaledCharTop=1===this._optionsService.options.lineHeight?0:Math.round((this.dimensions.scaledCellHeight-this.dimensions.scaledCharHeight)/2),this.dimensions.scaledCellWidth=this.dimensions.scaledCharWidth+Math.round(this._optionsService.options.letterSpacing),this.dimensions.scaledCharLeft=Math.floor(this._optionsService.options.letterSpacing/2),this.dimensions.scaledCanvasHeight=this._bufferService.rows*this.dimensions.scaledCellHeight,this.dimensions.scaledCanvasWidth=this._bufferService.cols*this.dimensions.scaledCellWidth,this.dimensions.canvasHeight=Math.round(this.dimensions.scaledCanvasHeight/window.devicePixelRatio),this.dimensions.canvasWidth=Math.round(this.dimensions.scaledCanvasWidth/window.devicePixelRatio),this.dimensions.actualCellHeight=this.dimensions.canvasHeight/this._bufferService.rows,this.dimensions.actualCellWidth=this.dimensions.canvasWidth/this._bufferService.cols)},o([s(4,_.IInstantiationService),s(5,_.IBufferService),s(6,f.ICharSizeService),s(7,_.IOptionsService)],t)}(u.Disposable);t.Renderer=g},1752:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.throwIfFalsy=void 0,t.throwIfFalsy=function(e){if(!e)throw new Error("value must not be falsy");return e}},4149:function(e,t,r){var i,n=this&&this.__extends||(i=function(e,t){return i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])},i(e,t)},function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function r(){this.constructor=e}i(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)}),o=this&&this.__decorate||function(e,t,r,i){var n,o=arguments.length,s=o<3?t:null===i?i=Object.getOwnPropertyDescriptor(t,r):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)s=Reflect.decorate(e,t,r,i);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(s=(o<3?n(s):o>3?n(t,r,s):n(t,r))||s);return o>3&&s&&Object.defineProperty(t,r,s),s},s=this&&this.__param||function(e,t){return function(r,i){t(r,i,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.SelectionRenderLayer=void 0;var a=r(1546),c=r(2585),l=function(e){function t(t,r,i,n,o,s){var a=e.call(this,t,"selection",r,!0,i,n,o,s)||this;return a._clearState(),a}return n(t,e),t.prototype._clearState=function(){this._state={start:void 0,end:void 0,columnSelectMode:void 0,ydisp:void 0}},t.prototype.resize=function(t){e.prototype.resize.call(this,t),this._clearState()},t.prototype.reset=function(){this._state.start&&this._state.end&&(this._clearState(),this._clearAll())},t.prototype.onSelectionChanged=function(e,t,r){if(this._didStateChange(e,t,r,this._bufferService.buffer.ydisp))if(this._clearAll(),e&&t){var i=e[1]-this._bufferService.buffer.ydisp,n=t[1]-this._bufferService.buffer.ydisp,o=Math.max(i,0),s=Math.min(n,this._bufferService.rows-1);if(o>=this._bufferService.rows||s<0)this._state.ydisp=this._bufferService.buffer.ydisp;else{if(this._ctx.fillStyle=this._colors.selectionTransparent.css,r){var a=e[0],c=t[0]-a,l=s-o+1;this._fillCells(a,o,c,l)}else{a=i===o?e[0]:0;var h=o===n?t[0]:this._bufferService.cols;this._fillCells(a,o,h-a,1);var u=Math.max(s-o-1,0);if(this._fillCells(0,o+1,this._bufferService.cols,u),o!==s){var f=n===s?t[0]:this._bufferService.cols;this._fillCells(0,s,f,1)}}this._state.start=[e[0],e[1]],this._state.end=[t[0],t[1]],this._state.columnSelectMode=r,this._state.ydisp=this._bufferService.buffer.ydisp}}else this._clearState()},t.prototype._didStateChange=function(e,t,r,i){return!this._areCoordinatesEqual(e,this._state.start)||!this._areCoordinatesEqual(t,this._state.end)||r!==this._state.columnSelectMode||i!==this._state.ydisp},t.prototype._areCoordinatesEqual=function(e,t){return!(!e||!t)&&e[0]===t[0]&&e[1]===t[1]},o([s(4,c.IBufferService),s(5,c.IOptionsService)],t)}(a.BaseRenderLayer);t.SelectionRenderLayer=l},9596:function(e,t,r){var i,n=this&&this.__extends||(i=function(e,t){return i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])},i(e,t)},function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function r(){this.constructor=e}i(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)}),o=this&&this.__decorate||function(e,t,r,i){var n,o=arguments.length,s=o<3?t:null===i?i=Object.getOwnPropertyDescriptor(t,r):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)s=Reflect.decorate(e,t,r,i);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(s=(o<3?n(s):o>3?n(t,r,s):n(t,r))||s);return o>3&&s&&Object.defineProperty(t,r,s),s},s=this&&this.__param||function(e,t){return function(r,i){t(r,i,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.TextRenderLayer=void 0;var a=r(3700),c=r(1546),l=r(3734),h=r(643),u=r(511),f=r(2585),_=r(4725),d=r(4269),p=function(e){function t(t,r,i,n,o,s,c,l){var h=e.call(this,t,"text",r,n,i,o,s,c)||this;return h._characterJoinerService=l,h._characterWidth=0,h._characterFont="",h._characterOverlapCache={},h._workCell=new u.CellData,h._state=new a.GridCache,h}return n(t,e),t.prototype.resize=function(t){e.prototype.resize.call(this,t);var r=this._getFont(!1,!1);this._characterWidth===t.scaledCharWidth&&this._characterFont===r||(this._characterWidth=t.scaledCharWidth,this._characterFont=r,this._characterOverlapCache={}),this._state.clear(),this._state.resize(this._bufferService.cols,this._bufferService.rows)},t.prototype.reset=function(){this._state.clear(),this._clearAll()},t.prototype._forEachCell=function(e,t,r){for(var i=e;i<=t;i++)for(var n=i+this._bufferService.buffer.ydisp,o=this._bufferService.buffer.lines.get(n),s=this._characterJoinerService.getJoinedCharacters(n),a=0;a<this._bufferService.cols;a++){o.loadCell(a,this._workCell);var c=this._workCell,l=!1,u=a;if(0!==c.getWidth()){if(s.length>0&&a===s[0][0]){l=!0;var f=s.shift();c=new d.JoinedCellData(this._workCell,o.translateToString(!0,f[0],f[1]),f[1]-f[0]),u=f[1]-1}!l&&this._isOverlapping(c)&&u<o.length-1&&o.getCodePoint(u+1)===h.NULL_CELL_CODE&&(c.content&=-12582913,c.content|=2<<22),r(c,a,i),a=u}}},t.prototype._drawBackground=function(e,t){var r=this,i=this._ctx,n=this._bufferService.cols,o=0,s=0,a=null;i.save(),this._forEachCell(e,t,(function(e,t,c){var h=null;e.isInverse()?h=e.isFgDefault()?r._colors.foreground.css:e.isFgRGB()?"rgb("+l.AttributeData.toColorRGB(e.getFgColor()).join(",")+")":r._colors.ansi[e.getFgColor()].css:e.isBgRGB()?h="rgb("+l.AttributeData.toColorRGB(e.getBgColor()).join(",")+")":e.isBgPalette()&&(h=r._colors.ansi[e.getBgColor()].css),null===a&&(o=t,s=c),c!==s?(i.fillStyle=a||"",r._fillCells(o,s,n-o,1),o=t,s=c):a!==h&&(i.fillStyle=a||"",r._fillCells(o,s,t-o,1),o=t,s=c),a=h})),null!==a&&(i.fillStyle=a,this._fillCells(o,s,n-o,1)),i.restore()},t.prototype._drawForeground=function(e,t){var r=this;this._forEachCell(e,t,(function(e,t,i){if(!e.isInvisible()&&(r._drawChars(e,t,i),e.isUnderline()||e.isStrikethrough())){if(r._ctx.save(),e.isInverse())if(e.isBgDefault())r._ctx.fillStyle=r._colors.background.css;else if(e.isBgRGB())r._ctx.fillStyle="rgb("+l.AttributeData.toColorRGB(e.getBgColor()).join(",")+")";else{var n=e.getBgColor();r._optionsService.options.drawBoldTextInBrightColors&&e.isBold()&&n<8&&(n+=8),r._ctx.fillStyle=r._colors.ansi[n].css}else if(e.isFgDefault())r._ctx.fillStyle=r._colors.foreground.css;else if(e.isFgRGB())r._ctx.fillStyle="rgb("+l.AttributeData.toColorRGB(e.getFgColor()).join(",")+")";else{var o=e.getFgColor();r._optionsService.options.drawBoldTextInBrightColors&&e.isBold()&&o<8&&(o+=8),r._ctx.fillStyle=r._colors.ansi[o].css}e.isStrikethrough()&&r._fillMiddleLineAtCells(t,i,e.getWidth()),e.isUnderline()&&r._fillBottomLineAtCells(t,i,e.getWidth()),r._ctx.restore()}}))},t.prototype.onGridChanged=function(e,t){0!==this._state.cache.length&&(this._charAtlas&&this._charAtlas.beginFrame(),this._clearCells(0,e,this._bufferService.cols,t-e+1),this._drawBackground(e,t),this._drawForeground(e,t))},t.prototype.onOptionsChanged=function(){this._setTransparency(this._optionsService.options.allowTransparency)},t.prototype._isOverlapping=function(e){if(1!==e.getWidth())return!1;if(e.getCode()<256)return!1;var t=e.getChars();if(this._characterOverlapCache.hasOwnProperty(t))return this._characterOverlapCache[t];this._ctx.save(),this._ctx.font=this._characterFont;var r=Math.floor(this._ctx.measureText(t).width)>this._characterWidth;return this._ctx.restore(),this._characterOverlapCache[t]=r,r},o([s(5,f.IBufferService),s(6,f.IOptionsService),s(7,_.ICharacterJoinerService)],t)}(c.BaseRenderLayer);t.TextRenderLayer=p},9616:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.BaseCharAtlas=void 0;var r=function(){function e(){this._didWarmUp=!1}return e.prototype.dispose=function(){},e.prototype.warmUp=function(){this._didWarmUp||(this._doWarmUp(),this._didWarmUp=!0)},e.prototype._doWarmUp=function(){},e.prototype.clear=function(){},e.prototype.beginFrame=function(){},e}();t.BaseCharAtlas=r},1420:(e,t,r)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.removeTerminalFromCache=t.acquireCharAtlas=void 0;var i=r(2040),n=r(1906),o=[];t.acquireCharAtlas=function(e,t,r,s,a){for(var c=(0,i.generateConfig)(s,a,e,r),l=0;l<o.length;l++){var h=(u=o[l]).ownedBy.indexOf(t);if(h>=0){if((0,i.configEquals)(u.config,c))return u.atlas;1===u.ownedBy.length?(u.atlas.dispose(),o.splice(l,1)):u.ownedBy.splice(h,1);break}}for(l=0;l<o.length;l++){var u=o[l];if((0,i.configEquals)(u.config,c))return u.ownedBy.push(t),u.atlas}var f={atlas:new n.DynamicCharAtlas(document,c),config:c,ownedBy:[t]};return o.push(f),f.atlas},t.removeTerminalFromCache=function(e){for(var t=0;t<o.length;t++){var r=o[t].ownedBy.indexOf(e);if(-1!==r){1===o[t].ownedBy.length?(o[t].atlas.dispose(),o.splice(t,1)):o[t].ownedBy.splice(r,1);break}}}},2040:function(e,t,r){var i=this&&this.__spreadArray||function(e,t,r){if(r||2===arguments.length)for(var i,n=0,o=t.length;n<o;n++)!i&&n in t||(i||(i=Array.prototype.slice.call(t,0,n)),i[n]=t[n]);return e.concat(i||Array.prototype.slice.call(t))};Object.defineProperty(t,"__esModule",{value:!0}),t.is256Color=t.configEquals=t.generateConfig=void 0;var n=r(643);t.generateConfig=function(e,t,r,n){var o={foreground:n.foreground,background:n.background,cursor:void 0,cursorAccent:void 0,selection:void 0,ansi:i([],n.ansi,!0)};return{devicePixelRatio:window.devicePixelRatio,scaledCharWidth:e,scaledCharHeight:t,fontFamily:r.fontFamily,fontSize:r.fontSize,fontWeight:r.fontWeight,fontWeightBold:r.fontWeightBold,allowTransparency:r.allowTransparency,colors:o}},t.configEquals=function(e,t){for(var r=0;r<e.colors.ansi.length;r++)if(e.colors.ansi[r].rgba!==t.colors.ansi[r].rgba)return!1;return e.devicePixelRatio===t.devicePixelRatio&&e.fontFamily===t.fontFamily&&e.fontSize===t.fontSize&&e.fontWeight===t.fontWeight&&e.fontWeightBold===t.fontWeightBold&&e.allowTransparency===t.allowTransparency&&e.scaledCharWidth===t.scaledCharWidth&&e.scaledCharHeight===t.scaledCharHeight&&e.colors.foreground===t.colors.foreground&&e.colors.background===t.colors.background},t.is256Color=function(e){return e<n.DEFAULT_COLOR}},8803:(e,t,r)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.CHAR_ATLAS_CELL_SPACING=t.TEXT_BASELINE=t.DIM_OPACITY=t.INVERTED_DEFAULT_COLOR=void 0;var i=r(6114);t.INVERTED_DEFAULT_COLOR=257,t.DIM_OPACITY=.5,t.TEXT_BASELINE=i.isFirefox?"bottom":"ideographic",t.CHAR_ATLAS_CELL_SPACING=1},1906:function(e,t,r){var i,n=this&&this.__extends||(i=function(e,t){return i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])},i(e,t)},function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function r(){this.constructor=e}i(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)});Object.defineProperty(t,"__esModule",{value:!0}),t.NoneCharAtlas=t.DynamicCharAtlas=t.getGlyphCacheKey=void 0;var o=r(8803),s=r(9616),a=r(5680),c=r(7001),l=r(6114),h=r(1752),u=r(4774),f=1024,_=1024,d={css:"rgba(0, 0, 0, 0)",rgba:0};function p(e){return e.code<<21|e.bg<<12|e.fg<<3|(e.bold?0:4)+(e.dim?0:2)+(e.italic?0:1)}t.getGlyphCacheKey=p;var v=function(e){function t(t,r){var i=e.call(this)||this;i._config=r,i._drawToCacheCount=0,i._glyphsWaitingOnBitmap=[],i._bitmapCommitTimeout=null,i._bitmap=null,i._cacheCanvas=t.createElement("canvas"),i._cacheCanvas.width=f,i._cacheCanvas.height=_,i._cacheCtx=(0,h.throwIfFalsy)(i._cacheCanvas.getContext("2d",{alpha:!0}));var n=t.createElement("canvas");n.width=i._config.scaledCharWidth,n.height=i._config.scaledCharHeight,i._tmpCtx=(0,h.throwIfFalsy)(n.getContext("2d",{alpha:i._config.allowTransparency})),i._width=Math.floor(f/i._config.scaledCharWidth),i._height=Math.floor(_/i._config.scaledCharHeight);var o=i._width*i._height;return i._cacheMap=new c.LRUMap(o),i._cacheMap.prealloc(o),i}return n(t,e),t.prototype.dispose=function(){null!==this._bitmapCommitTimeout&&(window.clearTimeout(this._bitmapCommitTimeout),this._bitmapCommitTimeout=null)},t.prototype.beginFrame=function(){this._drawToCacheCount=0},t.prototype.clear=function(){if(this._cacheMap.size>0){var e=this._width*this._height;this._cacheMap=new c.LRUMap(e),this._cacheMap.prealloc(e)}this._cacheCtx.clearRect(0,0,f,_),this._tmpCtx.clearRect(0,0,this._config.scaledCharWidth,this._config.scaledCharHeight)},t.prototype.draw=function(e,t,r,i){if(32===t.code)return!0;if(!this._canCache(t))return!1;var n=p(t),o=this._cacheMap.get(n);if(null!=o)return this._drawFromCache(e,o,r,i),!0;if(this._drawToCacheCount<100){var s;s=this._cacheMap.size<this._cacheMap.capacity?this._cacheMap.size:this._cacheMap.peek().index;var a=this._drawToCache(t,s);return this._cacheMap.set(n,a),this._drawFromCache(e,a,r,i),!0}return!1},t.prototype._canCache=function(e){return e.code<256},t.prototype._toCoordinateX=function(e){return e%this._width*this._config.scaledCharWidth},t.prototype._toCoordinateY=function(e){return Math.floor(e/this._width)*this._config.scaledCharHeight},t.prototype._drawFromCache=function(e,t,r,i){if(!t.isEmpty){var n=this._toCoordinateX(t.index),o=this._toCoordinateY(t.index);e.drawImage(t.inBitmap?this._bitmap:this._cacheCanvas,n,o,this._config.scaledCharWidth,this._config.scaledCharHeight,r,i,this._config.scaledCharWidth,this._config.scaledCharHeight)}},t.prototype._getColorFromAnsiIndex=function(e){return e<this._config.colors.ansi.length?this._config.colors.ansi[e]:a.DEFAULT_ANSI_COLORS[e]},t.prototype._getBackgroundColor=function(e){return this._config.allowTransparency?d:e.bg===o.INVERTED_DEFAULT_COLOR?this._config.colors.foreground:e.bg<256?this._getColorFromAnsiIndex(e.bg):this._config.colors.background},t.prototype._getForegroundColor=function(e){return e.fg===o.INVERTED_DEFAULT_COLOR?u.color.opaque(this._config.colors.background):e.fg<256?this._getColorFromAnsiIndex(e.fg):this._config.colors.foreground},t.prototype._drawToCache=function(e,t){this._drawToCacheCount++,this._tmpCtx.save();var r=this._getBackgroundColor(e);this._tmpCtx.globalCompositeOperation="copy",this._tmpCtx.fillStyle=r.css,this._tmpCtx.fillRect(0,0,this._config.scaledCharWidth,this._config.scaledCharHeight),this._tmpCtx.globalCompositeOperation="source-over";var i=e.bold?this._config.fontWeightBold:this._config.fontWeight,n=e.italic?"italic":"";this._tmpCtx.font=n+" "+i+" "+this._config.fontSize*this._config.devicePixelRatio+"px "+this._config.fontFamily,this._tmpCtx.textBaseline=o.TEXT_BASELINE,this._tmpCtx.fillStyle=this._getForegroundColor(e).css,e.dim&&(this._tmpCtx.globalAlpha=o.DIM_OPACITY),this._tmpCtx.fillText(e.chars,0,this._config.scaledCharHeight);var s=this._tmpCtx.getImageData(0,0,this._config.scaledCharWidth,this._config.scaledCharHeight),a=!1;if(this._config.allowTransparency||(a=y(s,r)),a&&"_"===e.chars&&!this._config.allowTransparency)for(var c=1;c<=5&&(this._tmpCtx.fillText(e.chars,0,this._config.scaledCharHeight-c),a=y(s=this._tmpCtx.getImageData(0,0,this._config.scaledCharWidth,this._config.scaledCharHeight),r));c++);this._tmpCtx.restore();var l=this._toCoordinateX(t),h=this._toCoordinateY(t);this._cacheCtx.putImageData(s,l,h);var u={index:t,isEmpty:a,inBitmap:!1};return this._addGlyphToBitmap(u),u},t.prototype._addGlyphToBitmap=function(e){var t=this;!("createImageBitmap"in window)||l.isFirefox||l.isSafari||(this._glyphsWaitingOnBitmap.push(e),null===this._bitmapCommitTimeout&&(this._bitmapCommitTimeout=window.setTimeout((function(){return t._generateBitmap()}),100)))},t.prototype._generateBitmap=function(){var e=this,t=this._glyphsWaitingOnBitmap;this._glyphsWaitingOnBitmap=[],window.createImageBitmap(this._cacheCanvas).then((function(r){e._bitmap=r;for(var i=0;i<t.length;i++)t[i].inBitmap=!0})),this._bitmapCommitTimeout=null},t}(s.BaseCharAtlas);t.DynamicCharAtlas=v;var g=function(e){function t(t,r){return e.call(this)||this}return n(t,e),t.prototype.draw=function(e,t,r,i){return!1},t}(s.BaseCharAtlas);function y(e,t){for(var r=!0,i=t.rgba>>>24,n=t.rgba>>>16&255,o=t.rgba>>>8&255,s=0;s<e.data.length;s+=4)e.data[s]===i&&e.data[s+1]===n&&e.data[s+2]===o?e.data[s+3]=0:r=!1;return r}t.NoneCharAtlas=g},7001:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.LRUMap=void 0;var r=function(){function e(e){this.capacity=e,this._map={},this._head=null,this._tail=null,this._nodePool=[],this.size=0}return e.prototype._unlinkNode=function(e){var t=e.prev,r=e.next;e===this._head&&(this._head=r),e===this._tail&&(this._tail=t),null!==t&&(t.next=r),null!==r&&(r.prev=t)},e.prototype._appendNode=function(e){var t=this._tail;null!==t&&(t.next=e),e.prev=t,e.next=null,this._tail=e,null===this._head&&(this._head=e)},e.prototype.prealloc=function(e){for(var t=this._nodePool,r=0;r<e;r++)t.push({prev:null,next:null,key:null,value:null})},e.prototype.get=function(e){var t=this._map[e];return void 0!==t?(this._unlinkNode(t),this._appendNode(t),t.value):null},e.prototype.peekValue=function(e){var t=this._map[e];return void 0!==t?t.value:null},e.prototype.peek=function(){var e=this._head;return null===e?null:e.value},e.prototype.set=function(e,t){var r=this._map[e];if(void 0!==r)r=this._map[e],this._unlinkNode(r),r.value=t;else if(this.size>=this.capacity)r=this._head,this._unlinkNode(r),delete this._map[r.key],r.key=e,r.value=t,this._map[e]=r;else{var i=this._nodePool;i.length>0?((r=i.pop()).key=e,r.value=t):r={prev:null,next:null,key:e,value:t},this._map[e]=r,this.size++}this._appendNode(r)},e}();t.LRUMap=r},1296:function(e,t,r){var i,n=this&&this.__extends||(i=function(e,t){return i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])},i(e,t)},function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function r(){this.constructor=e}i(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)}),o=this&&this.__decorate||function(e,t,r,i){var n,o=arguments.length,s=o<3?t:null===i?i=Object.getOwnPropertyDescriptor(t,r):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)s=Reflect.decorate(e,t,r,i);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(s=(o<3?n(s):o>3?n(t,r,s):n(t,r))||s);return o>3&&s&&Object.defineProperty(t,r,s),s},s=this&&this.__param||function(e,t){return function(r,i){t(r,i,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.DomRenderer=void 0;var a=r(3787),c=r(8803),l=r(844),h=r(4725),u=r(2585),f=r(8460),_=r(4774),d=r(9631),p="xterm-dom-renderer-owner-",v="xterm-fg-",g="xterm-bg-",y="xterm-focus",m=1,S=function(e){function t(t,r,i,n,o,s,c,l,h,u){var f=e.call(this)||this;return f._colors=t,f._element=r,f._screenElement=i,f._viewportElement=n,f._linkifier=o,f._linkifier2=s,f._charSizeService=l,f._optionsService=h,f._bufferService=u,f._terminalClass=m++,f._rowElements=[],f._rowContainer=document.createElement("div"),f._rowContainer.classList.add("xterm-rows"),f._rowContainer.style.lineHeight="normal",f._rowContainer.setAttribute("aria-hidden","true"),f._refreshRowElements(f._bufferService.cols,f._bufferService.rows),f._selectionContainer=document.createElement("div"),f._selectionContainer.classList.add("xterm-selection"),f._selectionContainer.setAttribute("aria-hidden","true"),f.dimensions={scaledCharWidth:0,scaledCharHeight:0,scaledCellWidth:0,scaledCellHeight:0,scaledCharLeft:0,scaledCharTop:0,scaledCanvasWidth:0,scaledCanvasHeight:0,canvasWidth:0,canvasHeight:0,actualCellWidth:0,actualCellHeight:0},f._updateDimensions(),f._injectCss(),f._rowFactory=c.createInstance(a.DomRendererRowFactory,document,f._colors),f._element.classList.add(p+f._terminalClass),f._screenElement.appendChild(f._rowContainer),f._screenElement.appendChild(f._selectionContainer),f._linkifier.onShowLinkUnderline((function(e){return f._onLinkHover(e)})),f._linkifier.onHideLinkUnderline((function(e){return f._onLinkLeave(e)})),f._linkifier2.onShowLinkUnderline((function(e){return f._onLinkHover(e)})),f._linkifier2.onHideLinkUnderline((function(e){return f._onLinkLeave(e)})),f}return n(t,e),Object.defineProperty(t.prototype,"onRequestRedraw",{get:function(){return(new f.EventEmitter).event},enumerable:!1,configurable:!0}),t.prototype.dispose=function(){this._element.classList.remove(p+this._terminalClass),(0,d.removeElementFromParent)(this._rowContainer,this._selectionContainer,this._themeStyleElement,this._dimensionsStyleElement),e.prototype.dispose.call(this)},t.prototype._updateDimensions=function(){this.dimensions.scaledCharWidth=this._charSizeService.width*window.devicePixelRatio,this.dimensions.scaledCharHeight=Math.ceil(this._charSizeService.height*window.devicePixelRatio),this.dimensions.scaledCellWidth=this.dimensions.scaledCharWidth+Math.round(this._optionsService.options.letterSpacing),this.dimensions.scaledCellHeight=Math.floor(this.dimensions.scaledCharHeight*this._optionsService.options.lineHeight),this.dimensions.scaledCharLeft=0,this.dimensions.scaledCharTop=0,this.dimensions.scaledCanvasWidth=this.dimensions.scaledCellWidth*this._bufferService.cols,this.dimensions.scaledCanvasHeight=this.dimensions.scaledCellHeight*this._bufferService.rows,this.dimensions.canvasWidth=Math.round(this.dimensions.scaledCanvasWidth/window.devicePixelRatio),this.dimensions.canvasHeight=Math.round(this.dimensions.scaledCanvasHeight/window.devicePixelRatio),this.dimensions.actualCellWidth=this.dimensions.canvasWidth/this._bufferService.cols,this.dimensions.actualCellHeight=this.dimensions.canvasHeight/this._bufferService.rows;for(var e=0,t=this._rowElements;e<t.length;e++){var r=t[e];r.style.width=this.dimensions.canvasWidth+"px",r.style.height=this.dimensions.actualCellHeight+"px",r.style.lineHeight=this.dimensions.actualCellHeight+"px",r.style.overflow="hidden"}this._dimensionsStyleElement||(this._dimensionsStyleElement=document.createElement("style"),this._screenElement.appendChild(this._dimensionsStyleElement));var i=this._terminalSelector+" .xterm-rows span { display: inline-block; height: 100%; vertical-align: top; width: "+this.dimensions.actualCellWidth+"px}";this._dimensionsStyleElement.textContent=i,this._selectionContainer.style.height=this._viewportElement.style.height,this._screenElement.style.width=this.dimensions.canvasWidth+"px",this._screenElement.style.height=this.dimensions.canvasHeight+"px"},t.prototype.setColors=function(e){this._colors=e,this._injectCss()},t.prototype._injectCss=function(){var e=this;this._themeStyleElement||(this._themeStyleElement=document.createElement("style"),this._screenElement.appendChild(this._themeStyleElement));var t=this._terminalSelector+" .xterm-rows { color: "+this._colors.foreground.css+"; font-family: "+this._optionsService.options.fontFamily+"; font-size: "+this._optionsService.options.fontSize+"px;}";t+=this._terminalSelector+" span:not(."+a.BOLD_CLASS+") { font-weight: "+this._optionsService.options.fontWeight+";}"+this._terminalSelector+" span."+a.BOLD_CLASS+" { font-weight: "+this._optionsService.options.fontWeightBold+";}"+this._terminalSelector+" span."+a.ITALIC_CLASS+" { font-style: italic;}",t+="@keyframes blink_box_shadow_"+this._terminalClass+" { 50% {  box-shadow: none; }}",t+="@keyframes blink_block_"+this._terminalClass+" { 0% {  background-color: "+this._colors.cursor.css+";  color: "+this._colors.cursorAccent.css+"; } 50% {  background-color: "+this._colors.cursorAccent.css+";  color: "+this._colors.cursor.css+"; }}",t+=this._terminalSelector+" .xterm-rows:not(.xterm-focus) ."+a.CURSOR_CLASS+"."+a.CURSOR_STYLE_BLOCK_CLASS+" { outline: 1px solid "+this._colors.cursor.css+"; outline-offset: -1px;}"+this._terminalSelector+" .xterm-rows.xterm-focus ."+a.CURSOR_CLASS+"."+a.CURSOR_BLINK_CLASS+":not(."+a.CURSOR_STYLE_BLOCK_CLASS+") { animation: blink_box_shadow_"+this._terminalClass+" 1s step-end infinite;}"+this._terminalSelector+" .xterm-rows.xterm-focus ."+a.CURSOR_CLASS+"."+a.CURSOR_BLINK_CLASS+"."+a.CURSOR_STYLE_BLOCK_CLASS+" { animation: blink_block_"+this._terminalClass+" 1s step-end infinite;}"+this._terminalSelector+" .xterm-rows.xterm-focus ."+a.CURSOR_CLASS+"."+a.CURSOR_STYLE_BLOCK_CLASS+" { background-color: "+this._colors.cursor.css+"; color: "+this._colors.cursorAccent.css+";}"+this._terminalSelector+" .xterm-rows ."+a.CURSOR_CLASS+"."+a.CURSOR_STYLE_BAR_CLASS+" { box-shadow: "+this._optionsService.options.cursorWidth+"px 0 0 "+this._colors.cursor.css+" inset;}"+this._terminalSelector+" .xterm-rows ."+a.CURSOR_CLASS+"."+a.CURSOR_STYLE_UNDERLINE_CLASS+" { box-shadow: 0 -1px 0 "+this._colors.cursor.css+" inset;}",t+=this._terminalSelector+" .xterm-selection { position: absolute; top: 0; left: 0; z-index: 1; pointer-events: none;}"+this._terminalSelector+" .xterm-selection div { position: absolute; background-color: "+this._colors.selectionTransparent.css+";}",this._colors.ansi.forEach((function(r,i){t+=e._terminalSelector+" ."+v+i+" { color: "+r.css+"; }"+e._terminalSelector+" ."+g+i+" { background-color: "+r.css+"; }"})),t+=this._terminalSelector+" ."+v+c.INVERTED_DEFAULT_COLOR+" { color: "+_.color.opaque(this._colors.background).css+"; }"+this._terminalSelector+" ."+g+c.INVERTED_DEFAULT_COLOR+" { background-color: "+this._colors.foreground.css+"; }",this._themeStyleElement.textContent=t},t.prototype.onDevicePixelRatioChange=function(){this._updateDimensions()},t.prototype._refreshRowElements=function(e,t){for(var r=this._rowElements.length;r<=t;r++){var i=document.createElement("div");this._rowContainer.appendChild(i),this._rowElements.push(i)}for(;this._rowElements.length>t;)this._rowContainer.removeChild(this._rowElements.pop())},t.prototype.onResize=function(e,t){this._refreshRowElements(e,t),this._updateDimensions()},t.prototype.onCharSizeChanged=function(){this._updateDimensions()},t.prototype.onBlur=function(){this._rowContainer.classList.remove(y)},t.prototype.onFocus=function(){this._rowContainer.classList.add(y)},t.prototype.onSelectionChanged=function(e,t,r){for(;this._selectionContainer.children.length;)this._selectionContainer.removeChild(this._selectionContainer.children[0]);if(e&&t){var i=e[1]-this._bufferService.buffer.ydisp,n=t[1]-this._bufferService.buffer.ydisp,o=Math.max(i,0),s=Math.min(n,this._bufferService.rows-1);if(!(o>=this._bufferService.rows||s<0)){var a=document.createDocumentFragment();if(r)a.appendChild(this._createSelectionElement(o,e[0],t[0],s-o+1));else{var c=i===o?e[0]:0,l=o===n?t[0]:this._bufferService.cols;a.appendChild(this._createSelectionElement(o,c,l));var h=s-o-1;if(a.appendChild(this._createSelectionElement(o+1,0,this._bufferService.cols,h)),o!==s){var u=n===s?t[0]:this._bufferService.cols;a.appendChild(this._createSelectionElement(s,0,u))}}this._selectionContainer.appendChild(a)}}},t.prototype._createSelectionElement=function(e,t,r,i){void 0===i&&(i=1);var n=document.createElement("div");return n.style.height=i*this.dimensions.actualCellHeight+"px",n.style.top=e*this.dimensions.actualCellHeight+"px",n.style.left=t*this.dimensions.actualCellWidth+"px",n.style.width=this.dimensions.actualCellWidth*(r-t)+"px",n},t.prototype.onCursorMove=function(){},t.prototype.onOptionsChanged=function(){this._updateDimensions(),this._injectCss()},t.prototype.clear=function(){for(var e=0,t=this._rowElements;e<t.length;e++)t[e].innerText=""},t.prototype.renderRows=function(e,t){for(var r=this._bufferService.buffer.ybase+this._bufferService.buffer.y,i=Math.min(this._bufferService.buffer.x,this._bufferService.cols-1),n=this._optionsService.options.cursorBlink,o=e;o<=t;o++){var s=this._rowElements[o];s.innerText="";var a=o+this._bufferService.buffer.ydisp,c=this._bufferService.buffer.lines.get(a),l=this._optionsService.options.cursorStyle;s.appendChild(this._rowFactory.createRow(c,a,a===r,l,i,n,this.dimensions.actualCellWidth,this._bufferService.cols))}},Object.defineProperty(t.prototype,"_terminalSelector",{get:function(){return"."+p+this._terminalClass},enumerable:!1,configurable:!0}),t.prototype._onLinkHover=function(e){this._setCellUnderline(e.x1,e.x2,e.y1,e.y2,e.cols,!0)},t.prototype._onLinkLeave=function(e){this._setCellUnderline(e.x1,e.x2,e.y1,e.y2,e.cols,!1)},t.prototype._setCellUnderline=function(e,t,r,i,n,o){for(;e!==t||r!==i;){var s=this._rowElements[r];if(!s)return;var a=s.children[e];a&&(a.style.textDecoration=o?"underline":"none"),++e>=n&&(e=0,r++)}},o([s(6,u.IInstantiationService),s(7,h.ICharSizeService),s(8,u.IOptionsService),s(9,u.IBufferService)],t)}(l.Disposable);t.DomRenderer=S},3787:function(e,t,r){var i=this&&this.__decorate||function(e,t,r,i){var n,o=arguments.length,s=o<3?t:null===i?i=Object.getOwnPropertyDescriptor(t,r):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)s=Reflect.decorate(e,t,r,i);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(s=(o<3?n(s):o>3?n(t,r,s):n(t,r))||s);return o>3&&s&&Object.defineProperty(t,r,s),s},n=this&&this.__param||function(e,t){return function(r,i){t(r,i,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.DomRendererRowFactory=t.CURSOR_STYLE_UNDERLINE_CLASS=t.CURSOR_STYLE_BAR_CLASS=t.CURSOR_STYLE_BLOCK_CLASS=t.CURSOR_BLINK_CLASS=t.CURSOR_CLASS=t.STRIKETHROUGH_CLASS=t.UNDERLINE_CLASS=t.ITALIC_CLASS=t.DIM_CLASS=t.BOLD_CLASS=void 0;var o=r(8803),s=r(643),a=r(511),c=r(2585),l=r(4774),h=r(4725),u=r(4269);t.BOLD_CLASS="xterm-bold",t.DIM_CLASS="xterm-dim",t.ITALIC_CLASS="xterm-italic",t.UNDERLINE_CLASS="xterm-underline",t.STRIKETHROUGH_CLASS="xterm-strikethrough",t.CURSOR_CLASS="xterm-cursor",t.CURSOR_BLINK_CLASS="xterm-cursor-blink",t.CURSOR_STYLE_BLOCK_CLASS="xterm-cursor-block",t.CURSOR_STYLE_BAR_CLASS="xterm-cursor-bar",t.CURSOR_STYLE_UNDERLINE_CLASS="xterm-cursor-underline";var f=function(){function e(e,t,r,i,n){this._document=e,this._colors=t,this._characterJoinerService=r,this._optionsService=i,this._coreService=n,this._workCell=new a.CellData}return e.prototype.setColors=function(e){this._colors=e},e.prototype.createRow=function(e,r,i,n,a,c,h,f){for(var d=this._document.createDocumentFragment(),p=this._characterJoinerService.getJoinedCharacters(r),v=0,g=Math.min(e.length,f)-1;g>=0;g--)if(e.loadCell(g,this._workCell).getCode()!==s.NULL_CELL_CODE||i&&g===a){v=g+1;break}for(g=0;g<v;g++){e.loadCell(g,this._workCell);var y=this._workCell.getWidth();if(0!==y){var m=!1,S=g,C=this._workCell;if(p.length>0&&g===p[0][0]){m=!0;var b=p.shift();C=new u.JoinedCellData(this._workCell,e.translateToString(!0,b[0],b[1]),b[1]-b[0]),S=b[1]-1,y=C.getWidth()}var w=this._document.createElement("span");if(y>1&&(w.style.width=h*y+"px"),m&&(w.style.display="inline",a>=g&&a<=S&&(a=g)),!this._coreService.isCursorHidden&&i&&g===a)switch(w.classList.add(t.CURSOR_CLASS),c&&w.classList.add(t.CURSOR_BLINK_CLASS),n){case"bar":w.classList.add(t.CURSOR_STYLE_BAR_CLASS);break;case"underline":w.classList.add(t.CURSOR_STYLE_UNDERLINE_CLASS);break;default:w.classList.add(t.CURSOR_STYLE_BLOCK_CLASS)}C.isBold()&&w.classList.add(t.BOLD_CLASS),C.isItalic()&&w.classList.add(t.ITALIC_CLASS),C.isDim()&&w.classList.add(t.DIM_CLASS),C.isUnderline()&&w.classList.add(t.UNDERLINE_CLASS),C.isInvisible()?w.textContent=s.WHITESPACE_CELL_CHAR:w.textContent=C.getChars()||s.WHITESPACE_CELL_CHAR,C.isStrikethrough()&&w.classList.add(t.STRIKETHROUGH_CLASS);var L=C.getFgColor(),E=C.getFgColorMode(),x=C.getBgColor(),M=C.getBgColorMode(),k=!!C.isInverse();if(k){var A=L;L=x,x=A;var R=E;E=M,M=R}switch(E){case 16777216:case 33554432:C.isBold()&&L<8&&this._optionsService.options.drawBoldTextInBrightColors&&(L+=8),this._applyMinimumContrast(w,this._colors.background,this._colors.ansi[L])||w.classList.add("xterm-fg-"+L);break;case 50331648:var T=l.rgba.toColor(L>>16&255,L>>8&255,255&L);this._applyMinimumContrast(w,this._colors.background,T)||this._addStyle(w,"color:#"+_(L.toString(16),"0",6));break;default:this._applyMinimumContrast(w,this._colors.background,this._colors.foreground)||k&&w.classList.add("xterm-fg-"+o.INVERTED_DEFAULT_COLOR)}switch(M){case 16777216:case 33554432:w.classList.add("xterm-bg-"+x);break;case 50331648:this._addStyle(w,"background-color:#"+_(x.toString(16),"0",6));break;default:k&&w.classList.add("xterm-bg-"+o.INVERTED_DEFAULT_COLOR)}d.appendChild(w),g=S}}return d},e.prototype._applyMinimumContrast=function(e,t,r){if(1===this._optionsService.options.minimumContrastRatio)return!1;var i=this._colors.contrastCache.getColor(this._workCell.bg,this._workCell.fg);return void 0===i&&(i=l.color.ensureContrastRatio(t,r,this._optionsService.options.minimumContrastRatio),this._colors.contrastCache.setColor(this._workCell.bg,this._workCell.fg,null!=i?i:null)),!!i&&(this._addStyle(e,"color:"+i.css),!0)},e.prototype._addStyle=function(e,t){e.setAttribute("style",""+(e.getAttribute("style")||"")+t+";")},i([n(2,h.ICharacterJoinerService),n(3,c.IOptionsService),n(4,c.ICoreService)],e)}();function _(e,t,r){for(;e.length<r;)e=t+e;return e}t.DomRendererRowFactory=f},456:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.SelectionModel=void 0;var r=function(){function e(e){this._bufferService=e,this.isSelectAllActive=!1,this.selectionStartLength=0}return e.prototype.clearSelection=function(){this.selectionStart=void 0,this.selectionEnd=void 0,this.isSelectAllActive=!1,this.selectionStartLength=0},Object.defineProperty(e.prototype,"finalSelectionStart",{get:function(){return this.isSelectAllActive?[0,0]:this.selectionEnd&&this.selectionStart&&this.areSelectionValuesReversed()?this.selectionEnd:this.selectionStart},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"finalSelectionEnd",{get:function(){if(this.isSelectAllActive)return[this._bufferService.cols,this._bufferService.buffer.ybase+this._bufferService.rows-1];if(this.selectionStart){if(!this.selectionEnd||this.areSelectionValuesReversed()){var e=this.selectionStart[0]+this.selectionStartLength;return e>this._bufferService.cols?e%this._bufferService.cols==0?[this._bufferService.cols,this.selectionStart[1]+Math.floor(e/this._bufferService.cols)-1]:[e%this._bufferService.cols,this.selectionStart[1]+Math.floor(e/this._bufferService.cols)]:[e,this.selectionStart[1]]}return this.selectionStartLength&&this.selectionEnd[1]===this.selectionStart[1]?[Math.max(this.selectionStart[0]+this.selectionStartLength,this.selectionEnd[0]),this.selectionEnd[1]]:this.selectionEnd}},enumerable:!1,configurable:!0}),e.prototype.areSelectionValuesReversed=function(){var e=this.selectionStart,t=this.selectionEnd;return!(!e||!t)&&(e[1]>t[1]||e[1]===t[1]&&e[0]>t[0])},e.prototype.onTrim=function(e){return this.selectionStart&&(this.selectionStart[1]-=e),this.selectionEnd&&(this.selectionEnd[1]-=e),this.selectionEnd&&this.selectionEnd[1]<0?(this.clearSelection(),!0):(this.selectionStart&&this.selectionStart[1]<0&&(this.selectionStart[1]=0),!1)},e}();t.SelectionModel=r},428:function(e,t,r){var i=this&&this.__decorate||function(e,t,r,i){var n,o=arguments.length,s=o<3?t:null===i?i=Object.getOwnPropertyDescriptor(t,r):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)s=Reflect.decorate(e,t,r,i);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(s=(o<3?n(s):o>3?n(t,r,s):n(t,r))||s);return o>3&&s&&Object.defineProperty(t,r,s),s},n=this&&this.__param||function(e,t){return function(r,i){t(r,i,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.CharSizeService=void 0;var o=r(2585),s=r(8460),a=function(){function e(e,t,r){this._optionsService=r,this.width=0,this.height=0,this._onCharSizeChange=new s.EventEmitter,this._measureStrategy=new c(e,t,this._optionsService)}return Object.defineProperty(e.prototype,"hasValidSize",{get:function(){return this.width>0&&this.height>0},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"onCharSizeChange",{get:function(){return this._onCharSizeChange.event},enumerable:!1,configurable:!0}),e.prototype.measure=function(){var e=this._measureStrategy.measure();e.width===this.width&&e.height===this.height||(this.width=e.width,this.height=e.height,this._onCharSizeChange.fire())},i([n(2,o.IOptionsService)],e)}();t.CharSizeService=a;var c=function(){function e(e,t,r){this._document=e,this._parentElement=t,this._optionsService=r,this._result={width:0,height:0},this._measureElement=this._document.createElement("span"),this._measureElement.classList.add("xterm-char-measure-element"),this._measureElement.textContent="W",this._measureElement.setAttribute("aria-hidden","true"),this._parentElement.appendChild(this._measureElement)}return e.prototype.measure=function(){this._measureElement.style.fontFamily=this._optionsService.options.fontFamily,this._measureElement.style.fontSize=this._optionsService.options.fontSize+"px";var e=this._measureElement.getBoundingClientRect();return 0!==e.width&&0!==e.height&&(this._result.width=e.width,this._result.height=Math.ceil(e.height)),this._result},e}()},4269:function(e,t,r){var i,n=this&&this.__extends||(i=function(e,t){return i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])},i(e,t)},function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function r(){this.constructor=e}i(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)}),o=this&&this.__decorate||function(e,t,r,i){var n,o=arguments.length,s=o<3?t:null===i?i=Object.getOwnPropertyDescriptor(t,r):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)s=Reflect.decorate(e,t,r,i);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(s=(o<3?n(s):o>3?n(t,r,s):n(t,r))||s);return o>3&&s&&Object.defineProperty(t,r,s),s},s=this&&this.__param||function(e,t){return function(r,i){t(r,i,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.CharacterJoinerService=t.JoinedCellData=void 0;var a=r(3734),c=r(643),l=r(511),h=r(2585),u=function(e){function t(t,r,i){var n=e.call(this)||this;return n.content=0,n.combinedData="",n.fg=t.fg,n.bg=t.bg,n.combinedData=r,n._width=i,n}return n(t,e),t.prototype.isCombined=function(){return 2097152},t.prototype.getWidth=function(){return this._width},t.prototype.getChars=function(){return this.combinedData},t.prototype.getCode=function(){return 2097151},t.prototype.setFromCharData=function(e){throw new Error("not implemented")},t.prototype.getAsCharData=function(){return[this.fg,this.getChars(),this.getWidth(),this.getCode()]},t}(a.AttributeData);t.JoinedCellData=u;var f=function(){function e(e){this._bufferService=e,this._characterJoiners=[],this._nextCharacterJoinerId=0,this._workCell=new l.CellData}return e.prototype.register=function(e){var t={id:this._nextCharacterJoinerId++,handler:e};return this._characterJoiners.push(t),t.id},e.prototype.deregister=function(e){for(var t=0;t<this._characterJoiners.length;t++)if(this._characterJoiners[t].id===e)return this._characterJoiners.splice(t,1),!0;return!1},e.prototype.getJoinedCharacters=function(e){if(0===this._characterJoiners.length)return[];var t=this._bufferService.buffer.lines.get(e);if(!t||0===t.length)return[];for(var r=[],i=t.translateToString(!0),n=0,o=0,s=0,a=t.getFg(0),l=t.getBg(0),h=0;h<t.getTrimmedLength();h++)if(t.loadCell(h,this._workCell),0!==this._workCell.getWidth()){if(this._workCell.fg!==a||this._workCell.bg!==l){if(h-n>1)for(var u=this._getJoinedRanges(i,s,o,t,n),f=0;f<u.length;f++)r.push(u[f]);n=h,s=o,a=this._workCell.fg,l=this._workCell.bg}o+=this._workCell.getChars().length||c.WHITESPACE_CELL_CHAR.length}if(this._bufferService.cols-n>1)for(u=this._getJoinedRanges(i,s,o,t,n),f=0;f<u.length;f++)r.push(u[f]);return r},e.prototype._getJoinedRanges=function(t,r,i,n,o){var s=t.substring(r,i),a=[];try{a=this._characterJoiners[0].handler(s)}catch(e){console.error(e)}for(var c=1;c<this._characterJoiners.length;c++)try{for(var l=this._characterJoiners[c].handler(s),h=0;h<l.length;h++)e._mergeRanges(a,l[h])}catch(e){console.error(e)}return this._stringRangesToCellRanges(a,n,o),a},e.prototype._stringRangesToCellRanges=function(e,t,r){var i=0,n=!1,o=0,s=e[i];if(s){for(var a=r;a<this._bufferService.cols;a++){var l=t.getWidth(a),h=t.getString(a).length||c.WHITESPACE_CELL_CHAR.length;if(0!==l){if(!n&&s[0]<=o&&(s[0]=a,n=!0),s[1]<=o){if(s[1]=a,!(s=e[++i]))break;s[0]<=o?(s[0]=a,n=!0):n=!1}o+=h}}s&&(s[1]=this._bufferService.cols)}},e._mergeRanges=function(e,t){for(var r=!1,i=0;i<e.length;i++){var n=e[i];if(r){if(t[1]<=n[0])return e[i-1][1]=t[1],e;if(t[1]<=n[1])return e[i-1][1]=Math.max(t[1],n[1]),e.splice(i,1),e;e.splice(i,1),i--}else{if(t[1]<=n[0])return e.splice(i,0,t),e;if(t[1]<=n[1])return n[0]=Math.min(t[0],n[0]),e;t[0]<n[1]&&(n[0]=Math.min(t[0],n[0]),r=!0)}}return r?e[e.length-1][1]=t[1]:e.push(t),e},e=o([s(0,h.IBufferService)],e)}();t.CharacterJoinerService=f},5114:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.CoreBrowserService=void 0;var r=function(){function e(e){this._textarea=e}return Object.defineProperty(e.prototype,"isFocused",{get:function(){return(this._textarea.getRootNode?this._textarea.getRootNode():document).activeElement===this._textarea&&document.hasFocus()},enumerable:!1,configurable:!0}),e}();t.CoreBrowserService=r},8934:function(e,t,r){var i=this&&this.__decorate||function(e,t,r,i){var n,o=arguments.length,s=o<3?t:null===i?i=Object.getOwnPropertyDescriptor(t,r):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)s=Reflect.decorate(e,t,r,i);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(s=(o<3?n(s):o>3?n(t,r,s):n(t,r))||s);return o>3&&s&&Object.defineProperty(t,r,s),s},n=this&&this.__param||function(e,t){return function(r,i){t(r,i,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.MouseService=void 0;var o=r(4725),s=r(9806),a=function(){function e(e,t){this._renderService=e,this._charSizeService=t}return e.prototype.getCoords=function(e,t,r,i,n){return(0,s.getCoords)(e,t,r,i,this._charSizeService.hasValidSize,this._renderService.dimensions.actualCellWidth,this._renderService.dimensions.actualCellHeight,n)},e.prototype.getRawByteCoords=function(e,t,r,i){var n=this.getCoords(e,t,r,i);return(0,s.getRawByteCoords)(n)},i([n(0,o.IRenderService),n(1,o.ICharSizeService)],e)}();t.MouseService=a},3230:function(e,t,r){var i,n=this&&this.__extends||(i=function(e,t){return i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])},i(e,t)},function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function r(){this.constructor=e}i(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)}),o=this&&this.__decorate||function(e,t,r,i){var n,o=arguments.length,s=o<3?t:null===i?i=Object.getOwnPropertyDescriptor(t,r):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)s=Reflect.decorate(e,t,r,i);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(s=(o<3?n(s):o>3?n(t,r,s):n(t,r))||s);return o>3&&s&&Object.defineProperty(t,r,s),s},s=this&&this.__param||function(e,t){return function(r,i){t(r,i,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.RenderService=void 0;var a=r(6193),c=r(8460),l=r(844),h=r(5596),u=r(3656),f=r(2585),_=r(4725),d=function(e){function t(t,r,i,n,o,s){var l=e.call(this)||this;if(l._renderer=t,l._rowCount=r,l._charSizeService=o,l._isPaused=!1,l._needsFullRefresh=!1,l._isNextRenderRedrawOnly=!0,l._needsSelectionRefresh=!1,l._canvasWidth=0,l._canvasHeight=0,l._selectionState={start:void 0,end:void 0,columnSelectMode:!1},l._onDimensionsChange=new c.EventEmitter,l._onRender=new c.EventEmitter,l._onRefreshRequest=new c.EventEmitter,l.register({dispose:function(){return l._renderer.dispose()}}),l._renderDebouncer=new a.RenderDebouncer((function(e,t){return l._renderRows(e,t)})),l.register(l._renderDebouncer),l._screenDprMonitor=new h.ScreenDprMonitor,l._screenDprMonitor.setListener((function(){return l.onDevicePixelRatioChange()})),l.register(l._screenDprMonitor),l.register(s.onResize((function(e){return l._fullRefresh()}))),l.register(n.onOptionChange((function(){return l._renderer.onOptionsChanged()}))),l.register(l._charSizeService.onCharSizeChange((function(){return l.onCharSizeChanged()}))),l._renderer.onRequestRedraw((function(e){return l.refreshRows(e.start,e.end,!0)})),l.register((0,u.addDisposableDomListener)(window,"resize",(function(){return l.onDevicePixelRatioChange()}))),"IntersectionObserver"in window){var f=new IntersectionObserver((function(e){return l._onIntersectionChange(e[e.length-1])}),{threshold:0});f.observe(i),l.register({dispose:function(){return f.disconnect()}})}return l}return n(t,e),Object.defineProperty(t.prototype,"onDimensionsChange",{get:function(){return this._onDimensionsChange.event},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"onRenderedBufferChange",{get:function(){return this._onRender.event},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"onRefreshRequest",{get:function(){return this._onRefreshRequest.event},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"dimensions",{get:function(){return this._renderer.dimensions},enumerable:!1,configurable:!0}),t.prototype._onIntersectionChange=function(e){this._isPaused=void 0===e.isIntersecting?0===e.intersectionRatio:!e.isIntersecting,this._isPaused||this._charSizeService.hasValidSize||this._charSizeService.measure(),!this._isPaused&&this._needsFullRefresh&&(this.refreshRows(0,this._rowCount-1),this._needsFullRefresh=!1)},t.prototype.refreshRows=function(e,t,r){void 0===r&&(r=!1),this._isPaused?this._needsFullRefresh=!0:(r||(this._isNextRenderRedrawOnly=!1),this._renderDebouncer.refresh(e,t,this._rowCount))},t.prototype._renderRows=function(e,t){this._renderer.renderRows(e,t),this._needsSelectionRefresh&&(this._renderer.onSelectionChanged(this._selectionState.start,this._selectionState.end,this._selectionState.columnSelectMode),this._needsSelectionRefresh=!1),this._isNextRenderRedrawOnly||this._onRender.fire({start:e,end:t}),this._isNextRenderRedrawOnly=!0},t.prototype.resize=function(e,t){this._rowCount=t,this._fireOnCanvasResize()},t.prototype.changeOptions=function(){this._renderer.onOptionsChanged(),this.refreshRows(0,this._rowCount-1),this._fireOnCanvasResize()},t.prototype._fireOnCanvasResize=function(){this._renderer.dimensions.canvasWidth===this._canvasWidth&&this._renderer.dimensions.canvasHeight===this._canvasHeight||this._onDimensionsChange.fire(this._renderer.dimensions)},t.prototype.dispose=function(){e.prototype.dispose.call(this)},t.prototype.setRenderer=function(e){var t=this;this._renderer.dispose(),this._renderer=e,this._renderer.onRequestRedraw((function(e){return t.refreshRows(e.start,e.end,!0)})),this._needsSelectionRefresh=!0,this._fullRefresh()},t.prototype._fullRefresh=function(){this._isPaused?this._needsFullRefresh=!0:this.refreshRows(0,this._rowCount-1)},t.prototype.clearTextureAtlas=function(){var e,t;null===(t=null===(e=this._renderer)||void 0===e?void 0:e.clearTextureAtlas)||void 0===t||t.call(e),this._fullRefresh()},t.prototype.setColors=function(e){this._renderer.setColors(e),this._fullRefresh()},t.prototype.onDevicePixelRatioChange=function(){this._charSizeService.measure(),this._renderer.onDevicePixelRatioChange(),this.refreshRows(0,this._rowCount-1)},t.prototype.onResize=function(e,t){this._renderer.onResize(e,t),this._fullRefresh()},t.prototype.onCharSizeChanged=function(){this._renderer.onCharSizeChanged()},t.prototype.onBlur=function(){this._renderer.onBlur()},t.prototype.onFocus=function(){this._renderer.onFocus()},t.prototype.onSelectionChanged=function(e,t,r){this._selectionState.start=e,this._selectionState.end=t,this._selectionState.columnSelectMode=r,this._renderer.onSelectionChanged(e,t,r)},t.prototype.onCursorMove=function(){this._renderer.onCursorMove()},t.prototype.clear=function(){this._renderer.clear()},o([s(3,f.IOptionsService),s(4,_.ICharSizeService),s(5,f.IBufferService)],t)}(l.Disposable);t.RenderService=d},9312:function(e,t,r){var i,n=this&&this.__extends||(i=function(e,t){return i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])},i(e,t)},function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function r(){this.constructor=e}i(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)}),o=this&&this.__decorate||function(e,t,r,i){var n,o=arguments.length,s=o<3?t:null===i?i=Object.getOwnPropertyDescriptor(t,r):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)s=Reflect.decorate(e,t,r,i);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(s=(o<3?n(s):o>3?n(t,r,s):n(t,r))||s);return o>3&&s&&Object.defineProperty(t,r,s),s},s=this&&this.__param||function(e,t){return function(r,i){t(r,i,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.SelectionService=void 0;var a=r(6114),c=r(456),l=r(511),h=r(8460),u=r(4725),f=r(2585),_=r(9806),d=r(9504),p=r(844),v=r(4841),g=String.fromCharCode(160),y=new RegExp(g,"g"),m=function(e){function t(t,r,i,n,o,s,a,u){var f=e.call(this)||this;return f._element=t,f._screenElement=r,f._linkifier=i,f._bufferService=n,f._coreService=o,f._mouseService=s,f._optionsService=a,f._renderService=u,f._dragScrollAmount=0,f._enabled=!0,f._workCell=new l.CellData,f._mouseDownTimeStamp=0,f._oldHasSelection=!1,f._oldSelectionStart=void 0,f._oldSelectionEnd=void 0,f._onLinuxMouseSelection=f.register(new h.EventEmitter),f._onRedrawRequest=f.register(new h.EventEmitter),f._onSelectionChange=f.register(new h.EventEmitter),f._onRequestScrollLines=f.register(new h.EventEmitter),f._mouseMoveListener=function(e){return f._onMouseMove(e)},f._mouseUpListener=function(e){return f._onMouseUp(e)},f._coreService.onUserInput((function(){f.hasSelection&&f.clearSelection()})),f._trimListener=f._bufferService.buffer.lines.onTrim((function(e){return f._onTrim(e)})),f.register(f._bufferService.buffers.onBufferActivate((function(e){return f._onBufferActivate(e)}))),f.enable(),f._model=new c.SelectionModel(f._bufferService),f._activeSelectionMode=0,f}return n(t,e),Object.defineProperty(t.prototype,"onLinuxMouseSelection",{get:function(){return this._onLinuxMouseSelection.event},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"onRequestRedraw",{get:function(){return this._onRedrawRequest.event},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"onSelectionChange",{get:function(){return this._onSelectionChange.event},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"onRequestScrollLines",{get:function(){return this._onRequestScrollLines.event},enumerable:!1,configurable:!0}),t.prototype.dispose=function(){this._removeMouseDownListeners()},t.prototype.reset=function(){this.clearSelection()},t.prototype.disable=function(){this.clearSelection(),this._enabled=!1},t.prototype.enable=function(){this._enabled=!0},Object.defineProperty(t.prototype,"selectionStart",{get:function(){return this._model.finalSelectionStart},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"selectionEnd",{get:function(){return this._model.finalSelectionEnd},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"hasSelection",{get:function(){var e=this._model.finalSelectionStart,t=this._model.finalSelectionEnd;return!(!e||!t||e[0]===t[0]&&e[1]===t[1])},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"selectionText",{get:function(){var e=this._model.finalSelectionStart,t=this._model.finalSelectionEnd;if(!e||!t)return"";var r=this._bufferService.buffer,i=[];if(3===this._activeSelectionMode){if(e[0]===t[0])return"";for(var n=e[1];n<=t[1];n++){var o=r.translateBufferLineToString(n,!0,e[0],t[0]);i.push(o)}}else{var s=e[1]===t[1]?t[0]:void 0;for(i.push(r.translateBufferLineToString(e[1],!0,e[0],s)),n=e[1]+1;n<=t[1]-1;n++){var c=r.lines.get(n);o=r.translateBufferLineToString(n,!0),(null==c?void 0:c.isWrapped)?i[i.length-1]+=o:i.push(o)}e[1]!==t[1]&&(c=r.lines.get(t[1]),o=r.translateBufferLineToString(t[1],!0,0,t[0]),c&&c.isWrapped?i[i.length-1]+=o:i.push(o))}return i.map((function(e){return e.replace(y," ")})).join(a.isWindows?"\r\n":"\n")},enumerable:!1,configurable:!0}),t.prototype.clearSelection=function(){this._model.clearSelection(),this._removeMouseDownListeners(),this.refresh(),this._onSelectionChange.fire()},t.prototype.refresh=function(e){var t=this;this._refreshAnimationFrame||(this._refreshAnimationFrame=window.requestAnimationFrame((function(){return t._refresh()}))),a.isLinux&&e&&this.selectionText.length&&this._onLinuxMouseSelection.fire(this.selectionText)},t.prototype._refresh=function(){this._refreshAnimationFrame=void 0,this._onRedrawRequest.fire({start:this._model.finalSelectionStart,end:this._model.finalSelectionEnd,columnSelectMode:3===this._activeSelectionMode})},t.prototype._isClickInSelection=function(e){var t=this._getMouseBufferCoords(e),r=this._model.finalSelectionStart,i=this._model.finalSelectionEnd;return!!(r&&i&&t)&&this._areCoordsInSelection(t,r,i)},t.prototype._areCoordsInSelection=function(e,t,r){return e[1]>t[1]&&e[1]<r[1]||t[1]===r[1]&&e[1]===t[1]&&e[0]>=t[0]&&e[0]<r[0]||t[1]<r[1]&&e[1]===r[1]&&e[0]<r[0]||t[1]<r[1]&&e[1]===t[1]&&e[0]>=t[0]},t.prototype._selectWordAtCursor=function(e,t){var r,i,n=null===(i=null===(r=this._linkifier.currentLink)||void 0===r?void 0:r.link)||void 0===i?void 0:i.range;if(n)return this._model.selectionStart=[n.start.x-1,n.start.y-1],this._model.selectionStartLength=(0,v.getRangeLength)(n,this._bufferService.cols),this._model.selectionEnd=void 0,!0;var o=this._getMouseBufferCoords(e);return!!o&&(this._selectWordAt(o,t),this._model.selectionEnd=void 0,!0)},t.prototype.selectAll=function(){this._model.isSelectAllActive=!0,this.refresh(),this._onSelectionChange.fire()},t.prototype.selectLines=function(e,t){this._model.clearSelection(),e=Math.max(e,0),t=Math.min(t,this._bufferService.buffer.lines.length-1),this._model.selectionStart=[0,e],this._model.selectionEnd=[this._bufferService.cols,t],this.refresh(),this._onSelectionChange.fire()},t.prototype._onTrim=function(e){this._model.onTrim(e)&&this.refresh()},t.prototype._getMouseBufferCoords=function(e){var t=this._mouseService.getCoords(e,this._screenElement,this._bufferService.cols,this._bufferService.rows,!0);if(t)return t[0]--,t[1]--,t[1]+=this._bufferService.buffer.ydisp,t},t.prototype._getMouseEventScrollAmount=function(e){var t=(0,_.getCoordsRelativeToElement)(e,this._screenElement)[1],r=this._renderService.dimensions.canvasHeight;return t>=0&&t<=r?0:(t>r&&(t-=r),t=Math.min(Math.max(t,-50),50),(t/=50)/Math.abs(t)+Math.round(14*t))},t.prototype.shouldForceSelection=function(e){return a.isMac?e.altKey&&this._optionsService.options.macOptionClickForcesSelection:e.shiftKey},t.prototype.onMouseDown=function(e){if(this._mouseDownTimeStamp=e.timeStamp,(2!==e.button||!this.hasSelection)&&0===e.button){if(!this._enabled){if(!this.shouldForceSelection(e))return;e.stopPropagation()}e.preventDefault(),this._dragScrollAmount=0,this._enabled&&e.shiftKey?this._onIncrementalClick(e):1===e.detail?this._onSingleClick(e):2===e.detail?this._onDoubleClick(e):3===e.detail&&this._onTripleClick(e),this._addMouseDownListeners(),this.refresh(!0)}},t.prototype._addMouseDownListeners=function(){var e=this;this._screenElement.ownerDocument&&(this._screenElement.ownerDocument.addEventListener("mousemove",this._mouseMoveListener),this._screenElement.ownerDocument.addEventListener("mouseup",this._mouseUpListener)),this._dragScrollIntervalTimer=window.setInterval((function(){return e._dragScroll()}),50)},t.prototype._removeMouseDownListeners=function(){this._screenElement.ownerDocument&&(this._screenElement.ownerDocument.removeEventListener("mousemove",this._mouseMoveListener),this._screenElement.ownerDocument.removeEventListener("mouseup",this._mouseUpListener)),clearInterval(this._dragScrollIntervalTimer),this._dragScrollIntervalTimer=void 0},t.prototype._onIncrementalClick=function(e){this._model.selectionStart&&(this._model.selectionEnd=this._getMouseBufferCoords(e))},t.prototype._onSingleClick=function(e){if(this._model.selectionStartLength=0,this._model.isSelectAllActive=!1,this._activeSelectionMode=this.shouldColumnSelect(e)?3:0,this._model.selectionStart=this._getMouseBufferCoords(e),this._model.selectionStart){this._model.selectionEnd=void 0;var t=this._bufferService.buffer.lines.get(this._model.selectionStart[1]);t&&t.length!==this._model.selectionStart[0]&&0===t.hasWidth(this._model.selectionStart[0])&&this._model.selectionStart[0]++}},t.prototype._onDoubleClick=function(e){this._selectWordAtCursor(e,!0)&&(this._activeSelectionMode=1)},t.prototype._onTripleClick=function(e){var t=this._getMouseBufferCoords(e);t&&(this._activeSelectionMode=2,this._selectLineAt(t[1]))},t.prototype.shouldColumnSelect=function(e){return e.altKey&&!(a.isMac&&this._optionsService.options.macOptionClickForcesSelection)},t.prototype._onMouseMove=function(e){if(e.stopImmediatePropagation(),this._model.selectionStart){var t=this._model.selectionEnd?[this._model.selectionEnd[0],this._model.selectionEnd[1]]:null;if(this._model.selectionEnd=this._getMouseBufferCoords(e),this._model.selectionEnd){2===this._activeSelectionMode?this._model.selectionEnd[1]<this._model.selectionStart[1]?this._model.selectionEnd[0]=0:this._model.selectionEnd[0]=this._bufferService.cols:1===this._activeSelectionMode&&this._selectToWordAt(this._model.selectionEnd),this._dragScrollAmount=this._getMouseEventScrollAmount(e),3!==this._activeSelectionMode&&(this._dragScrollAmount>0?this._model.selectionEnd[0]=this._bufferService.cols:this._dragScrollAmount<0&&(this._model.selectionEnd[0]=0));var r=this._bufferService.buffer;if(this._model.selectionEnd[1]<r.lines.length){var i=r.lines.get(this._model.selectionEnd[1]);i&&0===i.hasWidth(this._model.selectionEnd[0])&&this._model.selectionEnd[0]++}t&&t[0]===this._model.selectionEnd[0]&&t[1]===this._model.selectionEnd[1]||this.refresh(!0)}else this.refresh(!0)}},t.prototype._dragScroll=function(){if(this._model.selectionEnd&&this._model.selectionStart&&this._dragScrollAmount){this._onRequestScrollLines.fire({amount:this._dragScrollAmount,suppressScrollEvent:!1});var e=this._bufferService.buffer;this._dragScrollAmount>0?(3!==this._activeSelectionMode&&(this._model.selectionEnd[0]=this._bufferService.cols),this._model.selectionEnd[1]=Math.min(e.ydisp+this._bufferService.rows,e.lines.length-1)):(3!==this._activeSelectionMode&&(this._model.selectionEnd[0]=0),this._model.selectionEnd[1]=e.ydisp),this.refresh()}},t.prototype._onMouseUp=function(e){var t=e.timeStamp-this._mouseDownTimeStamp;if(this._removeMouseDownListeners(),this.selectionText.length<=1&&t<500&&e.altKey&&this._optionsService.getOption("altClickMovesCursor")){if(this._bufferService.buffer.ybase===this._bufferService.buffer.ydisp){var r=this._mouseService.getCoords(e,this._element,this._bufferService.cols,this._bufferService.rows,!1);if(r&&void 0!==r[0]&&void 0!==r[1]){var i=(0,d.moveToCellSequence)(r[0]-1,r[1]-1,this._bufferService,this._coreService.decPrivateModes.applicationCursorKeys);this._coreService.triggerDataEvent(i,!0)}}}else this._fireEventIfSelectionChanged()},t.prototype._fireEventIfSelectionChanged=function(){var e=this._model.finalSelectionStart,t=this._model.finalSelectionEnd,r=!(!e||!t||e[0]===t[0]&&e[1]===t[1]);r?e&&t&&(this._oldSelectionStart&&this._oldSelectionEnd&&e[0]===this._oldSelectionStart[0]&&e[1]===this._oldSelectionStart[1]&&t[0]===this._oldSelectionEnd[0]&&t[1]===this._oldSelectionEnd[1]||this._fireOnSelectionChange(e,t,r)):this._oldHasSelection&&this._fireOnSelectionChange(e,t,r)},t.prototype._fireOnSelectionChange=function(e,t,r){this._oldSelectionStart=e,this._oldSelectionEnd=t,this._oldHasSelection=r,this._onSelectionChange.fire()},t.prototype._onBufferActivate=function(e){var t=this;this.clearSelection(),this._trimListener.dispose(),this._trimListener=e.activeBuffer.lines.onTrim((function(e){return t._onTrim(e)}))},t.prototype._convertViewportColToCharacterIndex=function(e,t){for(var r=t[0],i=0;t[0]>=i;i++){var n=e.loadCell(i,this._workCell).getChars().length;0===this._workCell.getWidth()?r--:n>1&&t[0]!==i&&(r+=n-1)}return r},t.prototype.setSelection=function(e,t,r){this._model.clearSelection(),this._removeMouseDownListeners(),this._model.selectionStart=[e,t],this._model.selectionStartLength=r,this.refresh()},t.prototype.rightClickSelect=function(e){this._isClickInSelection(e)||(this._selectWordAtCursor(e,!1)&&this.refresh(!0),this._fireEventIfSelectionChanged())},t.prototype._getWordAt=function(e,t,r,i){if(void 0===r&&(r=!0),void 0===i&&(i=!0),!(e[0]>=this._bufferService.cols)){var n=this._bufferService.buffer,o=n.lines.get(e[1]);if(o){var s=n.translateBufferLineToString(e[1],!1),a=this._convertViewportColToCharacterIndex(o,e),c=a,l=e[0]-a,h=0,u=0,f=0,_=0;if(" "===s.charAt(a)){for(;a>0&&" "===s.charAt(a-1);)a--;for(;c<s.length&&" "===s.charAt(c+1);)c++}else{var d=e[0],p=e[0];0===o.getWidth(d)&&(h++,d--),2===o.getWidth(p)&&(u++,p++);var v=o.getString(p).length;for(v>1&&(_+=v-1,c+=v-1);d>0&&a>0&&!this._isCharWordSeparator(o.loadCell(d-1,this._workCell));){o.loadCell(d-1,this._workCell);var g=this._workCell.getChars().length;0===this._workCell.getWidth()?(h++,d--):g>1&&(f+=g-1,a-=g-1),a--,d--}for(;p<o.length&&c+1<s.length&&!this._isCharWordSeparator(o.loadCell(p+1,this._workCell));){o.loadCell(p+1,this._workCell);var y=this._workCell.getChars().length;2===this._workCell.getWidth()?(u++,p++):y>1&&(_+=y-1,c+=y-1),c++,p++}}c++;var m=a+l-h+f,S=Math.min(this._bufferService.cols,c-a+h+u-f-_);if(t||""!==s.slice(a,c).trim()){if(r&&0===m&&32!==o.getCodePoint(0)){var C=n.lines.get(e[1]-1);if(C&&o.isWrapped&&32!==C.getCodePoint(this._bufferService.cols-1)){var b=this._getWordAt([this._bufferService.cols-1,e[1]-1],!1,!0,!1);if(b){var w=this._bufferService.cols-b.start;m-=w,S+=w}}}if(i&&m+S===this._bufferService.cols&&32!==o.getCodePoint(this._bufferService.cols-1)){var L=n.lines.get(e[1]+1);if((null==L?void 0:L.isWrapped)&&32!==L.getCodePoint(0)){var E=this._getWordAt([0,e[1]+1],!1,!1,!0);E&&(S+=E.length)}}return{start:m,length:S}}}}},t.prototype._selectWordAt=function(e,t){var r=this._getWordAt(e,t);if(r){for(;r.start<0;)r.start+=this._bufferService.cols,e[1]--;this._model.selectionStart=[r.start,e[1]],this._model.selectionStartLength=r.length}},t.prototype._selectToWordAt=function(e){var t=this._getWordAt(e,!0);if(t){for(var r=e[1];t.start<0;)t.start+=this._bufferService.cols,r--;if(!this._model.areSelectionValuesReversed())for(;t.start+t.length>this._bufferService.cols;)t.length-=this._bufferService.cols,r++;this._model.selectionEnd=[this._model.areSelectionValuesReversed()?t.start:t.start+t.length,r]}},t.prototype._isCharWordSeparator=function(e){return 0!==e.getWidth()&&this._optionsService.options.wordSeparator.indexOf(e.getChars())>=0},t.prototype._selectLineAt=function(e){var t=this._bufferService.buffer.getWrappedRangeForLine(e);this._model.selectionStart=[0,t.first],this._model.selectionEnd=[this._bufferService.cols,t.last],this._model.selectionStartLength=0},o([s(3,f.IBufferService),s(4,f.ICoreService),s(5,u.IMouseService),s(6,f.IOptionsService),s(7,u.IRenderService)],t)}(p.Disposable);t.SelectionService=m},4725:(e,t,r)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ICharacterJoinerService=t.ISoundService=t.ISelectionService=t.IRenderService=t.IMouseService=t.ICoreBrowserService=t.ICharSizeService=void 0;var i=r(8343);t.ICharSizeService=(0,i.createDecorator)("CharSizeService"),t.ICoreBrowserService=(0,i.createDecorator)("CoreBrowserService"),t.IMouseService=(0,i.createDecorator)("MouseService"),t.IRenderService=(0,i.createDecorator)("RenderService"),t.ISelectionService=(0,i.createDecorator)("SelectionService"),t.ISoundService=(0,i.createDecorator)("SoundService"),t.ICharacterJoinerService=(0,i.createDecorator)("CharacterJoinerService")},357:function(e,t,r){var i=this&&this.__decorate||function(e,t,r,i){var n,o=arguments.length,s=o<3?t:null===i?i=Object.getOwnPropertyDescriptor(t,r):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)s=Reflect.decorate(e,t,r,i);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(s=(o<3?n(s):o>3?n(t,r,s):n(t,r))||s);return o>3&&s&&Object.defineProperty(t,r,s),s},n=this&&this.__param||function(e,t){return function(r,i){t(r,i,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.SoundService=void 0;var o=r(2585),s=function(){function e(e){this._optionsService=e}return Object.defineProperty(e,"audioContext",{get:function(){if(!e._audioContext){var t=window.AudioContext||window.webkitAudioContext;if(!t)return console.warn("Web Audio API is not supported by this browser. Consider upgrading to the latest version"),null;e._audioContext=new t}return e._audioContext},enumerable:!1,configurable:!0}),e.prototype.playBellSound=function(){var t=e.audioContext;if(t){var r=t.createBufferSource();t.decodeAudioData(this._base64ToArrayBuffer(this._removeMimeType(this._optionsService.options.bellSound)),(function(e){r.buffer=e,r.connect(t.destination),r.start(0)}))}},e.prototype._base64ToArrayBuffer=function(e){for(var t=window.atob(e),r=t.length,i=new Uint8Array(r),n=0;n<r;n++)i[n]=t.charCodeAt(n);return i.buffer},e.prototype._removeMimeType=function(e){return e.split(",")[1]},e=i([n(0,o.IOptionsService)],e)}();t.SoundService=s},6349:(e,t,r)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.CircularList=void 0;var i=r(8460),n=function(){function e(e){this._maxLength=e,this.onDeleteEmitter=new i.EventEmitter,this.onInsertEmitter=new i.EventEmitter,this.onTrimEmitter=new i.EventEmitter,this._array=new Array(this._maxLength),this._startIndex=0,this._length=0}return Object.defineProperty(e.prototype,"onDelete",{get:function(){return this.onDeleteEmitter.event},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"onInsert",{get:function(){return this.onInsertEmitter.event},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"onTrim",{get:function(){return this.onTrimEmitter.event},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"maxLength",{get:function(){return this._maxLength},set:function(e){if(this._maxLength!==e){for(var t=new Array(e),r=0;r<Math.min(e,this.length);r++)t[r]=this._array[this._getCyclicIndex(r)];this._array=t,this._maxLength=e,this._startIndex=0}},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"length",{get:function(){return this._length},set:function(e){if(e>this._length)for(var t=this._length;t<e;t++)this._array[t]=void 0;this._length=e},enumerable:!1,configurable:!0}),e.prototype.get=function(e){return this._array[this._getCyclicIndex(e)]},e.prototype.set=function(e,t){this._array[this._getCyclicIndex(e)]=t},e.prototype.push=function(e){this._array[this._getCyclicIndex(this._length)]=e,this._length===this._maxLength?(this._startIndex=++this._startIndex%this._maxLength,this.onTrimEmitter.fire(1)):this._length++},e.prototype.recycle=function(){if(this._length!==this._maxLength)throw new Error("Can only recycle when the buffer is full");return this._startIndex=++this._startIndex%this._maxLength,this.onTrimEmitter.fire(1),this._array[this._getCyclicIndex(this._length-1)]},Object.defineProperty(e.prototype,"isFull",{get:function(){return this._length===this._maxLength},enumerable:!1,configurable:!0}),e.prototype.pop=function(){return this._array[this._getCyclicIndex(this._length---1)]},e.prototype.splice=function(e,t){for(var r=[],i=2;i<arguments.length;i++)r[i-2]=arguments[i];if(t){for(var n=e;n<this._length-t;n++)this._array[this._getCyclicIndex(n)]=this._array[this._getCyclicIndex(n+t)];this._length-=t,this.onDeleteEmitter.fire({index:e,amount:t})}for(n=this._length-1;n>=e;n--)this._array[this._getCyclicIndex(n+r.length)]=this._array[this._getCyclicIndex(n)];for(n=0;n<r.length;n++)this._array[this._getCyclicIndex(e+n)]=r[n];if(r.length&&this.onInsertEmitter.fire({index:e,amount:r.length}),this._length+r.length>this._maxLength){var o=this._length+r.length-this._maxLength;this._startIndex+=o,this._length=this._maxLength,this.onTrimEmitter.fire(o)}else this._length+=r.length},e.prototype.trimStart=function(e){e>this._length&&(e=this._length),this._startIndex+=e,this._length-=e,this.onTrimEmitter.fire(e)},e.prototype.shiftElements=function(e,t,r){if(!(t<=0)){if(e<0||e>=this._length)throw new Error("start argument out of range");if(e+r<0)throw new Error("Cannot shift elements in list beyond index 0");if(r>0){for(var i=t-1;i>=0;i--)this.set(e+i+r,this.get(e+i));var n=e+t+r-this._length;if(n>0)for(this._length+=n;this._length>this._maxLength;)this._length--,this._startIndex++,this.onTrimEmitter.fire(1)}else for(i=0;i<t;i++)this.set(e+i+r,this.get(e+i))}},e.prototype._getCyclicIndex=function(e){return(this._startIndex+e)%this._maxLength},e}();t.CircularList=n},1439:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.clone=void 0,t.clone=function e(t,r){if(void 0===r&&(r=5),"object"!=typeof t)return t;var i=Array.isArray(t)?[]:{};for(var n in t)i[n]=r<=1?t[n]:t[n]&&e(t[n],r-1);return i}},8969:function(e,t,r){var i,n=this&&this.__extends||(i=function(e,t){return i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])},i(e,t)},function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function r(){this.constructor=e}i(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)});Object.defineProperty(t,"__esModule",{value:!0}),t.CoreTerminal=void 0;var o=r(844),s=r(2585),a=r(4348),c=r(7866),l=r(744),h=r(7302),u=r(6975),f=r(8460),_=r(1753),d=r(3730),p=r(1480),v=r(7994),g=r(9282),y=r(5435),m=r(5981),S=!1,C=function(e){function t(t){var r=e.call(this)||this;return r._onBinary=new f.EventEmitter,r._onData=new f.EventEmitter,r._onLineFeed=new f.EventEmitter,r._onResize=new f.EventEmitter,r._onScroll=new f.EventEmitter,r._instantiationService=new a.InstantiationService,r.optionsService=new h.OptionsService(t),r._instantiationService.setService(s.IOptionsService,r.optionsService),r._bufferService=r.register(r._instantiationService.createInstance(l.BufferService)),r._instantiationService.setService(s.IBufferService,r._bufferService),r._logService=r._instantiationService.createInstance(c.LogService),r._instantiationService.setService(s.ILogService,r._logService),r.coreService=r.register(r._instantiationService.createInstance(u.CoreService,(function(){return r.scrollToBottom()}))),r._instantiationService.setService(s.ICoreService,r.coreService),r.coreMouseService=r._instantiationService.createInstance(_.CoreMouseService),r._instantiationService.setService(s.ICoreMouseService,r.coreMouseService),r._dirtyRowService=r._instantiationService.createInstance(d.DirtyRowService),r._instantiationService.setService(s.IDirtyRowService,r._dirtyRowService),r.unicodeService=r._instantiationService.createInstance(p.UnicodeService),r._instantiationService.setService(s.IUnicodeService,r.unicodeService),r._charsetService=r._instantiationService.createInstance(v.CharsetService),r._instantiationService.setService(s.ICharsetService,r._charsetService),r._inputHandler=new y.InputHandler(r._bufferService,r._charsetService,r.coreService,r._dirtyRowService,r._logService,r.optionsService,r.coreMouseService,r.unicodeService),r.register((0,f.forwardEvent)(r._inputHandler.onLineFeed,r._onLineFeed)),r.register(r._inputHandler),r.register((0,f.forwardEvent)(r._bufferService.onResize,r._onResize)),r.register((0,f.forwardEvent)(r.coreService.onData,r._onData)),r.register((0,f.forwardEvent)(r.coreService.onBinary,r._onBinary)),r.register(r.optionsService.onOptionChange((function(e){return r._updateOptions(e)}))),r.register(r._bufferService.onScroll((function(e){r._onScroll.fire({position:r._bufferService.buffer.ydisp,source:0}),r._dirtyRowService.markRangeDirty(r._bufferService.buffer.scrollTop,r._bufferService.buffer.scrollBottom)}))),r.register(r._inputHandler.onScroll((function(e){r._onScroll.fire({position:r._bufferService.buffer.ydisp,source:0}),r._dirtyRowService.markRangeDirty(r._bufferService.buffer.scrollTop,r._bufferService.buffer.scrollBottom)}))),r._writeBuffer=new m.WriteBuffer((function(e,t){return r._inputHandler.parse(e,t)})),r}return n(t,e),Object.defineProperty(t.prototype,"onBinary",{get:function(){return this._onBinary.event},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"onData",{get:function(){return this._onData.event},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"onLineFeed",{get:function(){return this._onLineFeed.event},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"onResize",{get:function(){return this._onResize.event},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"onScroll",{get:function(){var e=this;return this._onScrollApi||(this._onScrollApi=new f.EventEmitter,this.register(this._onScroll.event((function(t){var r;null===(r=e._onScrollApi)||void 0===r||r.fire(t.position)})))),this._onScrollApi.event},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"cols",{get:function(){return this._bufferService.cols},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"rows",{get:function(){return this._bufferService.rows},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"buffers",{get:function(){return this._bufferService.buffers},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"options",{get:function(){return this.optionsService.options},set:function(e){for(var t in e)this.optionsService.options[t]=e[t]},enumerable:!1,configurable:!0}),t.prototype.dispose=function(){var t;this._isDisposed||(e.prototype.dispose.call(this),null===(t=this._windowsMode)||void 0===t||t.dispose(),this._windowsMode=void 0)},t.prototype.write=function(e,t){this._writeBuffer.write(e,t)},t.prototype.writeSync=function(e,t){this._logService.logLevel<=s.LogLevelEnum.WARN&&!S&&(this._logService.warn("writeSync is unreliable and will be removed soon."),S=!0),this._writeBuffer.writeSync(e,t)},t.prototype.resize=function(e,t){isNaN(e)||isNaN(t)||(e=Math.max(e,l.MINIMUM_COLS),t=Math.max(t,l.MINIMUM_ROWS),this._bufferService.resize(e,t))},t.prototype.scroll=function(e,t){void 0===t&&(t=!1),this._bufferService.scroll(e,t)},t.prototype.scrollLines=function(e,t,r){this._bufferService.scrollLines(e,t,r)},t.prototype.scrollPages=function(e){this._bufferService.scrollPages(e)},t.prototype.scrollToTop=function(){this._bufferService.scrollToTop()},t.prototype.scrollToBottom=function(){this._bufferService.scrollToBottom()},t.prototype.scrollToLine=function(e){this._bufferService.scrollToLine(e)},t.prototype.registerEscHandler=function(e,t){return this._inputHandler.registerEscHandler(e,t)},t.prototype.registerDcsHandler=function(e,t){return this._inputHandler.registerDcsHandler(e,t)},t.prototype.registerCsiHandler=function(e,t){return this._inputHandler.registerCsiHandler(e,t)},t.prototype.registerOscHandler=function(e,t){return this._inputHandler.registerOscHandler(e,t)},t.prototype._setup=function(){this.optionsService.options.windowsMode&&this._enableWindowsMode()},t.prototype.reset=function(){this._inputHandler.reset(),this._bufferService.reset(),this._charsetService.reset(),this.coreService.reset(),this.coreMouseService.reset()},t.prototype._updateOptions=function(e){var t;switch(e){case"scrollback":this.buffers.resize(this.cols,this.rows);break;case"windowsMode":this.optionsService.options.windowsMode?this._enableWindowsMode():(null===(t=this._windowsMode)||void 0===t||t.dispose(),this._windowsMode=void 0)}},t.prototype._enableWindowsMode=function(){var e=this;if(!this._windowsMode){var t=[];t.push(this.onLineFeed(g.updateWindowsModeWrappedState.bind(null,this._bufferService))),t.push(this.registerCsiHandler({final:"H"},(function(){return(0,g.updateWindowsModeWrappedState)(e._bufferService),!1}))),this._windowsMode={dispose:function(){for(var e=0,r=t;e<r.length;e++)r[e].dispose()}}}},t}(o.Disposable);t.CoreTerminal=C},8460:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.forwardEvent=t.EventEmitter=void 0;var r=function(){function e(){this._listeners=[],this._disposed=!1}return Object.defineProperty(e.prototype,"event",{get:function(){var e=this;return this._event||(this._event=function(t){return e._listeners.push(t),{dispose:function(){if(!e._disposed)for(var r=0;r<e._listeners.length;r++)if(e._listeners[r]===t)return void e._listeners.splice(r,1)}}}),this._event},enumerable:!1,configurable:!0}),e.prototype.fire=function(e,t){for(var r=[],i=0;i<this._listeners.length;i++)r.push(this._listeners[i]);for(i=0;i<r.length;i++)r[i].call(void 0,e,t)},e.prototype.dispose=function(){this._listeners&&(this._listeners.length=0),this._disposed=!0},e}();t.EventEmitter=r,t.forwardEvent=function(e,t){return e((function(e){return t.fire(e)}))}},5435:function(e,t,r){var i,n=this&&this.__extends||(i=function(e,t){return i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])},i(e,t)},function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function r(){this.constructor=e}i(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)});Object.defineProperty(t,"__esModule",{value:!0}),t.InputHandler=t.WindowsOptionsReportType=void 0;var o,s=r(2584),a=r(7116),c=r(2015),l=r(844),h=r(8273),u=r(482),f=r(8437),_=r(8460),d=r(643),p=r(511),v=r(3734),g=r(2585),y=r(6242),m=r(6351),S=r(5941),C={"(":0,")":1,"*":2,"+":3,"-":1,".":2},b=131072;function w(e,t){if(e>24)return t.setWinLines||!1;switch(e){case 1:return!!t.restoreWin;case 2:return!!t.minimizeWin;case 3:return!!t.setWinPosition;case 4:return!!t.setWinSizePixels;case 5:return!!t.raiseWin;case 6:return!!t.lowerWin;case 7:return!!t.refreshWin;case 8:return!!t.setWinSizeChars;case 9:return!!t.maximizeWin;case 10:return!!t.fullscreenWin;case 11:return!!t.getWinState;case 13:return!!t.getWinPosition;case 14:return!!t.getWinSizePixels;case 15:return!!t.getScreenSizePixels;case 16:return!!t.getCellSizePixels;case 18:return!!t.getWinSizeChars;case 19:return!!t.getScreenSizeChars;case 20:return!!t.getIconTitle;case 21:return!!t.getWinTitle;case 22:return!!t.pushTitle;case 23:return!!t.popTitle;case 24:return!!t.setWinLines}return!1}!function(e){e[e.GET_WIN_SIZE_PIXELS=0]="GET_WIN_SIZE_PIXELS",e[e.GET_CELL_SIZE_PIXELS=1]="GET_CELL_SIZE_PIXELS"}(o=t.WindowsOptionsReportType||(t.WindowsOptionsReportType={}));var L=function(){function e(e,t,r,i){this._bufferService=e,this._coreService=t,this._logService=r,this._optionsService=i,this._data=new Uint32Array(0)}return e.prototype.hook=function(e){this._data=new Uint32Array(0)},e.prototype.put=function(e,t,r){this._data=(0,h.concat)(this._data,e.subarray(t,r))},e.prototype.unhook=function(e){if(!e)return this._data=new Uint32Array(0),!0;var t=(0,u.utf32ToString)(this._data);switch(this._data=new Uint32Array(0),t){case'"q':this._coreService.triggerDataEvent(s.C0.ESC+'P1$r0"q'+s.C0.ESC+"\\");break;case'"p':this._coreService.triggerDataEvent(s.C0.ESC+'P1$r61;1"p'+s.C0.ESC+"\\");break;case"r":var r=this._bufferService.buffer.scrollTop+1+";"+(this._bufferService.buffer.scrollBottom+1)+"r";this._coreService.triggerDataEvent(s.C0.ESC+"P1$r"+r+s.C0.ESC+"\\");break;case"m":this._coreService.triggerDataEvent(s.C0.ESC+"P1$r0m"+s.C0.ESC+"\\");break;case" q":var i={block:2,underline:4,bar:6}[this._optionsService.options.cursorStyle];i-=this._optionsService.options.cursorBlink?1:0,this._coreService.triggerDataEvent(s.C0.ESC+"P1$r"+i+" q"+s.C0.ESC+"\\");break;default:this._logService.debug("Unknown DCS $q %s",t),this._coreService.triggerDataEvent(s.C0.ESC+"P0$r"+s.C0.ESC+"\\")}return!0},e}(),E=function(e){function t(t,r,i,n,o,l,h,d,v){void 0===v&&(v=new c.EscapeSequenceParser);var g=e.call(this)||this;g._bufferService=t,g._charsetService=r,g._coreService=i,g._dirtyRowService=n,g._logService=o,g._optionsService=l,g._coreMouseService=h,g._unicodeService=d,g._parser=v,g._parseBuffer=new Uint32Array(4096),g._stringDecoder=new u.StringToUtf32,g._utf8Decoder=new u.Utf8ToUtf32,g._workCell=new p.CellData,g._windowTitle="",g._iconName="",g._windowTitleStack=[],g._iconNameStack=[],g._curAttrData=f.DEFAULT_ATTR_DATA.clone(),g._eraseAttrDataInternal=f.DEFAULT_ATTR_DATA.clone(),g._onRequestBell=new _.EventEmitter,g._onRequestRefreshRows=new _.EventEmitter,g._onRequestReset=new _.EventEmitter,g._onRequestSendFocus=new _.EventEmitter,g._onRequestSyncScrollBar=new _.EventEmitter,g._onRequestWindowsOptionsReport=new _.EventEmitter,g._onA11yChar=new _.EventEmitter,g._onA11yTab=new _.EventEmitter,g._onCursorMove=new _.EventEmitter,g._onLineFeed=new _.EventEmitter,g._onScroll=new _.EventEmitter,g._onTitleChange=new _.EventEmitter,g._onColor=new _.EventEmitter,g._parseStack={paused:!1,cursorStartX:0,cursorStartY:0,decodedLength:0,position:0},g._specialColors=[256,257,258],g.register(g._parser),g._activeBuffer=g._bufferService.buffer,g.register(g._bufferService.buffers.onBufferActivate((function(e){return g._activeBuffer=e.activeBuffer}))),g._parser.setCsiHandlerFallback((function(e,t){g._logService.debug("Unknown CSI code: ",{identifier:g._parser.identToString(e),params:t.toArray()})})),g._parser.setEscHandlerFallback((function(e){g._logService.debug("Unknown ESC code: ",{identifier:g._parser.identToString(e)})})),g._parser.setExecuteHandlerFallback((function(e){g._logService.debug("Unknown EXECUTE code: ",{code:e})})),g._parser.setOscHandlerFallback((function(e,t,r){g._logService.debug("Unknown OSC code: ",{identifier:e,action:t,data:r})})),g._parser.setDcsHandlerFallback((function(e,t,r){"HOOK"===t&&(r=r.toArray()),g._logService.debug("Unknown DCS code: ",{identifier:g._parser.identToString(e),action:t,payload:r})})),g._parser.setPrintHandler((function(e,t,r){return g.print(e,t,r)})),g._parser.registerCsiHandler({final:"@"},(function(e){return g.insertChars(e)})),g._parser.registerCsiHandler({intermediates:" ",final:"@"},(function(e){return g.scrollLeft(e)})),g._parser.registerCsiHandler({final:"A"},(function(e){return g.cursorUp(e)})),g._parser.registerCsiHandler({intermediates:" ",final:"A"},(function(e){return g.scrollRight(e)})),g._parser.registerCsiHandler({final:"B"},(function(e){return g.cursorDown(e)})),g._parser.registerCsiHandler({final:"C"},(function(e){return g.cursorForward(e)})),g._parser.registerCsiHandler({final:"D"},(function(e){return g.cursorBackward(e)})),g._parser.registerCsiHandler({final:"E"},(function(e){return g.cursorNextLine(e)})),g._parser.registerCsiHandler({final:"F"},(function(e){return g.cursorPrecedingLine(e)})),g._parser.registerCsiHandler({final:"G"},(function(e){return g.cursorCharAbsolute(e)})),g._parser.registerCsiHandler({final:"H"},(function(e){return g.cursorPosition(e)})),g._parser.registerCsiHandler({final:"I"},(function(e){return g.cursorForwardTab(e)})),g._parser.registerCsiHandler({final:"J"},(function(e){return g.eraseInDisplay(e)})),g._parser.registerCsiHandler({prefix:"?",final:"J"},(function(e){return g.eraseInDisplay(e)})),g._parser.registerCsiHandler({final:"K"},(function(e){return g.eraseInLine(e)})),g._parser.registerCsiHandler({prefix:"?",final:"K"},(function(e){return g.eraseInLine(e)})),g._parser.registerCsiHandler({final:"L"},(function(e){return g.insertLines(e)})),g._parser.registerCsiHandler({final:"M"},(function(e){return g.deleteLines(e)})),g._parser.registerCsiHandler({final:"P"},(function(e){return g.deleteChars(e)})),g._parser.registerCsiHandler({final:"S"},(function(e){return g.scrollUp(e)})),g._parser.registerCsiHandler({final:"T"},(function(e){return g.scrollDown(e)})),g._parser.registerCsiHandler({final:"X"},(function(e){return g.eraseChars(e)})),g._parser.registerCsiHandler({final:"Z"},(function(e){return g.cursorBackwardTab(e)})),g._parser.registerCsiHandler({final:"`"},(function(e){return g.charPosAbsolute(e)})),g._parser.registerCsiHandler({final:"a"},(function(e){return g.hPositionRelative(e)})),g._parser.registerCsiHandler({final:"b"},(function(e){return g.repeatPrecedingCharacter(e)})),g._parser.registerCsiHandler({final:"c"},(function(e){return g.sendDeviceAttributesPrimary(e)})),g._parser.registerCsiHandler({prefix:">",final:"c"},(function(e){return g.sendDeviceAttributesSecondary(e)})),g._parser.registerCsiHandler({final:"d"},(function(e){return g.linePosAbsolute(e)})),g._parser.registerCsiHandler({final:"e"},(function(e){return g.vPositionRelative(e)})),g._parser.registerCsiHandler({final:"f"},(function(e){return g.hVPosition(e)})),g._parser.registerCsiHandler({final:"g"},(function(e){return g.tabClear(e)})),g._parser.registerCsiHandler({final:"h"},(function(e){return g.setMode(e)})),g._parser.registerCsiHandler({prefix:"?",final:"h"},(function(e){return g.setModePrivate(e)})),g._parser.registerCsiHandler({final:"l"},(function(e){return g.resetMode(e)})),g._parser.registerCsiHandler({prefix:"?",final:"l"},(function(e){return g.resetModePrivate(e)})),g._parser.registerCsiHandler({final:"m"},(function(e){return g.charAttributes(e)})),g._parser.registerCsiHandler({final:"n"},(function(e){return g.deviceStatus(e)})),g._parser.registerCsiHandler({prefix:"?",final:"n"},(function(e){return g.deviceStatusPrivate(e)})),g._parser.registerCsiHandler({intermediates:"!",final:"p"},(function(e){return g.softReset(e)})),g._parser.registerCsiHandler({intermediates:" ",final:"q"},(function(e){return g.setCursorStyle(e)})),g._parser.registerCsiHandler({final:"r"},(function(e){return g.setScrollRegion(e)})),g._parser.registerCsiHandler({final:"s"},(function(e){return g.saveCursor(e)})),g._parser.registerCsiHandler({final:"t"},(function(e){return g.windowOptions(e)})),g._parser.registerCsiHandler({final:"u"},(function(e){return g.restoreCursor(e)})),g._parser.registerCsiHandler({intermediates:"'",final:"}"},(function(e){return g.insertColumns(e)})),g._parser.registerCsiHandler({intermediates:"'",final:"~"},(function(e){return g.deleteColumns(e)})),g._parser.setExecuteHandler(s.C0.BEL,(function(){return g.bell()})),g._parser.setExecuteHandler(s.C0.LF,(function(){return g.lineFeed()})),g._parser.setExecuteHandler(s.C0.VT,(function(){return g.lineFeed()})),g._parser.setExecuteHandler(s.C0.FF,(function(){return g.lineFeed()})),g._parser.setExecuteHandler(s.C0.CR,(function(){return g.carriageReturn()})),g._parser.setExecuteHandler(s.C0.BS,(function(){return g.backspace()})),g._parser.setExecuteHandler(s.C0.HT,(function(){return g.tab()})),g._parser.setExecuteHandler(s.C0.SO,(function(){return g.shiftOut()})),g._parser.setExecuteHandler(s.C0.SI,(function(){return g.shiftIn()})),g._parser.setExecuteHandler(s.C1.IND,(function(){return g.index()})),g._parser.setExecuteHandler(s.C1.NEL,(function(){return g.nextLine()})),g._parser.setExecuteHandler(s.C1.HTS,(function(){return g.tabSet()})),g._parser.registerOscHandler(0,new y.OscHandler((function(e){return g.setTitle(e),g.setIconName(e),!0}))),g._parser.registerOscHandler(1,new y.OscHandler((function(e){return g.setIconName(e)}))),g._parser.registerOscHandler(2,new y.OscHandler((function(e){return g.setTitle(e)}))),g._parser.registerOscHandler(4,new y.OscHandler((function(e){return g.setOrReportIndexedColor(e)}))),g._parser.registerOscHandler(10,new y.OscHandler((function(e){return g.setOrReportFgColor(e)}))),g._parser.registerOscHandler(11,new y.OscHandler((function(e){return g.setOrReportBgColor(e)}))),g._parser.registerOscHandler(12,new y.OscHandler((function(e){return g.setOrReportCursorColor(e)}))),g._parser.registerOscHandler(104,new y.OscHandler((function(e){return g.restoreIndexedColor(e)}))),g._parser.registerOscHandler(110,new y.OscHandler((function(e){return g.restoreFgColor(e)}))),g._parser.registerOscHandler(111,new y.OscHandler((function(e){return g.restoreBgColor(e)}))),g._parser.registerOscHandler(112,new y.OscHandler((function(e){return g.restoreCursorColor(e)}))),g._parser.registerEscHandler({final:"7"},(function(){return g.saveCursor()})),g._parser.registerEscHandler({final:"8"},(function(){return g.restoreCursor()})),g._parser.registerEscHandler({final:"D"},(function(){return g.index()})),g._parser.registerEscHandler({final:"E"},(function(){return g.nextLine()})),g._parser.registerEscHandler({final:"H"},(function(){return g.tabSet()})),g._parser.registerEscHandler({final:"M"},(function(){return g.reverseIndex()})),g._parser.registerEscHandler({final:"="},(function(){return g.keypadApplicationMode()})),g._parser.registerEscHandler({final:">"},(function(){return g.keypadNumericMode()})),g._parser.registerEscHandler({final:"c"},(function(){return g.fullReset()})),g._parser.registerEscHandler({final:"n"},(function(){return g.setgLevel(2)})),g._parser.registerEscHandler({final:"o"},(function(){return g.setgLevel(3)})),g._parser.registerEscHandler({final:"|"},(function(){return g.setgLevel(3)})),g._parser.registerEscHandler({final:"}"},(function(){return g.setgLevel(2)})),g._parser.registerEscHandler({final:"~"},(function(){return g.setgLevel(1)})),g._parser.registerEscHandler({intermediates:"%",final:"@"},(function(){return g.selectDefaultCharset()})),g._parser.registerEscHandler({intermediates:"%",final:"G"},(function(){return g.selectDefaultCharset()}));var m=function(e){S._parser.registerEscHandler({intermediates:"(",final:e},(function(){return g.selectCharset("("+e)})),S._parser.registerEscHandler({intermediates:")",final:e},(function(){return g.selectCharset(")"+e)})),S._parser.registerEscHandler({intermediates:"*",final:e},(function(){return g.selectCharset("*"+e)})),S._parser.registerEscHandler({intermediates:"+",final:e},(function(){return g.selectCharset("+"+e)})),S._parser.registerEscHandler({intermediates:"-",final:e},(function(){return g.selectCharset("-"+e)})),S._parser.registerEscHandler({intermediates:".",final:e},(function(){return g.selectCharset("."+e)})),S._parser.registerEscHandler({intermediates:"/",final:e},(function(){return g.selectCharset("/"+e)}))},S=this;for(var C in a.CHARSETS)m(C);return g._parser.registerEscHandler({intermediates:"#",final:"8"},(function(){return g.screenAlignmentPattern()})),g._parser.setErrorHandler((function(e){return g._logService.error("Parsing error: ",e),e})),g._parser.registerDcsHandler({intermediates:"$",final:"q"},new L(g._bufferService,g._coreService,g._logService,g._optionsService)),g}return n(t,e),Object.defineProperty(t.prototype,"onRequestBell",{get:function(){return this._onRequestBell.event},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"onRequestRefreshRows",{get:function(){return this._onRequestRefreshRows.event},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"onRequestReset",{get:function(){return this._onRequestReset.event},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"onRequestSendFocus",{get:function(){return this._onRequestSendFocus.event},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"onRequestSyncScrollBar",{get:function(){return this._onRequestSyncScrollBar.event},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"onRequestWindowsOptionsReport",{get:function(){return this._onRequestWindowsOptionsReport.event},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"onA11yChar",{get:function(){return this._onA11yChar.event},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"onA11yTab",{get:function(){return this._onA11yTab.event},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"onCursorMove",{get:function(){return this._onCursorMove.event},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"onLineFeed",{get:function(){return this._onLineFeed.event},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"onScroll",{get:function(){return this._onScroll.event},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"onTitleChange",{get:function(){return this._onTitleChange.event},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"onColor",{get:function(){return this._onColor.event},enumerable:!1,configurable:!0}),t.prototype.dispose=function(){e.prototype.dispose.call(this)},t.prototype._preserveStack=function(e,t,r,i){this._parseStack.paused=!0,this._parseStack.cursorStartX=e,this._parseStack.cursorStartY=t,this._parseStack.decodedLength=r,this._parseStack.position=i},t.prototype._logSlowResolvingAsync=function(e){this._logService.logLevel<=g.LogLevelEnum.WARN&&Promise.race([e,new Promise((function(e,t){return setTimeout((function(){return t("#SLOW_TIMEOUT")}),5e3)}))]).catch((function(e){if("#SLOW_TIMEOUT"!==e)throw e;console.warn("async parser handler taking longer than 5000 ms")}))},t.prototype.parse=function(e,t){var r,i=this._activeBuffer.x,n=this._activeBuffer.y,o=0,s=this._parseStack.paused;if(s){if(r=this._parser.parse(this._parseBuffer,this._parseStack.decodedLength,t))return this._logSlowResolvingAsync(r),r;i=this._parseStack.cursorStartX,n=this._parseStack.cursorStartY,this._parseStack.paused=!1,e.length>b&&(o=this._parseStack.position+b)}if(this._logService.logLevel<=g.LogLevelEnum.DEBUG&&this._logService.debug("parsing data"+("string"==typeof e?' "'+e+'"':""),"string"==typeof e?e.split("").map((function(e){return e.charCodeAt(0)})):e),this._parseBuffer.length<e.length&&this._parseBuffer.length<b&&(this._parseBuffer=new Uint32Array(Math.min(e.length,b))),s||this._dirtyRowService.clearRange(),e.length>b)for(var a=o;a<e.length;a+=b){var c=a+b<e.length?a+b:e.length,l="string"==typeof e?this._stringDecoder.decode(e.substring(a,c),this._parseBuffer):this._utf8Decoder.decode(e.subarray(a,c),this._parseBuffer);if(r=this._parser.parse(this._parseBuffer,l))return this._preserveStack(i,n,l,a),this._logSlowResolvingAsync(r),r}else if(!s&&(l="string"==typeof e?this._stringDecoder.decode(e,this._parseBuffer):this._utf8Decoder.decode(e,this._parseBuffer),r=this._parser.parse(this._parseBuffer,l)))return this._preserveStack(i,n,l,0),this._logSlowResolvingAsync(r),r;this._activeBuffer.x===i&&this._activeBuffer.y===n||this._onCursorMove.fire(),this._onRequestRefreshRows.fire(this._dirtyRowService.start,this._dirtyRowService.end)},t.prototype.print=function(e,t,r){var i,n,o=this._charsetService.charset,s=this._optionsService.options.screenReaderMode,a=this._bufferService.cols,c=this._coreService.decPrivateModes.wraparound,l=this._coreService.modes.insertMode,h=this._curAttrData,f=this._activeBuffer.lines.get(this._activeBuffer.ybase+this._activeBuffer.y);this._dirtyRowService.markDirty(this._activeBuffer.y),this._activeBuffer.x&&r-t>0&&2===f.getWidth(this._activeBuffer.x-1)&&f.setCellFromCodePoint(this._activeBuffer.x-1,0,1,h.fg,h.bg,h.extended);for(var _=t;_<r;++_){if(i=e[_],n=this._unicodeService.wcwidth(i),i<127&&o){var p=o[String.fromCharCode(i)];p&&(i=p.charCodeAt(0))}if(s&&this._onA11yChar.fire((0,u.stringFromCodePoint)(i)),n||!this._activeBuffer.x){if(this._activeBuffer.x+n-1>=a)if(c){for(;this._activeBuffer.x<a;)f.setCellFromCodePoint(this._activeBuffer.x++,0,1,h.fg,h.bg,h.extended);this._activeBuffer.x=0,this._activeBuffer.y++,this._activeBuffer.y===this._activeBuffer.scrollBottom+1?(this._activeBuffer.y--,this._bufferService.scroll(this._eraseAttrData(),!0)):(this._activeBuffer.y>=this._bufferService.rows&&(this._activeBuffer.y=this._bufferService.rows-1),this._activeBuffer.lines.get(this._activeBuffer.ybase+this._activeBuffer.y).isWrapped=!0),f=this._activeBuffer.lines.get(this._activeBuffer.ybase+this._activeBuffer.y)}else if(this._activeBuffer.x=a-1,2===n)continue;if(l&&(f.insertCells(this._activeBuffer.x,n,this._activeBuffer.getNullCell(h),h),2===f.getWidth(a-1)&&f.setCellFromCodePoint(a-1,d.NULL_CELL_CODE,d.NULL_CELL_WIDTH,h.fg,h.bg,h.extended)),f.setCellFromCodePoint(this._activeBuffer.x++,i,n,h.fg,h.bg,h.extended),n>0)for(;--n;)f.setCellFromCodePoint(this._activeBuffer.x++,0,0,h.fg,h.bg,h.extended)}else f.getWidth(this._activeBuffer.x-1)?f.addCodepointToCell(this._activeBuffer.x-1,i):f.addCodepointToCell(this._activeBuffer.x-2,i)}r-t>0&&(f.loadCell(this._activeBuffer.x-1,this._workCell),2===this._workCell.getWidth()||this._workCell.getCode()>65535?this._parser.precedingCodepoint=0:this._workCell.isCombined()?this._parser.precedingCodepoint=this._workCell.getChars().charCodeAt(0):this._parser.precedingCodepoint=this._workCell.content),this._activeBuffer.x<a&&r-t>0&&0===f.getWidth(this._activeBuffer.x)&&!f.hasContent(this._activeBuffer.x)&&f.setCellFromCodePoint(this._activeBuffer.x,0,1,h.fg,h.bg,h.extended),this._dirtyRowService.markDirty(this._activeBuffer.y)},t.prototype.registerCsiHandler=function(e,t){var r=this;return"t"!==e.final||e.prefix||e.intermediates?this._parser.registerCsiHandler(e,t):this._parser.registerCsiHandler(e,(function(e){return!w(e.params[0],r._optionsService.options.windowOptions)||t(e)}))},t.prototype.registerDcsHandler=function(e,t){return this._parser.registerDcsHandler(e,new m.DcsHandler(t))},t.prototype.registerEscHandler=function(e,t){return this._parser.registerEscHandler(e,t)},t.prototype.registerOscHandler=function(e,t){return this._parser.registerOscHandler(e,new y.OscHandler(t))},t.prototype.bell=function(){return this._onRequestBell.fire(),!0},t.prototype.lineFeed=function(){return this._dirtyRowService.markDirty(this._activeBuffer.y),this._optionsService.options.convertEol&&(this._activeBuffer.x=0),this._activeBuffer.y++,this._activeBuffer.y===this._activeBuffer.scrollBottom+1?(this._activeBuffer.y--,this._bufferService.scroll(this._eraseAttrData())):this._activeBuffer.y>=this._bufferService.rows&&(this._activeBuffer.y=this._bufferService.rows-1),this._activeBuffer.x>=this._bufferService.cols&&this._activeBuffer.x--,this._dirtyRowService.markDirty(this._activeBuffer.y),this._onLineFeed.fire(),!0},t.prototype.carriageReturn=function(){return this._activeBuffer.x=0,!0},t.prototype.backspace=function(){var e;if(!this._coreService.decPrivateModes.reverseWraparound)return this._restrictCursor(),this._activeBuffer.x>0&&this._activeBuffer.x--,!0;if(this._restrictCursor(this._bufferService.cols),this._activeBuffer.x>0)this._activeBuffer.x--;else if(0===this._activeBuffer.x&&this._activeBuffer.y>this._activeBuffer.scrollTop&&this._activeBuffer.y<=this._activeBuffer.scrollBottom&&(null===(e=this._activeBuffer.lines.get(this._activeBuffer.ybase+this._activeBuffer.y))||void 0===e?void 0:e.isWrapped)){this._activeBuffer.lines.get(this._activeBuffer.ybase+this._activeBuffer.y).isWrapped=!1,this._activeBuffer.y--,this._activeBuffer.x=this._bufferService.cols-1;var t=this._activeBuffer.lines.get(this._activeBuffer.ybase+this._activeBuffer.y);t.hasWidth(this._activeBuffer.x)&&!t.hasContent(this._activeBuffer.x)&&this._activeBuffer.x--}return this._restrictCursor(),!0},t.prototype.tab=function(){if(this._activeBuffer.x>=this._bufferService.cols)return!0;var e=this._activeBuffer.x;return this._activeBuffer.x=this._activeBuffer.nextStop(),this._optionsService.options.screenReaderMode&&this._onA11yTab.fire(this._activeBuffer.x-e),!0},t.prototype.shiftOut=function(){return this._charsetService.setgLevel(1),!0},t.prototype.shiftIn=function(){return this._charsetService.setgLevel(0),!0},t.prototype._restrictCursor=function(e){void 0===e&&(e=this._bufferService.cols-1),this._activeBuffer.x=Math.min(e,Math.max(0,this._activeBuffer.x)),this._activeBuffer.y=this._coreService.decPrivateModes.origin?Math.min(this._activeBuffer.scrollBottom,Math.max(this._activeBuffer.scrollTop,this._activeBuffer.y)):Math.min(this._bufferService.rows-1,Math.max(0,this._activeBuffer.y)),this._dirtyRowService.markDirty(this._activeBuffer.y)},t.prototype._setCursor=function(e,t){this._dirtyRowService.markDirty(this._activeBuffer.y),this._coreService.decPrivateModes.origin?(this._activeBuffer.x=e,this._activeBuffer.y=this._activeBuffer.scrollTop+t):(this._activeBuffer.x=e,this._activeBuffer.y=t),this._restrictCursor(),this._dirtyRowService.markDirty(this._activeBuffer.y)},t.prototype._moveCursor=function(e,t){this._restrictCursor(),this._setCursor(this._activeBuffer.x+e,this._activeBuffer.y+t)},t.prototype.cursorUp=function(e){var t=this._activeBuffer.y-this._activeBuffer.scrollTop;return t>=0?this._moveCursor(0,-Math.min(t,e.params[0]||1)):this._moveCursor(0,-(e.params[0]||1)),!0},t.prototype.cursorDown=function(e){var t=this._activeBuffer.scrollBottom-this._activeBuffer.y;return t>=0?this._moveCursor(0,Math.min(t,e.params[0]||1)):this._moveCursor(0,e.params[0]||1),!0},t.prototype.cursorForward=function(e){return this._moveCursor(e.params[0]||1,0),!0},t.prototype.cursorBackward=function(e){return this._moveCursor(-(e.params[0]||1),0),!0},t.prototype.cursorNextLine=function(e){return this.cursorDown(e),this._activeBuffer.x=0,!0},t.prototype.cursorPrecedingLine=function(e){return this.cursorUp(e),this._activeBuffer.x=0,!0},t.prototype.cursorCharAbsolute=function(e){return this._setCursor((e.params[0]||1)-1,this._activeBuffer.y),!0},t.prototype.cursorPosition=function(e){return this._setCursor(e.length>=2?(e.params[1]||1)-1:0,(e.params[0]||1)-1),!0},t.prototype.charPosAbsolute=function(e){return this._setCursor((e.params[0]||1)-1,this._activeBuffer.y),!0},t.prototype.hPositionRelative=function(e){return this._moveCursor(e.params[0]||1,0),!0},t.prototype.linePosAbsolute=function(e){return this._setCursor(this._activeBuffer.x,(e.params[0]||1)-1),!0},t.prototype.vPositionRelative=function(e){return this._moveCursor(0,e.params[0]||1),!0},t.prototype.hVPosition=function(e){return this.cursorPosition(e),!0},t.prototype.tabClear=function(e){var t=e.params[0];return 0===t?delete this._activeBuffer.tabs[this._activeBuffer.x]:3===t&&(this._activeBuffer.tabs={}),!0},t.prototype.cursorForwardTab=function(e){if(this._activeBuffer.x>=this._bufferService.cols)return!0;for(var t=e.params[0]||1;t--;)this._activeBuffer.x=this._activeBuffer.nextStop();return!0},t.prototype.cursorBackwardTab=function(e){if(this._activeBuffer.x>=this._bufferService.cols)return!0;for(var t=e.params[0]||1;t--;)this._activeBuffer.x=this._activeBuffer.prevStop();return!0},t.prototype._eraseInBufferLine=function(e,t,r,i){void 0===i&&(i=!1);var n=this._activeBuffer.lines.get(this._activeBuffer.ybase+e);n.replaceCells(t,r,this._activeBuffer.getNullCell(this._eraseAttrData()),this._eraseAttrData()),i&&(n.isWrapped=!1)},t.prototype._resetBufferLine=function(e){var t=this._activeBuffer.lines.get(this._activeBuffer.ybase+e);t.fill(this._activeBuffer.getNullCell(this._eraseAttrData())),t.isWrapped=!1},t.prototype.eraseInDisplay=function(e){var t;switch(this._restrictCursor(this._bufferService.cols),e.params[0]){case 0:for(t=this._activeBuffer.y,this._dirtyRowService.markDirty(t),this._eraseInBufferLine(t++,this._activeBuffer.x,this._bufferService.cols,0===this._activeBuffer.x);t<this._bufferService.rows;t++)this._resetBufferLine(t);this._dirtyRowService.markDirty(t);break;case 1:for(t=this._activeBuffer.y,this._dirtyRowService.markDirty(t),this._eraseInBufferLine(t,0,this._activeBuffer.x+1,!0),this._activeBuffer.x+1>=this._bufferService.cols&&(this._activeBuffer.lines.get(t+1).isWrapped=!1);t--;)this._resetBufferLine(t);this._dirtyRowService.markDirty(0);break;case 2:for(t=this._bufferService.rows,this._dirtyRowService.markDirty(t-1);t--;)this._resetBufferLine(t);this._dirtyRowService.markDirty(0);break;case 3:var r=this._activeBuffer.lines.length-this._bufferService.rows;r>0&&(this._activeBuffer.lines.trimStart(r),this._activeBuffer.ybase=Math.max(this._activeBuffer.ybase-r,0),this._activeBuffer.ydisp=Math.max(this._activeBuffer.ydisp-r,0),this._onScroll.fire(0))}return!0},t.prototype.eraseInLine=function(e){switch(this._restrictCursor(this._bufferService.cols),e.params[0]){case 0:this._eraseInBufferLine(this._activeBuffer.y,this._activeBuffer.x,this._bufferService.cols,0===this._activeBuffer.x);break;case 1:this._eraseInBufferLine(this._activeBuffer.y,0,this._activeBuffer.x+1,!1);break;case 2:this._eraseInBufferLine(this._activeBuffer.y,0,this._bufferService.cols,!0)}return this._dirtyRowService.markDirty(this._activeBuffer.y),!0},t.prototype.insertLines=function(e){this._restrictCursor();var t=e.params[0]||1;if(this._activeBuffer.y>this._activeBuffer.scrollBottom||this._activeBuffer.y<this._activeBuffer.scrollTop)return!0;for(var r=this._activeBuffer.ybase+this._activeBuffer.y,i=this._bufferService.rows-1-this._activeBuffer.scrollBottom,n=this._bufferService.rows-1+this._activeBuffer.ybase-i+1;t--;)this._activeBuffer.lines.splice(n-1,1),this._activeBuffer.lines.splice(r,0,this._activeBuffer.getBlankLine(this._eraseAttrData()));return this._dirtyRowService.markRangeDirty(this._activeBuffer.y,this._activeBuffer.scrollBottom),this._activeBuffer.x=0,!0},t.prototype.deleteLines=function(e){this._restrictCursor();var t=e.params[0]||1;if(this._activeBuffer.y>this._activeBuffer.scrollBottom||this._activeBuffer.y<this._activeBuffer.scrollTop)return!0;var r,i=this._activeBuffer.ybase+this._activeBuffer.y;for(r=this._bufferService.rows-1-this._activeBuffer.scrollBottom,r=this._bufferService.rows-1+this._activeBuffer.ybase-r;t--;)this._activeBuffer.lines.splice(i,1),this._activeBuffer.lines.splice(r,0,this._activeBuffer.getBlankLine(this._eraseAttrData()));return this._dirtyRowService.markRangeDirty(this._activeBuffer.y,this._activeBuffer.scrollBottom),this._activeBuffer.x=0,!0},t.prototype.insertChars=function(e){this._restrictCursor();var t=this._activeBuffer.lines.get(this._activeBuffer.ybase+this._activeBuffer.y);return t&&(t.insertCells(this._activeBuffer.x,e.params[0]||1,this._activeBuffer.getNullCell(this._eraseAttrData()),this._eraseAttrData()),this._dirtyRowService.markDirty(this._activeBuffer.y)),!0},t.prototype.deleteChars=function(e){this._restrictCursor();var t=this._activeBuffer.lines.get(this._activeBuffer.ybase+this._activeBuffer.y);return t&&(t.deleteCells(this._activeBuffer.x,e.params[0]||1,this._activeBuffer.getNullCell(this._eraseAttrData()),this._eraseAttrData()),this._dirtyRowService.markDirty(this._activeBuffer.y)),!0},t.prototype.scrollUp=function(e){for(var t=e.params[0]||1;t--;)this._activeBuffer.lines.splice(this._activeBuffer.ybase+this._activeBuffer.scrollTop,1),this._activeBuffer.lines.splice(this._activeBuffer.ybase+this._activeBuffer.scrollBottom,0,this._activeBuffer.getBlankLine(this._eraseAttrData()));return this._dirtyRowService.markRangeDirty(this._activeBuffer.scrollTop,this._activeBuffer.scrollBottom),!0},t.prototype.scrollDown=function(e){for(var t=e.params[0]||1;t--;)this._activeBuffer.lines.splice(this._activeBuffer.ybase+this._activeBuffer.scrollBottom,1),this._activeBuffer.lines.splice(this._activeBuffer.ybase+this._activeBuffer.scrollTop,0,this._activeBuffer.getBlankLine(f.DEFAULT_ATTR_DATA));return this._dirtyRowService.markRangeDirty(this._activeBuffer.scrollTop,this._activeBuffer.scrollBottom),!0},t.prototype.scrollLeft=function(e){if(this._activeBuffer.y>this._activeBuffer.scrollBottom||this._activeBuffer.y<this._activeBuffer.scrollTop)return!0;for(var t=e.params[0]||1,r=this._activeBuffer.scrollTop;r<=this._activeBuffer.scrollBottom;++r){var i=this._activeBuffer.lines.get(this._activeBuffer.ybase+r);i.deleteCells(0,t,this._activeBuffer.getNullCell(this._eraseAttrData()),this._eraseAttrData()),i.isWrapped=!1}return this._dirtyRowService.markRangeDirty(this._activeBuffer.scrollTop,this._activeBuffer.scrollBottom),!0},t.prototype.scrollRight=function(e){if(this._activeBuffer.y>this._activeBuffer.scrollBottom||this._activeBuffer.y<this._activeBuffer.scrollTop)return!0;for(var t=e.params[0]||1,r=this._activeBuffer.scrollTop;r<=this._activeBuffer.scrollBottom;++r){var i=this._activeBuffer.lines.get(this._activeBuffer.ybase+r);i.insertCells(0,t,this._activeBuffer.getNullCell(this._eraseAttrData()),this._eraseAttrData()),i.isWrapped=!1}return this._dirtyRowService.markRangeDirty(this._activeBuffer.scrollTop,this._activeBuffer.scrollBottom),!0},t.prototype.insertColumns=function(e){if(this._activeBuffer.y>this._activeBuffer.scrollBottom||this._activeBuffer.y<this._activeBuffer.scrollTop)return!0;for(var t=e.params[0]||1,r=this._activeBuffer.scrollTop;r<=this._activeBuffer.scrollBottom;++r){var i=this._activeBuffer.lines.get(this._activeBuffer.ybase+r);i.insertCells(this._activeBuffer.x,t,this._activeBuffer.getNullCell(this._eraseAttrData()),this._eraseAttrData()),i.isWrapped=!1}return this._dirtyRowService.markRangeDirty(this._activeBuffer.scrollTop,this._activeBuffer.scrollBottom),!0},t.prototype.deleteColumns=function(e){if(this._activeBuffer.y>this._activeBuffer.scrollBottom||this._activeBuffer.y<this._activeBuffer.scrollTop)return!0;for(var t=e.params[0]||1,r=this._activeBuffer.scrollTop;r<=this._activeBuffer.scrollBottom;++r){var i=this._activeBuffer.lines.get(this._activeBuffer.ybase+r);i.deleteCells(this._activeBuffer.x,t,this._activeBuffer.getNullCell(this._eraseAttrData()),this._eraseAttrData()),i.isWrapped=!1}return this._dirtyRowService.markRangeDirty(this._activeBuffer.scrollTop,this._activeBuffer.scrollBottom),!0},t.prototype.eraseChars=function(e){this._restrictCursor();var t=this._activeBuffer.lines.get(this._activeBuffer.ybase+this._activeBuffer.y);return t&&(t.replaceCells(this._activeBuffer.x,this._activeBuffer.x+(e.params[0]||1),this._activeBuffer.getNullCell(this._eraseAttrData()),this._eraseAttrData()),this._dirtyRowService.markDirty(this._activeBuffer.y)),!0},t.prototype.repeatPrecedingCharacter=function(e){if(!this._parser.precedingCodepoint)return!0;for(var t=e.params[0]||1,r=new Uint32Array(t),i=0;i<t;++i)r[i]=this._parser.precedingCodepoint;return this.print(r,0,r.length),!0},t.prototype.sendDeviceAttributesPrimary=function(e){return e.params[0]>0||(this._is("xterm")||this._is("rxvt-unicode")||this._is("screen")?this._coreService.triggerDataEvent(s.C0.ESC+"[?1;2c"):this._is("linux")&&this._coreService.triggerDataEvent(s.C0.ESC+"[?6c")),!0},t.prototype.sendDeviceAttributesSecondary=function(e){return e.params[0]>0||(this._is("xterm")?this._coreService.triggerDataEvent(s.C0.ESC+"[>0;276;0c"):this._is("rxvt-unicode")?this._coreService.triggerDataEvent(s.C0.ESC+"[>85;95;0c"):this._is("linux")?this._coreService.triggerDataEvent(e.params[0]+"c"):this._is("screen")&&this._coreService.triggerDataEvent(s.C0.ESC+"[>83;40003;0c")),!0},t.prototype._is=function(e){return 0===(this._optionsService.options.termName+"").indexOf(e)},t.prototype.setMode=function(e){for(var t=0;t<e.length;t++)4===e.params[t]&&(this._coreService.modes.insertMode=!0);return!0},t.prototype.setModePrivate=function(e){for(var t=0;t<e.length;t++)switch(e.params[t]){case 1:this._coreService.decPrivateModes.applicationCursorKeys=!0;break;case 2:this._charsetService.setgCharset(0,a.DEFAULT_CHARSET),this._charsetService.setgCharset(1,a.DEFAULT_CHARSET),this._charsetService.setgCharset(2,a.DEFAULT_CHARSET),this._charsetService.setgCharset(3,a.DEFAULT_CHARSET);break;case 3:this._optionsService.options.windowOptions.setWinLines&&(this._bufferService.resize(132,this._bufferService.rows),this._onRequestReset.fire());break;case 6:this._coreService.decPrivateModes.origin=!0,this._setCursor(0,0);break;case 7:this._coreService.decPrivateModes.wraparound=!0;break;case 12:break;case 45:this._coreService.decPrivateModes.reverseWraparound=!0;break;case 66:this._logService.debug("Serial port requested application keypad."),this._coreService.decPrivateModes.applicationKeypad=!0,this._onRequestSyncScrollBar.fire();break;case 9:this._coreMouseService.activeProtocol="X10";break;case 1e3:this._coreMouseService.activeProtocol="VT200";break;case 1002:this._coreMouseService.activeProtocol="DRAG";break;case 1003:this._coreMouseService.activeProtocol="ANY";break;case 1004:this._coreService.decPrivateModes.sendFocus=!0,this._onRequestSendFocus.fire();break;case 1005:this._logService.debug("DECSET 1005 not supported (see #2507)");break;case 1006:this._coreMouseService.activeEncoding="SGR";break;case 1015:this._logService.debug("DECSET 1015 not supported (see #2507)");break;case 25:this._coreService.isCursorHidden=!1;break;case 1048:this.saveCursor();break;case 1049:this.saveCursor();case 47:case 1047:this._bufferService.buffers.activateAltBuffer(this._eraseAttrData()),this._coreService.isCursorInitialized=!0,this._onRequestRefreshRows.fire(0,this._bufferService.rows-1),this._onRequestSyncScrollBar.fire();break;case 2004:this._coreService.decPrivateModes.bracketedPasteMode=!0}return!0},t.prototype.resetMode=function(e){for(var t=0;t<e.length;t++)4===e.params[t]&&(this._coreService.modes.insertMode=!1);return!0},t.prototype.resetModePrivate=function(e){for(var t=0;t<e.length;t++)switch(e.params[t]){case 1:this._coreService.decPrivateModes.applicationCursorKeys=!1;break;case 3:this._optionsService.options.windowOptions.setWinLines&&(this._bufferService.resize(80,this._bufferService.rows),this._onRequestReset.fire());break;case 6:this._coreService.decPrivateModes.origin=!1,this._setCursor(0,0);break;case 7:this._coreService.decPrivateModes.wraparound=!1;break;case 12:break;case 45:this._coreService.decPrivateModes.reverseWraparound=!1;break;case 66:this._logService.debug("Switching back to normal keypad."),this._coreService.decPrivateModes.applicationKeypad=!1,this._onRequestSyncScrollBar.fire();break;case 9:case 1e3:case 1002:case 1003:this._coreMouseService.activeProtocol="NONE";break;case 1004:this._coreService.decPrivateModes.sendFocus=!1;break;case 1005:this._logService.debug("DECRST 1005 not supported (see #2507)");break;case 1006:this._coreMouseService.activeEncoding="DEFAULT";break;case 1015:this._logService.debug("DECRST 1015 not supported (see #2507)");break;case 25:this._coreService.isCursorHidden=!0;break;case 1048:this.restoreCursor();break;case 1049:case 47:case 1047:this._bufferService.buffers.activateNormalBuffer(),1049===e.params[t]&&this.restoreCursor(),this._coreService.isCursorInitialized=!0,this._onRequestRefreshRows.fire(0,this._bufferService.rows-1),this._onRequestSyncScrollBar.fire();break;case 2004:this._coreService.decPrivateModes.bracketedPasteMode=!1}return!0},t.prototype._updateAttrColor=function(e,t,r,i,n){return 2===t?(e|=50331648,e&=-16777216,e|=v.AttributeData.fromColorRGB([r,i,n])):5===t&&(e&=-50331904,e|=33554432|255&r),e},t.prototype._extractColor=function(e,t,r){var i=[0,0,-1,0,0,0],n=0,o=0;do{if(i[o+n]=e.params[t+o],e.hasSubParams(t+o)){var s=e.getSubParams(t+o),a=0;do{5===i[1]&&(n=1),i[o+a+1+n]=s[a]}while(++a<s.length&&a+o+1+n<i.length);break}if(5===i[1]&&o+n>=2||2===i[1]&&o+n>=5)break;i[1]&&(n=1)}while(++o+t<e.length&&o+n<i.length);for(a=2;a<i.length;++a)-1===i[a]&&(i[a]=0);switch(i[0]){case 38:r.fg=this._updateAttrColor(r.fg,i[1],i[3],i[4],i[5]);break;case 48:r.bg=this._updateAttrColor(r.bg,i[1],i[3],i[4],i[5]);break;case 58:r.extended=r.extended.clone(),r.extended.underlineColor=this._updateAttrColor(r.extended.underlineColor,i[1],i[3],i[4],i[5])}return o},t.prototype._processUnderline=function(e,t){t.extended=t.extended.clone(),(!~e||e>5)&&(e=1),t.extended.underlineStyle=e,t.fg|=268435456,0===e&&(t.fg&=-268435457),t.updateExtended()},t.prototype.charAttributes=function(e){if(1===e.length&&0===e.params[0])return this._curAttrData.fg=f.DEFAULT_ATTR_DATA.fg,this._curAttrData.bg=f.DEFAULT_ATTR_DATA.bg,!0;for(var t,r=e.length,i=this._curAttrData,n=0;n<r;n++)(t=e.params[n])>=30&&t<=37?(i.fg&=-50331904,i.fg|=16777216|t-30):t>=40&&t<=47?(i.bg&=-50331904,i.bg|=16777216|t-40):t>=90&&t<=97?(i.fg&=-50331904,i.fg|=16777224|t-90):t>=100&&t<=107?(i.bg&=-50331904,i.bg|=16777224|t-100):0===t?(i.fg=f.DEFAULT_ATTR_DATA.fg,i.bg=f.DEFAULT_ATTR_DATA.bg):1===t?i.fg|=134217728:3===t?i.bg|=67108864:4===t?(i.fg|=268435456,this._processUnderline(e.hasSubParams(n)?e.getSubParams(n)[0]:1,i)):5===t?i.fg|=536870912:7===t?i.fg|=67108864:8===t?i.fg|=1073741824:9===t?i.fg|=2147483648:2===t?i.bg|=134217728:21===t?this._processUnderline(2,i):22===t?(i.fg&=-134217729,i.bg&=-134217729):23===t?i.bg&=-67108865:24===t?i.fg&=-268435457:25===t?i.fg&=-536870913:27===t?i.fg&=-67108865:28===t?i.fg&=-1073741825:29===t?i.fg&=2147483647:39===t?(i.fg&=-67108864,i.fg|=16777215&f.DEFAULT_ATTR_DATA.fg):49===t?(i.bg&=-67108864,i.bg|=16777215&f.DEFAULT_ATTR_DATA.bg):38===t||48===t||58===t?n+=this._extractColor(e,n,i):59===t?(i.extended=i.extended.clone(),i.extended.underlineColor=-1,i.updateExtended()):100===t?(i.fg&=-67108864,i.fg|=16777215&f.DEFAULT_ATTR_DATA.fg,i.bg&=-67108864,i.bg|=16777215&f.DEFAULT_ATTR_DATA.bg):this._logService.debug("Unknown SGR attribute: %d.",t);return!0},t.prototype.deviceStatus=function(e){switch(e.params[0]){case 5:this._coreService.triggerDataEvent(s.C0.ESC+"[0n");break;case 6:var t=this._activeBuffer.y+1,r=this._activeBuffer.x+1;this._coreService.triggerDataEvent(s.C0.ESC+"["+t+";"+r+"R")}return!0},t.prototype.deviceStatusPrivate=function(e){if(6===e.params[0]){var t=this._activeBuffer.y+1,r=this._activeBuffer.x+1;this._coreService.triggerDataEvent(s.C0.ESC+"[?"+t+";"+r+"R")}return!0},t.prototype.softReset=function(e){return this._coreService.isCursorHidden=!1,this._onRequestSyncScrollBar.fire(),this._activeBuffer.scrollTop=0,this._activeBuffer.scrollBottom=this._bufferService.rows-1,this._curAttrData=f.DEFAULT_ATTR_DATA.clone(),this._coreService.reset(),this._charsetService.reset(),this._activeBuffer.savedX=0,this._activeBuffer.savedY=this._activeBuffer.ybase,this._activeBuffer.savedCurAttrData.fg=this._curAttrData.fg,this._activeBuffer.savedCurAttrData.bg=this._curAttrData.bg,this._activeBuffer.savedCharset=this._charsetService.charset,this._coreService.decPrivateModes.origin=!1,!0},t.prototype.setCursorStyle=function(e){var t=e.params[0]||1;switch(t){case 1:case 2:this._optionsService.options.cursorStyle="block";break;case 3:case 4:this._optionsService.options.cursorStyle="underline";break;case 5:case 6:this._optionsService.options.cursorStyle="bar"}var r=t%2==1;return this._optionsService.options.cursorBlink=r,!0},t.prototype.setScrollRegion=function(e){var t,r=e.params[0]||1;return(e.length<2||(t=e.params[1])>this._bufferService.rows||0===t)&&(t=this._bufferService.rows),t>r&&(this._activeBuffer.scrollTop=r-1,this._activeBuffer.scrollBottom=t-1,this._setCursor(0,0)),!0},t.prototype.windowOptions=function(e){if(!w(e.params[0],this._optionsService.options.windowOptions))return!0;var t=e.length>1?e.params[1]:0;switch(e.params[0]){case 14:2!==t&&this._onRequestWindowsOptionsReport.fire(o.GET_WIN_SIZE_PIXELS);break;case 16:this._onRequestWindowsOptionsReport.fire(o.GET_CELL_SIZE_PIXELS);break;case 18:this._bufferService&&this._coreService.triggerDataEvent(s.C0.ESC+"[8;"+this._bufferService.rows+";"+this._bufferService.cols+"t");break;case 22:0!==t&&2!==t||(this._windowTitleStack.push(this._windowTitle),this._windowTitleStack.length>10&&this._windowTitleStack.shift()),0!==t&&1!==t||(this._iconNameStack.push(this._iconName),this._iconNameStack.length>10&&this._iconNameStack.shift());break;case 23:0!==t&&2!==t||this._windowTitleStack.length&&this.setTitle(this._windowTitleStack.pop()),0!==t&&1!==t||this._iconNameStack.length&&this.setIconName(this._iconNameStack.pop())}return!0},t.prototype.saveCursor=function(e){return this._activeBuffer.savedX=this._activeBuffer.x,this._activeBuffer.savedY=this._activeBuffer.ybase+this._activeBuffer.y,this._activeBuffer.savedCurAttrData.fg=this._curAttrData.fg,this._activeBuffer.savedCurAttrData.bg=this._curAttrData.bg,this._activeBuffer.savedCharset=this._charsetService.charset,!0},t.prototype.restoreCursor=function(e){return this._activeBuffer.x=this._activeBuffer.savedX||0,this._activeBuffer.y=Math.max(this._activeBuffer.savedY-this._activeBuffer.ybase,0),this._curAttrData.fg=this._activeBuffer.savedCurAttrData.fg,this._curAttrData.bg=this._activeBuffer.savedCurAttrData.bg,this._charsetService.charset=this._savedCharset,this._activeBuffer.savedCharset&&(this._charsetService.charset=this._activeBuffer.savedCharset),this._restrictCursor(),!0},t.prototype.setTitle=function(e){return this._windowTitle=e,this._onTitleChange.fire(e),!0},t.prototype.setIconName=function(e){return this._iconName=e,!0},t.prototype.setOrReportIndexedColor=function(e){for(var t=[],r=e.split(";");r.length>1;){var i=r.shift(),n=r.shift();if(/^\d+$/.exec(i)){var o=parseInt(i);if(0<=o&&o<256)if("?"===n)t.push({type:0,index:o});else{var s=(0,S.parseColor)(n);s&&t.push({type:1,index:o,color:s})}}}return t.length&&this._onColor.fire(t),!0},t.prototype._setOrReportSpecialColor=function(e,t){for(var r=e.split(";"),i=0;i<r.length&&!(t>=this._specialColors.length);++i,++t)if("?"===r[i])this._onColor.fire([{type:0,index:this._specialColors[t]}]);else{var n=(0,S.parseColor)(r[i]);n&&this._onColor.fire([{type:1,index:this._specialColors[t],color:n}])}return!0},t.prototype.setOrReportFgColor=function(e){return this._setOrReportSpecialColor(e,0)},t.prototype.setOrReportBgColor=function(e){return this._setOrReportSpecialColor(e,1)},t.prototype.setOrReportCursorColor=function(e){return this._setOrReportSpecialColor(e,2)},t.prototype.restoreIndexedColor=function(e){if(!e)return this._onColor.fire([{type:2}]),!0;for(var t=[],r=e.split(";"),i=0;i<r.length;++i)if(/^\d+$/.exec(r[i])){var n=parseInt(r[i]);0<=n&&n<256&&t.push({type:2,index:n})}return t.length&&this._onColor.fire(t),!0},t.prototype.restoreFgColor=function(e){return this._onColor.fire([{type:2,index:256}]),!0},t.prototype.restoreBgColor=function(e){return this._onColor.fire([{type:2,index:257}]),!0},t.prototype.restoreCursorColor=function(e){return this._onColor.fire([{type:2,index:258}]),!0},t.prototype.nextLine=function(){return this._activeBuffer.x=0,this.index(),!0},t.prototype.keypadApplicationMode=function(){return this._logService.debug("Serial port requested application keypad."),this._coreService.decPrivateModes.applicationKeypad=!0,this._onRequestSyncScrollBar.fire(),!0},t.prototype.keypadNumericMode=function(){return this._logService.debug("Switching back to normal keypad."),this._coreService.decPrivateModes.applicationKeypad=!1,this._onRequestSyncScrollBar.fire(),!0},t.prototype.selectDefaultCharset=function(){return this._charsetService.setgLevel(0),this._charsetService.setgCharset(0,a.DEFAULT_CHARSET),!0},t.prototype.selectCharset=function(e){return 2!==e.length?(this.selectDefaultCharset(),!0):("/"===e[0]||this._charsetService.setgCharset(C[e[0]],a.CHARSETS[e[1]]||a.DEFAULT_CHARSET),!0)},t.prototype.index=function(){return this._restrictCursor(),this._activeBuffer.y++,this._activeBuffer.y===this._activeBuffer.scrollBottom+1?(this._activeBuffer.y--,this._bufferService.scroll(this._eraseAttrData())):this._activeBuffer.y>=this._bufferService.rows&&(this._activeBuffer.y=this._bufferService.rows-1),this._restrictCursor(),!0},t.prototype.tabSet=function(){return this._activeBuffer.tabs[this._activeBuffer.x]=!0,!0},t.prototype.reverseIndex=function(){if(this._restrictCursor(),this._activeBuffer.y===this._activeBuffer.scrollTop){var e=this._activeBuffer.scrollBottom-this._activeBuffer.scrollTop;this._activeBuffer.lines.shiftElements(this._activeBuffer.ybase+this._activeBuffer.y,e,1),this._activeBuffer.lines.set(this._activeBuffer.ybase+this._activeBuffer.y,this._activeBuffer.getBlankLine(this._eraseAttrData())),this._dirtyRowService.markRangeDirty(this._activeBuffer.scrollTop,this._activeBuffer.scrollBottom)}else this._activeBuffer.y--,this._restrictCursor();return!0},t.prototype.fullReset=function(){return this._parser.reset(),this._onRequestReset.fire(),!0},t.prototype.reset=function(){this._curAttrData=f.DEFAULT_ATTR_DATA.clone(),this._eraseAttrDataInternal=f.DEFAULT_ATTR_DATA.clone()},t.prototype._eraseAttrData=function(){return this._eraseAttrDataInternal.bg&=-67108864,this._eraseAttrDataInternal.bg|=67108863&this._curAttrData.bg,this._eraseAttrDataInternal},t.prototype.setgLevel=function(e){return this._charsetService.setgLevel(e),!0},t.prototype.screenAlignmentPattern=function(){var e=new p.CellData;e.content=1<<22|"E".charCodeAt(0),e.fg=this._curAttrData.fg,e.bg=this._curAttrData.bg,this._setCursor(0,0);for(var t=0;t<this._bufferService.rows;++t){var r=this._activeBuffer.ybase+this._activeBuffer.y+t,i=this._activeBuffer.lines.get(r);i&&(i.fill(e),i.isWrapped=!1)}return this._dirtyRowService.markAllDirty(),this._setCursor(0,0),!0},t}(l.Disposable);t.InputHandler=E},844:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.getDisposeArrayDisposable=t.disposeArray=t.Disposable=void 0;var r=function(){function e(){this._disposables=[],this._isDisposed=!1}return e.prototype.dispose=function(){this._isDisposed=!0;for(var e=0,t=this._disposables;e<t.length;e++)t[e].dispose();this._disposables.length=0},e.prototype.register=function(e){return this._disposables.push(e),e},e.prototype.unregister=function(e){var t=this._disposables.indexOf(e);-1!==t&&this._disposables.splice(t,1)},e}();function i(e){for(var t=0,r=e;t<r.length;t++)r[t].dispose();e.length=0}t.Disposable=r,t.disposeArray=i,t.getDisposeArrayDisposable=function(e){return{dispose:function(){return i(e)}}}},6114:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.isLinux=t.isWindows=t.isIphone=t.isIpad=t.isMac=t.isSafari=t.isFirefox=void 0;var r="undefined"==typeof navigator,i=r?"node":navigator.userAgent,n=r?"node":navigator.platform;t.isFirefox=i.includes("Firefox"),t.isSafari=/^((?!chrome|android).)*safari/i.test(i),t.isMac=["Macintosh","MacIntel","MacPPC","Mac68K"].includes(n),t.isIpad="iPad"===n,t.isIphone="iPhone"===n,t.isWindows=["Windows","Win16","Win32","WinCE"].includes(n),t.isLinux=n.indexOf("Linux")>=0},8273:(e,t)=>{function r(e,t,r,i){if(void 0===r&&(r=0),void 0===i&&(i=e.length),r>=e.length)return e;r=(e.length+r)%e.length,i=i>=e.length?e.length:(e.length+i)%e.length;for(var n=r;n<i;++n)e[n]=t;return e}Object.defineProperty(t,"__esModule",{value:!0}),t.concat=t.fillFallback=t.fill=void 0,t.fill=function(e,t,i,n){return e.fill?e.fill(t,i,n):r(e,t,i,n)},t.fillFallback=r,t.concat=function(e,t){var r=new e.constructor(e.length+t.length);return r.set(e),r.set(t,e.length),r}},9282:(e,t,r)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.updateWindowsModeWrappedState=void 0;var i=r(643);t.updateWindowsModeWrappedState=function(e){var t=e.buffer.lines.get(e.buffer.ybase+e.buffer.y-1),r=null==t?void 0:t.get(e.cols-1),n=e.buffer.lines.get(e.buffer.ybase+e.buffer.y);n&&r&&(n.isWrapped=r[i.CHAR_DATA_CODE_INDEX]!==i.NULL_CELL_CODE&&r[i.CHAR_DATA_CODE_INDEX]!==i.WHITESPACE_CELL_CODE)}},3734:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ExtendedAttrs=t.AttributeData=void 0;var r=function(){function e(){this.fg=0,this.bg=0,this.extended=new i}return e.toColorRGB=function(e){return[e>>>16&255,e>>>8&255,255&e]},e.fromColorRGB=function(e){return(255&e[0])<<16|(255&e[1])<<8|255&e[2]},e.prototype.clone=function(){var t=new e;return t.fg=this.fg,t.bg=this.bg,t.extended=this.extended.clone(),t},e.prototype.isInverse=function(){return 67108864&this.fg},e.prototype.isBold=function(){return 134217728&this.fg},e.prototype.isUnderline=function(){return 268435456&this.fg},e.prototype.isBlink=function(){return 536870912&this.fg},e.prototype.isInvisible=function(){return 1073741824&this.fg},e.prototype.isItalic=function(){return 67108864&this.bg},e.prototype.isDim=function(){return 134217728&this.bg},e.prototype.isStrikethrough=function(){return 2147483648&this.fg},e.prototype.getFgColorMode=function(){return 50331648&this.fg},e.prototype.getBgColorMode=function(){return 50331648&this.bg},e.prototype.isFgRGB=function(){return 50331648==(50331648&this.fg)},e.prototype.isBgRGB=function(){return 50331648==(50331648&this.bg)},e.prototype.isFgPalette=function(){return 16777216==(50331648&this.fg)||33554432==(50331648&this.fg)},e.prototype.isBgPalette=function(){return 16777216==(50331648&this.bg)||33554432==(50331648&this.bg)},e.prototype.isFgDefault=function(){return 0==(50331648&this.fg)},e.prototype.isBgDefault=function(){return 0==(50331648&this.bg)},e.prototype.isAttributeDefault=function(){return 0===this.fg&&0===this.bg},e.prototype.getFgColor=function(){switch(50331648&this.fg){case 16777216:case 33554432:return 255&this.fg;case 50331648:return 16777215&this.fg;default:return-1}},e.prototype.getBgColor=function(){switch(50331648&this.bg){case 16777216:case 33554432:return 255&this.bg;case 50331648:return 16777215&this.bg;default:return-1}},e.prototype.hasExtendedAttrs=function(){return 268435456&this.bg},e.prototype.updateExtended=function(){this.extended.isEmpty()?this.bg&=-268435457:this.bg|=268435456},e.prototype.getUnderlineColor=function(){if(268435456&this.bg&&~this.extended.underlineColor)switch(50331648&this.extended.underlineColor){case 16777216:case 33554432:return 255&this.extended.underlineColor;case 50331648:return 16777215&this.extended.underlineColor;default:return this.getFgColor()}return this.getFgColor()},e.prototype.getUnderlineColorMode=function(){return 268435456&this.bg&&~this.extended.underlineColor?50331648&this.extended.underlineColor:this.getFgColorMode()},e.prototype.isUnderlineColorRGB=function(){return 268435456&this.bg&&~this.extended.underlineColor?50331648==(50331648&this.extended.underlineColor):this.isFgRGB()},e.prototype.isUnderlineColorPalette=function(){return 268435456&this.bg&&~this.extended.underlineColor?16777216==(50331648&this.extended.underlineColor)||33554432==(50331648&this.extended.underlineColor):this.isFgPalette()},e.prototype.isUnderlineColorDefault=function(){return 268435456&this.bg&&~this.extended.underlineColor?0==(50331648&this.extended.underlineColor):this.isFgDefault()},e.prototype.getUnderlineStyle=function(){return 268435456&this.fg?268435456&this.bg?this.extended.underlineStyle:1:0},e}();t.AttributeData=r;var i=function(){function e(e,t){void 0===e&&(e=0),void 0===t&&(t=-1),this.underlineStyle=e,this.underlineColor=t}return e.prototype.clone=function(){return new e(this.underlineStyle,this.underlineColor)},e.prototype.isEmpty=function(){return 0===this.underlineStyle},e}();t.ExtendedAttrs=i},9092:(e,t,r)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.BufferStringIterator=t.Buffer=t.MAX_BUFFER_SIZE=void 0;var i=r(6349),n=r(8437),o=r(511),s=r(643),a=r(4634),c=r(4863),l=r(7116),h=r(3734);t.MAX_BUFFER_SIZE=4294967295;var u=function(){function e(e,t,r){this._hasScrollback=e,this._optionsService=t,this._bufferService=r,this.ydisp=0,this.ybase=0,this.y=0,this.x=0,this.savedY=0,this.savedX=0,this.savedCurAttrData=n.DEFAULT_ATTR_DATA.clone(),this.savedCharset=l.DEFAULT_CHARSET,this.markers=[],this._nullCell=o.CellData.fromCharData([0,s.NULL_CELL_CHAR,s.NULL_CELL_WIDTH,s.NULL_CELL_CODE]),this._whitespaceCell=o.CellData.fromCharData([0,s.WHITESPACE_CELL_CHAR,s.WHITESPACE_CELL_WIDTH,s.WHITESPACE_CELL_CODE]),this._cols=this._bufferService.cols,this._rows=this._bufferService.rows,this.lines=new i.CircularList(this._getCorrectBufferLength(this._rows)),this.scrollTop=0,this.scrollBottom=this._rows-1,this.setupTabStops()}return e.prototype.getNullCell=function(e){return e?(this._nullCell.fg=e.fg,this._nullCell.bg=e.bg,this._nullCell.extended=e.extended):(this._nullCell.fg=0,this._nullCell.bg=0,this._nullCell.extended=new h.ExtendedAttrs),this._nullCell},e.prototype.getWhitespaceCell=function(e){return e?(this._whitespaceCell.fg=e.fg,this._whitespaceCell.bg=e.bg,this._whitespaceCell.extended=e.extended):(this._whitespaceCell.fg=0,this._whitespaceCell.bg=0,this._whitespaceCell.extended=new h.ExtendedAttrs),this._whitespaceCell},e.prototype.getBlankLine=function(e,t){return new n.BufferLine(this._bufferService.cols,this.getNullCell(e),t)},Object.defineProperty(e.prototype,"hasScrollback",{get:function(){return this._hasScrollback&&this.lines.maxLength>this._rows},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"isCursorInViewport",{get:function(){var e=this.ybase+this.y-this.ydisp;return e>=0&&e<this._rows},enumerable:!1,configurable:!0}),e.prototype._getCorrectBufferLength=function(e){if(!this._hasScrollback)return e;var r=e+this._optionsService.options.scrollback;return r>t.MAX_BUFFER_SIZE?t.MAX_BUFFER_SIZE:r},e.prototype.fillViewportRows=function(e){if(0===this.lines.length){void 0===e&&(e=n.DEFAULT_ATTR_DATA);for(var t=this._rows;t--;)this.lines.push(this.getBlankLine(e))}},e.prototype.clear=function(){this.ydisp=0,this.ybase=0,this.y=0,this.x=0,this.lines=new i.CircularList(this._getCorrectBufferLength(this._rows)),this.scrollTop=0,this.scrollBottom=this._rows-1,this.setupTabStops()},e.prototype.resize=function(e,t){var r=this.getNullCell(n.DEFAULT_ATTR_DATA),i=this._getCorrectBufferLength(t);if(i>this.lines.maxLength&&(this.lines.maxLength=i),this.lines.length>0){if(this._cols<e)for(var o=0;o<this.lines.length;o++)this.lines.get(o).resize(e,r);var s=0;if(this._rows<t)for(var a=this._rows;a<t;a++)this.lines.length<t+this.ybase&&(this._optionsService.options.windowsMode?this.lines.push(new n.BufferLine(e,r)):this.ybase>0&&this.lines.length<=this.ybase+this.y+s+1?(this.ybase--,s++,this.ydisp>0&&this.ydisp--):this.lines.push(new n.BufferLine(e,r)));else for(a=this._rows;a>t;a--)this.lines.length>t+this.ybase&&(this.lines.length>this.ybase+this.y+1?this.lines.pop():(this.ybase++,this.ydisp++));if(i<this.lines.maxLength){var c=this.lines.length-i;c>0&&(this.lines.trimStart(c),this.ybase=Math.max(this.ybase-c,0),this.ydisp=Math.max(this.ydisp-c,0),this.savedY=Math.max(this.savedY-c,0)),this.lines.maxLength=i}this.x=Math.min(this.x,e-1),this.y=Math.min(this.y,t-1),s&&(this.y+=s),this.savedX=Math.min(this.savedX,e-1),this.scrollTop=0}if(this.scrollBottom=t-1,this._isReflowEnabled&&(this._reflow(e,t),this._cols>e))for(o=0;o<this.lines.length;o++)this.lines.get(o).resize(e,r);this._cols=e,this._rows=t},Object.defineProperty(e.prototype,"_isReflowEnabled",{get:function(){return this._hasScrollback&&!this._optionsService.options.windowsMode},enumerable:!1,configurable:!0}),e.prototype._reflow=function(e,t){this._cols!==e&&(e>this._cols?this._reflowLarger(e,t):this._reflowSmaller(e,t))},e.prototype._reflowLarger=function(e,t){var r=(0,a.reflowLargerGetLinesToRemove)(this.lines,this._cols,e,this.ybase+this.y,this.getNullCell(n.DEFAULT_ATTR_DATA));if(r.length>0){var i=(0,a.reflowLargerCreateNewLayout)(this.lines,r);(0,a.reflowLargerApplyNewLayout)(this.lines,i.layout),this._reflowLargerAdjustViewport(e,t,i.countRemoved)}},e.prototype._reflowLargerAdjustViewport=function(e,t,r){for(var i=this.getNullCell(n.DEFAULT_ATTR_DATA),o=r;o-- >0;)0===this.ybase?(this.y>0&&this.y--,this.lines.length<t&&this.lines.push(new n.BufferLine(e,i))):(this.ydisp===this.ybase&&this.ydisp--,this.ybase--);this.savedY=Math.max(this.savedY-r,0)},e.prototype._reflowSmaller=function(e,t){for(var r=this.getNullCell(n.DEFAULT_ATTR_DATA),i=[],o=0,s=this.lines.length-1;s>=0;s--){var c=this.lines.get(s);if(!(!c||!c.isWrapped&&c.getTrimmedLength()<=e)){for(var l=[c];c.isWrapped&&s>0;)c=this.lines.get(--s),l.unshift(c);var h=this.ybase+this.y;if(!(h>=s&&h<s+l.length)){var u,f=l[l.length-1].getTrimmedLength(),_=(0,a.reflowSmallerGetNewLineLengths)(l,this._cols,e),d=_.length-l.length;u=0===this.ybase&&this.y!==this.lines.length-1?Math.max(0,this.y-this.lines.maxLength+d):Math.max(0,this.lines.length-this.lines.maxLength+d);for(var p=[],v=0;v<d;v++){var g=this.getBlankLine(n.DEFAULT_ATTR_DATA,!0);p.push(g)}p.length>0&&(i.push({start:s+l.length+o,newLines:p}),o+=p.length),l.push.apply(l,p);var y=_.length-1,m=_[y];0===m&&(m=_[--y]);for(var S=l.length-d-1,C=f;S>=0;){var b=Math.min(C,m);if(l[y].copyCellsFrom(l[S],C-b,m-b,b,!0),0==(m-=b)&&(m=_[--y]),0==(C-=b)){S--;var w=Math.max(S,0);C=(0,a.getWrappedLineTrimmedLength)(l,w,this._cols)}}for(v=0;v<l.length;v++)_[v]<e&&l[v].setCell(_[v],r);for(var L=d-u;L-- >0;)0===this.ybase?this.y<t-1?(this.y++,this.lines.pop()):(this.ybase++,this.ydisp++):this.ybase<Math.min(this.lines.maxLength,this.lines.length+o)-t&&(this.ybase===this.ydisp&&this.ydisp++,this.ybase++);this.savedY=Math.min(this.savedY+d,this.ybase+t-1)}}}if(i.length>0){var E=[],x=[];for(v=0;v<this.lines.length;v++)x.push(this.lines.get(v));var M=this.lines.length,k=M-1,A=0,R=i[A];this.lines.length=Math.min(this.lines.maxLength,this.lines.length+o);var T=0;for(v=Math.min(this.lines.maxLength-1,M+o-1);v>=0;v--)if(R&&R.start>k+T){for(var B=R.newLines.length-1;B>=0;B--)this.lines.set(v--,R.newLines[B]);v++,E.push({index:k+1,amount:R.newLines.length}),T+=R.newLines.length,R=i[++A]}else this.lines.set(v,x[k--]);var O=0;for(v=E.length-1;v>=0;v--)E[v].index+=O,this.lines.onInsertEmitter.fire(E[v]),O+=E[v].amount;var D=Math.max(0,M+o-this.lines.maxLength);D>0&&this.lines.onTrimEmitter.fire(D)}},e.prototype.stringIndexToBufferIndex=function(e,t,r){for(void 0===r&&(r=!1);t;){var i=this.lines.get(e);if(!i)return[-1,-1];for(var n=r?i.getTrimmedLength():i.length,o=0;o<n;++o)if(i.get(o)[s.CHAR_DATA_WIDTH_INDEX]&&(t-=i.get(o)[s.CHAR_DATA_CHAR_INDEX].length||1),t<0)return[e,o];e++}return[e,0]},e.prototype.translateBufferLineToString=function(e,t,r,i){void 0===r&&(r=0);var n=this.lines.get(e);return n?n.translateToString(t,r,i):""},e.prototype.getWrappedRangeForLine=function(e){for(var t=e,r=e;t>0&&this.lines.get(t).isWrapped;)t--;for(;r+1<this.lines.length&&this.lines.get(r+1).isWrapped;)r++;return{first:t,last:r}},e.prototype.setupTabStops=function(e){for(null!=e?this.tabs[e]||(e=this.prevStop(e)):(this.tabs={},e=0);e<this._cols;e+=this._optionsService.options.tabStopWidth)this.tabs[e]=!0},e.prototype.prevStop=function(e){for(null==e&&(e=this.x);!this.tabs[--e]&&e>0;);return e>=this._cols?this._cols-1:e<0?0:e},e.prototype.nextStop=function(e){for(null==e&&(e=this.x);!this.tabs[++e]&&e<this._cols;);return e>=this._cols?this._cols-1:e<0?0:e},e.prototype.addMarker=function(e){var t=this,r=new c.Marker(e);return this.markers.push(r),r.register(this.lines.onTrim((function(e){r.line-=e,r.line<0&&r.dispose()}))),r.register(this.lines.onInsert((function(e){r.line>=e.index&&(r.line+=e.amount)}))),r.register(this.lines.onDelete((function(e){r.line>=e.index&&r.line<e.index+e.amount&&r.dispose(),r.line>e.index&&(r.line-=e.amount)}))),r.register(r.onDispose((function(){return t._removeMarker(r)}))),r},e.prototype._removeMarker=function(e){this.markers.splice(this.markers.indexOf(e),1)},e.prototype.iterator=function(e,t,r,i,n){return new f(this,e,t,r,i,n)},e}();t.Buffer=u;var f=function(){function e(e,t,r,i,n,o){void 0===r&&(r=0),void 0===i&&(i=e.lines.length),void 0===n&&(n=0),void 0===o&&(o=0),this._buffer=e,this._trimRight=t,this._startIndex=r,this._endIndex=i,this._startOverscan=n,this._endOverscan=o,this._startIndex<0&&(this._startIndex=0),this._endIndex>this._buffer.lines.length&&(this._endIndex=this._buffer.lines.length),this._current=this._startIndex}return e.prototype.hasNext=function(){return this._current<this._endIndex},e.prototype.next=function(){var e=this._buffer.getWrappedRangeForLine(this._current);e.first<this._startIndex-this._startOverscan&&(e.first=this._startIndex-this._startOverscan),e.last>this._endIndex+this._endOverscan&&(e.last=this._endIndex+this._endOverscan),e.first=Math.max(e.first,0),e.last=Math.min(e.last,this._buffer.lines.length);for(var t="",r=e.first;r<=e.last;++r)t+=this._buffer.translateBufferLineToString(r,this._trimRight);return this._current=e.last+1,{range:e,content:t}},e}();t.BufferStringIterator=f},8437:(e,t,r)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.BufferLine=t.DEFAULT_ATTR_DATA=void 0;var i=r(482),n=r(643),o=r(511),s=r(3734);t.DEFAULT_ATTR_DATA=Object.freeze(new s.AttributeData);var a=function(){function e(e,t,r){void 0===r&&(r=!1),this.isWrapped=r,this._combined={},this._extendedAttrs={},this._data=new Uint32Array(3*e);for(var i=t||o.CellData.fromCharData([0,n.NULL_CELL_CHAR,n.NULL_CELL_WIDTH,n.NULL_CELL_CODE]),s=0;s<e;++s)this.setCell(s,i);this.length=e}return e.prototype.get=function(e){var t=this._data[3*e+0],r=2097151&t;return[this._data[3*e+1],2097152&t?this._combined[e]:r?(0,i.stringFromCodePoint)(r):"",t>>22,2097152&t?this._combined[e].charCodeAt(this._combined[e].length-1):r]},e.prototype.set=function(e,t){this._data[3*e+1]=t[n.CHAR_DATA_ATTR_INDEX],t[n.CHAR_DATA_CHAR_INDEX].length>1?(this._combined[e]=t[1],this._data[3*e+0]=2097152|e|t[n.CHAR_DATA_WIDTH_INDEX]<<22):this._data[3*e+0]=t[n.CHAR_DATA_CHAR_INDEX].charCodeAt(0)|t[n.CHAR_DATA_WIDTH_INDEX]<<22},e.prototype.getWidth=function(e){return this._data[3*e+0]>>22},e.prototype.hasWidth=function(e){return 12582912&this._data[3*e+0]},e.prototype.getFg=function(e){return this._data[3*e+1]},e.prototype.getBg=function(e){return this._data[3*e+2]},e.prototype.hasContent=function(e){return 4194303&this._data[3*e+0]},e.prototype.getCodePoint=function(e){var t=this._data[3*e+0];return 2097152&t?this._combined[e].charCodeAt(this._combined[e].length-1):2097151&t},e.prototype.isCombined=function(e){return 2097152&this._data[3*e+0]},e.prototype.getString=function(e){var t=this._data[3*e+0];return 2097152&t?this._combined[e]:2097151&t?(0,i.stringFromCodePoint)(2097151&t):""},e.prototype.loadCell=function(e,t){var r=3*e;return t.content=this._data[r+0],t.fg=this._data[r+1],t.bg=this._data[r+2],2097152&t.content&&(t.combinedData=this._combined[e]),268435456&t.bg&&(t.extended=this._extendedAttrs[e]),t},e.prototype.setCell=function(e,t){2097152&t.content&&(this._combined[e]=t.combinedData),268435456&t.bg&&(this._extendedAttrs[e]=t.extended),this._data[3*e+0]=t.content,this._data[3*e+1]=t.fg,this._data[3*e+2]=t.bg},e.prototype.setCellFromCodePoint=function(e,t,r,i,n,o){268435456&n&&(this._extendedAttrs[e]=o),this._data[3*e+0]=t|r<<22,this._data[3*e+1]=i,this._data[3*e+2]=n},e.prototype.addCodepointToCell=function(e,t){var r=this._data[3*e+0];2097152&r?this._combined[e]+=(0,i.stringFromCodePoint)(t):(2097151&r?(this._combined[e]=(0,i.stringFromCodePoint)(2097151&r)+(0,i.stringFromCodePoint)(t),r&=-2097152,r|=2097152):r=t|1<<22,this._data[3*e+0]=r)},e.prototype.insertCells=function(e,t,r,i){if((e%=this.length)&&2===this.getWidth(e-1)&&this.setCellFromCodePoint(e-1,0,1,(null==i?void 0:i.fg)||0,(null==i?void 0:i.bg)||0,(null==i?void 0:i.extended)||new s.ExtendedAttrs),t<this.length-e){for(var n=new o.CellData,a=this.length-e-t-1;a>=0;--a)this.setCell(e+t+a,this.loadCell(e+a,n));for(a=0;a<t;++a)this.setCell(e+a,r)}else for(a=e;a<this.length;++a)this.setCell(a,r);2===this.getWidth(this.length-1)&&this.setCellFromCodePoint(this.length-1,0,1,(null==i?void 0:i.fg)||0,(null==i?void 0:i.bg)||0,(null==i?void 0:i.extended)||new s.ExtendedAttrs)},e.prototype.deleteCells=function(e,t,r,i){if(e%=this.length,t<this.length-e){for(var n=new o.CellData,a=0;a<this.length-e-t;++a)this.setCell(e+a,this.loadCell(e+t+a,n));for(a=this.length-t;a<this.length;++a)this.setCell(a,r)}else for(a=e;a<this.length;++a)this.setCell(a,r);e&&2===this.getWidth(e-1)&&this.setCellFromCodePoint(e-1,0,1,(null==i?void 0:i.fg)||0,(null==i?void 0:i.bg)||0,(null==i?void 0:i.extended)||new s.ExtendedAttrs),0!==this.getWidth(e)||this.hasContent(e)||this.setCellFromCodePoint(e,0,1,(null==i?void 0:i.fg)||0,(null==i?void 0:i.bg)||0,(null==i?void 0:i.extended)||new s.ExtendedAttrs)},e.prototype.replaceCells=function(e,t,r,i){for(e&&2===this.getWidth(e-1)&&this.setCellFromCodePoint(e-1,0,1,(null==i?void 0:i.fg)||0,(null==i?void 0:i.bg)||0,(null==i?void 0:i.extended)||new s.ExtendedAttrs),t<this.length&&2===this.getWidth(t-1)&&this.setCellFromCodePoint(t,0,1,(null==i?void 0:i.fg)||0,(null==i?void 0:i.bg)||0,(null==i?void 0:i.extended)||new s.ExtendedAttrs);e<t&&e<this.length;)this.setCell(e++,r)},e.prototype.resize=function(e,t){if(e!==this.length){if(e>this.length){var r=new Uint32Array(3*e);this.length&&(3*e<this._data.length?r.set(this._data.subarray(0,3*e)):r.set(this._data)),this._data=r;for(var i=this.length;i<e;++i)this.setCell(i,t)}else if(e){(r=new Uint32Array(3*e)).set(this._data.subarray(0,3*e)),this._data=r;var n=Object.keys(this._combined);for(i=0;i<n.length;i++){var o=parseInt(n[i],10);o>=e&&delete this._combined[o]}}else this._data=new Uint32Array(0),this._combined={};this.length=e}},e.prototype.fill=function(e){this._combined={},this._extendedAttrs={};for(var t=0;t<this.length;++t)this.setCell(t,e)},e.prototype.copyFrom=function(e){for(var t in this.length!==e.length?this._data=new Uint32Array(e._data):this._data.set(e._data),this.length=e.length,this._combined={},e._combined)this._combined[t]=e._combined[t];for(var t in this._extendedAttrs={},e._extendedAttrs)this._extendedAttrs[t]=e._extendedAttrs[t];this.isWrapped=e.isWrapped},e.prototype.clone=function(){var t=new e(0);for(var r in t._data=new Uint32Array(this._data),t.length=this.length,this._combined)t._combined[r]=this._combined[r];for(var r in this._extendedAttrs)t._extendedAttrs[r]=this._extendedAttrs[r];return t.isWrapped=this.isWrapped,t},e.prototype.getTrimmedLength=function(){for(var e=this.length-1;e>=0;--e)if(4194303&this._data[3*e+0])return e+(this._data[3*e+0]>>22);return 0},e.prototype.copyCellsFrom=function(e,t,r,i,n){var o=e._data;if(n)for(var s=i-1;s>=0;s--)for(var a=0;a<3;a++)this._data[3*(r+s)+a]=o[3*(t+s)+a];else for(s=0;s<i;s++)for(a=0;a<3;a++)this._data[3*(r+s)+a]=o[3*(t+s)+a];var c=Object.keys(e._combined);for(a=0;a<c.length;a++){var l=parseInt(c[a],10);l>=t&&(this._combined[l-t+r]=e._combined[l])}},e.prototype.translateToString=function(e,t,r){void 0===e&&(e=!1),void 0===t&&(t=0),void 0===r&&(r=this.length),e&&(r=Math.min(r,this.getTrimmedLength()));for(var o="";t<r;){var s=this._data[3*t+0],a=2097151&s;o+=2097152&s?this._combined[t]:a?(0,i.stringFromCodePoint)(a):n.WHITESPACE_CELL_CHAR,t+=s>>22||1}return o},e}();t.BufferLine=a},4841:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.getRangeLength=void 0,t.getRangeLength=function(e,t){if(e.start.y>e.end.y)throw new Error("Buffer range end ("+e.end.x+", "+e.end.y+") cannot be before start ("+e.start.x+", "+e.start.y+")");return t*(e.end.y-e.start.y)+(e.end.x-e.start.x+1)}},4634:(e,t)=>{function r(e,t,r){if(t===e.length-1)return e[t].getTrimmedLength();var i=!e[t].hasContent(r-1)&&1===e[t].getWidth(r-1),n=2===e[t+1].getWidth(0);return i&&n?r-1:r}Object.defineProperty(t,"__esModule",{value:!0}),t.getWrappedLineTrimmedLength=t.reflowSmallerGetNewLineLengths=t.reflowLargerApplyNewLayout=t.reflowLargerCreateNewLayout=t.reflowLargerGetLinesToRemove=void 0,t.reflowLargerGetLinesToRemove=function(e,t,i,n,o){for(var s=[],a=0;a<e.length-1;a++){var c=a,l=e.get(++c);if(l.isWrapped){for(var h=[e.get(a)];c<e.length&&l.isWrapped;)h.push(l),l=e.get(++c);if(n>=a&&n<c)a+=h.length-1;else{for(var u=0,f=r(h,u,t),_=1,d=0;_<h.length;){var p=r(h,_,t),v=p-d,g=i-f,y=Math.min(v,g);h[u].copyCellsFrom(h[_],d,f,y,!1),(f+=y)===i&&(u++,f=0),(d+=y)===p&&(_++,d=0),0===f&&0!==u&&2===h[u-1].getWidth(i-1)&&(h[u].copyCellsFrom(h[u-1],i-1,f++,1,!1),h[u-1].setCell(i-1,o))}h[u].replaceCells(f,i,o);for(var m=0,S=h.length-1;S>0&&(S>u||0===h[S].getTrimmedLength());S--)m++;m>0&&(s.push(a+h.length-m),s.push(m)),a+=h.length-1}}}return s},t.reflowLargerCreateNewLayout=function(e,t){for(var r=[],i=0,n=t[i],o=0,s=0;s<e.length;s++)if(n===s){var a=t[++i];e.onDeleteEmitter.fire({index:s-o,amount:a}),s+=a-1,o+=a,n=t[++i]}else r.push(s);return{layout:r,countRemoved:o}},t.reflowLargerApplyNewLayout=function(e,t){for(var r=[],i=0;i<t.length;i++)r.push(e.get(t[i]));for(i=0;i<r.length;i++)e.set(i,r[i]);e.length=t.length},t.reflowSmallerGetNewLineLengths=function(e,t,i){for(var n=[],o=e.map((function(i,n){return r(e,n,t)})).reduce((function(e,t){return e+t})),s=0,a=0,c=0;c<o;){if(o-c<i){n.push(o-c);break}s+=i;var l=r(e,a,t);s>l&&(s-=l,a++);var h=2===e[a].getWidth(s-1);h&&s--;var u=h?i-1:i;n.push(u),c+=u}return n},t.getWrappedLineTrimmedLength=r},5295:function(e,t,r){var i,n=this&&this.__extends||(i=function(e,t){return i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])},i(e,t)},function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function r(){this.constructor=e}i(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)});Object.defineProperty(t,"__esModule",{value:!0}),t.BufferSet=void 0;var o=r(9092),s=r(8460),a=function(e){function t(t,r){var i=e.call(this)||this;return i._optionsService=t,i._bufferService=r,i._onBufferActivate=i.register(new s.EventEmitter),i.reset(),i}return n(t,e),Object.defineProperty(t.prototype,"onBufferActivate",{get:function(){return this._onBufferActivate.event},enumerable:!1,configurable:!0}),t.prototype.reset=function(){this._normal=new o.Buffer(!0,this._optionsService,this._bufferService),this._normal.fillViewportRows(),this._alt=new o.Buffer(!1,this._optionsService,this._bufferService),this._activeBuffer=this._normal,this._onBufferActivate.fire({activeBuffer:this._normal,inactiveBuffer:this._alt}),this.setupTabStops()},Object.defineProperty(t.prototype,"alt",{get:function(){return this._alt},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"active",{get:function(){return this._activeBuffer},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"normal",{get:function(){return this._normal},enumerable:!1,configurable:!0}),t.prototype.activateNormalBuffer=function(){this._activeBuffer!==this._normal&&(this._normal.x=this._alt.x,this._normal.y=this._alt.y,this._alt.clear(),this._activeBuffer=this._normal,this._onBufferActivate.fire({activeBuffer:this._normal,inactiveBuffer:this._alt}))},t.prototype.activateAltBuffer=function(e){this._activeBuffer!==this._alt&&(this._alt.fillViewportRows(e),this._alt.x=this._normal.x,this._alt.y=this._normal.y,this._activeBuffer=this._alt,this._onBufferActivate.fire({activeBuffer:this._alt,inactiveBuffer:this._normal}))},t.prototype.resize=function(e,t){this._normal.resize(e,t),this._alt.resize(e,t)},t.prototype.setupTabStops=function(e){this._normal.setupTabStops(e),this._alt.setupTabStops(e)},t}(r(844).Disposable);t.BufferSet=a},511:function(e,t,r){var i,n=this&&this.__extends||(i=function(e,t){return i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])},i(e,t)},function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function r(){this.constructor=e}i(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)});Object.defineProperty(t,"__esModule",{value:!0}),t.CellData=void 0;var o=r(482),s=r(643),a=r(3734),c=function(e){function t(){var t=null!==e&&e.apply(this,arguments)||this;return t.content=0,t.fg=0,t.bg=0,t.extended=new a.ExtendedAttrs,t.combinedData="",t}return n(t,e),t.fromCharData=function(e){var r=new t;return r.setFromCharData(e),r},t.prototype.isCombined=function(){return 2097152&this.content},t.prototype.getWidth=function(){return this.content>>22},t.prototype.getChars=function(){return 2097152&this.content?this.combinedData:2097151&this.content?(0,o.stringFromCodePoint)(2097151&this.content):""},t.prototype.getCode=function(){return this.isCombined()?this.combinedData.charCodeAt(this.combinedData.length-1):2097151&this.content},t.prototype.setFromCharData=function(e){this.fg=e[s.CHAR_DATA_ATTR_INDEX],this.bg=0;var t=!1;if(e[s.CHAR_DATA_CHAR_INDEX].length>2)t=!0;else if(2===e[s.CHAR_DATA_CHAR_INDEX].length){var r=e[s.CHAR_DATA_CHAR_INDEX].charCodeAt(0);if(55296<=r&&r<=56319){var i=e[s.CHAR_DATA_CHAR_INDEX].charCodeAt(1);56320<=i&&i<=57343?this.content=1024*(r-55296)+i-56320+65536|e[s.CHAR_DATA_WIDTH_INDEX]<<22:t=!0}else t=!0}else this.content=e[s.CHAR_DATA_CHAR_INDEX].charCodeAt(0)|e[s.CHAR_DATA_WIDTH_INDEX]<<22;t&&(this.combinedData=e[s.CHAR_DATA_CHAR_INDEX],this.content=2097152|e[s.CHAR_DATA_WIDTH_INDEX]<<22)},t.prototype.getAsCharData=function(){return[this.fg,this.getChars(),this.getWidth(),this.getCode()]},t}(a.AttributeData);t.CellData=c},643:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.WHITESPACE_CELL_CODE=t.WHITESPACE_CELL_WIDTH=t.WHITESPACE_CELL_CHAR=t.NULL_CELL_CODE=t.NULL_CELL_WIDTH=t.NULL_CELL_CHAR=t.CHAR_DATA_CODE_INDEX=t.CHAR_DATA_WIDTH_INDEX=t.CHAR_DATA_CHAR_INDEX=t.CHAR_DATA_ATTR_INDEX=t.DEFAULT_ATTR=t.DEFAULT_COLOR=void 0,t.DEFAULT_COLOR=256,t.DEFAULT_ATTR=256|t.DEFAULT_COLOR<<9,t.CHAR_DATA_ATTR_INDEX=0,t.CHAR_DATA_CHAR_INDEX=1,t.CHAR_DATA_WIDTH_INDEX=2,t.CHAR_DATA_CODE_INDEX=3,t.NULL_CELL_CHAR="",t.NULL_CELL_WIDTH=1,t.NULL_CELL_CODE=0,t.WHITESPACE_CELL_CHAR=" ",t.WHITESPACE_CELL_WIDTH=1,t.WHITESPACE_CELL_CODE=32},4863:function(e,t,r){var i,n=this&&this.__extends||(i=function(e,t){return i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])},i(e,t)},function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function r(){this.constructor=e}i(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)});Object.defineProperty(t,"__esModule",{value:!0}),t.Marker=void 0;var o=r(8460),s=function(e){function t(r){var i=e.call(this)||this;return i.line=r,i._id=t._nextId++,i.isDisposed=!1,i._onDispose=new o.EventEmitter,i}return n(t,e),Object.defineProperty(t.prototype,"id",{get:function(){return this._id},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"onDispose",{get:function(){return this._onDispose.event},enumerable:!1,configurable:!0}),t.prototype.dispose=function(){this.isDisposed||(this.isDisposed=!0,this.line=-1,this._onDispose.fire(),e.prototype.dispose.call(this))},t._nextId=1,t}(r(844).Disposable);t.Marker=s},7116:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.DEFAULT_CHARSET=t.CHARSETS=void 0,t.CHARSETS={},t.DEFAULT_CHARSET=t.CHARSETS.B,t.CHARSETS[0]={"`":"◆",a:"▒",b:"␉",c:"␌",d:"␍",e:"␊",f:"°",g:"±",h:"␤",i:"␋",j:"┘",k:"┐",l:"┌",m:"└",n:"┼",o:"⎺",p:"⎻",q:"─",r:"⎼",s:"⎽",t:"├",u:"┤",v:"┴",w:"┬",x:"│",y:"≤",z:"≥","{":"π","|":"≠","}":"£","~":"·"},t.CHARSETS.A={"#":"£"},t.CHARSETS.B=void 0,t.CHARSETS[4]={"#":"£","@":"¾","[":"ij","\\":"½","]":"|","{":"¨","|":"f","}":"¼","~":"´"},t.CHARSETS.C=t.CHARSETS[5]={"[":"Ä","\\":"Ö","]":"Å","^":"Ü","`":"é","{":"ä","|":"ö","}":"å","~":"ü"},t.CHARSETS.R={"#":"£","@":"à","[":"°","\\":"ç","]":"§","{":"é","|":"ù","}":"è","~":"¨"},t.CHARSETS.Q={"@":"à","[":"â","\\":"ç","]":"ê","^":"î","`":"ô","{":"é","|":"ù","}":"è","~":"û"},t.CHARSETS.K={"@":"§","[":"Ä","\\":"Ö","]":"Ü","{":"ä","|":"ö","}":"ü","~":"ß"},t.CHARSETS.Y={"#":"£","@":"§","[":"°","\\":"ç","]":"é","`":"ù","{":"à","|":"ò","}":"è","~":"ì"},t.CHARSETS.E=t.CHARSETS[6]={"@":"Ä","[":"Æ","\\":"Ø","]":"Å","^":"Ü","`":"ä","{":"æ","|":"ø","}":"å","~":"ü"},t.CHARSETS.Z={"#":"£","@":"§","[":"¡","\\":"Ñ","]":"¿","{":"°","|":"ñ","}":"ç"},t.CHARSETS.H=t.CHARSETS[7]={"@":"É","[":"Ä","\\":"Ö","]":"Å","^":"Ü","`":"é","{":"ä","|":"ö","}":"å","~":"ü"},t.CHARSETS["="]={"#":"ù","@":"à","[":"é","\\":"ç","]":"ê","^":"î",_:"è","`":"ô","{":"ä","|":"ö","}":"ü","~":"û"}},2584:(e,t)=>{var r,i;Object.defineProperty(t,"__esModule",{value:!0}),t.C1=t.C0=void 0,(i=t.C0||(t.C0={})).NUL="\0",i.SOH="",i.STX="",i.ETX="",i.EOT="",i.ENQ="",i.ACK="",i.BEL="",i.BS="\b",i.HT="\t",i.LF="\n",i.VT="\v",i.FF="\f",i.CR="\r",i.SO="",i.SI="",i.DLE="",i.DC1="",i.DC2="",i.DC3="",i.DC4="",i.NAK="",i.SYN="",i.ETB="",i.CAN="",i.EM="",i.SUB="",i.ESC="",i.FS="",i.GS="",i.RS="",i.US="",i.SP=" ",i.DEL="",(r=t.C1||(t.C1={})).PAD="",r.HOP="",r.BPH="",r.NBH="",r.IND="",r.NEL="",r.SSA="",r.ESA="",r.HTS="",r.HTJ="",r.VTS="",r.PLD="",r.PLU="",r.RI="",r.SS2="",r.SS3="",r.DCS="",r.PU1="",r.PU2="",r.STS="",r.CCH="",r.MW="",r.SPA="",r.EPA="",r.SOS="",r.SGCI="",r.SCI="",r.CSI="",r.ST="",r.OSC="",r.PM="",r.APC=""},7399:(e,t,r)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.evaluateKeyboardEvent=void 0;var i=r(2584),n={48:["0",")"],49:["1","!"],50:["2","@"],51:["3","#"],52:["4","$"],53:["5","%"],54:["6","^"],55:["7","&"],56:["8","*"],57:["9","("],186:[";",":"],187:["=","+"],188:[",","<"],189:["-","_"],190:[".",">"],191:["/","?"],192:["`","~"],219:["[","{"],220:["\\","|"],221:["]","}"],222:["'",'"']};t.evaluateKeyboardEvent=function(e,t,r,o){var s={type:0,cancel:!1,key:void 0},a=(e.shiftKey?1:0)|(e.altKey?2:0)|(e.ctrlKey?4:0)|(e.metaKey?8:0);switch(e.keyCode){case 0:"UIKeyInputUpArrow"===e.key?s.key=t?i.C0.ESC+"OA":i.C0.ESC+"[A":"UIKeyInputLeftArrow"===e.key?s.key=t?i.C0.ESC+"OD":i.C0.ESC+"[D":"UIKeyInputRightArrow"===e.key?s.key=t?i.C0.ESC+"OC":i.C0.ESC+"[C":"UIKeyInputDownArrow"===e.key&&(s.key=t?i.C0.ESC+"OB":i.C0.ESC+"[B");break;case 8:if(e.shiftKey){s.key=i.C0.BS;break}if(e.altKey){s.key=i.C0.ESC+i.C0.DEL;break}s.key=i.C0.DEL;break;case 9:if(e.shiftKey){s.key=i.C0.ESC+"[Z";break}s.key=i.C0.HT,s.cancel=!0;break;case 13:s.key=e.altKey?i.C0.ESC+i.C0.CR:i.C0.CR,s.cancel=!0;break;case 27:s.key=i.C0.ESC,e.altKey&&(s.key=i.C0.ESC+i.C0.ESC),s.cancel=!0;break;case 37:if(e.metaKey)break;a?(s.key=i.C0.ESC+"[1;"+(a+1)+"D",s.key===i.C0.ESC+"[1;3D"&&(s.key=i.C0.ESC+(r?"b":"[1;5D"))):s.key=t?i.C0.ESC+"OD":i.C0.ESC+"[D";break;case 39:if(e.metaKey)break;a?(s.key=i.C0.ESC+"[1;"+(a+1)+"C",s.key===i.C0.ESC+"[1;3C"&&(s.key=i.C0.ESC+(r?"f":"[1;5C"))):s.key=t?i.C0.ESC+"OC":i.C0.ESC+"[C";break;case 38:if(e.metaKey)break;a?(s.key=i.C0.ESC+"[1;"+(a+1)+"A",r||s.key!==i.C0.ESC+"[1;3A"||(s.key=i.C0.ESC+"[1;5A")):s.key=t?i.C0.ESC+"OA":i.C0.ESC+"[A";break;case 40:if(e.metaKey)break;a?(s.key=i.C0.ESC+"[1;"+(a+1)+"B",r||s.key!==i.C0.ESC+"[1;3B"||(s.key=i.C0.ESC+"[1;5B")):s.key=t?i.C0.ESC+"OB":i.C0.ESC+"[B";break;case 45:e.shiftKey||e.ctrlKey||(s.key=i.C0.ESC+"[2~");break;case 46:s.key=a?i.C0.ESC+"[3;"+(a+1)+"~":i.C0.ESC+"[3~";break;case 36:s.key=a?i.C0.ESC+"[1;"+(a+1)+"H":t?i.C0.ESC+"OH":i.C0.ESC+"[H";break;case 35:s.key=a?i.C0.ESC+"[1;"+(a+1)+"F":t?i.C0.ESC+"OF":i.C0.ESC+"[F";break;case 33:e.shiftKey?s.type=2:s.key=i.C0.ESC+"[5~";break;case 34:e.shiftKey?s.type=3:s.key=i.C0.ESC+"[6~";break;case 112:s.key=a?i.C0.ESC+"[1;"+(a+1)+"P":i.C0.ESC+"OP";break;case 113:s.key=a?i.C0.ESC+"[1;"+(a+1)+"Q":i.C0.ESC+"OQ";break;case 114:s.key=a?i.C0.ESC+"[1;"+(a+1)+"R":i.C0.ESC+"OR";break;case 115:s.key=a?i.C0.ESC+"[1;"+(a+1)+"S":i.C0.ESC+"OS";break;case 116:s.key=a?i.C0.ESC+"[15;"+(a+1)+"~":i.C0.ESC+"[15~";break;case 117:s.key=a?i.C0.ESC+"[17;"+(a+1)+"~":i.C0.ESC+"[17~";break;case 118:s.key=a?i.C0.ESC+"[18;"+(a+1)+"~":i.C0.ESC+"[18~";break;case 119:s.key=a?i.C0.ESC+"[19;"+(a+1)+"~":i.C0.ESC+"[19~";break;case 120:s.key=a?i.C0.ESC+"[20;"+(a+1)+"~":i.C0.ESC+"[20~";break;case 121:s.key=a?i.C0.ESC+"[21;"+(a+1)+"~":i.C0.ESC+"[21~";break;case 122:s.key=a?i.C0.ESC+"[23;"+(a+1)+"~":i.C0.ESC+"[23~";break;case 123:s.key=a?i.C0.ESC+"[24;"+(a+1)+"~":i.C0.ESC+"[24~";break;default:if(!e.ctrlKey||e.shiftKey||e.altKey||e.metaKey)if(r&&!o||!e.altKey||e.metaKey)!r||e.altKey||e.ctrlKey||e.shiftKey||!e.metaKey?e.key&&!e.ctrlKey&&!e.altKey&&!e.metaKey&&e.keyCode>=48&&1===e.key.length?s.key=e.key:e.key&&e.ctrlKey&&"_"===e.key&&(s.key=i.C0.US):65===e.keyCode&&(s.type=1);else{var c=n[e.keyCode],l=null==c?void 0:c[e.shiftKey?1:0];if(l)s.key=i.C0.ESC+l;else if(e.keyCode>=65&&e.keyCode<=90){var h=e.ctrlKey?e.keyCode-64:e.keyCode+32;s.key=i.C0.ESC+String.fromCharCode(h)}}else e.keyCode>=65&&e.keyCode<=90?s.key=String.fromCharCode(e.keyCode-64):32===e.keyCode?s.key=i.C0.NUL:e.keyCode>=51&&e.keyCode<=55?s.key=String.fromCharCode(e.keyCode-51+27):56===e.keyCode?s.key=i.C0.DEL:219===e.keyCode?s.key=i.C0.ESC:220===e.keyCode?s.key=i.C0.FS:221===e.keyCode&&(s.key=i.C0.GS)}return s}},482:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.Utf8ToUtf32=t.StringToUtf32=t.utf32ToString=t.stringFromCodePoint=void 0,t.stringFromCodePoint=function(e){return e>65535?(e-=65536,String.fromCharCode(55296+(e>>10))+String.fromCharCode(e%1024+56320)):String.fromCharCode(e)},t.utf32ToString=function(e,t,r){void 0===t&&(t=0),void 0===r&&(r=e.length);for(var i="",n=t;n<r;++n){var o=e[n];o>65535?(o-=65536,i+=String.fromCharCode(55296+(o>>10))+String.fromCharCode(o%1024+56320)):i+=String.fromCharCode(o)}return i};var r=function(){function e(){this._interim=0}return e.prototype.clear=function(){this._interim=0},e.prototype.decode=function(e,t){var r=e.length;if(!r)return 0;var i=0,n=0;this._interim&&(56320<=(a=e.charCodeAt(n++))&&a<=57343?t[i++]=1024*(this._interim-55296)+a-56320+65536:(t[i++]=this._interim,t[i++]=a),this._interim=0);for(var o=n;o<r;++o){var s=e.charCodeAt(o);if(55296<=s&&s<=56319){if(++o>=r)return this._interim=s,i;var a;56320<=(a=e.charCodeAt(o))&&a<=57343?t[i++]=1024*(s-55296)+a-56320+65536:(t[i++]=s,t[i++]=a)}else 65279!==s&&(t[i++]=s)}return i},e}();t.StringToUtf32=r;var i=function(){function e(){this.interim=new Uint8Array(3)}return e.prototype.clear=function(){this.interim.fill(0)},e.prototype.decode=function(e,t){var r=e.length;if(!r)return 0;var i,n,o,s,a=0,c=0,l=0;if(this.interim[0]){var h=!1,u=this.interim[0];u&=192==(224&u)?31:224==(240&u)?15:7;for(var f=0,_=void 0;(_=63&this.interim[++f])&&f<4;)u<<=6,u|=_;for(var d=192==(224&this.interim[0])?2:224==(240&this.interim[0])?3:4,p=d-f;l<p;){if(l>=r)return 0;if(128!=(192&(_=e[l++]))){l--,h=!0;break}this.interim[f++]=_,u<<=6,u|=63&_}h||(2===d?u<128?l--:t[a++]=u:3===d?u<2048||u>=55296&&u<=57343||65279===u||(t[a++]=u):u<65536||u>1114111||(t[a++]=u)),this.interim.fill(0)}for(var v=r-4,g=l;g<r;){for(;!(!(g<v)||128&(i=e[g])||128&(n=e[g+1])||128&(o=e[g+2])||128&(s=e[g+3]));)t[a++]=i,t[a++]=n,t[a++]=o,t[a++]=s,g+=4;if((i=e[g++])<128)t[a++]=i;else if(192==(224&i)){if(g>=r)return this.interim[0]=i,a;if(128!=(192&(n=e[g++]))){g--;continue}if((c=(31&i)<<6|63&n)<128){g--;continue}t[a++]=c}else if(224==(240&i)){if(g>=r)return this.interim[0]=i,a;if(128!=(192&(n=e[g++]))){g--;continue}if(g>=r)return this.interim[0]=i,this.interim[1]=n,a;if(128!=(192&(o=e[g++]))){g--;continue}if((c=(15&i)<<12|(63&n)<<6|63&o)<2048||c>=55296&&c<=57343||65279===c)continue;t[a++]=c}else if(240==(248&i)){if(g>=r)return this.interim[0]=i,a;if(128!=(192&(n=e[g++]))){g--;continue}if(g>=r)return this.interim[0]=i,this.interim[1]=n,a;if(128!=(192&(o=e[g++]))){g--;continue}if(g>=r)return this.interim[0]=i,this.interim[1]=n,this.interim[2]=o,a;if(128!=(192&(s=e[g++]))){g--;continue}if((c=(7&i)<<18|(63&n)<<12|(63&o)<<6|63&s)<65536||c>1114111)continue;t[a++]=c}}return a},e}();t.Utf8ToUtf32=i},225:(e,t,r)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.UnicodeV6=void 0;var i,n=r(8273),o=[[768,879],[1155,1158],[1160,1161],[1425,1469],[1471,1471],[1473,1474],[1476,1477],[1479,1479],[1536,1539],[1552,1557],[1611,1630],[1648,1648],[1750,1764],[1767,1768],[1770,1773],[1807,1807],[1809,1809],[1840,1866],[1958,1968],[2027,2035],[2305,2306],[2364,2364],[2369,2376],[2381,2381],[2385,2388],[2402,2403],[2433,2433],[2492,2492],[2497,2500],[2509,2509],[2530,2531],[2561,2562],[2620,2620],[2625,2626],[2631,2632],[2635,2637],[2672,2673],[2689,2690],[2748,2748],[2753,2757],[2759,2760],[2765,2765],[2786,2787],[2817,2817],[2876,2876],[2879,2879],[2881,2883],[2893,2893],[2902,2902],[2946,2946],[3008,3008],[3021,3021],[3134,3136],[3142,3144],[3146,3149],[3157,3158],[3260,3260],[3263,3263],[3270,3270],[3276,3277],[3298,3299],[3393,3395],[3405,3405],[3530,3530],[3538,3540],[3542,3542],[3633,3633],[3636,3642],[3655,3662],[3761,3761],[3764,3769],[3771,3772],[3784,3789],[3864,3865],[3893,3893],[3895,3895],[3897,3897],[3953,3966],[3968,3972],[3974,3975],[3984,3991],[3993,4028],[4038,4038],[4141,4144],[4146,4146],[4150,4151],[4153,4153],[4184,4185],[4448,4607],[4959,4959],[5906,5908],[5938,5940],[5970,5971],[6002,6003],[6068,6069],[6071,6077],[6086,6086],[6089,6099],[6109,6109],[6155,6157],[6313,6313],[6432,6434],[6439,6440],[6450,6450],[6457,6459],[6679,6680],[6912,6915],[6964,6964],[6966,6970],[6972,6972],[6978,6978],[7019,7027],[7616,7626],[7678,7679],[8203,8207],[8234,8238],[8288,8291],[8298,8303],[8400,8431],[12330,12335],[12441,12442],[43014,43014],[43019,43019],[43045,43046],[64286,64286],[65024,65039],[65056,65059],[65279,65279],[65529,65531]],s=[[68097,68099],[68101,68102],[68108,68111],[68152,68154],[68159,68159],[119143,119145],[119155,119170],[119173,119179],[119210,119213],[119362,119364],[917505,917505],[917536,917631],[917760,917999]],a=function(){function e(){if(this.version="6",!i){i=new Uint8Array(65536),(0,n.fill)(i,1),i[0]=0,(0,n.fill)(i,0,1,32),(0,n.fill)(i,0,127,160),(0,n.fill)(i,2,4352,4448),i[9001]=2,i[9002]=2,(0,n.fill)(i,2,11904,42192),i[12351]=1,(0,n.fill)(i,2,44032,55204),(0,n.fill)(i,2,63744,64256),(0,n.fill)(i,2,65040,65050),(0,n.fill)(i,2,65072,65136),(0,n.fill)(i,2,65280,65377),(0,n.fill)(i,2,65504,65511);for(var e=0;e<o.length;++e)(0,n.fill)(i,0,o[e][0],o[e][1]+1)}}return e.prototype.wcwidth=function(e){return e<32?0:e<127?1:e<65536?i[e]:function(e,t){var r,i=0,n=t.length-1;if(e<t[0][0]||e>t[n][1])return!1;for(;n>=i;)if(e>t[r=i+n>>1][1])i=r+1;else{if(!(e<t[r][0]))return!0;n=r-1}return!1}(e,s)?0:e>=131072&&e<=196605||e>=196608&&e<=262141?2:1},e}();t.UnicodeV6=a},5981:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.WriteBuffer=void 0;var r="undefined"==typeof queueMicrotask?function(e){Promise.resolve().then(e)}:queueMicrotask,i=function(){function e(e){this._action=e,this._writeBuffer=[],this._callbacks=[],this._pendingData=0,this._bufferOffset=0,this._isSyncWriting=!1,this._syncCalls=0}return e.prototype.writeSync=function(e,t){if(void 0!==t&&this._syncCalls>t)this._syncCalls=0;else if(this._pendingData+=e.length,this._writeBuffer.push(e),this._callbacks.push(void 0),this._syncCalls++,!this._isSyncWriting){var r;for(this._isSyncWriting=!0;r=this._writeBuffer.shift();){this._action(r);var i=this._callbacks.shift();i&&i()}this._pendingData=0,this._bufferOffset=2147483647,this._isSyncWriting=!1,this._syncCalls=0}},e.prototype.write=function(e,t){var r=this;if(this._pendingData>5e7)throw new Error("write data discarded, use flow control to avoid losing data");this._writeBuffer.length||(this._bufferOffset=0,setTimeout((function(){return r._innerWrite()}))),this._pendingData+=e.length,this._writeBuffer.push(e),this._callbacks.push(t)},e.prototype._innerWrite=function(e,t){var i=this;void 0===e&&(e=0),void 0===t&&(t=!0);for(var n=e||Date.now();this._writeBuffer.length>this._bufferOffset;){var o=this._writeBuffer[this._bufferOffset],s=this._action(o,t);if(s)return void s.catch((function(e){return r((function(){throw e})),Promise.resolve(!1)})).then((function(e){return Date.now()-n>=12?setTimeout((function(){return i._innerWrite(0,e)})):i._innerWrite(n,e)}));var a=this._callbacks[this._bufferOffset];if(a&&a(),this._bufferOffset++,this._pendingData-=o.length,Date.now()-n>=12)break}this._writeBuffer.length>this._bufferOffset?(this._bufferOffset>50&&(this._writeBuffer=this._writeBuffer.slice(this._bufferOffset),this._callbacks=this._callbacks.slice(this._bufferOffset),this._bufferOffset=0),setTimeout((function(){return i._innerWrite()}))):(this._writeBuffer.length=0,this._callbacks.length=0,this._pendingData=0,this._bufferOffset=0)},e}();t.WriteBuffer=i},5941:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.toRgbString=t.parseColor=void 0;var r=/^([\da-f]{1})\/([\da-f]{1})\/([\da-f]{1})$|^([\da-f]{2})\/([\da-f]{2})\/([\da-f]{2})$|^([\da-f]{3})\/([\da-f]{3})\/([\da-f]{3})$|^([\da-f]{4})\/([\da-f]{4})\/([\da-f]{4})$/,i=/^[\da-f]+$/;function n(e,t){var r=e.toString(16),i=r.length<2?"0"+r:r;switch(t){case 4:return r[0];case 8:return i;case 12:return(i+i).slice(0,3);default:return i+i}}t.parseColor=function(e){if(e){var t=e.toLowerCase();if(0===t.indexOf("rgb:")){t=t.slice(4);var n=r.exec(t);if(n){var o=n[1]?15:n[4]?255:n[7]?4095:65535;return[Math.round(parseInt(n[1]||n[4]||n[7]||n[10],16)/o*255),Math.round(parseInt(n[2]||n[5]||n[8]||n[11],16)/o*255),Math.round(parseInt(n[3]||n[6]||n[9]||n[12],16)/o*255)]}}else if(0===t.indexOf("#")&&(t=t.slice(1),i.exec(t)&&[3,6,9,12].includes(t.length))){for(var s=t.length/3,a=[0,0,0],c=0;c<3;++c){var l=parseInt(t.slice(s*c,s*c+s),16);a[c]=1===s?l<<4:2===s?l:3===s?l>>4:l>>8}return a}}},t.toRgbString=function(e,t){void 0===t&&(t=16);var r=e[0],i=e[1],o=e[2];return"rgb:"+n(r,t)+"/"+n(i,t)+"/"+n(o,t)}},5770:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.PAYLOAD_LIMIT=void 0,t.PAYLOAD_LIMIT=1e7},6351:(e,t,r)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.DcsHandler=t.DcsParser=void 0;var i=r(482),n=r(8742),o=r(5770),s=[],a=function(){function e(){this._handlers=Object.create(null),this._active=s,this._ident=0,this._handlerFb=function(){},this._stack={paused:!1,loopPosition:0,fallThrough:!1}}return e.prototype.dispose=function(){this._handlers=Object.create(null),this._handlerFb=function(){},this._active=s},e.prototype.registerHandler=function(e,t){void 0===this._handlers[e]&&(this._handlers[e]=[]);var r=this._handlers[e];return r.push(t),{dispose:function(){var e=r.indexOf(t);-1!==e&&r.splice(e,1)}}},e.prototype.clearHandler=function(e){this._handlers[e]&&delete this._handlers[e]},e.prototype.setHandlerFallback=function(e){this._handlerFb=e},e.prototype.reset=function(){if(this._active.length)for(var e=this._stack.paused?this._stack.loopPosition-1:this._active.length-1;e>=0;--e)this._active[e].unhook(!1);this._stack.paused=!1,this._active=s,this._ident=0},e.prototype.hook=function(e,t){if(this.reset(),this._ident=e,this._active=this._handlers[e]||s,this._active.length)for(var r=this._active.length-1;r>=0;r--)this._active[r].hook(t);else this._handlerFb(this._ident,"HOOK",t)},e.prototype.put=function(e,t,r){if(this._active.length)for(var n=this._active.length-1;n>=0;n--)this._active[n].put(e,t,r);else this._handlerFb(this._ident,"PUT",(0,i.utf32ToString)(e,t,r))},e.prototype.unhook=function(e,t){if(void 0===t&&(t=!0),this._active.length){var r=!1,i=this._active.length-1,n=!1;if(this._stack.paused&&(i=this._stack.loopPosition-1,r=t,n=this._stack.fallThrough,this._stack.paused=!1),!n&&!1===r){for(;i>=0&&!0!==(r=this._active[i].unhook(e));i--)if(r instanceof Promise)return this._stack.paused=!0,this._stack.loopPosition=i,this._stack.fallThrough=!1,r;i--}for(;i>=0;i--)if((r=this._active[i].unhook(!1))instanceof Promise)return this._stack.paused=!0,this._stack.loopPosition=i,this._stack.fallThrough=!0,r}else this._handlerFb(this._ident,"UNHOOK",e);this._active=s,this._ident=0},e}();t.DcsParser=a;var c=new n.Params;c.addParam(0);var l=function(){function e(e){this._handler=e,this._data="",this._params=c,this._hitLimit=!1}return e.prototype.hook=function(e){this._params=e.length>1||e.params[0]?e.clone():c,this._data="",this._hitLimit=!1},e.prototype.put=function(e,t,r){this._hitLimit||(this._data+=(0,i.utf32ToString)(e,t,r),this._data.length>o.PAYLOAD_LIMIT&&(this._data="",this._hitLimit=!0))},e.prototype.unhook=function(e){var t=this,r=!1;if(this._hitLimit)r=!1;else if(e&&(r=this._handler(this._data,this._params))instanceof Promise)return r.then((function(e){return t._params=c,t._data="",t._hitLimit=!1,e}));return this._params=c,this._data="",this._hitLimit=!1,r},e}();t.DcsHandler=l},2015:function(e,t,r){var i,n=this&&this.__extends||(i=function(e,t){return i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])},i(e,t)},function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function r(){this.constructor=e}i(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)});Object.defineProperty(t,"__esModule",{value:!0}),t.EscapeSequenceParser=t.VT500_TRANSITION_TABLE=t.TransitionTable=void 0;var o=r(844),s=r(8273),a=r(8742),c=r(6242),l=r(6351),h=function(){function e(e){this.table=new Uint8Array(e)}return e.prototype.setDefault=function(e,t){(0,s.fill)(this.table,e<<4|t)},e.prototype.add=function(e,t,r,i){this.table[t<<8|e]=r<<4|i},e.prototype.addMany=function(e,t,r,i){for(var n=0;n<e.length;n++)this.table[t<<8|e[n]]=r<<4|i},e}();t.TransitionTable=h;var u=160;t.VT500_TRANSITION_TABLE=function(){var e=new h(4095),t=Array.apply(null,Array(256)).map((function(e,t){return t})),r=function(e,r){return t.slice(e,r)},i=r(32,127),n=r(0,24);n.push(25),n.push.apply(n,r(28,32));var o,s=r(0,14);for(o in e.setDefault(1,0),e.addMany(i,0,2,0),s)e.addMany([24,26,153,154],o,3,0),e.addMany(r(128,144),o,3,0),e.addMany(r(144,152),o,3,0),e.add(156,o,0,0),e.add(27,o,11,1),e.add(157,o,4,8),e.addMany([152,158,159],o,0,7),e.add(155,o,11,3),e.add(144,o,11,9);return e.addMany(n,0,3,0),e.addMany(n,1,3,1),e.add(127,1,0,1),e.addMany(n,8,0,8),e.addMany(n,3,3,3),e.add(127,3,0,3),e.addMany(n,4,3,4),e.add(127,4,0,4),e.addMany(n,6,3,6),e.addMany(n,5,3,5),e.add(127,5,0,5),e.addMany(n,2,3,2),e.add(127,2,0,2),e.add(93,1,4,8),e.addMany(i,8,5,8),e.add(127,8,5,8),e.addMany([156,27,24,26,7],8,6,0),e.addMany(r(28,32),8,0,8),e.addMany([88,94,95],1,0,7),e.addMany(i,7,0,7),e.addMany(n,7,0,7),e.add(156,7,0,0),e.add(127,7,0,7),e.add(91,1,11,3),e.addMany(r(64,127),3,7,0),e.addMany(r(48,60),3,8,4),e.addMany([60,61,62,63],3,9,4),e.addMany(r(48,60),4,8,4),e.addMany(r(64,127),4,7,0),e.addMany([60,61,62,63],4,0,6),e.addMany(r(32,64),6,0,6),e.add(127,6,0,6),e.addMany(r(64,127),6,0,0),e.addMany(r(32,48),3,9,5),e.addMany(r(32,48),5,9,5),e.addMany(r(48,64),5,0,6),e.addMany(r(64,127),5,7,0),e.addMany(r(32,48),4,9,5),e.addMany(r(32,48),1,9,2),e.addMany(r(32,48),2,9,2),e.addMany(r(48,127),2,10,0),e.addMany(r(48,80),1,10,0),e.addMany(r(81,88),1,10,0),e.addMany([89,90,92],1,10,0),e.addMany(r(96,127),1,10,0),e.add(80,1,11,9),e.addMany(n,9,0,9),e.add(127,9,0,9),e.addMany(r(28,32),9,0,9),e.addMany(r(32,48),9,9,12),e.addMany(r(48,60),9,8,10),e.addMany([60,61,62,63],9,9,10),e.addMany(n,11,0,11),e.addMany(r(32,128),11,0,11),e.addMany(r(28,32),11,0,11),e.addMany(n,10,0,10),e.add(127,10,0,10),e.addMany(r(28,32),10,0,10),e.addMany(r(48,60),10,8,10),e.addMany([60,61,62,63],10,0,11),e.addMany(r(32,48),10,9,12),e.addMany(n,12,0,12),e.add(127,12,0,12),e.addMany(r(28,32),12,0,12),e.addMany(r(32,48),12,9,12),e.addMany(r(48,64),12,0,11),e.addMany(r(64,127),12,12,13),e.addMany(r(64,127),10,12,13),e.addMany(r(64,127),9,12,13),e.addMany(n,13,13,13),e.addMany(i,13,13,13),e.add(127,13,0,13),e.addMany([27,156,24,26],13,14,0),e.add(u,0,2,0),e.add(u,8,5,8),e.add(u,6,0,6),e.add(u,11,0,11),e.add(u,13,13,13),e}();var f=function(e){function r(r){void 0===r&&(r=t.VT500_TRANSITION_TABLE);var i=e.call(this)||this;return i._transitions=r,i._parseStack={state:0,handlers:[],handlerPos:0,transition:0,chunkPos:0},i.initialState=0,i.currentState=i.initialState,i._params=new a.Params,i._params.addParam(0),i._collect=0,i.precedingCodepoint=0,i._printHandlerFb=function(e,t,r){},i._executeHandlerFb=function(e){},i._csiHandlerFb=function(e,t){},i._escHandlerFb=function(e){},i._errorHandlerFb=function(e){return e},i._printHandler=i._printHandlerFb,i._executeHandlers=Object.create(null),i._csiHandlers=Object.create(null),i._escHandlers=Object.create(null),i._oscParser=new c.OscParser,i._dcsParser=new l.DcsParser,i._errorHandler=i._errorHandlerFb,i.registerEscHandler({final:"\\"},(function(){return!0})),i}return n(r,e),r.prototype._identifier=function(e,t){void 0===t&&(t=[64,126]);var r=0;if(e.prefix){if(e.prefix.length>1)throw new Error("only one byte as prefix supported");if((r=e.prefix.charCodeAt(0))&&60>r||r>63)throw new Error("prefix must be in range 0x3c .. 0x3f")}if(e.intermediates){if(e.intermediates.length>2)throw new Error("only two bytes as intermediates are supported");for(var i=0;i<e.intermediates.length;++i){var n=e.intermediates.charCodeAt(i);if(32>n||n>47)throw new Error("intermediate must be in range 0x20 .. 0x2f");r<<=8,r|=n}}if(1!==e.final.length)throw new Error("final must be a single byte");var o=e.final.charCodeAt(0);if(t[0]>o||o>t[1])throw new Error("final must be in range "+t[0]+" .. "+t[1]);return(r<<=8)|o},r.prototype.identToString=function(e){for(var t=[];e;)t.push(String.fromCharCode(255&e)),e>>=8;return t.reverse().join("")},r.prototype.dispose=function(){this._csiHandlers=Object.create(null),this._executeHandlers=Object.create(null),this._escHandlers=Object.create(null),this._oscParser.dispose(),this._dcsParser.dispose()},r.prototype.setPrintHandler=function(e){this._printHandler=e},r.prototype.clearPrintHandler=function(){this._printHandler=this._printHandlerFb},r.prototype.registerEscHandler=function(e,t){var r=this._identifier(e,[48,126]);void 0===this._escHandlers[r]&&(this._escHandlers[r]=[]);var i=this._escHandlers[r];return i.push(t),{dispose:function(){var e=i.indexOf(t);-1!==e&&i.splice(e,1)}}},r.prototype.clearEscHandler=function(e){this._escHandlers[this._identifier(e,[48,126])]&&delete this._escHandlers[this._identifier(e,[48,126])]},r.prototype.setEscHandlerFallback=function(e){this._escHandlerFb=e},r.prototype.setExecuteHandler=function(e,t){this._executeHandlers[e.charCodeAt(0)]=t},r.prototype.clearExecuteHandler=function(e){this._executeHandlers[e.charCodeAt(0)]&&delete this._executeHandlers[e.charCodeAt(0)]},r.prototype.setExecuteHandlerFallback=function(e){this._executeHandlerFb=e},r.prototype.registerCsiHandler=function(e,t){var r=this._identifier(e);void 0===this._csiHandlers[r]&&(this._csiHandlers[r]=[]);var i=this._csiHandlers[r];return i.push(t),{dispose:function(){var e=i.indexOf(t);-1!==e&&i.splice(e,1)}}},r.prototype.clearCsiHandler=function(e){this._csiHandlers[this._identifier(e)]&&delete this._csiHandlers[this._identifier(e)]},r.prototype.setCsiHandlerFallback=function(e){this._csiHandlerFb=e},r.prototype.registerDcsHandler=function(e,t){return this._dcsParser.registerHandler(this._identifier(e),t)},r.prototype.clearDcsHandler=function(e){this._dcsParser.clearHandler(this._identifier(e))},r.prototype.setDcsHandlerFallback=function(e){this._dcsParser.setHandlerFallback(e)},r.prototype.registerOscHandler=function(e,t){return this._oscParser.registerHandler(e,t)},r.prototype.clearOscHandler=function(e){this._oscParser.clearHandler(e)},r.prototype.setOscHandlerFallback=function(e){this._oscParser.setHandlerFallback(e)},r.prototype.setErrorHandler=function(e){this._errorHandler=e},r.prototype.clearErrorHandler=function(){this._errorHandler=this._errorHandlerFb},r.prototype.reset=function(){this.currentState=this.initialState,this._oscParser.reset(),this._dcsParser.reset(),this._params.reset(),this._params.addParam(0),this._collect=0,this.precedingCodepoint=0,0!==this._parseStack.state&&(this._parseStack.state=2,this._parseStack.handlers=[])},r.prototype._preserveStack=function(e,t,r,i,n){this._parseStack.state=e,this._parseStack.handlers=t,this._parseStack.handlerPos=r,this._parseStack.transition=i,this._parseStack.chunkPos=n},r.prototype.parse=function(e,t,r){var i,n=0,o=0,s=0;if(this._parseStack.state)if(2===this._parseStack.state)this._parseStack.state=0,s=this._parseStack.chunkPos+1;else{if(void 0===r||1===this._parseStack.state)throw this._parseStack.state=1,new Error("improper continuation due to previous async handler, giving up parsing");var a=this._parseStack.handlers,c=this._parseStack.handlerPos-1;switch(this._parseStack.state){case 3:if(!1===r&&c>-1)for(;c>=0&&!0!==(i=a[c](this._params));c--)if(i instanceof Promise)return this._parseStack.handlerPos=c,i;this._parseStack.handlers=[];break;case 4:if(!1===r&&c>-1)for(;c>=0&&!0!==(i=a[c]());c--)if(i instanceof Promise)return this._parseStack.handlerPos=c,i;this._parseStack.handlers=[];break;case 6:if(n=e[this._parseStack.chunkPos],i=this._dcsParser.unhook(24!==n&&26!==n,r))return i;27===n&&(this._parseStack.transition|=1),this._params.reset(),this._params.addParam(0),this._collect=0;break;case 5:if(n=e[this._parseStack.chunkPos],i=this._oscParser.end(24!==n&&26!==n,r))return i;27===n&&(this._parseStack.transition|=1),this._params.reset(),this._params.addParam(0),this._collect=0}this._parseStack.state=0,s=this._parseStack.chunkPos+1,this.precedingCodepoint=0,this.currentState=15&this._parseStack.transition}for(var l=s;l<t;++l){switch(n=e[l],(o=this._transitions.table[this.currentState<<8|(n<160?n:u)])>>4){case 2:for(var h=l+1;;++h){if(h>=t||(n=e[h])<32||n>126&&n<u){this._printHandler(e,l,h),l=h-1;break}if(++h>=t||(n=e[h])<32||n>126&&n<u){this._printHandler(e,l,h),l=h-1;break}if(++h>=t||(n=e[h])<32||n>126&&n<u){this._printHandler(e,l,h),l=h-1;break}if(++h>=t||(n=e[h])<32||n>126&&n<u){this._printHandler(e,l,h),l=h-1;break}}break;case 3:this._executeHandlers[n]?this._executeHandlers[n]():this._executeHandlerFb(n),this.precedingCodepoint=0;break;case 0:break;case 1:if(this._errorHandler({position:l,code:n,currentState:this.currentState,collect:this._collect,params:this._params,abort:!1}).abort)return;break;case 7:for(var f=(a=this._csiHandlers[this._collect<<8|n])?a.length-1:-1;f>=0&&!0!==(i=a[f](this._params));f--)if(i instanceof Promise)return this._preserveStack(3,a,f,o,l),i;f<0&&this._csiHandlerFb(this._collect<<8|n,this._params),this.precedingCodepoint=0;break;case 8:do{switch(n){case 59:this._params.addParam(0);break;case 58:this._params.addSubParam(-1);break;default:this._params.addDigit(n-48)}}while(++l<t&&(n=e[l])>47&&n<60);l--;break;case 9:this._collect<<=8,this._collect|=n;break;case 10:for(var _=this._escHandlers[this._collect<<8|n],d=_?_.length-1:-1;d>=0&&!0!==(i=_[d]());d--)if(i instanceof Promise)return this._preserveStack(4,_,d,o,l),i;d<0&&this._escHandlerFb(this._collect<<8|n),this.precedingCodepoint=0;break;case 11:this._params.reset(),this._params.addParam(0),this._collect=0;break;case 12:this._dcsParser.hook(this._collect<<8|n,this._params);break;case 13:for(var p=l+1;;++p)if(p>=t||24===(n=e[p])||26===n||27===n||n>127&&n<u){this._dcsParser.put(e,l,p),l=p-1;break}break;case 14:if(i=this._dcsParser.unhook(24!==n&&26!==n))return this._preserveStack(6,[],0,o,l),i;27===n&&(o|=1),this._params.reset(),this._params.addParam(0),this._collect=0,this.precedingCodepoint=0;break;case 4:this._oscParser.start();break;case 5:for(var v=l+1;;v++)if(v>=t||(n=e[v])<32||n>127&&n<u){this._oscParser.put(e,l,v),l=v-1;break}break;case 6:if(i=this._oscParser.end(24!==n&&26!==n))return this._preserveStack(5,[],0,o,l),i;27===n&&(o|=1),this._params.reset(),this._params.addParam(0),this._collect=0,this.precedingCodepoint=0}this.currentState=15&o}},r}(o.Disposable);t.EscapeSequenceParser=f},6242:(e,t,r)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.OscHandler=t.OscParser=void 0;var i=r(5770),n=r(482),o=[],s=function(){function e(){this._state=0,this._active=o,this._id=-1,this._handlers=Object.create(null),this._handlerFb=function(){},this._stack={paused:!1,loopPosition:0,fallThrough:!1}}return e.prototype.registerHandler=function(e,t){void 0===this._handlers[e]&&(this._handlers[e]=[]);var r=this._handlers[e];return r.push(t),{dispose:function(){var e=r.indexOf(t);-1!==e&&r.splice(e,1)}}},e.prototype.clearHandler=function(e){this._handlers[e]&&delete this._handlers[e]},e.prototype.setHandlerFallback=function(e){this._handlerFb=e},e.prototype.dispose=function(){this._handlers=Object.create(null),this._handlerFb=function(){},this._active=o},e.prototype.reset=function(){if(2===this._state)for(var e=this._stack.paused?this._stack.loopPosition-1:this._active.length-1;e>=0;--e)this._active[e].end(!1);this._stack.paused=!1,this._active=o,this._id=-1,this._state=0},e.prototype._start=function(){if(this._active=this._handlers[this._id]||o,this._active.length)for(var e=this._active.length-1;e>=0;e--)this._active[e].start();else this._handlerFb(this._id,"START")},e.prototype._put=function(e,t,r){if(this._active.length)for(var i=this._active.length-1;i>=0;i--)this._active[i].put(e,t,r);else this._handlerFb(this._id,"PUT",(0,n.utf32ToString)(e,t,r))},e.prototype.start=function(){this.reset(),this._state=1},e.prototype.put=function(e,t,r){if(3!==this._state){if(1===this._state)for(;t<r;){var i=e[t++];if(59===i){this._state=2,this._start();break}if(i<48||57<i)return void(this._state=3);-1===this._id&&(this._id=0),this._id=10*this._id+i-48}2===this._state&&r-t>0&&this._put(e,t,r)}},e.prototype.end=function(e,t){if(void 0===t&&(t=!0),0!==this._state){if(3!==this._state)if(1===this._state&&this._start(),this._active.length){var r=!1,i=this._active.length-1,n=!1;if(this._stack.paused&&(i=this._stack.loopPosition-1,r=t,n=this._stack.fallThrough,this._stack.paused=!1),!n&&!1===r){for(;i>=0&&!0!==(r=this._active[i].end(e));i--)if(r instanceof Promise)return this._stack.paused=!0,this._stack.loopPosition=i,this._stack.fallThrough=!1,r;i--}for(;i>=0;i--)if((r=this._active[i].end(!1))instanceof Promise)return this._stack.paused=!0,this._stack.loopPosition=i,this._stack.fallThrough=!0,r}else this._handlerFb(this._id,"END",e);this._active=o,this._id=-1,this._state=0}},e}();t.OscParser=s;var a=function(){function e(e){this._handler=e,this._data="",this._hitLimit=!1}return e.prototype.start=function(){this._data="",this._hitLimit=!1},e.prototype.put=function(e,t,r){this._hitLimit||(this._data+=(0,n.utf32ToString)(e,t,r),this._data.length>i.PAYLOAD_LIMIT&&(this._data="",this._hitLimit=!0))},e.prototype.end=function(e){var t=this,r=!1;if(this._hitLimit)r=!1;else if(e&&(r=this._handler(this._data))instanceof Promise)return r.then((function(e){return t._data="",t._hitLimit=!1,e}));return this._data="",this._hitLimit=!1,r},e}();t.OscHandler=a},8742:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.Params=void 0;var r=2147483647,i=function(){function e(e,t){if(void 0===e&&(e=32),void 0===t&&(t=32),this.maxLength=e,this.maxSubParamsLength=t,t>256)throw new Error("maxSubParamsLength must not be greater than 256");this.params=new Int32Array(e),this.length=0,this._subParams=new Int32Array(t),this._subParamsLength=0,this._subParamsIdx=new Uint16Array(e),this._rejectDigits=!1,this._rejectSubDigits=!1,this._digitIsSub=!1}return e.fromArray=function(t){var r=new e;if(!t.length)return r;for(var i=Array.isArray(t[0])?1:0;i<t.length;++i){var n=t[i];if(Array.isArray(n))for(var o=0;o<n.length;++o)r.addSubParam(n[o]);else r.addParam(n)}return r},e.prototype.clone=function(){var t=new e(this.maxLength,this.maxSubParamsLength);return t.params.set(this.params),t.length=this.length,t._subParams.set(this._subParams),t._subParamsLength=this._subParamsLength,t._subParamsIdx.set(this._subParamsIdx),t._rejectDigits=this._rejectDigits,t._rejectSubDigits=this._rejectSubDigits,t._digitIsSub=this._digitIsSub,t},e.prototype.toArray=function(){for(var e=[],t=0;t<this.length;++t){e.push(this.params[t]);var r=this._subParamsIdx[t]>>8,i=255&this._subParamsIdx[t];i-r>0&&e.push(Array.prototype.slice.call(this._subParams,r,i))}return e},e.prototype.reset=function(){this.length=0,this._subParamsLength=0,this._rejectDigits=!1,this._rejectSubDigits=!1,this._digitIsSub=!1},e.prototype.addParam=function(e){if(this._digitIsSub=!1,this.length>=this.maxLength)this._rejectDigits=!0;else{if(e<-1)throw new Error("values lesser than -1 are not allowed");this._subParamsIdx[this.length]=this._subParamsLength<<8|this._subParamsLength,this.params[this.length++]=e>r?r:e}},e.prototype.addSubParam=function(e){if(this._digitIsSub=!0,this.length)if(this._rejectDigits||this._subParamsLength>=this.maxSubParamsLength)this._rejectSubDigits=!0;else{if(e<-1)throw new Error("values lesser than -1 are not allowed");this._subParams[this._subParamsLength++]=e>r?r:e,this._subParamsIdx[this.length-1]++}},e.prototype.hasSubParams=function(e){return(255&this._subParamsIdx[e])-(this._subParamsIdx[e]>>8)>0},e.prototype.getSubParams=function(e){var t=this._subParamsIdx[e]>>8,r=255&this._subParamsIdx[e];return r-t>0?this._subParams.subarray(t,r):null},e.prototype.getSubParamsAll=function(){for(var e={},t=0;t<this.length;++t){var r=this._subParamsIdx[t]>>8,i=255&this._subParamsIdx[t];i-r>0&&(e[t]=this._subParams.slice(r,i))}return e},e.prototype.addDigit=function(e){var t;if(!(this._rejectDigits||!(t=this._digitIsSub?this._subParamsLength:this.length)||this._digitIsSub&&this._rejectSubDigits)){var i=this._digitIsSub?this._subParams:this.params,n=i[t-1];i[t-1]=~n?Math.min(10*n+e,r):e}},e}();t.Params=i},5741:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.AddonManager=void 0;var r=function(){function e(){this._addons=[]}return e.prototype.dispose=function(){for(var e=this._addons.length-1;e>=0;e--)this._addons[e].instance.dispose()},e.prototype.loadAddon=function(e,t){var r=this,i={instance:t,dispose:t.dispose,isDisposed:!1};this._addons.push(i),t.dispose=function(){return r._wrappedAddonDispose(i)},t.activate(e)},e.prototype._wrappedAddonDispose=function(e){if(!e.isDisposed){for(var t=-1,r=0;r<this._addons.length;r++)if(this._addons[r]===e){t=r;break}if(-1===t)throw new Error("Could not dispose an addon that has not been loaded");e.isDisposed=!0,e.dispose.apply(e.instance),this._addons.splice(t,1)}},e}();t.AddonManager=r},8771:(e,t,r)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.BufferApiView=void 0;var i=r(3785),n=r(511),o=function(){function e(e,t){this._buffer=e,this.type=t}return e.prototype.init=function(e){return this._buffer=e,this},Object.defineProperty(e.prototype,"cursorY",{get:function(){return this._buffer.y},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"cursorX",{get:function(){return this._buffer.x},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"viewportY",{get:function(){return this._buffer.ydisp},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"baseY",{get:function(){return this._buffer.ybase},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"length",{get:function(){return this._buffer.lines.length},enumerable:!1,configurable:!0}),e.prototype.getLine=function(e){var t=this._buffer.lines.get(e);if(t)return new i.BufferLineApiView(t)},e.prototype.getNullCell=function(){return new n.CellData},e}();t.BufferApiView=o},3785:(e,t,r)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.BufferLineApiView=void 0;var i=r(511),n=function(){function e(e){this._line=e}return Object.defineProperty(e.prototype,"isWrapped",{get:function(){return this._line.isWrapped},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"length",{get:function(){return this._line.length},enumerable:!1,configurable:!0}),e.prototype.getCell=function(e,t){if(!(e<0||e>=this._line.length))return t?(this._line.loadCell(e,t),t):this._line.loadCell(e,new i.CellData)},e.prototype.translateToString=function(e,t,r){return this._line.translateToString(e,t,r)},e}();t.BufferLineApiView=n},8285:(e,t,r)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.BufferNamespaceApi=void 0;var i=r(8771),n=r(8460),o=function(){function e(e){var t=this;this._core=e,this._onBufferChange=new n.EventEmitter,this._normal=new i.BufferApiView(this._core.buffers.normal,"normal"),this._alternate=new i.BufferApiView(this._core.buffers.alt,"alternate"),this._core.buffers.onBufferActivate((function(){return t._onBufferChange.fire(t.active)}))}return Object.defineProperty(e.prototype,"onBufferChange",{get:function(){return this._onBufferChange.event},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"active",{get:function(){if(this._core.buffers.active===this._core.buffers.normal)return this.normal;if(this._core.buffers.active===this._core.buffers.alt)return this.alternate;throw new Error("Active buffer is neither normal nor alternate")},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"normal",{get:function(){return this._normal.init(this._core.buffers.normal)},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"alternate",{get:function(){return this._alternate.init(this._core.buffers.alt)},enumerable:!1,configurable:!0}),e}();t.BufferNamespaceApi=o},7975:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ParserApi=void 0;var r=function(){function e(e){this._core=e}return e.prototype.registerCsiHandler=function(e,t){return this._core.registerCsiHandler(e,(function(e){return t(e.toArray())}))},e.prototype.addCsiHandler=function(e,t){return this.registerCsiHandler(e,t)},e.prototype.registerDcsHandler=function(e,t){return this._core.registerDcsHandler(e,(function(e,r){return t(e,r.toArray())}))},e.prototype.addDcsHandler=function(e,t){return this.registerDcsHandler(e,t)},e.prototype.registerEscHandler=function(e,t){return this._core.registerEscHandler(e,t)},e.prototype.addEscHandler=function(e,t){return this.registerEscHandler(e,t)},e.prototype.registerOscHandler=function(e,t){return this._core.registerOscHandler(e,t)},e.prototype.addOscHandler=function(e,t){return this.registerOscHandler(e,t)},e}();t.ParserApi=r},7090:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.UnicodeApi=void 0;var r=function(){function e(e){this._core=e}return e.prototype.register=function(e){this._core.unicodeService.register(e)},Object.defineProperty(e.prototype,"versions",{get:function(){return this._core.unicodeService.versions},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"activeVersion",{get:function(){return this._core.unicodeService.activeVersion},set:function(e){this._core.unicodeService.activeVersion=e},enumerable:!1,configurable:!0}),e}();t.UnicodeApi=r},744:function(e,t,r){var i,n=this&&this.__extends||(i=function(e,t){return i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])},i(e,t)},function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function r(){this.constructor=e}i(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)}),o=this&&this.__decorate||function(e,t,r,i){var n,o=arguments.length,s=o<3?t:null===i?i=Object.getOwnPropertyDescriptor(t,r):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)s=Reflect.decorate(e,t,r,i);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(s=(o<3?n(s):o>3?n(t,r,s):n(t,r))||s);return o>3&&s&&Object.defineProperty(t,r,s),s},s=this&&this.__param||function(e,t){return function(r,i){t(r,i,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.BufferService=t.MINIMUM_ROWS=t.MINIMUM_COLS=void 0;var a=r(2585),c=r(5295),l=r(8460),h=r(844);t.MINIMUM_COLS=2,t.MINIMUM_ROWS=1;var u=function(e){function r(r){var i=e.call(this)||this;return i._optionsService=r,i.isUserScrolling=!1,i._onResize=new l.EventEmitter,i._onScroll=new l.EventEmitter,i.cols=Math.max(r.options.cols||0,t.MINIMUM_COLS),i.rows=Math.max(r.options.rows||0,t.MINIMUM_ROWS),i.buffers=new c.BufferSet(r,i),i}return n(r,e),Object.defineProperty(r.prototype,"onResize",{get:function(){return this._onResize.event},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"onScroll",{get:function(){return this._onScroll.event},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"buffer",{get:function(){return this.buffers.active},enumerable:!1,configurable:!0}),r.prototype.dispose=function(){e.prototype.dispose.call(this),this.buffers.dispose()},r.prototype.resize=function(e,t){this.cols=e,this.rows=t,this.buffers.resize(e,t),this.buffers.setupTabStops(this.cols),this._onResize.fire({cols:e,rows:t})},r.prototype.reset=function(){this.buffers.reset(),this.isUserScrolling=!1},r.prototype.scroll=function(e,t){void 0===t&&(t=!1);var r,i=this.buffer;(r=this._cachedBlankLine)&&r.length===this.cols&&r.getFg(0)===e.fg&&r.getBg(0)===e.bg||(r=i.getBlankLine(e,t),this._cachedBlankLine=r),r.isWrapped=t;var n=i.ybase+i.scrollTop,o=i.ybase+i.scrollBottom;if(0===i.scrollTop){var s=i.lines.isFull;o===i.lines.length-1?s?i.lines.recycle().copyFrom(r):i.lines.push(r.clone()):i.lines.splice(o+1,0,r.clone()),s?this.isUserScrolling&&(i.ydisp=Math.max(i.ydisp-1,0)):(i.ybase++,this.isUserScrolling||i.ydisp++)}else{var a=o-n+1;i.lines.shiftElements(n+1,a-1,-1),i.lines.set(o,r.clone())}this.isUserScrolling||(i.ydisp=i.ybase),this._onScroll.fire(i.ydisp)},r.prototype.scrollLines=function(e,t,r){var i=this.buffer;if(e<0){if(0===i.ydisp)return;this.isUserScrolling=!0}else e+i.ydisp>=i.ybase&&(this.isUserScrolling=!1);var n=i.ydisp;i.ydisp=Math.max(Math.min(i.ydisp+e,i.ybase),0),n!==i.ydisp&&(t||this._onScroll.fire(i.ydisp))},r.prototype.scrollPages=function(e){this.scrollLines(e*(this.rows-1))},r.prototype.scrollToTop=function(){this.scrollLines(-this.buffer.ydisp)},r.prototype.scrollToBottom=function(){this.scrollLines(this.buffer.ybase-this.buffer.ydisp)},r.prototype.scrollToLine=function(e){var t=e-this.buffer.ydisp;0!==t&&this.scrollLines(t)},o([s(0,a.IOptionsService)],r)}(h.Disposable);t.BufferService=u},7994:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.CharsetService=void 0;var r=function(){function e(){this.glevel=0,this._charsets=[]}return e.prototype.reset=function(){this.charset=void 0,this._charsets=[],this.glevel=0},e.prototype.setgLevel=function(e){this.glevel=e,this.charset=this._charsets[e]},e.prototype.setgCharset=function(e,t){this._charsets[e]=t,this.glevel===e&&(this.charset=t)},e}();t.CharsetService=r},1753:function(e,t,r){var i=this&&this.__decorate||function(e,t,r,i){var n,o=arguments.length,s=o<3?t:null===i?i=Object.getOwnPropertyDescriptor(t,r):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)s=Reflect.decorate(e,t,r,i);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(s=(o<3?n(s):o>3?n(t,r,s):n(t,r))||s);return o>3&&s&&Object.defineProperty(t,r,s),s},n=this&&this.__param||function(e,t){return function(r,i){t(r,i,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.CoreMouseService=void 0;var o=r(2585),s=r(8460),a={NONE:{events:0,restrict:function(){return!1}},X10:{events:1,restrict:function(e){return 4!==e.button&&1===e.action&&(e.ctrl=!1,e.alt=!1,e.shift=!1,!0)}},VT200:{events:19,restrict:function(e){return 32!==e.action}},DRAG:{events:23,restrict:function(e){return 32!==e.action||3!==e.button}},ANY:{events:31,restrict:function(e){return!0}}};function c(e,t){var r=(e.ctrl?16:0)|(e.shift?4:0)|(e.alt?8:0);return 4===e.button?(r|=64,r|=e.action):(r|=3&e.button,4&e.button&&(r|=64),8&e.button&&(r|=128),32===e.action?r|=32:0!==e.action||t||(r|=3)),r}var l=String.fromCharCode,h={DEFAULT:function(e){var t=[c(e,!1)+32,e.col+32,e.row+32];return t[0]>255||t[1]>255||t[2]>255?"":"[M"+l(t[0])+l(t[1])+l(t[2])},SGR:function(e){var t=0===e.action&&4!==e.button?"m":"M";return"[<"+c(e,!0)+";"+e.col+";"+e.row+t}},u=function(){function e(e,t){this._bufferService=e,this._coreService=t,this._protocols={},this._encodings={},this._activeProtocol="",this._activeEncoding="",this._onProtocolChange=new s.EventEmitter,this._lastEvent=null;for(var r=0,i=Object.keys(a);r<i.length;r++){var n=i[r];this.addProtocol(n,a[n])}for(var o=0,c=Object.keys(h);o<c.length;o++){var l=c[o];this.addEncoding(l,h[l])}this.reset()}return e.prototype.addProtocol=function(e,t){this._protocols[e]=t},e.prototype.addEncoding=function(e,t){this._encodings[e]=t},Object.defineProperty(e.prototype,"activeProtocol",{get:function(){return this._activeProtocol},set:function(e){if(!this._protocols[e])throw new Error('unknown protocol "'+e+'"');this._activeProtocol=e,this._onProtocolChange.fire(this._protocols[e].events)},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"areMouseEventsActive",{get:function(){return 0!==this._protocols[this._activeProtocol].events},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"activeEncoding",{get:function(){return this._activeEncoding},set:function(e){if(!this._encodings[e])throw new Error('unknown encoding "'+e+'"');this._activeEncoding=e},enumerable:!1,configurable:!0}),e.prototype.reset=function(){this.activeProtocol="NONE",this.activeEncoding="DEFAULT",this._lastEvent=null},Object.defineProperty(e.prototype,"onProtocolChange",{get:function(){return this._onProtocolChange.event},enumerable:!1,configurable:!0}),e.prototype.triggerMouseEvent=function(e){if(e.col<0||e.col>=this._bufferService.cols||e.row<0||e.row>=this._bufferService.rows)return!1;if(4===e.button&&32===e.action)return!1;if(3===e.button&&32!==e.action)return!1;if(4!==e.button&&(2===e.action||3===e.action))return!1;if(e.col++,e.row++,32===e.action&&this._lastEvent&&this._compareEvents(this._lastEvent,e))return!1;if(!this._protocols[this._activeProtocol].restrict(e))return!1;var t=this._encodings[this._activeEncoding](e);return t&&("DEFAULT"===this._activeEncoding?this._coreService.triggerBinaryEvent(t):this._coreService.triggerDataEvent(t,!0)),this._lastEvent=e,!0},e.prototype.explainEvents=function(e){return{down:!!(1&e),up:!!(2&e),drag:!!(4&e),move:!!(8&e),wheel:!!(16&e)}},e.prototype._compareEvents=function(e,t){return e.col===t.col&&e.row===t.row&&e.button===t.button&&e.action===t.action&&e.ctrl===t.ctrl&&e.alt===t.alt&&e.shift===t.shift},i([n(0,o.IBufferService),n(1,o.ICoreService)],e)}();t.CoreMouseService=u},6975:function(e,t,r){var i,n=this&&this.__extends||(i=function(e,t){return i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])},i(e,t)},function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function r(){this.constructor=e}i(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)}),o=this&&this.__decorate||function(e,t,r,i){var n,o=arguments.length,s=o<3?t:null===i?i=Object.getOwnPropertyDescriptor(t,r):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)s=Reflect.decorate(e,t,r,i);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(s=(o<3?n(s):o>3?n(t,r,s):n(t,r))||s);return o>3&&s&&Object.defineProperty(t,r,s),s},s=this&&this.__param||function(e,t){return function(r,i){t(r,i,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.CoreService=void 0;var a=r(2585),c=r(8460),l=r(1439),h=r(844),u=Object.freeze({insertMode:!1}),f=Object.freeze({applicationCursorKeys:!1,applicationKeypad:!1,bracketedPasteMode:!1,origin:!1,reverseWraparound:!1,sendFocus:!1,wraparound:!0}),_=function(e){function t(t,r,i,n){var o=e.call(this)||this;return o._bufferService=r,o._logService=i,o._optionsService=n,o.isCursorInitialized=!1,o.isCursorHidden=!1,o._onData=o.register(new c.EventEmitter),o._onUserInput=o.register(new c.EventEmitter),o._onBinary=o.register(new c.EventEmitter),o._scrollToBottom=t,o.register({dispose:function(){return o._scrollToBottom=void 0}}),o.modes=(0,l.clone)(u),o.decPrivateModes=(0,l.clone)(f),o}return n(t,e),Object.defineProperty(t.prototype,"onData",{get:function(){return this._onData.event},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"onUserInput",{get:function(){return this._onUserInput.event},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"onBinary",{get:function(){return this._onBinary.event},enumerable:!1,configurable:!0}),t.prototype.reset=function(){this.modes=(0,l.clone)(u),this.decPrivateModes=(0,l.clone)(f)},t.prototype.triggerDataEvent=function(e,t){if(void 0===t&&(t=!1),!this._optionsService.options.disableStdin){var r=this._bufferService.buffer;r.ybase!==r.ydisp&&this._scrollToBottom(),t&&this._onUserInput.fire(),this._logService.debug('sending data "'+e+'"',(function(){return e.split("").map((function(e){return e.charCodeAt(0)}))})),this._onData.fire(e)}},t.prototype.triggerBinaryEvent=function(e){this._optionsService.options.disableStdin||(this._logService.debug('sending binary "'+e+'"',(function(){return e.split("").map((function(e){return e.charCodeAt(0)}))})),this._onBinary.fire(e))},o([s(1,a.IBufferService),s(2,a.ILogService),s(3,a.IOptionsService)],t)}(h.Disposable);t.CoreService=_},3730:function(e,t,r){var i=this&&this.__decorate||function(e,t,r,i){var n,o=arguments.length,s=o<3?t:null===i?i=Object.getOwnPropertyDescriptor(t,r):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)s=Reflect.decorate(e,t,r,i);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(s=(o<3?n(s):o>3?n(t,r,s):n(t,r))||s);return o>3&&s&&Object.defineProperty(t,r,s),s},n=this&&this.__param||function(e,t){return function(r,i){t(r,i,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.DirtyRowService=void 0;var o=r(2585),s=function(){function e(e){this._bufferService=e,this.clearRange()}return Object.defineProperty(e.prototype,"start",{get:function(){return this._start},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"end",{get:function(){return this._end},enumerable:!1,configurable:!0}),e.prototype.clearRange=function(){this._start=this._bufferService.buffer.y,this._end=this._bufferService.buffer.y},e.prototype.markDirty=function(e){e<this._start?this._start=e:e>this._end&&(this._end=e)},e.prototype.markRangeDirty=function(e,t){if(e>t){var r=e;e=t,t=r}e<this._start&&(this._start=e),t>this._end&&(this._end=t)},e.prototype.markAllDirty=function(){this.markRangeDirty(0,this._bufferService.rows-1)},i([n(0,o.IBufferService)],e)}();t.DirtyRowService=s},4348:function(e,t,r){var i=this&&this.__spreadArray||function(e,t,r){if(r||2===arguments.length)for(var i,n=0,o=t.length;n<o;n++)!i&&n in t||(i||(i=Array.prototype.slice.call(t,0,n)),i[n]=t[n]);return e.concat(i||Array.prototype.slice.call(t))};Object.defineProperty(t,"__esModule",{value:!0}),t.InstantiationService=t.ServiceCollection=void 0;var n=r(2585),o=r(8343),s=function(){function e(){for(var e=[],t=0;t<arguments.length;t++)e[t]=arguments[t];this._entries=new Map;for(var r=0,i=e;r<i.length;r++){var n=i[r],o=n[0],s=n[1];this.set(o,s)}}return e.prototype.set=function(e,t){var r=this._entries.get(e);return this._entries.set(e,t),r},e.prototype.forEach=function(e){this._entries.forEach((function(t,r){return e(r,t)}))},e.prototype.has=function(e){return this._entries.has(e)},e.prototype.get=function(e){return this._entries.get(e)},e}();t.ServiceCollection=s;var a=function(){function e(){this._services=new s,this._services.set(n.IInstantiationService,this)}return e.prototype.setService=function(e,t){this._services.set(e,t)},e.prototype.getService=function(e){return this._services.get(e)},e.prototype.createInstance=function(e){for(var t=[],r=1;r<arguments.length;r++)t[r-1]=arguments[r];for(var n=(0,o.getServiceDependencies)(e).sort((function(e,t){return e.index-t.index})),s=[],a=0,c=n;a<c.length;a++){var l=c[a],h=this._services.get(l.id);if(!h)throw new Error("[createInstance] "+e.name+" depends on UNKNOWN service "+l.id+".");s.push(h)}var u=n.length>0?n[0].index:t.length;if(t.length!==u)throw new Error("[createInstance] First service dependency of "+e.name+" at position "+(u+1)+" conflicts with "+t.length+" static arguments");return new(e.bind.apply(e,i([void 0],i(i([],t,!0),s,!0),!1)))},e}();t.InstantiationService=a},7866:function(e,t,r){var i=this&&this.__decorate||function(e,t,r,i){var n,o=arguments.length,s=o<3?t:null===i?i=Object.getOwnPropertyDescriptor(t,r):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)s=Reflect.decorate(e,t,r,i);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(s=(o<3?n(s):o>3?n(t,r,s):n(t,r))||s);return o>3&&s&&Object.defineProperty(t,r,s),s},n=this&&this.__param||function(e,t){return function(r,i){t(r,i,e)}},o=this&&this.__spreadArray||function(e,t,r){if(r||2===arguments.length)for(var i,n=0,o=t.length;n<o;n++)!i&&n in t||(i||(i=Array.prototype.slice.call(t,0,n)),i[n]=t[n]);return e.concat(i||Array.prototype.slice.call(t))};Object.defineProperty(t,"__esModule",{value:!0}),t.LogService=void 0;var s=r(2585),a={debug:s.LogLevelEnum.DEBUG,info:s.LogLevelEnum.INFO,warn:s.LogLevelEnum.WARN,error:s.LogLevelEnum.ERROR,off:s.LogLevelEnum.OFF},c=function(){function e(e){var t=this;this._optionsService=e,this.logLevel=s.LogLevelEnum.OFF,this._updateLogLevel(),this._optionsService.onOptionChange((function(e){"logLevel"===e&&t._updateLogLevel()}))}return e.prototype._updateLogLevel=function(){this.logLevel=a[this._optionsService.options.logLevel]},e.prototype._evalLazyOptionalParams=function(e){for(var t=0;t<e.length;t++)"function"==typeof e[t]&&(e[t]=e[t]())},e.prototype._log=function(e,t,r){this._evalLazyOptionalParams(r),e.call.apply(e,o([console,"xterm.js: "+t],r,!1))},e.prototype.debug=function(e){for(var t=[],r=1;r<arguments.length;r++)t[r-1]=arguments[r];this.logLevel<=s.LogLevelEnum.DEBUG&&this._log(console.log,e,t)},e.prototype.info=function(e){for(var t=[],r=1;r<arguments.length;r++)t[r-1]=arguments[r];this.logLevel<=s.LogLevelEnum.INFO&&this._log(console.info,e,t)},e.prototype.warn=function(e){for(var t=[],r=1;r<arguments.length;r++)t[r-1]=arguments[r];this.logLevel<=s.LogLevelEnum.WARN&&this._log(console.warn,e,t)},e.prototype.error=function(e){for(var t=[],r=1;r<arguments.length;r++)t[r-1]=arguments[r];this.logLevel<=s.LogLevelEnum.ERROR&&this._log(console.error,e,t)},i([n(0,s.IOptionsService)],e)}();t.LogService=c},7302:function(e,t,r){var i=this&&this.__assign||function(){return i=Object.assign||function(e){for(var t,r=1,i=arguments.length;r<i;r++)for(var n in t=arguments[r])Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n]);return e},i.apply(this,arguments)};Object.defineProperty(t,"__esModule",{value:!0}),t.OptionsService=t.DEFAULT_OPTIONS=t.DEFAULT_BELL_SOUND=void 0;var n=r(8460),o=r(6114);t.DEFAULT_BELL_SOUND="data:audio/mp3;base64,SUQzBAAAAAAAI1RTU0UAAAAPAAADTGF2ZjU4LjMyLjEwNAAAAAAAAAAAAAAA//tQxAADB8AhSmxhIIEVCSiJrDCQBTcu3UrAIwUdkRgQbFAZC1CQEwTJ9mjRvBA4UOLD8nKVOWfh+UlK3z/177OXrfOdKl7pyn3Xf//WreyTRUoAWgBgkOAGbZHBgG1OF6zM82DWbZaUmMBptgQhGjsyYqc9ae9XFz280948NMBWInljyzsNRFLPWdnZGWrddDsjK1unuSrVN9jJsK8KuQtQCtMBjCEtImISdNKJOopIpBFpNSMbIHCSRpRR5iakjTiyzLhchUUBwCgyKiweBv/7UsQbg8isVNoMPMjAAAA0gAAABEVFGmgqK////9bP/6XCykxBTUUzLjEwMKqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",t.DEFAULT_OPTIONS={cols:80,rows:24,cursorBlink:!1,cursorStyle:"block",cursorWidth:1,customGlyphs:!0,bellSound:t.DEFAULT_BELL_SOUND,bellStyle:"none",drawBoldTextInBrightColors:!0,fastScrollModifier:"alt",fastScrollSensitivity:5,fontFamily:"courier-new, courier, monospace",fontSize:15,fontWeight:"normal",fontWeightBold:"bold",lineHeight:1,linkTooltipHoverDuration:500,letterSpacing:0,logLevel:"info",scrollback:1e3,scrollSensitivity:1,screenReaderMode:!1,macOptionIsMeta:!1,macOptionClickForcesSelection:!1,minimumContrastRatio:1,disableStdin:!1,allowProposedApi:!0,allowTransparency:!1,tabStopWidth:8,theme:{},rightClickSelectsWord:o.isMac,rendererType:"canvas",windowOptions:{},windowsMode:!1,wordSeparator:" ()[]{}',\"`",altClickMovesCursor:!0,convertEol:!1,termName:"xterm",cancelEvents:!1};var s=["normal","bold","100","200","300","400","500","600","700","800","900"],a=function(){function e(e){for(var r in this._onOptionChange=new n.EventEmitter,this._options=i({},t.DEFAULT_OPTIONS),e)if(r in this._options)try{var o=e[r];this._options[r]=this._sanitizeAndValidateOption(r,o)}catch(e){console.error(e)}this.options=this._setupOptions(this._options)}return Object.defineProperty(e.prototype,"onOptionChange",{get:function(){return this._onOptionChange.event},enumerable:!1,configurable:!0}),e.prototype._setupOptions=function(e){var r=this,n=i({},e),o=function(e){Object.defineProperty(n,e,{get:function(){if(!(e in t.DEFAULT_OPTIONS))throw new Error('No option with key "'+e+'"');return r._options[e]},set:function(i){if(!(e in t.DEFAULT_OPTIONS))throw new Error('No option with key "'+e+'"');i=r._sanitizeAndValidateOption(e,i),r._options[e]!==i&&(r._options[e]=i,r._onOptionChange.fire(e))}})};for(var s in n)o(s);return n},e.prototype.setOption=function(e,t){this.options[e]=t},e.prototype._sanitizeAndValidateOption=function(e,r){switch(e){case"bellStyle":case"cursorStyle":case"rendererType":case"wordSeparator":r||(r=t.DEFAULT_OPTIONS[e]);break;case"fontWeight":case"fontWeightBold":if("number"==typeof r&&1<=r&&r<=1e3)break;r=s.includes(r)?r:t.DEFAULT_OPTIONS[e];break;case"cursorWidth":r=Math.floor(r);case"lineHeight":case"tabStopWidth":if(r<1)throw new Error(e+" cannot be less than 1, value: "+r);break;case"minimumContrastRatio":r=Math.max(1,Math.min(21,Math.round(10*r)/10));break;case"scrollback":if((r=Math.min(r,4294967295))<0)throw new Error(e+" cannot be less than 0, value: "+r);break;case"fastScrollSensitivity":case"scrollSensitivity":if(r<=0)throw new Error(e+" cannot be less than or equal to 0, value: "+r);case"rows":case"cols":if(!r&&0!==r)throw new Error(e+" must be numeric, value: "+r)}return r},e.prototype.getOption=function(e){return this.options[e]},e}();t.OptionsService=a},8343:(e,t)=>{function r(e,t,r){t.di$target===t?t.di$dependencies.push({id:e,index:r}):(t.di$dependencies=[{id:e,index:r}],t.di$target=t)}Object.defineProperty(t,"__esModule",{value:!0}),t.createDecorator=t.getServiceDependencies=t.serviceRegistry=void 0,t.serviceRegistry=new Map,t.getServiceDependencies=function(e){return e.di$dependencies||[]},t.createDecorator=function(e){if(t.serviceRegistry.has(e))return t.serviceRegistry.get(e);var i=function(e,t,n){if(3!==arguments.length)throw new Error("@IServiceName-decorator can only be used to decorate a parameter");r(i,e,n)};return i.toString=function(){return e},t.serviceRegistry.set(e,i),i}},2585:(e,t,r)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.IUnicodeService=t.IOptionsService=t.ILogService=t.LogLevelEnum=t.IInstantiationService=t.IDirtyRowService=t.ICharsetService=t.ICoreService=t.ICoreMouseService=t.IBufferService=void 0;var i,n=r(8343);t.IBufferService=(0,n.createDecorator)("BufferService"),t.ICoreMouseService=(0,n.createDecorator)("CoreMouseService"),t.ICoreService=(0,n.createDecorator)("CoreService"),t.ICharsetService=(0,n.createDecorator)("CharsetService"),t.IDirtyRowService=(0,n.createDecorator)("DirtyRowService"),t.IInstantiationService=(0,n.createDecorator)("InstantiationService"),(i=t.LogLevelEnum||(t.LogLevelEnum={}))[i.DEBUG=0]="DEBUG",i[i.INFO=1]="INFO",i[i.WARN=2]="WARN",i[i.ERROR=3]="ERROR",i[i.OFF=4]="OFF",t.ILogService=(0,n.createDecorator)("LogService"),t.IOptionsService=(0,n.createDecorator)("OptionsService"),t.IUnicodeService=(0,n.createDecorator)("UnicodeService")},1480:(e,t,r)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.UnicodeService=void 0;var i=r(8460),n=r(225),o=function(){function e(){this._providers=Object.create(null),this._active="",this._onChange=new i.EventEmitter;var e=new n.UnicodeV6;this.register(e),this._active=e.version,this._activeProvider=e}return Object.defineProperty(e.prototype,"onChange",{get:function(){return this._onChange.event},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"versions",{get:function(){return Object.keys(this._providers)},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"activeVersion",{get:function(){return this._active},set:function(e){if(!this._providers[e])throw new Error('unknown Unicode version "'+e+'"');this._active=e,this._activeProvider=this._providers[e],this._onChange.fire(e)},enumerable:!1,configurable:!0}),e.prototype.register=function(e){this._providers[e.version]=e},e.prototype.wcwidth=function(e){return this._activeProvider.wcwidth(e)},e.prototype.getStringCellWidth=function(e){for(var t=0,r=e.length,i=0;i<r;++i){var n=e.charCodeAt(i);if(55296<=n&&n<=56319){if(++i>=r)return t+this.wcwidth(n);var o=e.charCodeAt(i);56320<=o&&o<=57343?n=1024*(n-55296)+o-56320+65536:t+=this.wcwidth(o)}t+=this.wcwidth(n)}return t},e}();t.UnicodeService=o}},t={};function r(i){var n=t[i];if(void 0!==n)return n.exports;var o=t[i]={exports:{}};return e[i].call(o.exports,o,o.exports,r),o.exports}var i={};return(()=>{var e=i;Object.defineProperty(e,"__esModule",{value:!0}),e.Terminal=void 0;var t=r(3236),n=r(9042),o=r(7975),s=r(7090),a=r(5741),c=r(8285),l=["cols","rows"],h=function(){function e(e){var r=this;this._core=new t.Terminal(e),this._addonManager=new a.AddonManager,this._publicOptions={};var i=function(e){Object.defineProperty(n._publicOptions,e,{get:function(){return r._core.options[e]},set:function(t){r._checkReadonlyOptions(e),r._core.options[e]=t}})},n=this;for(var o in this._core.options)i(o)}return e.prototype._checkReadonlyOptions=function(e){if(l.includes(e))throw new Error('Option "'+e+'" can only be set in the constructor')},e.prototype._checkProposedApi=function(){if(!this._core.optionsService.options.allowProposedApi)throw new Error("You must set the allowProposedApi option to true to use proposed API")},Object.defineProperty(e.prototype,"onBell",{get:function(){return this._core.onBell},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"onBinary",{get:function(){return this._core.onBinary},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"onCursorMove",{get:function(){return this._core.onCursorMove},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"onData",{get:function(){return this._core.onData},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"onKey",{get:function(){return this._core.onKey},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"onLineFeed",{get:function(){return this._core.onLineFeed},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"onRender",{get:function(){return this._core.onRender},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"onResize",{get:function(){return this._core.onResize},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"onScroll",{get:function(){return this._core.onScroll},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"onSelectionChange",{get:function(){return this._core.onSelectionChange},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"onTitleChange",{get:function(){return this._core.onTitleChange},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"element",{get:function(){return this._core.element},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"parser",{get:function(){return this._checkProposedApi(),this._parser||(this._parser=new o.ParserApi(this._core)),this._parser},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"unicode",{get:function(){return this._checkProposedApi(),new s.UnicodeApi(this._core)},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"textarea",{get:function(){return this._core.textarea},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"rows",{get:function(){return this._core.rows},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"cols",{get:function(){return this._core.cols},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"buffer",{get:function(){return this._checkProposedApi(),this._buffer||(this._buffer=new c.BufferNamespaceApi(this._core)),this._buffer},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"markers",{get:function(){return this._checkProposedApi(),this._core.markers},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"modes",{get:function(){var e=this._core.coreService.decPrivateModes,t="none";switch(this._core.coreMouseService.activeProtocol){case"X10":t="x10";break;case"VT200":t="vt200";break;case"DRAG":t="drag";break;case"ANY":t="any"}return{applicationCursorKeysMode:e.applicationCursorKeys,applicationKeypadMode:e.applicationKeypad,bracketedPasteMode:e.bracketedPasteMode,insertMode:this._core.coreService.modes.insertMode,mouseTrackingMode:t,originMode:e.origin,reverseWraparoundMode:e.reverseWraparound,sendFocusMode:e.sendFocus,wraparoundMode:e.wraparound}},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"options",{get:function(){return this._publicOptions},set:function(e){for(var t in e)this._publicOptions[t]=e[t]},enumerable:!1,configurable:!0}),e.prototype.blur=function(){this._core.blur()},e.prototype.focus=function(){this._core.focus()},e.prototype.resize=function(e,t){this._verifyIntegers(e,t),this._core.resize(e,t)},e.prototype.open=function(e){this._core.open(e)},e.prototype.attachCustomKeyEventHandler=function(e){this._core.attachCustomKeyEventHandler(e)},e.prototype.registerLinkMatcher=function(e,t,r){return this._checkProposedApi(),this._core.registerLinkMatcher(e,t,r)},e.prototype.deregisterLinkMatcher=function(e){this._checkProposedApi(),this._core.deregisterLinkMatcher(e)},e.prototype.registerLinkProvider=function(e){return this._checkProposedApi(),this._core.registerLinkProvider(e)},e.prototype.registerCharacterJoiner=function(e){return this._checkProposedApi(),this._core.registerCharacterJoiner(e)},e.prototype.deregisterCharacterJoiner=function(e){this._checkProposedApi(),this._core.deregisterCharacterJoiner(e)},e.prototype.registerMarker=function(e){return this._checkProposedApi(),this._verifyIntegers(e),this._core.addMarker(e)},e.prototype.addMarker=function(e){return this.registerMarker(e)},e.prototype.hasSelection=function(){return this._core.hasSelection()},e.prototype.select=function(e,t,r){this._verifyIntegers(e,t,r),this._core.select(e,t,r)},e.prototype.getSelection=function(){return this._core.getSelection()},e.prototype.getSelectionPosition=function(){return this._core.getSelectionPosition()},e.prototype.clearSelection=function(){this._core.clearSelection()},e.prototype.selectAll=function(){this._core.selectAll()},e.prototype.selectLines=function(e,t){this._verifyIntegers(e,t),this._core.selectLines(e,t)},e.prototype.dispose=function(){this._addonManager.dispose(),this._core.dispose()},e.prototype.scrollLines=function(e){this._verifyIntegers(e),this._core.scrollLines(e)},e.prototype.scrollPages=function(e){this._verifyIntegers(e),this._core.scrollPages(e)},e.prototype.scrollToTop=function(){this._core.scrollToTop()},e.prototype.scrollToBottom=function(){this._core.scrollToBottom()},e.prototype.scrollToLine=function(e){this._verifyIntegers(e),this._core.scrollToLine(e)},e.prototype.clear=function(){this._core.clear()},e.prototype.write=function(e,t){this._core.write(e,t)},e.prototype.writeUtf8=function(e,t){this._core.write(e,t)},e.prototype.writeln=function(e,t){this._core.write(e),this._core.write("\r\n",t)},e.prototype.paste=function(e){this._core.paste(e)},e.prototype.getOption=function(e){return this._core.optionsService.getOption(e)},e.prototype.setOption=function(e,t){this._checkReadonlyOptions(e),this._core.optionsService.setOption(e,t)},e.prototype.refresh=function(e,t){this._verifyIntegers(e,t),this._core.refresh(e,t)},e.prototype.reset=function(){this._core.reset()},e.prototype.clearTextureAtlas=function(){this._core.clearTextureAtlas()},e.prototype.loadAddon=function(e){return this._addonManager.loadAddon(this,e)},Object.defineProperty(e,"strings",{get:function(){return n},enumerable:!1,configurable:!0}),e.prototype._verifyIntegers=function(){for(var e=[],t=0;t<arguments.length;t++)e[t]=arguments[t];for(var r=0,i=e;r<i.length;r++){var n=i[r];if(n===1/0||isNaN(n)||n%1!=0)throw new Error("This API only accepts integers")}},e}();e.Terminal=h})(),i})()}));
//# sourceMappingURL=xterm.js.map;
/*******************************************************************************
 * @license
 * Copyright (c) 2016 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 * 
 * Contributors: IBM Corporation - initial API and implementation
 ******************************************************************************/
/*eslint-env browser, amd*/
/*global Terminal*/
define('tty/shell',[
	"socket.io/socket.io",
	"requirejs/domReady",
	'orion/widgets/input/DropDownMenu',
	'orion/widgets/input/SettingsSelect',
	'orion/commands',
	"orion/PageUtil",
	"xterm/xterm"
], function(io, onReady, DropDownMenu, SettingsSelect, mCommands, PageUtil, Terminal) {

	var term, serviceRegistry;
	var colorScheme = "Dark";

	onReady(function() {
		var socket, charWidth, charHeight, rows = 24, cols = 80;
		var fitToDiv = function(term) {
			if (socket === null) return;
			var termContainer = document.getElementById("terminalBox"),
				newWidth = termContainer.clientWidth,
				newHeight = termContainer.clientHeight;
			if (charWidth === undefined) {
				var span = document.createElement("span");
				span.textContent = "X";
				termContainer.appendChild(span);
				var rect = span.getBoundingClientRect();
				charWidth = rect.right - rect.left;
				charHeight = rect.bottom - rect.top + 2;
				termContainer.removeChild(span);
			}
			var newRows = (newHeight - 10) / (charHeight || 12);
			var newCols = Math.max(80, (newWidth - 10) / (charWidth || 12));
			if (newRows === rows && newCols !== cols) return;
			rows = newRows;
			cols = newCols;
			term.resize(Math.floor(newCols), Math.floor(newRows));
			socket.emit('resize', Math.floor(newCols), Math.floor(newRows));
		};

		var socketioPath = location.pathname.substr(0, location.pathname.indexOf('tty')) + 'socket.io/';
		socket = io.connect('/tty', { path: socketioPath });
		socket.on('connect', function() {
			socket.emit('start', getCWD());
		});
		socket.on('fail', function(error) {
			console.log(error);
		});
	
		socket.on('ready', function() {
			term = new Terminal({
				cols: cols,
				rows: rows,
				cursorBlink: true
			});
			
			term.on('data', function(data) {
				socket.emit('data', data);
			});

			term.on('title', function(title) {
				document.title = title;
			});
			var termContainer = document.getElementById("terminalBox");
			term.open(termContainer);
			
			fitToDiv(term);

			var timeout;
			window.addEventListener("resize", function() {
				if (timeout) clearTimeout(timeout);
				timeout = setTimeout(function() {
					fitToDiv(term);
					timeout = null;
				}, 500);
			});
			socket.on('data', function(data) {
				term.write(data);
			});
			socket.on('disconnect', function() {
				term.destroy();
			});
			
			changeScheme(colorScheme);
		});
		
	});
	
	function getCWD() {
		var result = PageUtil.matchResourceParameters(window.location.href).resource;
		return result.length > 0 ? result : null;
	}

	function changeScheme(schemeName) {
		var t;
		if (term !== null) {
			t = document.querySelector('.terminal');
			t.setAttribute('scheme', schemeName);
		}
		if (serviceRegistry) {
			serviceRegistry.getService("orion.core.preference").put("/orion/console", {"colorScheme": schemeName});
		}
	}

	function createCommands(registry, commandRegistry) {
		serviceRegistry = registry;
		serviceRegistry.getService("orion.core.preference").get("/orion/console").then(function(prefs) {
			colorScheme = prefs.colorScheme || colorScheme;
			changeScheme(colorScheme);
		});
		
		var that = this;
		var settingsCommand = new mCommands.Command({
			imageClass: "core-sprite-wrench", //$NON-NLS-0$
			tooltip: "Settings",
			id: "orion.term.settings", //$NON-NLS-0$
			visibleWhen: /** @callback */ function(items, data) {
				return true;
			},
			callback: function(data) {
				var dropDown = settingsCommand.settingsDropDown;
				if (!dropDown || dropDown.isDestroyed()) {
					dropDown = settingsCommand.settingsDropDown = new DropDownMenu(data.domNode.parentNode, data.domNode, {
						noClick: true,
						selectionClass: 'dropdownSelection' //$NON-NLS-0$
					});
					var menu = dropDown.getContentNode();
					var select = new SettingsSelect({
						options: ["Dark", "Light", "Solarized"].map(function(l) {
							return {label: l, value: l, selected: colorScheme === l};
						}),
						fieldlabel: "Color Scheme:",
						local: true
					});
					menu.appendChild(select.node);
					select.postChange = changeScheme;
					select.show();
					menu.tabIndex = menu.style.marginTop = 0;
				}
				dropDown.click();
			}
		});
		commandRegistry.addCommand(settingsCommand);
		commandRegistry.registerCommandContribution("settingsActions", "orion.term.settings", 1, null, false, null, null, this); //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
	}

	return {
		createCommands: createCommands
	};
});

/*******************************************************************************
 * @license
 * Copyright (c) 2016 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 * 
 * Contributors: IBM Corporation - initial API and implementation
 ******************************************************************************/
/*eslint-env browser, amd*/

define('tty/ttyShell',[
	"i18n!orion/shell/nls/messages",
	"orion/bootstrap",
	"orion/commandRegistry",
	"orion/fileClient",
	"orion/searchClient",
	"orion/globalCommands",
	'orion/webui/littlelib',
	"tty/shell"
], function(messages, mBootstrap, mCommandRegistry, mFileClient, mSearchClient, mGlobalCommands, lib, shell) {

	mBootstrap.startup().then(function(core) {
		var serviceRegistry = core.serviceRegistry;
		var preferences = core.preferences;

		var commandRegistry = new mCommandRegistry.CommandRegistry({});
		var fileClient = new mFileClient.FileClient(serviceRegistry);
		var searcher = new mSearchClient.Searcher({serviceRegistry: serviceRegistry, commandService: commandRegistry, fileService: fileClient});
		mGlobalCommands.generateBanner("orion-shellPage", serviceRegistry, commandRegistry, preferences, searcher); //$NON-NLS-0$
		mGlobalCommands.setPageTarget({task: messages.Shell, serviceRegistry: serviceRegistry, commandService: commandRegistry});
		
		shell.createCommands(serviceRegistry, commandRegistry, preferences);
		
		["pageActions", "pageNavigationActions", "settingsActions"].forEach(function(id) { //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$ //$NON-NLS-3$
			var toolbar = lib.node(id);
			if (toolbar) {
				commandRegistry.destroy(toolbar);
				commandRegistry.renderCommands(toolbar.id, toolbar, this, this, "button"); //$NON-NLS-0$
			}
		});
	});
});

