// This file was generated by libdot/bin/concat.sh.
// It has been marked read-only for your safety. Rather than
// edit it directly, please modify one of these source files.
//
// libdot/js/lib.js
// libdot/js/lib_polyfill.js
// libdot/js/lib_array.js
// libdot/js/lib_codec.js
// libdot/js/lib_colors.js
// libdot/js/lib_f.js
// libdot/js/lib_i18n.js
// libdot/js/lib_message_manager.js
// libdot/js/lib_preference_manager.js
// libdot/js/lib_resource.js
// libdot/js/lib_storage.js
// libdot/js/lib_storage_chrome.js
// libdot/js/lib_storage_local.js
// libdot/js/lib_storage_memory.js
// libdot/third_party/fast-text-encoding/text.js
// libdot/third_party/wcwidth/lib_wc.js
'use strict';// SOURCE FILE: libdot/js/lib.js
// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
function _slicedToArray(arr,i){return _arrayWithHoles(arr)||_iterableToArrayLimit(arr,i)||_nonIterableRest();}function _nonIterableRest(){throw new TypeError("Invalid attempt to destructure non-iterable instance");}function _iterableToArrayLimit(arr,i){var _arr=[];var _n=true;var _d=false;var _e=undefined;try{for(var _i=arr[Symbol.iterator](),_s;!(_n=(_s=_i.next()).done);_n=true){_arr.push(_s.value);if(i&&_arr.length===i)break;}}catch(err){_d=true;_e=err;}finally{try{if(!_n&&_i["return"]!=null)_i["return"]();}finally{if(_d)throw _e;}}return _arr;}function _arrayWithHoles(arr){if(Array.isArray(arr))return arr;}function _instanceof(left,right){if(right!=null&&typeof Symbol!=="undefined"&&right[Symbol.hasInstance]){return right[Symbol.hasInstance](left);}else{return left instanceof right;}}function _typeof(obj){if(typeof Symbol==="function"&&typeof Symbol.iterator==="symbol"){_typeof=function _typeof(obj){return typeof obj;};}else{_typeof=function _typeof(obj){return obj&&typeof Symbol==="function"&&obj.constructor===Symbol&&obj!==Symbol.prototype?"symbol":typeof obj;};}return _typeof(obj);}var lib={};/**
* List of functions that need to be invoked during library initialization.
*
* Each element in the initCallbacks_ array is itself a two-element array.
* Element 0 is a short string describing the owner of the init routine, useful
* for debugging. Element 1 is the callback function.
*/lib.initCallbacks_=[];/**
* Register an initialization function.
*
* The initialization functions are invoked in registration order when
* lib.init() is invoked. Each function will receive a single parameter, which
* is a function to be invoked when it completes its part of the initialization.
*
* @param {string} name A short descriptive name of the init routine useful for
* debugging.
* @param {function(function)} callback The initialization function to register.
* @return {function} The callback parameter.
*/lib.registerInit=function(name,callback){lib.initCallbacks_.push([name,callback]);return callback;};/**
* Initialize the library.
*
* This will ensure that all registered runtime dependencies are met, and
* invoke any registered initialization functions.
*
* Initialization is asynchronous. The library is not ready for use until
* the onInit function is invoked.
*
* @param {function()} onInit The function to invoke when initialization is
* complete.
* @param {function(*)} opt_logFunction An optional function to send
* initialization related log messages to.
*/lib.init=function(onInit,opt_logFunction){var ary=lib.initCallbacks_;var initNext=function initNext(){if(ary.length){var rec=ary.shift();if(opt_logFunction)opt_logFunction('init: '+rec[0]);rec[1](initNext);}else{onInit();}};if(typeof onInit!='function')throw new Error('Missing or invalid argument: onInit');setTimeout(initNext,0);};// SOURCE FILE: libdot/js/lib_polyfill.js
// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @fileoverview Polyfills for ES2016+ features we want to use.
*/ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/padStart
if(!String.prototype.padStart){String.prototype.padStart=function(targetLength,padString){// If the string is already long enough, nothing to do!
targetLength-=this.length;if(targetLength<=0)return String(this);if(padString===undefined)padString=' ';// In case the pad is multiple chars long.
if(targetLength>padString.length)padString=padString.repeat(targetLength/padString.length+1);return padString.slice(0,targetLength)+String(this);};}// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/padEnd
if(!String.prototype.padEnd){String.prototype.padEnd=function(targetLength,padString){// If the string is already long enough, nothing to do!
targetLength-=this.length;if(targetLength<=0)return String(this);if(padString===undefined)padString=' ';// In case the pad is multiple chars long.
if(targetLength>padString.length)padString=padString.repeat(targetLength/padString.length+1);return String(this)+padString.slice(0,targetLength);};}// https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_objects/Object/values
// https://github.com/tc39/proposal-object-values-entries/blob/master/polyfill.js
if(!Object.values||!Object.entries){var reduce=Function.bind.call(Function.call,Array.prototype.reduce);var isEnumerable=Function.bind.call(Function.call,Object.prototype.propertyIsEnumerable);var concat=Function.bind.call(Function.call,Array.prototype.concat);if(!Object.values){Object.values=function values(O){return reduce(Reflect.ownKeys(O),function(v,k){return concat(v,typeof k==='string'&&isEnumerable(O,k)?[O[k]]:[]);},[]);};}if(!Object.entries){Object.entries=function entries(O){return reduce(Reflect.ownKeys(O),function(e,k){return concat(e,typeof k==='string'&&isEnumerable(O,k)?[[k,O[k]]]:[]);},[]);};}}// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/finally
// https://github.com/tc39/proposal-promise-finally/blob/master/polyfill.js
if(typeof Promise.prototype.finally!=='function'){var speciesConstructor=function speciesConstructor(O,defaultConstructor){if(!O||_typeof(O)!=='object'&&typeof O!=='function'){throw new TypeError('Assertion failed: Type(O) is not Object');}var C=O.constructor;if(typeof C==='undefined'){return defaultConstructor;}if(!C||_typeof(C)!=='object'&&typeof C!=='function'){throw new TypeError('O.constructor is not an Object');}var S=typeof Symbol==='function'&&_typeof(Symbol.species)==='symbol'?C[Symbol.species]:undefined;if(S==null){return defaultConstructor;}if(typeof S==='function'&&S.prototype){return S;}throw new TypeError('no constructor found');};var shim={finally:function _finally(onFinally){var promise=this;if(_typeof(promise)!=='object'||promise===null){throw new TypeError('"this" value is not an Object');}var C=speciesConstructor(promise,Promise);if(typeof onFinally!=='function'){return Promise.prototype.then.call(promise,onFinally,onFinally);}return Promise.prototype.then.call(promise,function(x){return new C(function(resolve){return resolve(onFinally());}).then(function(){return x;});},function(e){return new C(function(resolve){return resolve(onFinally());}).then(function(){throw e;});});}};Object.defineProperty(Promise.prototype,'finally',{configurable:true,writable:true,value:shim.finally});}// SOURCE FILE: libdot/js/lib_array.js
// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @fileoverview Helper functions for (typed) arrays.
*/lib.array={};/**
* Concatenate an arbitrary number of typed arrays of the same type into a new
* typed array of this type.
*
* @template TYPED_ARRAY
* @param {...!TYPED_ARRAY} arrays
* @returns {!TYPED_ARRAY}
*/lib.array.concatTyped=function(){var resultLength=0;for(var _len=arguments.length,arrays=new Array(_len),_key=0;_key<_len;_key++){arrays[_key]=arguments[_key];}for(var _i=0,_arrays=arrays;_i<_arrays.length;_i++){var array=_arrays[_i];resultLength+=array.length;}var result=new arrays[0].constructor(resultLength);var pos=0;for(var _i2=0,_arrays2=arrays;_i2<_arrays2.length;_i2++){var _array=_arrays2[_i2];result.set(_array,pos);pos+=_array.length;}return result;};/**
* Compare two array-like objects entrywise.
*
* @template ARRAY_LIKE
* @param {?ARRAY_LIKE} a
* @param {?ARRAY_LIKE} b
* @returns {!boolean} true if both arrays are null or they agree entrywise;
* false otherwise.
*/lib.array.compare=function(a,b){if(a===null||b===null){return a===null&&b===null;}if(a.length!==b.length){return false;}for(var i=0;i<a.length;i++){if(a[i]!==b[i]){return false;}}return true;};// SOURCE FILE: libdot/js/lib_codec.js
// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
lib.codec={};/**
* Join an array of code units to a string.
*
* The code units must not be larger than 65535. The individual code units may
* be for UTF-8 or UTF-16 -- it doesn't matter since UTF-16 can handle all UTF-8
* code units.
*
* The input array type may be an Array or a typed Array (e.g. Uint8Array).
*
* @param {Array<number>} array The code units to generate for the string.
* @return {string} A UTF-16 encoded string.
*/lib.codec.codeUnitArrayToString=function(array){// String concat is faster than Array.join.
//
// String.fromCharCode.apply is faster than this if called less frequently
// and with smaller array sizes (like <32K). But it's a recursive call so
// larger arrays will blow the stack and fail. We also seem to be faster
// (or at least more constant time) when called frequently.
var ret='';for(var i=0;i<array.length;++i){ret+=String.fromCharCode(array[i]);}return ret;};/**
* Create an array of code units from a UTF-16 encoded string.
*
* @param {string} str The string to extract code units from.
* @param {type=} type The type of the return value.
* @return {Array<number>} The array of code units.
*/lib.codec.stringToCodeUnitArray=function(str){var type=arguments.length>1&&arguments[1]!==undefined?arguments[1]:Array;// Indexing string directly is faster than Array.map.
var ret=new type(str.length);for(var i=0;i<str.length;++i){ret[i]=str.charCodeAt(i);}return ret;};// SOURCE FILE: libdot/js/lib_colors.js
// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* Namespace for color utilities.
*/lib.colors={};/**
* First, some canned regular expressions we're going to use in this file.
*
*
* BRACE YOURSELF
*
* ,~~~~.
* |>_< ~~
* 3`---'-/.
* 3:::::\v\
* =o=:::::\,\
* | :::::\,,\
*
* THE REGULAR EXPRESSIONS
* ARE COMING.
*
* There's no way to break long RE literals in JavaScript. Fix that why don't
* you? Oh, and also there's no way to write a string that doesn't interpret
* escapes.
*
* Instead, we stoop to this .replace() trick.
*/lib.colors.re_={// CSS hex color, #RGB.
hex16:/#([a-f0-9])([a-f0-9])([a-f0-9])/i,// CSS hex color, #RRGGBB.
hex24:/#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/i,// CSS rgb color, rgb(rrr,ggg,bbb).
rgb:new RegExp(('^/s*rgb/s*/(/s*(/d{1,3})/s*,/s*(/d{1,3})/s*,'+'/s*(/d{1,3})/s*/)/s*$').replace(/\//g,'\\'),'i'),// CSS rgb color, rgb(rrr,ggg,bbb,aaa).
rgba:new RegExp(('^/s*rgba/s*'+'/(/s*(/d{1,3})/s*,/s*(/d{1,3})/s*,/s*(/d{1,3})/s*'+'(?:,/s*(/d+(?:/./d+)?)/s*)/)/s*$').replace(/\//g,'\\'),'i'),// Either RGB or RGBA.
rgbx:new RegExp(('^/s*rgba?/s*'+'/(/s*(/d{1,3})/s*,/s*(/d{1,3})/s*,/s*(/d{1,3})/s*'+'(?:,/s*(/d+(?:/./d+)?)/s*)?/)/s*$').replace(/\//g,'\\'),'i'),// An X11 "rgb:dddd/dddd/dddd" value.
x11rgb:/^\s*rgb:([a-f0-9]{1,4})\/([a-f0-9]{1,4})\/([a-f0-9]{1,4})\s*$/i,// English color name.
name:/[a-z][a-z0-9\s]+/};/**
* Convert a CSS rgb(ddd,ddd,ddd) color value into an X11 color value.
*
* Other CSS color values are ignored to ensure sanitary data handling.
*
* Each 'ddd' component is a one byte value specified in decimal.
*
* @param {string} value The CSS color value to convert.
* @return {string} The X11 color value or null if the value could not be
* converted.
*/lib.colors.rgbToX11=function(value){function scale(v){v=(Math.min(v,255)*257).toString(16);return lib.f.zpad(v,4);}var ary=value.match(lib.colors.re_.rgbx);if(!ary)return null;return'rgb:'+scale(ary[1])+'/'+scale(ary[2])+'/'+scale(ary[3]);};/**
* Convert a legacy X11 colover value into an CSS rgb(...) color value.
*
* They take the form:
* 12 bit: #RGB -> #R000G000B000
* 24 bit: #RRGGBB -> #RR00GG00BB00
* 36 bit: #RRRGGGBBB -> #RRR0GGG0BBB0
* 48 bit: #RRRRGGGGBBBB
* These are the most significant bits.
*
* Truncate values back down to 24 bit since that's all CSS supports.
*/lib.colors.x11HexToCSS=function(v){if(!v.startsWith('#'))return null;// Strip the leading # off.
v=v.substr(1);// Reject unknown sizes.
if([3,6,9,12].indexOf(v.length)==-1)return null;// Reject non-hex values.
if(v.match(/[^a-f0-9]/i))return null;// Split the colors out.
var size=v.length/3;var r=v.substr(0,size);var g=v.substr(size,size);var b=v.substr(size+size,size);// Normalize to 16 bits.
function norm16(v){v=parseInt(v,16);return size==2?v:// 16 bit
size==1?v<<4:// 8 bit
v>>4*(size-2);// 24 or 32 bit
}return lib.colors.arrayToRGBA([r,g,b].map(norm16));};/**
* Convert an X11 color value into an CSS rgb(...) color value.
*
* The X11 value may be an X11 color name, or an RGB value of the form
* rgb:hhhh/hhhh/hhhh. If a component value is less than 4 digits it is
* padded out to 4, then scaled down to fit in a single byte.
*
* @param {string} value The X11 color value to convert.
* @return {string} The CSS color value or null if the value could not be
* converted.
*/lib.colors.x11ToCSS=function(v){function scale(v){// Pad out values with less than four digits. This padding (probably)
// matches xterm. It's difficult to say for sure since xterm seems to
// arrive at a padded value and then perform some combination of
// gamma correction, color space transformation, and quantization.
if(v.length==1){// Single digits pad out to four by repeating the character. "f" becomes
// "ffff". Scaling down a hex value of this pattern by 257 is the same
// as cutting off one byte. We skip the middle step and just double
// the character.
return parseInt(v+v,16);}if(v.length==2){// Similar deal here. X11 pads two digit values by repeating the
// byte (or scale up by 257). Since we're going to scale it back
// down anyway, we can just return the original value.
return parseInt(v,16);}if(v.length==3){// Three digit values seem to be padded by repeating the final digit.
// e.g. 10f becomes 10ff.
v=v+v.substr(2);}// Scale down the 2 byte value.
return Math.round(parseInt(v,16)/257);}var ary=v.match(lib.colors.re_.x11rgb);if(!ary){// Handle the legacy format.
if(v.startsWith('#'))return lib.colors.x11HexToCSS(v);else return lib.colors.nameToRGB(v);}ary.splice(0,1);return lib.colors.arrayToRGBA(ary.map(scale));};/**
* Converts one or more CSS '#RRGGBB' color values into their rgb(...)
* form.
*
* Arrays are converted in place. If a value cannot be converted, it is
* replaced with null.
*
* @param {string|Array.<string>} A single RGB value or array of RGB values to
* convert.
* @return {string|Array.<string>} The converted value or values.
*/lib.colors.hexToRGB=function(arg){var hex16=lib.colors.re_.hex16;var hex24=lib.colors.re_.hex24;function convert(hex){if(hex.length==4){hex=hex.replace(hex16,function(h,r,g,b){return"#"+r+r+g+g+b+b;});}var ary=hex.match(hex24);if(!ary)return null;return'rgb('+parseInt(ary[1],16)+', '+parseInt(ary[2],16)+', '+parseInt(ary[3],16)+')';}if(_instanceof(arg,Array)){for(var i=0;i<arg.length;i++){arg[i]=convert(arg[i]);}}else{arg=convert(arg);}return arg;};/**
* Converts one or more CSS rgb(...) forms into their '#RRGGBB' color values.
*
* If given an rgba(...) form, the alpha field is thrown away.
*
* Arrays are converted in place. If a value cannot be converted, it is
* replaced with null.
*
* @param {string|Array.<string>} A single rgb(...) value or array of rgb(...)
* values to convert.
* @return {string|Array.<string>} The converted value or values.
*/lib.colors.rgbToHex=function(arg){function convert(rgb){var ary=lib.colors.crackRGB(rgb);if(!ary)return null;return'#'+lib.f.zpad((parseInt(ary[0])<<16|parseInt(ary[1])<<8|parseInt(ary[2])<<0).toString(16),6);}if(_instanceof(arg,Array)){for(var i=0;i<arg.length;i++){arg[i]=convert(arg[i]);}}else{arg=convert(arg);}return arg;};/**
* Take any valid css color definition and turn it into an rgb or rgba value.
*
* Returns null if the value could not be normalized.
*/lib.colors.normalizeCSS=function(def){if(def.startsWith('#'))return lib.colors.hexToRGB(def);if(lib.colors.re_.rgbx.test(def))return def;return lib.colors.nameToRGB(def);};/**
* Convert a 3 or 4 element array into an rgba(...) string.
*/lib.colors.arrayToRGBA=function(ary){var alpha=ary.length>3?ary[3]:1;return'rgba('+ary[0]+', '+ary[1]+', '+ary[2]+', '+alpha+')';};/**
* Overwrite the alpha channel of an rgb/rgba color.
*/lib.colors.setAlpha=function(rgb,alpha){var ary=lib.colors.crackRGB(rgb);ary[3]=alpha;return lib.colors.arrayToRGBA(ary);};/**
* Mix a percentage of a tint color into a base color.
*/lib.colors.mix=function(base,tint,percent){var ary1=lib.colors.crackRGB(base);var ary2=lib.colors.crackRGB(tint);for(var i=0;i<4;++i){var diff=ary2[i]-ary1[i];ary1[i]=Math.round(parseInt(ary1[i])+diff*percent);}return lib.colors.arrayToRGBA(ary1);};/**
* Split an rgb/rgba color into an array of its components.
*
* On success, a 4 element array will be returned. For rgb values, the alpha
* will be set to 1.
*/lib.colors.crackRGB=function(color){if(color.startsWith('rgba')){var ary=color.match(lib.colors.re_.rgba);if(ary){ary.shift();return Array.from(ary);}}else{var ary=color.match(lib.colors.re_.rgb);if(ary){ary.shift();ary.push('1');return Array.from(ary);}}console.error('Couldn\'t crack: '+color);return null;};/**
* Convert an X11 color name into a CSS rgb(...) value.
*
* Names are stripped of spaces and converted to lowercase. If the name is
* unknown, null is returned.
*
* This list of color name to RGB mapping is derived from the stock X11
* rgb.txt file.
*
* @param {string} name The color name to convert.
* @return {string} The corresponding CSS rgb(...) value.
*/lib.colors.nameToRGB=function(name){if(name in lib.colors.colorNames)return lib.colors.colorNames[name];name=name.toLowerCase();if(name in lib.colors.colorNames)return lib.colors.colorNames[name];name=name.replace(/\s+/g,'');if(name in lib.colors.colorNames)return lib.colors.colorNames[name];return null;};/**
* The stock color palette.
*/lib.colors.stockColorPalette=lib.colors.hexToRGB([// The "ANSI 16"...
'#000000','#CC0000','#4E9A06','#C4A000','#3465A4','#75507B','#06989A','#D3D7CF','#555753','#EF2929','#00BA13','#FCE94F','#729FCF','#F200CB','#00B5BD','#EEEEEC',// The 6x6 color cubes...
'#000000','#00005F','#000087','#0000AF','#0000D7','#0000FF','#005F00','#005F5F','#005F87','#005FAF','#005FD7','#005FFF','#008700','#00875F','#008787','#0087AF','#0087D7','#0087FF','#00AF00','#00AF5F','#00AF87','#00AFAF','#00AFD7','#00AFFF','#00D700','#00D75F','#00D787','#00D7AF','#00D7D7','#00D7FF','#00FF00','#00FF5F','#00FF87','#00FFAF','#00FFD7','#00FFFF','#5F0000','#5F005F','#5F0087','#5F00AF','#5F00D7','#5F00FF','#5F5F00','#5F5F5F','#5F5F87','#5F5FAF','#5F5FD7','#5F5FFF','#5F8700','#5F875F','#5F8787','#5F87AF','#5F87D7','#5F87FF','#5FAF00','#5FAF5F','#5FAF87','#5FAFAF','#5FAFD7','#5FAFFF','#5FD700','#5FD75F','#5FD787','#5FD7AF','#5FD7D7','#5FD7FF','#5FFF00','#5FFF5F','#5FFF87','#5FFFAF','#5FFFD7','#5FFFFF','#870000','#87005F','#870087','#8700AF','#8700D7','#8700FF','#875F00','#875F5F','#875F87','#875FAF','#875FD7','#875FFF','#878700','#87875F','#878787','#8787AF','#8787D7','#8787FF','#87AF00','#87AF5F','#87AF87','#87AFAF','#87AFD7','#87AFFF','#87D700','#87D75F','#87D787','#87D7AF','#87D7D7','#87D7FF','#87FF00','#87FF5F','#87FF87','#87FFAF','#87FFD7','#87FFFF','#AF0000','#AF005F','#AF0087','#AF00AF','#AF00D7','#AF00FF','#AF5F00','#AF5F5F','#AF5F87','#AF5FAF','#AF5FD7','#AF5FFF','#AF8700','#AF875F','#AF8787','#AF87AF','#AF87D7','#AF87FF','#AFAF00','#AFAF5F','#AFAF87','#AFAFAF','#AFAFD7','#AFAFFF','#AFD700','#AFD75F','#AFD787','#AFD7AF','#AFD7D7','#AFD7FF','#AFFF00','#AFFF5F','#AFFF87','#AFFFAF','#AFFFD7','#AFFFFF','#D70000','#D7005F','#D70087','#D700AF','#D700D7','#D700FF','#D75F00','#D75F5F','#D75F87','#D75FAF','#D75FD7','#D75FFF','#D78700','#D7875F','#D78787','#D787AF','#D787D7','#D787FF','#D7AF00','#D7AF5F','#D7AF87','#D7AFAF','#D7AFD7','#D7AFFF','#D7D700','#D7D75F','#D7D787','#D7D7AF','#D7D7D7','#D7D7FF','#D7FF00','#D7FF5F','#D7FF87','#D7FFAF','#D7FFD7','#D7FFFF','#FF0000','#FF005F','#FF0087','#FF00AF','#FF00D7','#FF00FF','#FF5F00','#FF5F5F','#FF5F87','#FF5FAF','#FF5FD7','#FF5FFF','#FF8700','#FF875F','#FF8787','#FF87AF','#FF87D7','#FF87FF','#FFAF00','#FFAF5F','#FFAF87','#FFAFAF','#FFAFD7','#FFAFFF','#FFD700','#FFD75F','#FFD787','#FFD7AF','#FFD7D7','#FFD7FF','#FFFF00','#FFFF5F','#FFFF87','#FFFFAF','#FFFFD7','#FFFFFF',// The greyscale ramp...
'#080808','#121212','#1C1C1C','#262626','#303030','#3A3A3A','#444444','#4E4E4E','#585858','#626262','#6C6C6C','#767676','#808080','#8A8A8A','#949494','#9E9E9E','#A8A8A8','#B2B2B2','#BCBCBC','#C6C6C6','#D0D0D0','#DADADA','#E4E4E4','#EEEEEE']);/**
* The current color palette, possibly with user changes.
*/lib.colors.colorPalette=lib.colors.stockColorPalette;/**
* Named colors according to the stock X11 rgb.txt file.
*/lib.colors.colorNames={"aliceblue":"rgb(240, 248, 255)","antiquewhite":"rgb(250, 235, 215)","antiquewhite1":"rgb(255, 239, 219)","antiquewhite2":"rgb(238, 223, 204)","antiquewhite3":"rgb(205, 192, 176)","antiquewhite4":"rgb(139, 131, 120)","aquamarine":"rgb(127, 255, 212)","aquamarine1":"rgb(127, 255, 212)","aquamarine2":"rgb(118, 238, 198)","aquamarine3":"rgb(102, 205, 170)","aquamarine4":"rgb(69, 139, 116)","azure":"rgb(240, 255, 255)","azure1":"rgb(240, 255, 255)","azure2":"rgb(224, 238, 238)","azure3":"rgb(193, 205, 205)","azure4":"rgb(131, 139, 139)","beige":"rgb(245, 245, 220)","bisque":"rgb(255, 228, 196)","bisque1":"rgb(255, 228, 196)","bisque2":"rgb(238, 213, 183)","bisque3":"rgb(205, 183, 158)","bisque4":"rgb(139, 125, 107)","black":"rgb(0, 0, 0)","blanchedalmond":"rgb(255, 235, 205)","blue":"rgb(0, 0, 255)","blue1":"rgb(0, 0, 255)","blue2":"rgb(0, 0, 238)","blue3":"rgb(0, 0, 205)","blue4":"rgb(0, 0, 139)","blueviolet":"rgb(138, 43, 226)","brown":"rgb(165, 42, 42)","brown1":"rgb(255, 64, 64)","brown2":"rgb(238, 59, 59)","brown3":"rgb(205, 51, 51)","brown4":"rgb(139, 35, 35)","burlywood":"rgb(222, 184, 135)","burlywood1":"rgb(255, 211, 155)","burlywood2":"rgb(238, 197, 145)","burlywood3":"rgb(205, 170, 125)","burlywood4":"rgb(139, 115, 85)","cadetblue":"rgb(95, 158, 160)","cadetblue1":"rgb(152, 245, 255)","cadetblue2":"rgb(142, 229, 238)","cadetblue3":"rgb(122, 197, 205)","cadetblue4":"rgb(83, 134, 139)","chartreuse":"rgb(127, 255, 0)","chartreuse1":"rgb(127, 255, 0)","chartreuse2":"rgb(118, 238, 0)","chartreuse3":"rgb(102, 205, 0)","chartreuse4":"rgb(69, 139, 0)","chocolate":"rgb(210, 105, 30)","chocolate1":"rgb(255, 127, 36)","chocolate2":"rgb(238, 118, 33)","chocolate3":"rgb(205, 102, 29)","chocolate4":"rgb(139, 69, 19)","coral":"rgb(255, 127, 80)","coral1":"rgb(255, 114, 86)","coral2":"rgb(238, 106, 80)","coral3":"rgb(205, 91, 69)","coral4":"rgb(139, 62, 47)","cornflowerblue":"rgb(100, 149, 237)","cornsilk":"rgb(255, 248, 220)","cornsilk1":"rgb(255, 248, 220)","cornsilk2":"rgb(238, 232, 205)","cornsilk3":"rgb(205, 200, 177)","cornsilk4":"rgb(139, 136, 120)","cyan":"rgb(0, 255, 255)","cyan1":"rgb(0, 255, 255)","cyan2":"rgb(0, 238, 238)","cyan3":"rgb(0, 205, 205)","cyan4":"rgb(0, 139, 139)","darkblue":"rgb(0, 0, 139)","darkcyan":"rgb(0, 139, 139)","darkgoldenrod":"rgb(184, 134, 11)","darkgoldenrod1":"rgb(255, 185, 15)","darkgoldenrod2":"rgb(238, 173, 14)","darkgoldenrod3":"rgb(205, 149, 12)","darkgoldenrod4":"rgb(139, 101, 8)","darkgray":"rgb(169, 169, 169)","darkgreen":"rgb(0, 100, 0)","darkgrey":"rgb(169, 169, 169)","darkkhaki":"rgb(189, 183, 107)","darkmagenta":"rgb(139, 0, 139)","darkolivegreen":"rgb(85, 107, 47)","darkolivegreen1":"rgb(202, 255, 112)","darkolivegreen2":"rgb(188, 238, 104)","darkolivegreen3":"rgb(162, 205, 90)","darkolivegreen4":"rgb(110, 139, 61)","darkorange":"rgb(255, 140, 0)","darkorange1":"rgb(255, 127, 0)","darkorange2":"rgb(238, 118, 0)","darkorange3":"rgb(205, 102, 0)","darkorange4":"rgb(139, 69, 0)","darkorchid":"rgb(153, 50, 204)","darkorchid1":"rgb(191, 62, 255)","darkorchid2":"rgb(178, 58, 238)","darkorchid3":"rgb(154, 50, 205)","darkorchid4":"rgb(104, 34, 139)","darkred":"rgb(139, 0, 0)","darksalmon":"rgb(233, 150, 122)","darkseagreen":"rgb(143, 188, 143)","darkseagreen1":"rgb(193, 255, 193)","darkseagreen2":"rgb(180, 238, 180)","darkseagreen3":"rgb(155, 205, 155)","darkseagreen4":"rgb(105, 139, 105)","darkslateblue":"rgb(72, 61, 139)","darkslategray":"rgb(47, 79, 79)","darkslategray1":"rgb(151, 255, 255)","darkslategray2":"rgb(141, 238, 238)","darkslategray3":"rgb(121, 205, 205)","darkslategray4":"rgb(82, 139, 139)","darkslategrey":"rgb(47, 79, 79)","darkturquoise":"rgb(0, 206, 209)","darkviolet":"rgb(148, 0, 211)","debianred":"rgb(215, 7, 81)","deeppink":"rgb(255, 20, 147)","deeppink1":"rgb(255, 20, 147)","deeppink2":"rgb(238, 18, 137)","deeppink3":"rgb(205, 16, 118)","deeppink4":"rgb(139, 10, 80)","deepskyblue":"rgb(0, 191, 255)","deepskyblue1":"rgb(0, 191, 255)","deepskyblue2":"rgb(0, 178, 238)","deepskyblue3":"rgb(0, 154, 205)","deepskyblue4":"rgb(0, 104, 139)","dimgray":"rgb(105, 105, 105)","dimgrey":"rgb(105, 105, 105)","dodgerblue":"rgb(30, 144, 255)","dodgerblue1":"rgb(30, 144, 255)","dodgerblue2":"rgb(28, 134, 238)","dodgerblue3":"rgb(24, 116, 205)","dodgerblue4":"rgb(16, 78, 139)","firebrick":"rgb(178, 34, 34)","firebrick1":"rgb(255, 48, 48)","firebrick2":"rgb(238, 44, 44)","firebrick3":"rgb(205, 38, 38)","firebrick4":"rgb(139, 26, 26)","floralwhite":"rgb(255, 250, 240)","forestgreen":"rgb(34, 139, 34)","gainsboro":"rgb(220, 220, 220)","ghostwhite":"rgb(248, 248, 255)","gold":"rgb(255, 215, 0)","gold1":"rgb(255, 215, 0)","gold2":"rgb(238, 201, 0)","gold3":"rgb(205, 173, 0)","gold4":"rgb(139, 117, 0)","goldenrod":"rgb(218, 165, 32)","goldenrod1":"rgb(255, 193, 37)","goldenrod2":"rgb(238, 180, 34)","goldenrod3":"rgb(205, 155, 29)","goldenrod4":"rgb(139, 105, 20)","gray":"rgb(190, 190, 190)","gray0":"rgb(0, 0, 0)","gray1":"rgb(3, 3, 3)","gray10":"rgb(26, 26, 26)","gray100":"rgb(255, 255, 255)","gray11":"rgb(28, 28, 28)","gray12":"rgb(31, 31, 31)","gray13":"rgb(33, 33, 33)","gray14":"rgb(36, 36, 36)","gray15":"rgb(38, 38, 38)","gray16":"rgb(41, 41, 41)","gray17":"rgb(43, 43, 43)","gray18":"rgb(46, 46, 46)","gray19":"rgb(48, 48, 48)","gray2":"rgb(5, 5, 5)","gray20":"rgb(51, 51, 51)","gray21":"rgb(54, 54, 54)","gray22":"rgb(56, 56, 56)","gray23":"rgb(59, 59, 59)","gray24":"rgb(61, 61, 61)","gray25":"rgb(64, 64, 64)","gray26":"rgb(66, 66, 66)","gray27":"rgb(69, 69, 69)","gray28":"rgb(71, 71, 71)","gray29":"rgb(74, 74, 74)","gray3":"rgb(8, 8, 8)","gray30":"rgb(77, 77, 77)","gray31":"rgb(79, 79, 79)","gray32":"rgb(82, 82, 82)","gray33":"rgb(84, 84, 84)","gray34":"rgb(87, 87, 87)","gray35":"rgb(89, 89, 89)","gray36":"rgb(92, 92, 92)","gray37":"rgb(94, 94, 94)","gray38":"rgb(97, 97, 97)","gray39":"rgb(99, 99, 99)","gray4":"rgb(10, 10, 10)","gray40":"rgb(102, 102, 102)","gray41":"rgb(105, 105, 105)","gray42":"rgb(107, 107, 107)","gray43":"rgb(110, 110, 110)","gray44":"rgb(112, 112, 112)","gray45":"rgb(115, 115, 115)","gray46":"rgb(117, 117, 117)","gray47":"rgb(120, 120, 120)","gray48":"rgb(122, 122, 122)","gray49":"rgb(125, 125, 125)","gray5":"rgb(13, 13, 13)","gray50":"rgb(127, 127, 127)","gray51":"rgb(130, 130, 130)","gray52":"rgb(133, 133, 133)","gray53":"rgb(135, 135, 135)","gray54":"rgb(138, 138, 138)","gray55":"rgb(140, 140, 140)","gray56":"rgb(143, 143, 143)","gray57":"rgb(145, 145, 145)","gray58":"rgb(148, 148, 148)","gray59":"rgb(150, 150, 150)","gray6":"rgb(15, 15, 15)","gray60":"rgb(153, 153, 153)","gray61":"rgb(156, 156, 156)","gray62":"rgb(158, 158, 158)","gray63":"rgb(161, 161, 161)","gray64":"rgb(163, 163, 163)","gray65":"rgb(166, 166, 166)","gray66":"rgb(168, 168, 168)","gray67":"rgb(171, 171, 171)","gray68":"rgb(173, 173, 173)","gray69":"rgb(176, 176, 176)","gray7":"rgb(18, 18, 18)","gray70":"rgb(179, 179, 179)","gray71":"rgb(181, 181, 181)","gray72":"rgb(184, 184, 184)","gray73":"rgb(186, 186, 186)","gray74":"rgb(189, 189, 189)","gray75":"rgb(191, 191, 191)","gray76":"rgb(194, 194, 194)","gray77":"rgb(196, 196, 196)","gray78":"rgb(199, 199, 199)","gray79":"rgb(201, 201, 201)","gray8":"rgb(20, 20, 20)","gray80":"rgb(204, 204, 204)","gray81":"rgb(207, 207, 207)","gray82":"rgb(209, 209, 209)","gray83":"rgb(212, 212, 212)","gray84":"rgb(214, 214, 214)","gray85":"rgb(217, 217, 217)","gray86":"rgb(219, 219, 219)","gray87":"rgb(222, 222, 222)","gray88":"rgb(224, 224, 224)","gray89":"rgb(227, 227, 227)","gray9":"rgb(23, 23, 23)","gray90":"rgb(229, 229, 229)","gray91":"rgb(232, 232, 232)","gray92":"rgb(235, 235, 235)","gray93":"rgb(237, 237, 237)","gray94":"rgb(240, 240, 240)","gray95":"rgb(242, 242, 242)","gray96":"rgb(245, 245, 245)","gray97":"rgb(247, 247, 247)","gray98":"rgb(250, 250, 250)","gray99":"rgb(252, 252, 252)","green":"rgb(0, 255, 0)","green1":"rgb(0, 255, 0)","green2":"rgb(0, 238, 0)","green3":"rgb(0, 205, 0)","green4":"rgb(0, 139, 0)","greenyellow":"rgb(173, 255, 47)","grey":"rgb(190, 190, 190)","grey0":"rgb(0, 0, 0)","grey1":"rgb(3, 3, 3)","grey10":"rgb(26, 26, 26)","grey100":"rgb(255, 255, 255)","grey11":"rgb(28, 28, 28)","grey12":"rgb(31, 31, 31)","grey13":"rgb(33, 33, 33)","grey14":"rgb(36, 36, 36)","grey15":"rgb(38, 38, 38)","grey16":"rgb(41, 41, 41)","grey17":"rgb(43, 43, 43)","grey18":"rgb(46, 46, 46)","grey19":"rgb(48, 48, 48)","grey2":"rgb(5, 5, 5)","grey20":"rgb(51, 51, 51)","grey21":"rgb(54, 54, 54)","grey22":"rgb(56, 56, 56)","grey23":"rgb(59, 59, 59)","grey24":"rgb(61, 61, 61)","grey25":"rgb(64, 64, 64)","grey26":"rgb(66, 66, 66)","grey27":"rgb(69, 69, 69)","grey28":"rgb(71, 71, 71)","grey29":"rgb(74, 74, 74)","grey3":"rgb(8, 8, 8)","grey30":"rgb(77, 77, 77)","grey31":"rgb(79, 79, 79)","grey32":"rgb(82, 82, 82)","grey33":"rgb(84, 84, 84)","grey34":"rgb(87, 87, 87)","grey35":"rgb(89, 89, 89)","grey36":"rgb(92, 92, 92)","grey37":"rgb(94, 94, 94)","grey38":"rgb(97, 97, 97)","grey39":"rgb(99, 99, 99)","grey4":"rgb(10, 10, 10)","grey40":"rgb(102, 102, 102)","grey41":"rgb(105, 105, 105)","grey42":"rgb(107, 107, 107)","grey43":"rgb(110, 110, 110)","grey44":"rgb(112, 112, 112)","grey45":"rgb(115, 115, 115)","grey46":"rgb(117, 117, 117)","grey47":"rgb(120, 120, 120)","grey48":"rgb(122, 122, 122)","grey49":"rgb(125, 125, 125)","grey5":"rgb(13, 13, 13)","grey50":"rgb(127, 127, 127)","grey51":"rgb(130, 130, 130)","grey52":"rgb(133, 133, 133)","grey53":"rgb(135, 135, 135)","grey54":"rgb(138, 138, 138)","grey55":"rgb(140, 140, 140)","grey56":"rgb(143, 143, 143)","grey57":"rgb(145, 145, 145)","grey58":"rgb(148, 148, 148)","grey59":"rgb(150, 150, 150)","grey6":"rgb(15, 15, 15)","grey60":"rgb(153, 153, 153)","grey61":"rgb(156, 156, 156)","grey62":"rgb(158, 158, 158)","grey63":"rgb(161, 161, 161)","grey64":"rgb(163, 163, 163)","grey65":"rgb(166, 166, 166)","grey66":"rgb(168, 168, 168)","grey67":"rgb(171, 171, 171)","grey68":"rgb(173, 173, 173)","grey69":"rgb(176, 176, 176)","grey7":"rgb(18, 18, 18)","grey70":"rgb(179, 179, 179)","grey71":"rgb(181, 181, 181)","grey72":"rgb(184, 184, 184)","grey73":"rgb(186, 186, 186)","grey74":"rgb(189, 189, 189)","grey75":"rgb(191, 191, 191)","grey76":"rgb(194, 194, 194)","grey77":"rgb(196, 196, 196)","grey78":"rgb(199, 199, 199)","grey79":"rgb(201, 201, 201)","grey8":"rgb(20, 20, 20)","grey80":"rgb(204, 204, 204)","grey81":"rgb(207, 207, 207)","grey82":"rgb(209, 209, 209)","grey83":"rgb(212, 212, 212)","grey84":"rgb(214, 214, 214)","grey85":"rgb(217, 217, 217)","grey86":"rgb(219, 219, 219)","grey87":"rgb(222, 222, 222)","grey88":"rgb(224, 224, 224)","grey89":"rgb(227, 227, 227)","grey9":"rgb(23, 23, 23)","grey90":"rgb(229, 229, 229)","grey91":"rgb(232, 232, 232)","grey92":"rgb(235, 235, 235)","grey93":"rgb(237, 237, 237)","grey94":"rgb(240, 240, 240)","grey95":"rgb(242, 242, 242)","grey96":"rgb(245, 245, 245)","grey97":"rgb(247, 247, 247)","grey98":"rgb(250, 250, 250)","grey99":"rgb(252, 252, 252)","honeydew":"rgb(240, 255, 240)","honeydew1":"rgb(240, 255, 240)","honeydew2":"rgb(224, 238, 224)","honeydew3":"rgb(193, 205, 193)","honeydew4":"rgb(131, 139, 131)","hotpink":"rgb(255, 105, 180)","hotpink1":"rgb(255, 110, 180)","hotpink2":"rgb(238, 106, 167)","hotpink3":"rgb(205, 96, 144)","hotpink4":"rgb(139, 58, 98)","indianred":"rgb(205, 92, 92)","indianred1":"rgb(255, 106, 106)","indianred2":"rgb(238, 99, 99)","indianred3":"rgb(205, 85, 85)","indianred4":"rgb(139, 58, 58)","ivory":"rgb(255, 255, 240)","ivory1":"rgb(255, 255, 240)","ivory2":"rgb(238, 238, 224)","ivory3":"rgb(205, 205, 193)","ivory4":"rgb(139, 139, 131)","khaki":"rgb(240, 230, 140)","khaki1":"rgb(255, 246, 143)","khaki2":"rgb(238, 230, 133)","khaki3":"rgb(205, 198, 115)","khaki4":"rgb(139, 134, 78)","lavender":"rgb(230, 230, 250)","lavenderblush":"rgb(255, 240, 245)","lavenderblush1":"rgb(255, 240, 245)","lavenderblush2":"rgb(238, 224, 229)","lavenderblush3":"rgb(205, 193, 197)","lavenderblush4":"rgb(139, 131, 134)","lawngreen":"rgb(124, 252, 0)","lemonchiffon":"rgb(255, 250, 205)","lemonchiffon1":"rgb(255, 250, 205)","lemonchiffon2":"rgb(238, 233, 191)","lemonchiffon3":"rgb(205, 201, 165)","lemonchiffon4":"rgb(139, 137, 112)","lightblue":"rgb(173, 216, 230)","lightblue1":"rgb(191, 239, 255)","lightblue2":"rgb(178, 223, 238)","lightblue3":"rgb(154, 192, 205)","lightblue4":"rgb(104, 131, 139)","lightcoral":"rgb(240, 128, 128)","lightcyan":"rgb(224, 255, 255)","lightcyan1":"rgb(224, 255, 255)","lightcyan2":"rgb(209, 238, 238)","lightcyan3":"rgb(180, 205, 205)","lightcyan4":"rgb(122, 139, 139)","lightgoldenrod":"rgb(238, 221, 130)","lightgoldenrod1":"rgb(255, 236, 139)","lightgoldenrod2":"rgb(238, 220, 130)","lightgoldenrod3":"rgb(205, 190, 112)","lightgoldenrod4":"rgb(139, 129, 76)","lightgoldenrodyellow":"rgb(250, 250, 210)","lightgray":"rgb(211, 211, 211)","lightgreen":"rgb(144, 238, 144)","lightgrey":"rgb(211, 211, 211)","lightpink":"rgb(255, 182, 193)","lightpink1":"rgb(255, 174, 185)","lightpink2":"rgb(238, 162, 173)","lightpink3":"rgb(205, 140, 149)","lightpink4":"rgb(139, 95, 101)","lightsalmon":"rgb(255, 160, 122)","lightsalmon1":"rgb(255, 160, 122)","lightsalmon2":"rgb(238, 149, 114)","lightsalmon3":"rgb(205, 129, 98)","lightsalmon4":"rgb(139, 87, 66)","lightseagreen":"rgb(32, 178, 170)","lightskyblue":"rgb(135, 206, 250)","lightskyblue1":"rgb(176, 226, 255)","lightskyblue2":"rgb(164, 211, 238)","lightskyblue3":"rgb(141, 182, 205)","lightskyblue4":"rgb(96, 123, 139)","lightslateblue":"rgb(132, 112, 255)","lightslategray":"rgb(119, 136, 153)","lightslategrey":"rgb(119, 136, 153)","lightsteelblue":"rgb(176, 196, 222)","lightsteelblue1":"rgb(202, 225, 255)","lightsteelblue2":"rgb(188, 210, 238)","lightsteelblue3":"rgb(162, 181, 205)","lightsteelblue4":"rgb(110, 123, 139)","lightyellow":"rgb(255, 255, 224)","lightyellow1":"rgb(255, 255, 224)","lightyellow2":"rgb(238, 238, 209)","lightyellow3":"rgb(205, 205, 180)","lightyellow4":"rgb(139, 139, 122)","limegreen":"rgb(50, 205, 50)","linen":"rgb(250, 240, 230)","magenta":"rgb(255, 0, 255)","magenta1":"rgb(255, 0, 255)","magenta2":"rgb(238, 0, 238)","magenta3":"rgb(205, 0, 205)","magenta4":"rgb(139, 0, 139)","maroon":"rgb(176, 48, 96)","maroon1":"rgb(255, 52, 179)","maroon2":"rgb(238, 48, 167)","maroon3":"rgb(205, 41, 144)","maroon4":"rgb(139, 28, 98)","mediumaquamarine":"rgb(102, 205, 170)","mediumblue":"rgb(0, 0, 205)","mediumorchid":"rgb(186, 85, 211)","mediumorchid1":"rgb(224, 102, 255)","mediumorchid2":"rgb(209, 95, 238)","mediumorchid3":"rgb(180, 82, 205)","mediumorchid4":"rgb(122, 55, 139)","mediumpurple":"rgb(147, 112, 219)","mediumpurple1":"rgb(171, 130, 255)","mediumpurple2":"rgb(159, 121, 238)","mediumpurple3":"rgb(137, 104, 205)","mediumpurple4":"rgb(93, 71, 139)","mediumseagreen":"rgb(60, 179, 113)","mediumslateblue":"rgb(123, 104, 238)","mediumspringgreen":"rgb(0, 250, 154)","mediumturquoise":"rgb(72, 209, 204)","mediumvioletred":"rgb(199, 21, 133)","midnightblue":"rgb(25, 25, 112)","mintcream":"rgb(245, 255, 250)","mistyrose":"rgb(255, 228, 225)","mistyrose1":"rgb(255, 228, 225)","mistyrose2":"rgb(238, 213, 210)","mistyrose3":"rgb(205, 183, 181)","mistyrose4":"rgb(139, 125, 123)","moccasin":"rgb(255, 228, 181)","navajowhite":"rgb(255, 222, 173)","navajowhite1":"rgb(255, 222, 173)","navajowhite2":"rgb(238, 207, 161)","navajowhite3":"rgb(205, 179, 139)","navajowhite4":"rgb(139, 121, 94)","navy":"rgb(0, 0, 128)","navyblue":"rgb(0, 0, 128)","oldlace":"rgb(253, 245, 230)","olivedrab":"rgb(107, 142, 35)","olivedrab1":"rgb(192, 255, 62)","olivedrab2":"rgb(179, 238, 58)","olivedrab3":"rgb(154, 205, 50)","olivedrab4":"rgb(105, 139, 34)","orange":"rgb(255, 165, 0)","orange1":"rgb(255, 165, 0)","orange2":"rgb(238, 154, 0)","orange3":"rgb(205, 133, 0)","orange4":"rgb(139, 90, 0)","orangered":"rgb(255, 69, 0)","orangered1":"rgb(255, 69, 0)","orangered2":"rgb(238, 64, 0)","orangered3":"rgb(205, 55, 0)","orangered4":"rgb(139, 37, 0)","orchid":"rgb(218, 112, 214)","orchid1":"rgb(255, 131, 250)","orchid2":"rgb(238, 122, 233)","orchid3":"rgb(205, 105, 201)","orchid4":"rgb(139, 71, 137)","palegoldenrod":"rgb(238, 232, 170)","palegreen":"rgb(152, 251, 152)","palegreen1":"rgb(154, 255, 154)","palegreen2":"rgb(144, 238, 144)","palegreen3":"rgb(124, 205, 124)","palegreen4":"rgb(84, 139, 84)","paleturquoise":"rgb(175, 238, 238)","paleturquoise1":"rgb(187, 255, 255)","paleturquoise2":"rgb(174, 238, 238)","paleturquoise3":"rgb(150, 205, 205)","paleturquoise4":"rgb(102, 139, 139)","palevioletred":"rgb(219, 112, 147)","palevioletred1":"rgb(255, 130, 171)","palevioletred2":"rgb(238, 121, 159)","palevioletred3":"rgb(205, 104, 137)","palevioletred4":"rgb(139, 71, 93)","papayawhip":"rgb(255, 239, 213)","peachpuff":"rgb(255, 218, 185)","peachpuff1":"rgb(255, 218, 185)","peachpuff2":"rgb(238, 203, 173)","peachpuff3":"rgb(205, 175, 149)","peachpuff4":"rgb(139, 119, 101)","peru":"rgb(205, 133, 63)","pink":"rgb(255, 192, 203)","pink1":"rgb(255, 181, 197)","pink2":"rgb(238, 169, 184)","pink3":"rgb(205, 145, 158)","pink4":"rgb(139, 99, 108)","plum":"rgb(221, 160, 221)","plum1":"rgb(255, 187, 255)","plum2":"rgb(238, 174, 238)","plum3":"rgb(205, 150, 205)","plum4":"rgb(139, 102, 139)","powderblue":"rgb(176, 224, 230)","purple":"rgb(160, 32, 240)","purple1":"rgb(155, 48, 255)","purple2":"rgb(145, 44, 238)","purple3":"rgb(125, 38, 205)","purple4":"rgb(85, 26, 139)","red":"rgb(255, 0, 0)","red1":"rgb(255, 0, 0)","red2":"rgb(238, 0, 0)","red3":"rgb(205, 0, 0)","red4":"rgb(139, 0, 0)","rosybrown":"rgb(188, 143, 143)","rosybrown1":"rgb(255, 193, 193)","rosybrown2":"rgb(238, 180, 180)","rosybrown3":"rgb(205, 155, 155)","rosybrown4":"rgb(139, 105, 105)","royalblue":"rgb(65, 105, 225)","royalblue1":"rgb(72, 118, 255)","royalblue2":"rgb(67, 110, 238)","royalblue3":"rgb(58, 95, 205)","royalblue4":"rgb(39, 64, 139)","saddlebrown":"rgb(139, 69, 19)","salmon":"rgb(250, 128, 114)","salmon1":"rgb(255, 140, 105)","salmon2":"rgb(238, 130, 98)","salmon3":"rgb(205, 112, 84)","salmon4":"rgb(139, 76, 57)","sandybrown":"rgb(244, 164, 96)","seagreen":"rgb(46, 139, 87)","seagreen1":"rgb(84, 255, 159)","seagreen2":"rgb(78, 238, 148)","seagreen3":"rgb(67, 205, 128)","seagreen4":"rgb(46, 139, 87)","seashell":"rgb(255, 245, 238)","seashell1":"rgb(255, 245, 238)","seashell2":"rgb(238, 229, 222)","seashell3":"rgb(205, 197, 191)","seashell4":"rgb(139, 134, 130)","sienna":"rgb(160, 82, 45)","sienna1":"rgb(255, 130, 71)","sienna2":"rgb(238, 121, 66)","sienna3":"rgb(205, 104, 57)","sienna4":"rgb(139, 71, 38)","skyblue":"rgb(135, 206, 235)","skyblue1":"rgb(135, 206, 255)","skyblue2":"rgb(126, 192, 238)","skyblue3":"rgb(108, 166, 205)","skyblue4":"rgb(74, 112, 139)","slateblue":"rgb(106, 90, 205)","slateblue1":"rgb(131, 111, 255)","slateblue2":"rgb(122, 103, 238)","slateblue3":"rgb(105, 89, 205)","slateblue4":"rgb(71, 60, 139)","slategray":"rgb(112, 128, 144)","slategray1":"rgb(198, 226, 255)","slategray2":"rgb(185, 211, 238)","slategray3":"rgb(159, 182, 205)","slategray4":"rgb(108, 123, 139)","slategrey":"rgb(112, 128, 144)","snow":"rgb(255, 250, 250)","snow1":"rgb(255, 250, 250)","snow2":"rgb(238, 233, 233)","snow3":"rgb(205, 201, 201)","snow4":"rgb(139, 137, 137)","springgreen":"rgb(0, 255, 127)","springgreen1":"rgb(0, 255, 127)","springgreen2":"rgb(0, 238, 118)","springgreen3":"rgb(0, 205, 102)","springgreen4":"rgb(0, 139, 69)","steelblue":"rgb(70, 130, 180)","steelblue1":"rgb(99, 184, 255)","steelblue2":"rgb(92, 172, 238)","steelblue3":"rgb(79, 148, 205)","steelblue4":"rgb(54, 100, 139)","tan":"rgb(210, 180, 140)","tan1":"rgb(255, 165, 79)","tan2":"rgb(238, 154, 73)","tan3":"rgb(205, 133, 63)","tan4":"rgb(139, 90, 43)","thistle":"rgb(216, 191, 216)","thistle1":"rgb(255, 225, 255)","thistle2":"rgb(238, 210, 238)","thistle3":"rgb(205, 181, 205)","thistle4":"rgb(139, 123, 139)","tomato":"rgb(255, 99, 71)","tomato1":"rgb(255, 99, 71)","tomato2":"rgb(238, 92, 66)","tomato3":"rgb(205, 79, 57)","tomato4":"rgb(139, 54, 38)","turquoise":"rgb(64, 224, 208)","turquoise1":"rgb(0, 245, 255)","turquoise2":"rgb(0, 229, 238)","turquoise3":"rgb(0, 197, 205)","turquoise4":"rgb(0, 134, 139)","violet":"rgb(238, 130, 238)","violetred":"rgb(208, 32, 144)","violetred1":"rgb(255, 62, 150)","violetred2":"rgb(238, 58, 140)","violetred3":"rgb(205, 50, 120)","violetred4":"rgb(139, 34, 82)","wheat":"rgb(245, 222, 179)","wheat1":"rgb(255, 231, 186)","wheat2":"rgb(238, 216, 174)","wheat3":"rgb(205, 186, 150)","wheat4":"rgb(139, 126, 102)","white":"rgb(255, 255, 255)","whitesmoke":"rgb(245, 245, 245)","yellow":"rgb(255, 255, 0)","yellow1":"rgb(255, 255, 0)","yellow2":"rgb(238, 238, 0)","yellow3":"rgb(205, 205, 0)","yellow4":"rgb(139, 139, 0)","yellowgreen":"rgb(154, 205, 50)"};// SOURCE FILE: libdot/js/lib_f.js
// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* Grab bag of utility functions.
*/lib.f={};/**
* Replace variable references in a string.
*
* Variables are of the form %FUNCTION(VARNAME). FUNCTION is an optional
* escape function to apply to the value.
*
* For example
* lib.f.replaceVars("%(greeting), %encodeURIComponent(name)",
* { greeting: "Hello",
* name: "Google+" });
*
* Will result in "Hello, Google%2B".
*/lib.f.replaceVars=function(str,vars){return str.replace(/%([a-z]*)\(([^\)]+)\)/gi,function(match,fn,varname){if(typeof vars[varname]=='undefined')throw'Unknown variable: '+varname;var rv=vars[varname];if(fn in lib.f.replaceVars.functions){rv=lib.f.replaceVars.functions[fn](rv);}else if(fn){throw'Unknown escape function: '+fn;}return rv;});};/**
* Functions that can be used with replaceVars.
*
* Clients can add to this list to extend lib.f.replaceVars().
*/lib.f.replaceVars.functions={encodeURI:encodeURI,encodeURIComponent:encodeURIComponent,escapeHTML:function escapeHTML(str){var map={'<':'<','>':'>','&':'&','"':'"',"'":'''};return str.replace(/[<>&\"\']/g,function(m){return map[m];});}};lib.f.getURL=function(path){if(lib.f.getURL.chromeSupported())return chrome.runtime.getURL(path);return path;};lib.f.getURL.chromeSupported=function(){return window.chrome&&chrome.runtime&&chrome.runtime.getURL;};/**
* Clamp a given integer to a specified range.
*
* @param {integer} v The value to be clamped.
* @param {integer} min The minimum acceptable value.
* @param {integer} max The maximum acceptable value.
*/lib.f.clamp=function(v,min,max){if(v<min)return min;if(v>max)return max;return v;};/**
* Left pad a number to a given length with leading zeros.
*
* @param {string|integer} number The number to pad.
* @param {integer} length The desired length.
* @return {string} The padded number as a string.
*/lib.f.zpad=function(number,length){return String(number).padStart(length,'0');};/**
* Return a string containing a given number of space characters.
*
* This method maintains a static cache of the largest amount of whitespace
* ever requested. It shouldn't be used to generate an insanely huge amount of
* whitespace.
*
* @param {integer} length The desired amount of whitespace.
* @param {string} A string of spaces of the requested length.
*/lib.f.getWhitespace=function(length){if(length<=0)return'';var f=this.getWhitespace;if(!f.whitespace)f.whitespace=' ';while(length>f.whitespace.length){f.whitespace+=f.whitespace;}return f.whitespace.substr(0,length);};/**
* Return the current call stack after skipping a given number of frames.
*
* This method is intended to be used for debugging only. It returns an
* Object instead of an Array, because the console stringifies arrays by
* default and that's not what we want.
*
* A typical call might look like...
*
* console.log('Something wicked this way came', lib.f.getStack());
* // Notice the comma ^
*
* This would print the message to the js console, followed by an object
* which can be clicked to reveal the stack.
*
* @param {number=} ignoreFrames How many inner stack frames to ignore. The
* innermost 'getStack' call is always ignored.
* @param {number=} count How many frames to return.
*/lib.f.getStack=function(){var ignoreFrames=arguments.length>0&&arguments[0]!==undefined?arguments[0]:0;var count=arguments.length>1&&arguments[1]!==undefined?arguments[1]:undefined;var stackArray=new Error().stack.split('\n');// Always ignore the Error() object and getStack call itself.
// [0] = 'Error'
// [1] = ' at Object.lib.f.getStack (file:///.../lib_f.js:267:23)'
ignoreFrames+=2;var max=stackArray.length-ignoreFrames;if(count===undefined)count=max;else count=lib.f.clamp(count,0,max);// Remove the leading spaces and "at" from each line:
// ' at window.onload (file:///.../lib_test.js:11:18)'
var stackObject=new Array();for(var i=ignoreFrames;i<count+ignoreFrames;++i){stackObject.push(stackArray[i].replace(/^\s*at\s+/,''));}return stackObject;};/**
* Divides the two numbers and floors the results, unless the remainder is less
* than an incredibly small value, in which case it returns the ceiling.
* This is useful when the number are truncated approximations of longer
* values, and so doing division with these numbers yields a result incredibly
* close to a whole number.
*
* @param {number} numerator
* @param {number} denominator
* @return {number}
*/lib.f.smartFloorDivide=function(numerator,denominator){var val=numerator/denominator;var ceiling=Math.ceil(val);if(ceiling-val<.0001){return ceiling;}else{return Math.floor(val);}};/**
* Get a random integer in a range (inclusive).
*
* @param {number} min The lowest integer in the range.
* @param {number} max The highest integer in the range.
* @return {number} A random number between min & max.
*/lib.f.randomInt=function(min,max){return Math.floor(Math.random()*(max-min+1))+min;};/**
* Get the current OS.
*
* @return {Promise<string>} A promise that resolves to a constant in
* runtime.PlatformOs.
*/lib.f.getOs=function(){// Try the brower extensions API.
if(window.browser&&browser.runtime&&browser.runtime.getPlatformInfo)return browser.runtime.getPlatformInfo().then(function(info){return info.os;});// Use the native Chrome API if available.
if(window.chrome&&chrome.runtime&&chrome.runtime.getPlatformInfo){return new Promise(function(resolve,reject){return chrome.runtime.getPlatformInfo(function(info){return resolve(info.os);});});}// Fallback logic. Capture the major OS's. The rest should support the
// browser API above.
if(window.navigator&&navigator.userAgent){var ua=navigator.userAgent;if(ua.includes('Mac OS X'))return Promise.resolve('mac');else if(ua.includes('CrOS'))return Promise.resolve('cros');else if(ua.includes('Linux'))return Promise.resolve('linux');else if(ua.includes('Android'))return Promise.resolve('android');else if(ua.includes('Windows'))return Promise.resolve('windows');}// Still here? No idea.
return Promise.reject(null);};/**
* Get the current Chrome milestone version.
*
* @return {number} The milestone number if we're running on Chrome, else NaN.
*/lib.f.getChromeMilestone=function(){if(window.navigator&&navigator.userAgent){var ary=navigator.userAgent.match(/\sChrome\/(\d+)/);if(ary)return parseInt(ary[1]);}// Returning NaN will make all number comparisons fail.
return NaN;};/**
* Return the lastError string in the browser.
*
* This object might live in different locations, and it isn't always defined
* (if there hasn't been a "last error"). Wrap all that ugliness here.
*
* @param {string=} defaultMsg The default message if no error is found.
* @return {string} The last error message from the browser.
*/lib.f.lastError=function(){var defaultMsg=arguments.length>0&&arguments[0]!==undefined?arguments[0]:null;var lastError;if(window.browser&&browser.runtime)lastError=browser.runtime.lastError;else if(window.chrome&&chrome.runtime)lastError=chrome.runtime.lastError;if(lastError&&lastError.message)return lastError.message;else return defaultMsg;};/**
* Just like window.open, but enforce noopener.
*
* If we're not careful, the website we open will have access to use via its
* window.opener field. Newer browser support putting 'noopener' into the
* features argument, but there are many which still don't. So hack it.
*
* @param {string=} url The URL to point the new window to.
* @param {string=} name The name of the new window.
* @param {string=} features The window features to enable.
* @return {Window} The newly opened window.
*/lib.f.openWindow=function(url){var name=arguments.length>1&&arguments[1]!==undefined?arguments[1]:undefined;var features=arguments.length>2&&arguments[2]!==undefined?arguments[2]:undefined;// We create the window first without the URL loaded.
var win=window.open(undefined,name,features);// If the system is blocking window.open, don't crash.
if(win!==null){// Clear the opener setting before redirecting.
win.opener=null;// Now it's safe to redirect. Skip this step if the url is not set so we
// mimic the window.open behavior more precisely.
if(url){win.location=url;}}return win;};// SOURCE FILE: libdot/js/lib_i18n.js
// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* Wrappers over the browser i18n helpers.
*
* Arguably some of these functions should be l10n, but oh well.
*/lib.i18n={};/**
* Convenience shortcut to the browser i18n object.
*/lib.i18n.browser_=window.browser&&browser.i18n?browser.i18n:window.chrome&&chrome.i18n?chrome.i18n:null;/**
* Get the list of accepted UI languages.
*
* https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/i18n/getAcceptLanguages
*
* @param {function(Array)} callback Function to invoke with the results. The
* parameter is a list of locale names.
*/lib.i18n.getAcceptLanguages=function(callback){if(lib.i18n.browser_){lib.i18n.browser_.getAcceptLanguages(callback);}else{setTimeout(function(){callback([navigator.language.replace(/-/g,'_')]);},0);}};/**
* Get a message by name, optionally replacing arguments too.
*
* https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/i18n/getMessage
*
* @param {string} msgname The id for this localized string.
* @param {string[]=} substitutions Any replacements in the string.
* @param {string=} fallback Translation if the message wasn't found.
* @return {string} The translated message.
*/lib.i18n.getMessage=function(msgname){var substitutions=arguments.length>1&&arguments[1]!==undefined?arguments[1]:[];var fallback=arguments.length>2&&arguments[2]!==undefined?arguments[2]:'';// First let the native browser APIs handle everything for us.
if(lib.i18n.browser_){var message=lib.i18n.browser_.getMessage(msgname,substitutions);if(message)return message;}// Do our best to get something reasonable.
return lib.i18n.replaceReferences(fallback,substitutions);};/**
* Replace $1...$n references with the elements of the args array.
*
* This largely behaves like Chrome's getMessage helper. The $# references are
* always replaced/removed regardless of the specified substitutions.
*
* @param {string} msg String containing the message and argument references.
* @param {string[]=} args Array containing the argument values.
* @return {string} The message with replacements expanded.
*/lib.i18n.replaceReferences=function(msg){var args=arguments.length>1&&arguments[1]!==undefined?arguments[1]:[];// The Chrome API allows a single substitution as a string rather than array.
if(args===null){args=[];}if(!_instanceof(args,Array)){args=[args];}return msg.replace(/\$(\d+)/g,function(m,index){return index<=args.length?args[index-1]:'';});};// SOURCE FILE: libdot/js/lib_message_manager.js
// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* MessageManager class handles internationalized strings.
*
* Note: chrome.i18n isn't sufficient because...
* 1. There's a bug in chrome that makes it unavailable in iframes:
* https://crbug.com/130200
* 2. The client code may not be packaged in a Chrome extension.
* 3. The client code may be part of a library packaged in a third-party
* Chrome extension.
*
* @param {Array} languages List of languages to load, in the order they
* should be loaded. Newer messages replace older ones. 'en' is
* automatically added as the first language if it is not already present.
*/lib.MessageManager=function(languages){this.languages_=languages.map(function(el){return el.replace(/-/g,'_');});if(this.languages_.indexOf('en')==-1)this.languages_.unshift('en');this.messages={};};/**
* Add message definitions to the message manager.
*
* This takes an object of the same format of a Chrome messages.json file. See
* <https://developer.chrome.com/extensions/i18n-messages>.
*/lib.MessageManager.prototype.addMessages=function(defs){for(var key in defs){var def=defs[key];if(!def.placeholders){this.messages[key]=def.message;}else{// Replace "$NAME$" placeholders with "$1", etc.
this.messages[key]=def.message.replace(/\$([a-z][^\s\$]+)\$/ig,function(m,name){return defs[key].placeholders[name.toLowerCase()].content;});}}};/**
* Load the first available language message bundle.
*
* @param {string} pattern A url pattern containing a "$1" where the locale
* name should go.
* @param {function(Array,Array)} onComplete Function to be called when loading
* is complete. The two arrays are the list of successful and failed
* locale names. If the first parameter is length 0, no locales were
* loaded.
*/lib.MessageManager.prototype.findAndLoadMessages=function(pattern,onComplete){var languages=this.languages_.concat();var loaded=[];var failed=[];function onLanguageComplete(state){if(state){loaded=languages.shift();}else{failed=languages.shift();}if(languages.length){tryNextLanguage();}else{onComplete(loaded,failed);}}var tryNextLanguage=function(){this.loadMessages(this.replaceReferences(pattern,languages),onLanguageComplete.bind(this,true),onLanguageComplete.bind(this,false));}.bind(this);tryNextLanguage();};/**
* Load messages from a messages.json file.
*/lib.MessageManager.prototype.loadMessages=function(url,onSuccess,opt_onError){var _this=this;var xhr=new XMLHttpRequest();xhr.onload=function(){_this.addMessages(JSON.parse(xhr.responseText));onSuccess();};if(opt_onError)xhr.onerror=function(){return opt_onError(xhr);};xhr.open('GET',url);xhr.send();};/**
* Per-instance copy of replaceReferences.
*/lib.MessageManager.prototype.replaceReferences=lib.i18n.replaceReferences;/**
* Get a message by name, optionally replacing arguments too.
*
* @param {string} msgname String containing the name of the message to get.
* @param {Array} opt_args Optional array containing the argument values.
* @param {string} opt_default Optional value to return if the msgname is not
* found. Returns the message name by default.
*/lib.MessageManager.prototype.get=function(msgname,opt_args,opt_default){// First try the integrated browser getMessage. We prefer that over any
// registered messages as only the browser supports translations.
var message=lib.i18n.getMessage(msgname,opt_args);if(message)return message;// Look it up in the registered cache next.
message=this.messages[msgname];if(!message){console.warn('Unknown message: '+msgname);message=opt_default===undefined?msgname:opt_default;// Register the message with the default to avoid multiple warnings.
this.messages[msgname]=message;}return this.replaceReferences(message,opt_args);};/**
* Process all of the "i18n" html attributes found in a given dom fragment.
*
* The real work happens in processI18nAttribute.
*/lib.MessageManager.prototype.processI18nAttributes=function(dom){var nodes=dom.querySelectorAll('[i18n]');for(var i=0;i<nodes.length;i++){this.processI18nAttribute(nodes[i]);}};/**
* Process the "i18n" attribute in the specified node.
*
* The i18n attribute should contain a JSON object. The keys are taken to
* be attribute names, and the values are message names.
*
* If the JSON object has a "_" (underscore) key, its value is used as the
* textContent of the element.
*
* Message names can refer to other attributes on the same element with by
* prefixing with a dollar sign. For example...
*
* <button id='send-button'
* i18n='{"aria-label": "$id", "_": "SEND_BUTTON_LABEL"}'
* ></button>
*
* The aria-label message name will be computed as "SEND_BUTTON_ARIA_LABEL".
* Notice that the "id" attribute was appended to the target attribute, and
* the result converted to UPPER_AND_UNDER style.
*/lib.MessageManager.prototype.processI18nAttribute=function(node){// Convert the "lower-and-dashes" attribute names into
// "UPPER_AND_UNDER" style.
var thunk=function thunk(str){return str.replace(/-/g,'_').toUpperCase();};var i18n=node.getAttribute('i18n');if(!i18n)return;try{i18n=JSON.parse(i18n);}catch(ex){console.error('Can\'t parse '+node.tagName+'#'+node.id+': '+i18n);throw ex;}// Load all the messages specified in the i18n attributes.
for(var key in i18n){// The node attribute we'll be setting.
var attr=key;var msgname=i18n[key];// For "=foo", re-use the referenced message name.
if(msgname.startsWith('=')){key=msgname.substr(1);msgname=i18n[key];}// For "$foo", calculate the message name.
if(msgname.startsWith('$'))msgname=thunk(node.getAttribute(msgname.substr(1))+'_'+key);// Finally load the message.
var msg=this.get(msgname);if(attr=='_')node.textContent=msg;else node.setAttribute(attr,msg);}};// SOURCE FILE: libdot/js/lib_preference_manager.js
// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* Constructor for lib.PreferenceManager objects.
*
* These objects deal with persisting changes to stable storage and notifying
* consumers when preferences change.
*
* It is intended that the backing store could be something other than HTML5
* storage, but there aren't any use cases at the moment. In the future there
* may be a chrome api to store sync-able name/value pairs, and we'd want
* that.
*
* @param {lib.Storage.*} storage The storage object to use as a backing
* store.
* @param {string} opt_prefix The optional prefix to be used for all preference
* names. The '/' character should be used to separate levels of hierarchy,
* if you're going to have that kind of thing. If provided, the prefix
* should start with a '/'. If not provided, it defaults to '/'.
*/lib.PreferenceManager=function(storage,opt_prefix){this.storage=storage;this.storageObserver_=this.onStorageChange_.bind(this);this.isActive_=false;this.activate();this.trace=false;var prefix=opt_prefix||'/';if(!prefix.endsWith('/'))prefix+='/';this.prefix=prefix;// Internal state for when we're doing a bulk import from JSON and we want
// to elide redundant storage writes (for quota reasons).
this.isImportingJson_=false;this.prefRecords_={};this.globalObservers_=[];this.childFactories_={};// Map of list-name to {map of child pref managers}
// As in...
//
// this.childLists_ = {
// 'profile-ids': {
// 'one': PreferenceManager,
// 'two': PreferenceManager,
// ...
// },
//
// 'frob-ids': {
// ...
// }
// }
this.childLists_={};};/**
* Used internally to indicate that the current value of the preference should
* be taken from the default value defined with the preference.
*
* Equality tests against this value MUST use '===' or '!==' to be accurate.
*/lib.PreferenceManager.prototype.DEFAULT_VALUE=Symbol('DEFAULT_VALUE');/**
* An individual preference.
*
* These objects are managed by the PreferenceManager, you shouldn't need to
* handle them directly.
*/lib.PreferenceManager.Record=function(name,defaultValue){this.name=name;this.defaultValue=defaultValue;this.currentValue=this.DEFAULT_VALUE;this.observers=[];};/**
* A local copy of the DEFAULT_VALUE constant to make it less verbose.
*/lib.PreferenceManager.Record.prototype.DEFAULT_VALUE=lib.PreferenceManager.prototype.DEFAULT_VALUE;/**
* Register a callback to be invoked when this preference changes.
*
* @param {function(value, string, lib.PreferenceManager} observer The function
* to invoke. It will receive the new value, the name of the preference,
* and a reference to the PreferenceManager as parameters.
*/lib.PreferenceManager.Record.prototype.addObserver=function(observer){this.observers.push(observer);};/**
* Unregister an observer callback.
*
* @param {function} observer A previously registered callback.
*/lib.PreferenceManager.Record.prototype.removeObserver=function(observer){var i=this.observers.indexOf(observer);if(i>=0)this.observers.splice(i,1);};/**
* Fetch the value of this preference.
*/lib.PreferenceManager.Record.prototype.get=function(){if(this.currentValue===this.DEFAULT_VALUE){if(/^(string|number)$/.test(_typeof(this.defaultValue)))return this.defaultValue;if(_typeof(this.defaultValue)=='object'){// We want to return a COPY of the default value so that users can
// modify the array or object without changing the default value.
return JSON.parse(JSON.stringify(this.defaultValue));}return this.defaultValue;}return this.currentValue;};/**
* Stop this preference manager from tracking storage changes.
*
* Call this if you're going to swap out one preference manager for another so
* that you don't get notified about irrelevant changes.
*/lib.PreferenceManager.prototype.deactivate=function(){if(!this.isActive_)throw new Error('Not activated');this.isActive_=false;this.storage.removeObserver(this.storageObserver_);};/**
* Start tracking storage changes.
*
* If you previously deactivated this preference manager, you can reactivate it
* with this method. You don't need to call this at initialization time, as
* it's automatically called as part of the constructor.
*/lib.PreferenceManager.prototype.activate=function(){if(this.isActive_)throw new Error('Already activated');this.isActive_=true;this.storage.addObserver(this.storageObserver_);};/**
* Read the backing storage for these preferences.
*
* You should do this once at initialization time to prime the local cache
* of preference values. The preference manager will monitor the backing
* storage for changes, so you should not need to call this more than once.
*
* This function recursively reads storage for all child preference managers as
* well.
*
* This function is asynchronous, if you need to read preference values, you
* *must* wait for the callback.
*
* @param {function()} opt_callback Optional function to invoke when the read
* has completed.
*/lib.PreferenceManager.prototype.readStorage=function(opt_callback){var _this2=this;var pendingChildren=0;function onChildComplete(){if(--pendingChildren==0&&opt_callback)opt_callback();}var keys=Object.keys(this.prefRecords_).map(function(el){return _this2.prefix+el;});if(this.trace)console.log('Preferences read: '+this.prefix);this.storage.getItems(keys,function(items){var prefixLength=this.prefix.length;for(var key in items){var value=items[key];var name=key.substr(prefixLength);var needSync=name in this.childLists_&&JSON.stringify(value)!=JSON.stringify(this.prefRecords_[name].currentValue);this.prefRecords_[name].currentValue=value;if(needSync){pendingChildren++;this.syncChildList(name,onChildComplete);}}if(pendingChildren==0&&opt_callback)setTimeout(opt_callback);}.bind(this));};/**
* Define a preference.
*
* This registers a name, default value, and onChange handler for a preference.
*
* @param {string} name The name of the preference. This will be prefixed by
* the prefix of this PreferenceManager before written to local storage.
* @param {string|number|boolean|Object|Array|null} value The default value of
* this preference. Anything that can be represented in JSON is a valid
* default value.
* @param {function(value, string, lib.PreferenceManager} opt_observer A
* function to invoke when the preference changes. It will receive the new
* value, the name of the preference, and a reference to the
* PreferenceManager as parameters.
*/lib.PreferenceManager.prototype.definePreference=function(name,value,opt_onChange){var record=this.prefRecords_[name];if(record){this.changeDefault(name,value);}else{record=this.prefRecords_[name]=new lib.PreferenceManager.Record(name,value);}if(opt_onChange)record.addObserver(opt_onChange);};/**
* Define multiple preferences with a single function call.
*
* @param {Array} defaults An array of 3-element arrays. Each three element
* array should contain the [key, value, onChange] parameters for a
* preference.
*/lib.PreferenceManager.prototype.definePreferences=function(defaults){for(var i=0;i<defaults.length;i++){this.definePreference(defaults[i][0],defaults[i][1],defaults[i][2]);}};/**
* Define an ordered list of child preferences.
*
* Child preferences are different from just storing an array of JSON objects
* in that each child is an instance of a preference manager. This means you
* can observe changes to individual child preferences, and get some validation
* that you're not reading or writing to an undefined child preference value.
*
* @param {string} listName A name for the list of children. This must be
* unique in this preference manager. The listName will become a
* preference on this PreferenceManager used to store the ordered list of
* child ids. It is also used in get/add/remove operations to identify the
* list of children to operate on.
* @param {function} childFactory A function that will be used to generate
* instances of these children. The factory function will receive the
* parent lib.PreferenceManager object and a unique id for the new child
* preferences.
*/lib.PreferenceManager.prototype.defineChildren=function(listName,childFactory){// Define a preference to hold the ordered list of child ids.
this.definePreference(listName,[],this.onChildListChange_.bind(this,listName));this.childFactories_[listName]=childFactory;this.childLists_[listName]={};};/**
* Register to observe preference changes.
*
* @param {Function} global A callback that will happen for every preference.
* Pass null if you don't need one.
* @param {Object} map A map of preference specific callbacks. Pass null if
* you don't need any.
*/lib.PreferenceManager.prototype.addObservers=function(global,map){if(global&&typeof global!='function')throw new Error('Invalid param: globals');if(global)this.globalObservers_.push(global);if(!map)return;for(var name in map){if(!(name in this.prefRecords_))throw new Error('Unknown preference: '+name);this.prefRecords_[name].addObserver(map[name]);}};/**
* Dispatch the change observers for all known preferences.
*
* It may be useful to call this after readStorage completes, in order to
* get application state in sync with user preferences.
*
* This can be used if you've changed a preference manager out from under
* a live object, for example when switching to a different prefix.
*/lib.PreferenceManager.prototype.notifyAll=function(){for(var name in this.prefRecords_){this.notifyChange_(name);}};/**
* Notify the change observers for a given preference.
*
* @param {string} name The name of the preference that changed.
*/lib.PreferenceManager.prototype.notifyChange_=function(name){var record=this.prefRecords_[name];if(!record)throw new Error('Unknown preference: '+name);var currentValue=record.get();for(var i=0;i<this.globalObservers_.length;i++){this.globalObservers_[i](name,currentValue);}for(var i=0;i<record.observers.length;i++){record.observers[i](currentValue,name,this);}};/**
* Create a new child PreferenceManager for the given child list.
*
* The optional hint parameter is an opaque prefix added to the auto-generated
* unique id for this child. Your child factory can parse out the prefix
* and use it.
*
* @param {string} listName The child list to create the new instance from.
* @param {string} opt_hint Optional hint to include in the child id.
* @param {string} opt_id Optional id to override the generated id.
*/lib.PreferenceManager.prototype.createChild=function(listName,opt_hint,opt_id){var ids=this.get(listName);var id;if(opt_id){id=opt_id;if(ids.indexOf(id)!=-1)throw new Error('Duplicate child: '+listName+': '+id);}else{// Pick a random, unique 4-digit hex identifier for the new profile.
while(!id||ids.indexOf(id)!=-1){id=lib.f.randomInt(1,0xffff).toString(16);id=lib.f.zpad(id,4);if(opt_hint)id=opt_hint+':'+id;}}var childManager=this.childFactories_[listName](this,id);childManager.trace=this.trace;childManager.resetAll();this.childLists_[listName][id]=childManager;ids.push(id);this.set(listName,ids,undefined,!this.isImportingJson_);return childManager;};/**
* Remove a child preferences instance.
*
* Removes a child preference manager and clears any preferences stored in it.
*
* @param {string} listName The name of the child list containing the child to
* remove.
* @param {string} id The child ID.
*/lib.PreferenceManager.prototype.removeChild=function(listName,id){var prefs=this.getChild(listName,id);prefs.resetAll();var ids=this.get(listName);var i=ids.indexOf(id);if(i!=-1){ids.splice(i,1);this.set(listName,ids,undefined,!this.isImportingJson_);}delete this.childLists_[listName][id];};/**
* Return a child PreferenceManager instance for a given id.
*
* If the child list or child id is not known this will return the specified
* default value or throw an exception if no default value is provided.
*
* @param {string} listName The child list to look in.
* @param {string} id The child ID.
* @param {*} opt_default The optional default value to return if the child
* is not found.
*/lib.PreferenceManager.prototype.getChild=function(listName,id,opt_default){if(!(listName in this.childLists_))throw new Error('Unknown child list: '+listName);var childList=this.childLists_[listName];if(!(id in childList)){if(typeof opt_default=='undefined')throw new Error('Unknown "'+listName+'" child: '+id);return opt_default;}return childList[id];};/**
* Calculate the difference between two lists of child ids.
*
* Given two arrays of child ids, this function will return an object
* with "added", "removed", and "common" properties. Each property is
* a map of child-id to `true`. For example, given...
*
* a = ['child-x', 'child-y']
* b = ['child-y']
*
* diffChildLists(a, b) =>
* { added: { 'child-x': true }, removed: {}, common: { 'child-y': true } }
*
* The added/removed properties assume that `a` is the current list.
*
* @param {Array[string]} a The most recent list of child ids.
* @param {Array[string]} b An older list of child ids.
* @return {Object} An object with added/removed/common properties.
*/lib.PreferenceManager.diffChildLists=function(a,b){var rv={added:{},removed:{},common:{}};for(var i=0;i<a.length;i++){if(b.indexOf(a[i])!=-1){rv.common[a[i]]=true;}else{rv.added[a[i]]=true;}}for(var i=0;i<b.length;i++){if(b[i]in rv.added||b[i]in rv.common)continue;rv.removed[b[i]]=true;}return rv;};/**
* Synchronize a list of child PreferenceManagers instances with the current
* list stored in prefs.
*
* This will instantiate any missing managers and read current preference values
* from storage. Any active managers that no longer appear in preferences will
* be deleted.
*
* @param {string} listName The child list to synchronize.
* @param {function()} opt_callback Optional function to invoke when the sync
* is complete.
*/lib.PreferenceManager.prototype.syncChildList=function(listName,opt_callback){var pendingChildren=0;function onChildStorage(){if(--pendingChildren==0&&opt_callback)opt_callback();}// The list of child ids that we *should* have a manager for.
var currentIds=this.get(listName);// The known managers at the start of the sync. Any manager still in this
// list at the end should be discarded.
var oldIds=Object.keys(this.childLists_[listName]);var rv=lib.PreferenceManager.diffChildLists(currentIds,oldIds);for(var i=0;i<currentIds.length;i++){var id=currentIds[i];var managerIndex=oldIds.indexOf(id);if(managerIndex>=0)oldIds.splice(managerIndex,1);if(!this.childLists_[listName][id]){var childManager=this.childFactories_[listName](this,id);if(!childManager){console.warn('Unable to restore child: '+listName+': '+id);continue;}childManager.trace=this.trace;this.childLists_[listName][id]=childManager;pendingChildren++;childManager.readStorage(onChildStorage);}}for(var i=0;i<oldIds.length;i++){delete this.childLists_[listName][oldIds[i]];}if(!pendingChildren&&opt_callback)setTimeout(opt_callback);};/**
* Reset a preference to its default state.
*
* This will dispatch the onChange handler if the preference value actually
* changes.
*
* @param {string} name The preference to reset.
*/lib.PreferenceManager.prototype.reset=function(name){var record=this.prefRecords_[name];if(!record)throw new Error('Unknown preference: '+name);this.storage.removeItem(this.prefix+name);if(record.currentValue!==this.DEFAULT_VALUE){record.currentValue=this.DEFAULT_VALUE;this.notifyChange_(name);}};/**
* Reset all preferences back to their default state.
*/lib.PreferenceManager.prototype.resetAll=function(){var changed=[];for(var listName in this.childLists_){var childList=this.childLists_[listName];for(var id in childList){childList[id].resetAll();}}for(var name in this.prefRecords_){if(this.prefRecords_[name].currentValue!==this.DEFAULT_VALUE){this.prefRecords_[name].currentValue=this.DEFAULT_VALUE;changed.push(name);}}var keys=Object.keys(this.prefRecords_).map(function(el){return this.prefix+el;}.bind(this));this.storage.removeItems(keys);changed.forEach(this.notifyChange_.bind(this));};/**
* Return true if two values should be considered not-equal.
*
* If both values are the same scalar type and compare equal this function
* returns false (no difference), otherwise return true.
*
* This is used in places where we want to check if a preference has changed.
* Rather than take the time to compare complex values we just consider them
* to always be different.
*
* @param {*} a A value to compare.
* @param {*} b A value to compare.
*/lib.PreferenceManager.prototype.diff=function(a,b){// If the types are different.
if(_typeof(a)!==_typeof(b)){return true;}// Or if the type is not a simple primitive one.
if(!/^(undefined|boolean|number|string)$/.test(_typeof(a))){// Special case the null object.
if(a===null&&b===null){return false;}else{return true;}}// Do a normal compare for primitive types.
return a!==b;};/**
* Change the default value of a preference.
*
* This is useful when subclassing preference managers.
*
* The function does not alter the current value of the preference, unless
* it has the old default value. When that happens, the change observers
* will be notified.
*
* @param {string} name The name of the parameter to change.
* @param {*} newValue The new default value for the preference.
*/lib.PreferenceManager.prototype.changeDefault=function(name,newValue){var record=this.prefRecords_[name];if(!record)throw new Error('Unknown preference: '+name);if(!this.diff(record.defaultValue,newValue)){// Default value hasn't changed.
return;}if(record.currentValue!==this.DEFAULT_VALUE){// This pref has a specific value, just change the default and we're done.
record.defaultValue=newValue;return;}record.defaultValue=newValue;this.notifyChange_(name);};/**
* Change the default value of multiple preferences.
*
* @param {Object} map A map of name -> value pairs specifying the new default
* values.
*/lib.PreferenceManager.prototype.changeDefaults=function(map){for(var key in map){this.changeDefault(key,map[key]);}};/**
* Set a preference to a specific value.
*
* This will dispatch the onChange handler if the preference value actually
* changes.
*
* @param {string} name The preference to set.
* @param {*} newValue The value to set. Anything that can be represented in
* JSON is a valid value.
* @param {function()=} onComplete Callback when the set call completes.
* @param {boolean=} saveToStorage Whether to commit the change to the backing
* storage or only the in-memory record copy.
*/lib.PreferenceManager.prototype.set=function(name,newValue){var onComplete=arguments.length>2&&arguments[2]!==undefined?arguments[2]:undefined;var saveToStorage=arguments.length>3&&arguments[3]!==undefined?arguments[3]:true;var record=this.prefRecords_[name];if(!record)throw new Error('Unknown preference: '+name);var oldValue=record.get();if(!this.diff(oldValue,newValue))return;if(this.diff(record.defaultValue,newValue)){record.currentValue=newValue;if(saveToStorage)this.storage.setItem(this.prefix+name,newValue,onComplete);}else{record.currentValue=this.DEFAULT_VALUE;if(saveToStorage)this.storage.removeItem(this.prefix+name,onComplete);}// We need to manually send out the notification on this instance. If we
// The storage event won't fire a notification because we've already changed
// the currentValue, so it won't see a difference. If we delayed changing
// currentValue until the storage event, a pref read immediately after a write
// would return the previous value.
//
// The notification is in a timeout so clients don't accidentally depend on
// a synchronous notification.
setTimeout(this.notifyChange_.bind(this,name),0);};/**
* Get the value of a preference.
*
* @param {string} key The preference to get.
*/lib.PreferenceManager.prototype.get=function(name){var record=this.prefRecords_[name];if(!record)throw new Error('Unknown preference: '+name);return record.get();};/**
* Return all non-default preferences as a JSON object.
*
* This includes any nested preference managers as well.
*/lib.PreferenceManager.prototype.exportAsJson=function(){var rv={};for(var name in this.prefRecords_){if(name in this.childLists_){rv[name]=[];var childIds=this.get(name);for(var i=0;i<childIds.length;i++){var id=childIds[i];rv[name].push({id:id,json:this.getChild(name,id).exportAsJson()});}}else{var record=this.prefRecords_[name];if(record.currentValue!=this.DEFAULT_VALUE)rv[name]=record.currentValue;}}return rv;};/**
* Import a JSON blob of preferences previously generated with exportAsJson.
*
* This will create nested preference managers as well.
*/lib.PreferenceManager.prototype.importFromJson=function(json,opt_onComplete){var _this3=this;this.isImportingJson_=true;var pendingWrites=0;var onWriteStorage=function onWriteStorage(){if(--pendingWrites<1){if(opt_onComplete)opt_onComplete();// We've delayed updates to the child arrays, so flush them now.
for(var _name in json){if(_name in _this3.childLists_)_this3.set(_name,_this3.get(_name));}_this3.isImportingJson_=false;}};for(var name in json){if(name in this.childLists_){var childList=json[name];for(var i=0;i<childList.length;i++){var id=childList[i].id;var childPrefManager=this.childLists_[name][id];if(!childPrefManager)childPrefManager=this.createChild(name,null,id);childPrefManager.importFromJson(childList[i].json,onWriteStorage);pendingWrites++;}}else{// The set is synchronous.
this.set(name,json[name]);}}// If we didn't update any children, no async work has been queued, so make
// the completion callback directly.
if(pendingWrites==0&&opt_onComplete)opt_onComplete();};/**
* Called when one of the child list preferences changes.
*/lib.PreferenceManager.prototype.onChildListChange_=function(listName){this.syncChildList(listName);};/**
* Called when a key in the storage changes.
*/lib.PreferenceManager.prototype.onStorageChange_=function(map){for(var key in map){if(this.prefix){if(key.lastIndexOf(this.prefix,0)!=0)continue;}var name=key.substr(this.prefix.length);if(!(name in this.prefRecords_)){// Sometimes we'll get notified about prefs that are no longer defined.
continue;}var record=this.prefRecords_[name];var newValue=map[key].newValue;var currentValue=record.currentValue;if(currentValue===record.DEFAULT_VALUE)currentValue=void 0;if(this.diff(currentValue,newValue)){if(typeof newValue=='undefined'||newValue===null){record.currentValue=record.DEFAULT_VALUE;}else{record.currentValue=newValue;}this.notifyChange_(name);}}};// SOURCE FILE: libdot/js/lib_resource.js
// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* Storage for canned resources.
*
* These are usually non-JavaScript things that are collected during a build
* step and converted into a series of 'lib.resource.add(...)' calls. See
* the "@resource" directive from libdot/bin/concat for the canonical use
* case.
*
* This is global storage, so you should prefix your resource names to avoid
* collisions.
*/lib.resource={resources_:{}};/**
* Add a resource.
*
* @param {string} name A name for the resource. You should prefix this to
* avoid collisions with resources from a shared library.
* @param {string} type A mime type for the resource, or "raw" if not
* applicable.
* @param {*} data The value of the resource.
*/lib.resource.add=function(name,type,data){lib.resource.resources_[name]={type:type,name:name,data:data};};/**
* Retrieve a resource record.
*
* The resource data is stored on the "data" property of the returned object.
*
* @param {string} name The name of the resource to get.
* @param {*} opt_defaultValue The optional value to return if the resource is
* not defined.
* @return {object} An object with "type", "name", and "data" properties.
*/lib.resource.get=function(name,opt_defaultValue){if(!(name in lib.resource.resources_)){if(typeof opt_defaultValue=='undefined')throw'Unknown resource: '+name;return opt_defaultValue;}return lib.resource.resources_[name];};/**
* Retrieve resource data.
*
* @param {string} name The name of the resource to get.
* @param {*} opt_defaultValue The optional value to return if the resource is
* not defined.
* @return {*} The resource data.
*/lib.resource.getData=function(name,opt_defaultValue){if(!(name in lib.resource.resources_)){if(typeof opt_defaultValue=='undefined')throw'Unknown resource: '+name;return opt_defaultValue;}return lib.resource.resources_[name].data;};/**
* Retrieve resource as a data: url.
*
* @param {string} name The name of the resource to get.
* @param {*} opt_defaultValue The optional value to return if the resource is
* not defined.
* @return {*} A data: url encoded version of the resource.
*/lib.resource.getDataUrl=function(name,opt_defaultValue){var resource=lib.resource.get(name,opt_defaultValue);return'data:'+resource.type+','+resource.data;};// SOURCE FILE: libdot/js/lib_storage.js
// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* Namespace for implementations of persistent, possibly cloud-backed
* storage.
*/lib.Storage=new Object();// SOURCE FILE: libdot/js/lib_storage_chrome.js
// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* chrome.storage based class with an async interface that is interchangeable
* with other lib.Storage.* implementations.
*/lib.Storage.Chrome=function(storage){this.storage_=storage;this.observers_=[];chrome.storage.onChanged.addListener(this.onChanged_.bind(this));};/**
* Called by the storage implementation when the storage is modified.
*/lib.Storage.Chrome.prototype.onChanged_=function(changes,areaname){if(chrome.storage[areaname]!=this.storage_)return;for(var i=0;i<this.observers_.length;i++){this.observers_[i](changes);}};/**
* Register a function to observe storage changes.
*
* @param {function(map)} callback The function to invoke when the storage
* changes.
*/lib.Storage.Chrome.prototype.addObserver=function(callback){this.observers_.push(callback);};/**
* Unregister a change observer.
*
* @param {function} observer A previously registered callback.
*/lib.Storage.Chrome.prototype.removeObserver=function(callback){var i=this.observers_.indexOf(callback);if(i!=-1)this.observers_.splice(i,1);};/**
* Delete everything in this storage.
*
* @param {function(map)} callback The function to invoke when the delete
* has completed.
*/lib.Storage.Chrome.prototype.clear=function(opt_callback){this.storage_.clear();if(opt_callback)setTimeout(opt_callback,0);};/**
* Return the current value of a storage item.
*
* @param {string} key The key to look up.
* @param {function(value) callback The function to invoke when the value has
* been retrieved.
*/lib.Storage.Chrome.prototype.getItem=function(key,callback){this.storage_.get(key,callback);};/**
* Fetch the values of multiple storage items.
*
* @param {Array} keys The keys to look up.
* @param {function(map) callback The function to invoke when the values have
* been retrieved.
*/lib.Storage.Chrome.prototype.getItems=function(keys,callback){this.storage_.get(keys,callback);};/**
* Set a value in storage.
*
* @param {string} key The key for the value to be stored.
* @param {*} value The value to be stored. Anything that can be serialized
* with JSON is acceptable.
* @param {function()} opt_callback Optional function to invoke when the
* set is complete. You don't have to wait for the set to complete in order
* to read the value, since the local cache is updated synchronously.
*/lib.Storage.Chrome.prototype.setItem=function(key,value,opt_callback){var _this4=this;var onComplete=function onComplete(){var err=lib.f.lastError();if(err){// Doesn't seem to be any better way of handling this.
// https://crbug.com/764759
if(err.indexOf('MAX_WRITE_OPERATIONS')){console.warn("Will retry save of ".concat(key," after exceeding quota: ").concat(err));setTimeout(function(){return _this4.setItem(key,value,onComplete);},1000);return;}else{console.error("Unknown runtime error: ".concat(err));}}if(opt_callback)opt_callback();};var obj={};obj[key]=value;this.storage_.set(obj,onComplete);};/**
* Set multiple values in storage.
*
* @param {Object} map A map of key/values to set in storage.
* @param {function()} opt_callback Optional function to invoke when the
* set is complete. You don't have to wait for the set to complete in order
* to read the value, since the local cache is updated synchronously.
*/lib.Storage.Chrome.prototype.setItems=function(obj,opt_callback){this.storage_.set(obj,opt_callback);};/**
* Remove an item from storage.
*
* @param {string} key The key to be removed.
* @param {function()} opt_callback Optional function to invoke when the
* remove is complete. You don't have to wait for the set to complete in
* order to read the value, since the local cache is updated synchronously.
*/lib.Storage.Chrome.prototype.removeItem=function(key,opt_callback){this.storage_.remove(key,opt_callback);};/**
* Remove multiple items from storage.
*
* @param {Array} keys The keys to be removed.
* @param {function()} opt_callback Optional function to invoke when the
* remove is complete. You don't have to wait for the set to complete in
* order to read the value, since the local cache is updated synchronously.
*/lib.Storage.Chrome.prototype.removeItems=function(keys,opt_callback){this.storage_.remove(keys,opt_callback);};// SOURCE FILE: libdot/js/lib_storage_local.js
// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* window.localStorage based class with an async interface that is
* interchangeable with other lib.Storage.* implementations.
*/lib.Storage.Local=function(){this.observers_=[];this.storage_=window.localStorage;window.addEventListener('storage',this.onStorage_.bind(this));};/**
* Called by the storage implementation when the storage is modified.
*/lib.Storage.Local.prototype.onStorage_=function(e){if(e.storageArea!=this.storage_)return;// JS throws an exception if JSON.parse is given an empty string. So here we
// only parse if the value is truthy. This mean the empty string, undefined
// and null will not be parsed.
var prevValue=e.oldValue?JSON.parse(e.oldValue):e.oldValue;var curValue=e.newValue?JSON.parse(e.newValue):e.newValue;var o={};o[e.key]={oldValue:prevValue,newValue:curValue};for(var i=0;i<this.observers_.length;i++){this.observers_[i](o);}};/**
* Register a function to observe storage changes.
*
* @param {function(map)} callback The function to invoke when the storage
* changes.
*/lib.Storage.Local.prototype.addObserver=function(callback){this.observers_.push(callback);};/**
* Unregister a change observer.
*
* @param {function} observer A previously registered callback.
*/lib.Storage.Local.prototype.removeObserver=function(callback){var i=this.observers_.indexOf(callback);if(i!=-1)this.observers_.splice(i,1);};/**
* Delete everything in this storage.
*
* @param {function(map)} callback The function to invoke when the delete
* has completed.
*/lib.Storage.Local.prototype.clear=function(opt_callback){this.storage_.clear();if(opt_callback)setTimeout(opt_callback,0);};/**
* Return the current value of a storage item.
*
* @param {string} key The key to look up.
* @param {function(value) callback The function to invoke when the value has
* been retrieved.
*/lib.Storage.Local.prototype.getItem=function(key,callback){var value=this.storage_.getItem(key);if(typeof value=='string'){try{value=JSON.parse(value);}catch(e){// If we can't parse the value, just return it unparsed.
}}setTimeout(callback.bind(null,value),0);};/**
* Fetch the values of multiple storage items.
*
* @param {Array} keys The keys to look up.
* @param {function(map) callback The function to invoke when the values have
* been retrieved.
*/lib.Storage.Local.prototype.getItems=function(keys,callback){var rv={};for(var i=keys.length-1;i>=0;i--){var key=keys[i];var value=this.storage_.getItem(key);if(typeof value=='string'){try{rv[key]=JSON.parse(value);}catch(e){// If we can't parse the value, just return it unparsed.
rv[key]=value;}}else{keys.splice(i,1);}}setTimeout(callback.bind(null,rv),0);};/**
* Set a value in storage.
*
* @param {string} key The key for the value to be stored.
* @param {*} value The value to be stored. Anything that can be serialized
* with JSON is acceptable.
* @param {function()} opt_callback Optional function to invoke when the
* set is complete. You don't have to wait for the set to complete in order
* to read the value, since the local cache is updated synchronously.
*/lib.Storage.Local.prototype.setItem=function(key,value,opt_callback){this.storage_.setItem(key,JSON.stringify(value));if(opt_callback)setTimeout(opt_callback,0);};/**
* Set multiple values in storage.
*
* @param {Object} map A map of key/values to set in storage.
* @param {function()} opt_callback Optional function to invoke when the
* set is complete. You don't have to wait for the set to complete in order
* to read the value, since the local cache is updated synchronously.
*/lib.Storage.Local.prototype.setItems=function(obj,opt_callback){for(var key in obj){this.storage_.setItem(key,JSON.stringify(obj[key]));}if(opt_callback)setTimeout(opt_callback,0);};/**
* Remove an item from storage.
*
* @param {string} key The key to be removed.
* @param {function()} opt_callback Optional function to invoke when the
* remove is complete. You don't have to wait for the set to complete in
* order to read the value, since the local cache is updated synchronously.
*/lib.Storage.Local.prototype.removeItem=function(key,opt_callback){this.storage_.removeItem(key);if(opt_callback)setTimeout(opt_callback,0);};/**
* Remove multiple items from storage.
*
* @param {Array} keys The keys to be removed.
* @param {function()} opt_callback Optional function to invoke when the
* remove is complete. You don't have to wait for the set to complete in
* order to read the value, since the local cache is updated synchronously.
*/lib.Storage.Local.prototype.removeItems=function(ary,opt_callback){for(var i=0;i<ary.length;i++){this.storage_.removeItem(ary[i]);}if(opt_callback)setTimeout(opt_callback,0);};// SOURCE FILE: libdot/js/lib_storage_memory.js
// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* In-memory storage class with an async interface that is interchangeable with
* other lib.Storage.* implementations.
*/lib.Storage.Memory=function(){this.observers_=[];this.storage_={};};/**
* Register a function to observe storage changes.
*
* @param {function(map)} callback The function to invoke when the storage
* changes.
*/lib.Storage.Memory.prototype.addObserver=function(callback){this.observers_.push(callback);};/**
* Unregister a change observer.
*
* @param {function} observer A previously registered callback.
*/lib.Storage.Memory.prototype.removeObserver=function(callback){var i=this.observers_.indexOf(callback);if(i!=-1)this.observers_.splice(i,1);};/**
* Delete everything in this storage.
*
* @param {function(map)} callback The function to invoke when the delete
* has completed.
*/lib.Storage.Memory.prototype.clear=function(opt_callback){var e={};for(var key in this.storage_){e[key]={oldValue:this.storage_[key],newValue:void 0};}this.storage_={};setTimeout(function(){for(var i=0;i<this.observers_.length;i++){this.observers_[i](e);}}.bind(this),0);if(opt_callback)setTimeout(opt_callback,0);};/**
* Return the current value of a storage item.
*
* @param {string} key The key to look up.
* @param {function(value) callback The function to invoke when the value has
* been retrieved.
*/lib.Storage.Memory.prototype.getItem=function(key,callback){var value=this.storage_[key];if(typeof value=='string'){try{value=JSON.parse(value);}catch(e){// If we can't parse the value, just return it unparsed.
}}setTimeout(callback.bind(null,value),0);};/**
* Fetch the values of multiple storage items.
*
* @param {Array} keys The keys to look up.
* @param {function(map) callback The function to invoke when the values have
* been retrieved.
*/lib.Storage.Memory.prototype.getItems=function(keys,callback){var rv={};for(var i=keys.length-1;i>=0;i--){var key=keys[i];var value=this.storage_[key];if(typeof value=='string'){try{rv[key]=JSON.parse(value);}catch(e){// If we can't parse the value, just return it unparsed.
rv[key]=value;}}else{keys.splice(i,1);}}setTimeout(callback.bind(null,rv),0);};/**
* Set a value in storage.
*
* @param {string} key The key for the value to be stored.
* @param {*} value The value to be stored. Anything that can be serialized
* with JSON is acceptable.
* @param {function()} opt_callback Optional function to invoke when the
* set is complete. You don't have to wait for the set to complete in order
* to read the value, since the local cache is updated synchronously.
*/lib.Storage.Memory.prototype.setItem=function(key,value,opt_callback){var oldValue=this.storage_[key];this.storage_[key]=JSON.stringify(value);var e={};e[key]={oldValue:oldValue,newValue:value};setTimeout(function(){for(var i=0;i<this.observers_.length;i++){this.observers_[i](e);}}.bind(this),0);if(opt_callback)setTimeout(opt_callback,0);};/**
* Set multiple values in storage.
*
* @param {Object} map A map of key/values to set in storage.
* @param {function()} opt_callback Optional function to invoke when the
* set is complete. You don't have to wait for the set to complete in order
* to read the value, since the local cache is updated synchronously.
*/lib.Storage.Memory.prototype.setItems=function(obj,opt_callback){var e={};for(var key in obj){e[key]={oldValue:this.storage_[key],newValue:obj[key]};this.storage_[key]=JSON.stringify(obj[key]);}setTimeout(function(){for(var i=0;i<this.observers_.length;i++){this.observers_[i](e);}}.bind(this));if(opt_callback)setTimeout(opt_callback,0);};/**
* Remove an item from storage.
*
* @param {string} key The key to be removed.
* @param {function()} opt_callback Optional function to invoke when the
* remove is complete. You don't have to wait for the set to complete in
* order to read the value, since the local cache is updated synchronously.
*/lib.Storage.Memory.prototype.removeItem=function(key,opt_callback){delete this.storage_[key];if(opt_callback)setTimeout(opt_callback,0);};/**
* Remove multiple items from storage.
*
* @param {Array} keys The keys to be removed.
* @param {function()} opt_callback Optional function to invoke when the
* remove is complete. You don't have to wait for the set to complete in
* order to read the value, since the local cache is updated synchronously.
*/lib.Storage.Memory.prototype.removeItems=function(ary,opt_callback){for(var i=0;i<ary.length;i++){delete this.storage_[ary[i]];}if(opt_callback)setTimeout(opt_callback,0);};// SOURCE FILE: libdot/third_party/fast-text-encoding/text.js
/*
* Copyright 2017 Sam Thorogood. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/ /**
* @fileoverview Polyfill for TextEncoder and TextDecoder.
*
* You probably want `text.min.js`, and not this file directly.
*/(function(scope){'use strict';// fail early
if(scope['TextEncoder']&&scope['TextDecoder']){return false;}/**
* @constructor
* @param {string=} utfLabel
*/function FastTextEncoder(){var utfLabel=arguments.length>0&&arguments[0]!==undefined?arguments[0]:'utf-8';if(utfLabel!=='utf-8'){throw new RangeError("Failed to construct 'TextEncoder': The encoding label provided ('".concat(utfLabel,"') is invalid."));}}Object.defineProperty(FastTextEncoder.prototype,'encoding',{value:'utf-8'});/**
* @param {string} string
* @param {{stream: boolean}=} options
* @return {!Uint8Array}
*/FastTextEncoder.prototype.encode=function(string){var options=arguments.length>1&&arguments[1]!==undefined?arguments[1]:{stream:false};if(options.stream){throw new Error("Failed to encode: the 'stream' option is unsupported.");}var pos=0;var len=string.length;var out=[];var at=0;// output position
var tlen=Math.max(32,len+(len>>1)+7);// 1.5x size
var target=new Uint8Array(tlen>>3<<3);// ... but at 8 byte offset
while(pos<len){var value=string.charCodeAt(pos++);if(value>=0xd800&&value<=0xdbff){// high surrogate
if(pos<len){var extra=string.charCodeAt(pos);if((extra&0xfc00)===0xdc00){++pos;value=((value&0x3ff)<<10)+(extra&0x3ff)+0x10000;}}if(value>=0xd800&&value<=0xdbff){continue;// drop lone surrogate
}}// expand the buffer if we couldn't write 4 bytes
if(at+4>target.length){tlen+=8;// minimum extra
tlen*=1.0+pos/string.length*2;// take 2x the remaining
tlen=tlen>>3<<3;// 8 byte offset
var update=new Uint8Array(tlen);update.set(target);target=update;}if((value&0xffffff80)===0){// 1-byte
target[at++]=value;// ASCII
continue;}else if((value&0xfffff800)===0){// 2-byte
target[at++]=value>>6&0x1f|0xc0;}else if((value&0xffff0000)===0){// 3-byte
target[at++]=value>>12&0x0f|0xe0;target[at++]=value>>6&0x3f|0x80;}else if((value&0xffe00000)===0){// 4-byte
target[at++]=value>>18&0x07|0xf0;target[at++]=value>>12&0x3f|0x80;target[at++]=value>>6&0x3f|0x80;}else{// FIXME: do we care
continue;}target[at++]=value&0x3f|0x80;}return target.slice(0,at);};/**
* @constructor
* @param {string=} utfLabel
* @param {{fatal: boolean}=} options
*/function FastTextDecoder(){var utfLabel=arguments.length>0&&arguments[0]!==undefined?arguments[0]:'utf-8';var options=arguments.length>1&&arguments[1]!==undefined?arguments[1]:{fatal:false};if(utfLabel!=='utf-8'){throw new RangeError("Failed to construct 'TextDecoder': The encoding label provided ('".concat(utfLabel,"') is invalid."));}if(options.fatal){throw new Error("Failed to construct 'TextDecoder': the 'fatal' option is unsupported.");}}Object.defineProperty(FastTextDecoder.prototype,'encoding',{value:'utf-8'});Object.defineProperty(FastTextDecoder.prototype,'fatal',{value:false});Object.defineProperty(FastTextDecoder.prototype,'ignoreBOM',{value:false});/**
* @param {(!ArrayBuffer|!ArrayBufferView)} buffer
* @param {{stream: boolean}=} options
*/FastTextDecoder.prototype.decode=function(buffer){var options=arguments.length>1&&arguments[1]!==undefined?arguments[1]:{stream:false};if(options['stream']){throw new Error("Failed to decode: the 'stream' option is unsupported.");}var bytes=new Uint8Array(buffer);var pos=0;var len=bytes.length;var out=[];while(pos<len){var byte1=bytes[pos++];if(byte1===0){break;// NULL
}if((byte1&0x80)===0){// 1-byte
out.push(byte1);}else if((byte1&0xe0)===0xc0){// 2-byte
var byte2=bytes[pos++]&0x3f;out.push((byte1&0x1f)<<6|byte2);}else if((byte1&0xf0)===0xe0){var _byte=bytes[pos++]&0x3f;var byte3=bytes[pos++]&0x3f;out.push((byte1&0x1f)<<12|_byte<<6|byte3);}else if((byte1&0xf8)===0xf0){var _byte2=bytes[pos++]&0x3f;var _byte3=bytes[pos++]&0x3f;var byte4=bytes[pos++]&0x3f;// this can be > 0xffff, so possibly generate surrogates
var codepoint=(byte1&0x07)<<0x12|_byte2<<0x0c|_byte3<<0x06|byte4;if(codepoint>0xffff){// codepoint &= ~0x10000;
codepoint-=0x10000;out.push(codepoint>>>10&0x3ff|0xd800);codepoint=0xdc00|codepoint&0x3ff;}out.push(codepoint);}else{// FIXME: we're ignoring this
}}return String.fromCharCode.apply(null,out);};scope['TextEncoder']=FastTextEncoder;scope['TextDecoder']=FastTextDecoder;})(typeof window!=='undefined'?window:typeof global!=='undefined'?global:void 0);// SOURCE FILE: libdot/third_party/wcwidth/lib_wc.js
// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
// Use of lib.wc source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* This JavaScript library is ported from the wcwidth.js module of node.js.
* The original implementation can be found at:
* https://npmjs.org/package/wcwidth.js
*/ /**
* JavaScript porting of Markus Kuhn's wcwidth() implementation
*
* The following explanation comes from the original C implementation:
*
* This is an implementation of wcwidth() and wcswidth() (defined in
* IEEE Std 1002.1-2001) for Unicode.
*
* http://www.opengroup.org/onlinepubs/007904975/functions/wcwidth.html
* http://www.opengroup.org/onlinepubs/007904975/functions/wcswidth.html
*
* In fixed-width output devices, Latin characters all occupy a single
* "cell" position of equal width, whereas ideographic CJK characters
* occupy two such cells. Interoperability between terminal-line
* applications and (teletype-style) character terminals using the
* UTF-8 encoding requires agreement on which character should advance
* the cursor by how many cell positions. No established formal
* standards exist at present on which Unicode character shall occupy
* how many cell positions on character terminals. These routines are
* a first attempt of defining such behavior based on simple rules
* applied to data provided by the Unicode Consortium.
*
* For some graphical characters, the Unicode standard explicitly
* defines a character-cell width via the definition of the East Asian
* FullWidth (F), Wide (W), Half-width (H), and Narrow (Na) classes.
* In all these cases, there is no ambiguity about which width a
* terminal shall use. For characters in the East Asian Ambiguous (A)
* class, the width choice depends purely on a preference of backward
* compatibility with either historic CJK or Western practice.
* Choosing single-width for these characters is easy to justify as
* the appropriate long-term solution, as the CJK practice of
* displaying these characters as double-width comes from historic
* implementation simplicity (8-bit encoded characters were displayed
* single-width and 16-bit ones double-width, even for Greek,
* Cyrillic, etc.) and not any typographic considerations.
*
* Much less clear is the choice of width for the Not East Asian
* (Neutral) class. Existing practice does not dictate a width for any
* of these characters. It would nevertheless make sense
* typographically to allocate two character cells to characters such
* as for instance EM SPACE or VOLUME INTEGRAL, which cannot be
* represented adequately with a single-width glyph. The following
* routines at present merely assign a single-cell width to all
* neutral characters, in the interest of simplicity. This is not
* entirely satisfactory and should be reconsidered before
* establishing a formal standard in lib.wc area. At the moment, the
* decision which Not East Asian (Neutral) characters should be
* represented by double-width glyphs cannot yet be answered by
* applying a simple rule from the Unicode database content. Setting
* up a proper standard for the behavior of UTF-8 character terminals
* will require a careful analysis not only of each Unicode character,
* but also of each presentation form, something the author of these
* routines has avoided to do so far.
*
* http://www.unicode.org/unicode/reports/tr11/
*
* Markus Kuhn -- 2007-05-26 (Unicode 5.0)
*
* Permission to use, copy, modify, and distribute lib.wc software
* for any purpose and without fee is hereby granted. The author
* disclaims all warranties with regard to lib.wc software.
*
* Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
*/ /**
* The following function defines the column width of an ISO 10646 character
* as follows:
*
* - The null character (U+0000) has a column width of 0.
* - Other C0/C1 control characters and DEL will lead to a return value of -1.
* - Non-spacing and enclosing combining characters (general category code Mn
* or Me in the Unicode database) have a column width of 0.
* - SOFT HYPHEN (U+00AD) has a column width of 1.
* - Other format characters (general category code Cf in the Unicode database)
* and ZERO WIDTH SPACE (U+200B) have a column width of 0.
* - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF) have a
* column width of 0.
* - Spacing characters in the East Asian Wide (W) or East Asian Full-width (F)
* category as defined in Unicode Technical Report #11 have a column width of
* 2.
* - East Asian Ambiguous characters are taken into account if
* regardCjkAmbiguous flag is enabled. They have a column width of 2.
* - All remaining characters (including all printable ISO 8859-1 and WGL4
* characters, Unicode control characters, etc.) have a column width of 1.
*
* This implementation assumes that characters are encoded in ISO 10646.
*/lib.wc={};// Width of a nul character.
lib.wc.nulWidth=0;// Width of a control character.
lib.wc.controlWidth=0;// Flag whether to consider East Asian Ambiguous characters.
lib.wc.regardCjkAmbiguous=false;// Width of an East Asian Ambiguous character.
lib.wc.cjkAmbiguousWidth=2;// Sorted list of non-overlapping intervals of non-spacing characters
// generated by the `./ranges.py` helper.
lib.wc.combining=[[0x00ad,0x00ad],[0x0300,0x036f],[0x0483,0x0489],[0x0591,0x05bd],[0x05bf,0x05bf],[0x05c1,0x05c2],[0x05c4,0x05c5],[0x05c7,0x05c7],[0x0610,0x061a],[0x061c,0x061c],[0x064b,0x065f],[0x0670,0x0670],[0x06d6,0x06dc],[0x06df,0x06e4],[0x06e7,0x06e8],[0x06ea,0x06ed],[0x0711,0x0711],[0x0730,0x074a],[0x07a6,0x07b0],[0x07eb,0x07f3],[0x07fd,0x07fd],[0x0816,0x0819],[0x081b,0x0823],[0x0825,0x0827],[0x0829,0x082d],[0x0859,0x085b],[0x08d3,0x08e1],[0x08e3,0x0902],[0x093a,0x093a],[0x093c,0x093c],[0x0941,0x0948],[0x094d,0x094d],[0x0951,0x0957],[0x0962,0x0963],[0x0981,0x0981],[0x09bc,0x09bc],[0x09c1,0x09c4],[0x09cd,0x09cd],[0x09e2,0x09e3],[0x09fe,0x09fe],[0x0a01,0x0a02],[0x0a3c,0x0a3c],[0x0a41,0x0a42],[0x0a47,0x0a48],[0x0a4b,0x0a4d],[0x0a51,0x0a51],[0x0a70,0x0a71],[0x0a75,0x0a75],[0x0a81,0x0a82],[0x0abc,0x0abc],[0x0ac1,0x0ac5],[0x0ac7,0x0ac8],[0x0acd,0x0acd],[0x0ae2,0x0ae3],[0x0afa,0x0aff],[0x0b01,0x0b01],[0x0b3c,0x0b3c],[0x0b3f,0x0b3f],[0x0b41,0x0b44],[0x0b4d,0x0b4d],[0x0b56,0x0b56],[0x0b62,0x0b63],[0x0b82,0x0b82],[0x0bc0,0x0bc0],[0x0bcd,0x0bcd],[0x0c00,0x0c00],[0x0c04,0x0c04],[0x0c3e,0x0c40],[0x0c46,0x0c48],[0x0c4a,0x0c4d],[0x0c55,0x0c56],[0x0c62,0x0c63],[0x0c81,0x0c81],[0x0cbc,0x0cbc],[0x0cbf,0x0cbf],[0x0cc6,0x0cc6],[0x0ccc,0x0ccd],[0x0ce2,0x0ce3],[0x0d00,0x0d01],[0x0d3b,0x0d3c],[0x0d41,0x0d44],[0x0d4d,0x0d4d],[0x0d62,0x0d63],[0x0dca,0x0dca],[0x0dd2,0x0dd4],[0x0dd6,0x0dd6],[0x0e31,0x0e31],[0x0e34,0x0e3a],[0x0e47,0x0e4e],[0x0eb1,0x0eb1],[0x0eb4,0x0eb9],[0x0ebb,0x0ebc],[0x0ec8,0x0ecd],[0x0f18,0x0f19],[0x0f35,0x0f35],[0x0f37,0x0f37],[0x0f39,0x0f39],[0x0f71,0x0f7e],[0x0f80,0x0f84],[0x0f86,0x0f87],[0x0f8d,0x0f97],[0x0f99,0x0fbc],[0x0fc6,0x0fc6],[0x102d,0x1030],[0x1032,0x1037],[0x1039,0x103a],[0x103d,0x103e],[0x1058,0x1059],[0x105e,0x1060],[0x1071,0x1074],[0x1082,0x1082],[0x1085,0x1086],[0x108d,0x108d],[0x109d,0x109d],[0x1160,0x11ff],[0x135d,0x135f],[0x1712,0x1714],[0x1732,0x1734],[0x1752,0x1753],[0x1772,0x1773],[0x17b4,0x17b5],[0x17b7,0x17bd],[0x17c6,0x17c6],[0x17c9,0x17d3],[0x17dd,0x17dd],[0x180b,0x180e],[0x1885,0x1886],[0x18a9,0x18a9],[0x1920,0x1922],[0x1927,0x1928],[0x1932,0x1932],[0x1939,0x193b],[0x1a17,0x1a18],[0x1a1b,0x1a1b],[0x1a56,0x1a56],[0x1a58,0x1a5e],[0x1a60,0x1a60],[0x1a62,0x1a62],[0x1a65,0x1a6c],[0x1a73,0x1a7c],[0x1a7f,0x1a7f],[0x1ab0,0x1abe],[0x1b00,0x1b03],[0x1b34,0x1b34],[0x1b36,0x1b3a],[0x1b3c,0x1b3c],[0x1b42,0x1b42],[0x1b6b,0x1b73],[0x1b80,0x1b81],[0x1ba2,0x1ba5],[0x1ba8,0x1ba9],[0x1bab,0x1bad],[0x1be6,0x1be6],[0x1be8,0x1be9],[0x1bed,0x1bed],[0x1bef,0x1bf1],[0x1c2c,0x1c33],[0x1c36,0x1c37],[0x1cd0,0x1cd2],[0x1cd4,0x1ce0],[0x1ce2,0x1ce8],[0x1ced,0x1ced],[0x1cf4,0x1cf4],[0x1cf8,0x1cf9],[0x1dc0,0x1df9],[0x1dfb,0x1dff],[0x200b,0x200f],[0x202a,0x202e],[0x2060,0x2064],[0x2066,0x206f],[0x20d0,0x20f0],[0x2cef,0x2cf1],[0x2d7f,0x2d7f],[0x2de0,0x2dff],[0x302a,0x302d],[0x3099,0x309a],[0xa66f,0xa672],[0xa674,0xa67d],[0xa69e,0xa69f],[0xa6f0,0xa6f1],[0xa802,0xa802],[0xa806,0xa806],[0xa80b,0xa80b],[0xa825,0xa826],[0xa8c4,0xa8c5],[0xa8e0,0xa8f1],[0xa8ff,0xa8ff],[0xa926,0xa92d],[0xa947,0xa951],[0xa980,0xa982],[0xa9b3,0xa9b3],[0xa9b6,0xa9b9],[0xa9bc,0xa9bc],[0xa9e5,0xa9e5],[0xaa29,0xaa2e],[0xaa31,0xaa32],[0xaa35,0xaa36],[0xaa43,0xaa43],[0xaa4c,0xaa4c],[0xaa7c,0xaa7c],[0xaab0,0xaab0],[0xaab2,0xaab4],[0xaab7,0xaab8],[0xaabe,0xaabf],[0xaac1,0xaac1],[0xaaec,0xaaed],[0xaaf6,0xaaf6],[0xabe5,0xabe5],[0xabe8,0xabe8],[0xabed,0xabed],[0xfb1e,0xfb1e],[0xfe00,0xfe0f],[0xfe20,0xfe2f],[0xfeff,0xfeff],[0xfff9,0xfffb],[0x101fd,0x101fd],[0x102e0,0x102e0],[0x10376,0x1037a],[0x10a01,0x10a03],[0x10a05,0x10a06],[0x10a0c,0x10a0f],[0x10a38,0x10a3a],[0x10a3f,0x10a3f],[0x10ae5,0x10ae6],[0x10d24,0x10d27],[0x10f46,0x10f50],[0x11001,0x11001],[0x11038,0x11046],[0x1107f,0x11081],[0x110b3,0x110b6],[0x110b9,0x110ba],[0x11100,0x11102],[0x11127,0x1112b],[0x1112d,0x11134],[0x11173,0x11173],[0x11180,0x11181],[0x111b6,0x111be],[0x111c9,0x111cc],[0x1122f,0x11231],[0x11234,0x11234],[0x11236,0x11237],[0x1123e,0x1123e],[0x112df,0x112df],[0x112e3,0x112ea],[0x11300,0x11301],[0x1133b,0x1133c],[0x11340,0x11340],[0x11366,0x1136c],[0x11370,0x11374],[0x11438,0x1143f],[0x11442,0x11444],[0x11446,0x11446],[0x1145e,0x1145e],[0x114b3,0x114b8],[0x114ba,0x114ba],[0x114bf,0x114c0],[0x114c2,0x114c3],[0x115b2,0x115b5],[0x115bc,0x115bd],[0x115bf,0x115c0],[0x115dc,0x115dd],[0x11633,0x1163a],[0x1163d,0x1163d],[0x1163f,0x11640],[0x116ab,0x116ab],[0x116ad,0x116ad],[0x116b0,0x116b5],[0x116b7,0x116b7],[0x1171d,0x1171f],[0x11722,0x11725],[0x11727,0x1172b],[0x1182f,0x11837],[0x11839,0x1183a],[0x11a01,0x11a0a],[0x11a33,0x11a38],[0x11a3b,0x11a3e],[0x11a47,0x11a47],[0x11a51,0x11a56],[0x11a59,0x11a5b],[0x11a8a,0x11a96],[0x11a98,0x11a99],[0x11c30,0x11c36],[0x11c38,0x11c3d],[0x11c3f,0x11c3f],[0x11c92,0x11ca7],[0x11caa,0x11cb0],[0x11cb2,0x11cb3],[0x11cb5,0x11cb6],[0x11d31,0x11d36],[0x11d3a,0x11d3a],[0x11d3c,0x11d3d],[0x11d3f,0x11d45],[0x11d47,0x11d47],[0x11d90,0x11d91],[0x11d95,0x11d95],[0x11d97,0x11d97],[0x11ef3,0x11ef4],[0x16af0,0x16af4],[0x16b30,0x16b36],[0x16f8f,0x16f92],[0x1bc9d,0x1bc9e],[0x1bca0,0x1bca3],[0x1d167,0x1d169],[0x1d173,0x1d182],[0x1d185,0x1d18b],[0x1d1aa,0x1d1ad],[0x1d242,0x1d244],[0x1da00,0x1da36],[0x1da3b,0x1da6c],[0x1da75,0x1da75],[0x1da84,0x1da84],[0x1da9b,0x1da9f],[0x1daa1,0x1daaf],[0x1e000,0x1e006],[0x1e008,0x1e018],[0x1e01b,0x1e021],[0x1e023,0x1e024],[0x1e026,0x1e02a],[0x1e8d0,0x1e8d6],[0x1e944,0x1e94a],[0xe0001,0xe0001],[0xe0020,0xe007f],[0xe0100,0xe01ef]];// Sorted list of non-overlapping intervals of East Asian Ambiguous characters
// generated by the `./ranges.py` helper.
lib.wc.ambiguous=[[0x00a1,0x00a1],[0x00a4,0x00a4],[0x00a7,0x00a8],[0x00aa,0x00aa],[0x00ad,0x00ae],[0x00b0,0x00b4],[0x00b6,0x00ba],[0x00bc,0x00bf],[0x00c6,0x00c6],[0x00d0,0x00d0],[0x00d7,0x00d8],[0x00de,0x00e1],[0x00e6,0x00e6],[0x00e8,0x00ea],[0x00ec,0x00ed],[0x00f0,0x00f0],[0x00f2,0x00f3],[0x00f7,0x00fa],[0x00fc,0x00fc],[0x00fe,0x00fe],[0x0101,0x0101],[0x0111,0x0111],[0x0113,0x0113],[0x011b,0x011b],[0x0126,0x0127],[0x012b,0x012b],[0x0131,0x0133],[0x0138,0x0138],[0x013f,0x0142],[0x0144,0x0144],[0x0148,0x014b],[0x014d,0x014d],[0x0152,0x0153],[0x0166,0x0167],[0x016b,0x016b],[0x01ce,0x01ce],[0x01d0,0x01d0],[0x01d2,0x01d2],[0x01d4,0x01d4],[0x01d6,0x01d6],[0x01d8,0x01d8],[0x01da,0x01da],[0x01dc,0x01dc],[0x0251,0x0251],[0x0261,0x0261],[0x02c4,0x02c4],[0x02c7,0x02c7],[0x02c9,0x02cb],[0x02cd,0x02cd],[0x02d0,0x02d0],[0x02d8,0x02db],[0x02dd,0x02dd],[0x02df,0x02df],[0x0300,0x036f],[0x0391,0x03a1],[0x03a3,0x03a9],[0x03b1,0x03c1],[0x03c3,0x03c9],[0x0401,0x0401],[0x0410,0x044f],[0x0451,0x0451],[0x1100,0x115f],[0x2010,0x2010],[0x2013,0x2016],[0x2018,0x2019],[0x201c,0x201d],[0x2020,0x2022],[0x2024,0x2027],[0x2030,0x2030],[0x2032,0x2033],[0x2035,0x2035],[0x203b,0x203b],[0x203e,0x203e],[0x2074,0x2074],[0x207f,0x207f],[0x2081,0x2084],[0x20ac,0x20ac],[0x2103,0x2103],[0x2105,0x2105],[0x2109,0x2109],[0x2113,0x2113],[0x2116,0x2116],[0x2121,0x2122],[0x2126,0x2126],[0x212b,0x212b],[0x2153,0x2154],[0x215b,0x215e],[0x2160,0x216b],[0x2170,0x2179],[0x2189,0x2189],[0x2190,0x2199],[0x21b8,0x21b9],[0x21d2,0x21d2],[0x21d4,0x21d4],[0x21e7,0x21e7],[0x2200,0x2200],[0x2202,0x2203],[0x2207,0x2208],[0x220b,0x220b],[0x220f,0x220f],[0x2211,0x2211],[0x2215,0x2215],[0x221a,0x221a],[0x221d,0x2220],[0x2223,0x2223],[0x2225,0x2225],[0x2227,0x222c],[0x222e,0x222e],[0x2234,0x2237],[0x223c,0x223d],[0x2248,0x2248],[0x224c,0x224c],[0x2252,0x2252],[0x2260,0x2261],[0x2264,0x2267],[0x226a,0x226b],[0x226e,0x226f],[0x2282,0x2283],[0x2286,0x2287],[0x2295,0x2295],[0x2299,0x2299],[0x22a5,0x22a5],[0x22bf,0x22bf],[0x2312,0x2312],[0x231a,0x231b],[0x2329,0x232a],[0x23e9,0x23ec],[0x23f0,0x23f0],[0x23f3,0x23f3],[0x2460,0x24e9],[0x24eb,0x254b],[0x2550,0x2573],[0x2580,0x258f],[0x2592,0x2595],[0x25a0,0x25a1],[0x25a3,0x25a9],[0x25b2,0x25b3],[0x25b6,0x25b7],[0x25bc,0x25bd],[0x25c0,0x25c1],[0x25c6,0x25c8],[0x25cb,0x25cb],[0x25ce,0x25d1],[0x25e2,0x25e5],[0x25ef,0x25ef],[0x25fd,0x25fe],[0x2605,0x2606],[0x2609,0x2609],[0x260e,0x260f],[0x2614,0x2615],[0x261c,0x261c],[0x261e,0x261e],[0x2640,0x2640],[0x2642,0x2642],[0x2648,0x2653],[0x2660,0x2661],[0x2663,0x2665],[0x2667,0x266a],[0x266c,0x266d],[0x266f,0x266f],[0x267f,0x267f],[0x2693,0x2693],[0x269e,0x269f],[0x26a1,0x26a1],[0x26aa,0x26ab],[0x26bd,0x26bf],[0x26c4,0x26e1],[0x26e3,0x26e3],[0x26e8,0x26ff],[0x2705,0x2705],[0x270a,0x270b],[0x2728,0x2728],[0x273d,0x273d],[0x274c,0x274c],[0x274e,0x274e],[0x2753,0x2755],[0x2757,0x2757],[0x2776,0x277f],[0x2795,0x2797],[0x27b0,0x27b0],[0x27bf,0x27bf],[0x2b1b,0x2b1c],[0x2b50,0x2b50],[0x2b55,0x2b59],[0x2e80,0x2fdf],[0x2ff0,0x303e],[0x3040,0x4dbf],[0x4e00,0xa4cf],[0xa960,0xa97f],[0xac00,0xd7a3],[0xe000,0xfaff],[0xfe00,0xfe19],[0xfe30,0xfe6f],[0xff01,0xff60],[0xffe0,0xffe6],[0xfffd,0xfffd],[0x16fe0,0x16fe1],[0x17000,0x18aff],[0x1b000,0x1b12f],[0x1b170,0x1b2ff],[0x1f004,0x1f004],[0x1f0cf,0x1f0cf],[0x1f100,0x1f10a],[0x1f110,0x1f12d],[0x1f130,0x1f169],[0x1f170,0x1f1ac],[0x1f200,0x1f202],[0x1f210,0x1f23b],[0x1f240,0x1f248],[0x1f250,0x1f251],[0x1f260,0x1f265],[0x1f300,0x1f320],[0x1f32d,0x1f335],[0x1f337,0x1f37c],[0x1f37e,0x1f393],[0x1f3a0,0x1f3ca],[0x1f3cf,0x1f3d3],[0x1f3e0,0x1f3f0],[0x1f3f4,0x1f3f4],[0x1f3f8,0x1f43e],[0x1f440,0x1f440],[0x1f442,0x1f4fc],[0x1f4ff,0x1f53d],[0x1f54b,0x1f54e],[0x1f550,0x1f567],[0x1f57a,0x1f57a],[0x1f595,0x1f596],[0x1f5a4,0x1f5a4],[0x1f5fb,0x1f64f],[0x1f680,0x1f6c5],[0x1f6cc,0x1f6cc],[0x1f6d0,0x1f6d2],[0x1f6eb,0x1f6ec],[0x1f6f4,0x1f6f9],[0x1f910,0x1f93e],[0x1f940,0x1f970],[0x1f973,0x1f976],[0x1f97a,0x1f97a],[0x1f97c,0x1f9a2],[0x1f9b0,0x1f9b9],[0x1f9c0,0x1f9c2],[0x1f9d0,0x1f9ff],[0x20000,0x2fffd],[0x30000,0x3fffd],[0xe0100,0xe01ef],[0xf0000,0xffffd],[0x100000,0x10fffd]];// Sorted list of non-overlapping intervals of East Asian Unambiguous characters
// generated by the `./ranges.py` helper.
lib.wc.unambiguous=[[0x1100,0x115f],[0x231a,0x231b],[0x2329,0x232a],[0x23e9,0x23ec],[0x23f0,0x23f0],[0x23f3,0x23f3],[0x25fd,0x25fe],[0x2614,0x2615],[0x2648,0x2653],[0x267f,0x267f],[0x2693,0x2693],[0x26a1,0x26a1],[0x26aa,0x26ab],[0x26bd,0x26be],[0x26c4,0x26c5],[0x26ce,0x26ce],[0x26d4,0x26d4],[0x26ea,0x26ea],[0x26f2,0x26f3],[0x26f5,0x26f5],[0x26fa,0x26fa],[0x26fd,0x26fd],[0x2705,0x2705],[0x270a,0x270b],[0x2728,0x2728],[0x274c,0x274c],[0x274e,0x274e],[0x2753,0x2755],[0x2757,0x2757],[0x2795,0x2797],[0x27b0,0x27b0],[0x27bf,0x27bf],[0x2b1b,0x2b1c],[0x2b50,0x2b50],[0x2b55,0x2b55],[0x2e80,0x2fdf],[0x2ff0,0x303e],[0x3040,0x3247],[0x3250,0x4dbf],[0x4e00,0xa4cf],[0xa960,0xa97f],[0xac00,0xd7a3],[0xf900,0xfaff],[0xfe10,0xfe19],[0xfe30,0xfe6f],[0xff01,0xff60],[0xffe0,0xffe6],[0x16fe0,0x16fe1],[0x17000,0x18aff],[0x1b000,0x1b12f],[0x1b170,0x1b2ff],[0x1f004,0x1f004],[0x1f0cf,0x1f0cf],[0x1f18e,0x1f18e],[0x1f191,0x1f19a],[0x1f200,0x1f202],[0x1f210,0x1f23b],[0x1f240,0x1f248],[0x1f250,0x1f251],[0x1f260,0x1f265],[0x1f300,0x1f320],[0x1f32d,0x1f335],[0x1f337,0x1f37c],[0x1f37e,0x1f393],[0x1f3a0,0x1f3ca],[0x1f3cf,0x1f3d3],[0x1f3e0,0x1f3f0],[0x1f3f4,0x1f3f4],[0x1f3f8,0x1f43e],[0x1f440,0x1f440],[0x1f442,0x1f4fc],[0x1f4ff,0x1f53d],[0x1f54b,0x1f54e],[0x1f550,0x1f567],[0x1f57a,0x1f57a],[0x1f595,0x1f596],[0x1f5a4,0x1f5a4],[0x1f5fb,0x1f64f],[0x1f680,0x1f6c5],[0x1f6cc,0x1f6cc],[0x1f6d0,0x1f6d2],[0x1f6eb,0x1f6ec],[0x1f6f4,0x1f6f9],[0x1f910,0x1f93e],[0x1f940,0x1f970],[0x1f973,0x1f976],[0x1f97a,0x1f97a],[0x1f97c,0x1f9a2],[0x1f9b0,0x1f9b9],[0x1f9c0,0x1f9c2],[0x1f9d0,0x1f9ff],[0x20000,0x2fffd],[0x30000,0x3fffd]];/**
* Binary search to check if the given unicode character is in the table.
*
* @param {integer} ucs A unicode character code.
* @param {Object} table A sorted list of internals to match against.
* @return {boolean} True if the given character is in the table.
*/lib.wc.binaryTableSearch_=function(ucs,table){var min=0,max=table.length-1;var mid;if(ucs<table[min][0]||ucs>table[max][1])return false;while(max>=min){mid=Math.floor((min+max)/2);if(ucs>table[mid][1]){min=mid+1;}else if(ucs<table[mid][0]){max=mid-1;}else{return true;}}return false;};/**
* Binary search to check if the given unicode character is a space character.
*
* @param {integer} ucs A unicode character code.
*
* @return {boolean} True if the given character is a space character; false
* otherwise.
*/lib.wc.isSpace=function(ucs){return lib.wc.binaryTableSearch_(ucs,lib.wc.combining);};/**
* Auxiliary function for checking if the given unicode character is a East
* Asian Ambiguous character.
*
* @param {integer} ucs A unicode character code.
*
* @return {boolean} True if the given character is a East Asian Ambiguous
* character.
*/lib.wc.isCjkAmbiguous=function(ucs){return lib.wc.binaryTableSearch_(ucs,lib.wc.ambiguous);};/**
* Determine the column width of the given character.
*
* @param {integer} ucs A unicode character code.
*
* @return {integer} The column width of the given character.
*/lib.wc.charWidth=function(ucs){if(lib.wc.regardCjkAmbiguous){return lib.wc.charWidthRegardAmbiguous(ucs);}else{return lib.wc.charWidthDisregardAmbiguous(ucs);}};/**
* Determine the column width of the given character without considering East
* Asian Ambiguous characters.
*
* @param {integer} ucs A unicode character code.
*
* @return {integer} The column width of the given character.
*/lib.wc.charWidthDisregardAmbiguous=function(ucs){// Optimize for ASCII characters.
if(ucs<0x7f){if(ucs>=0x20)return 1;else if(ucs==0)return lib.wc.nulWidth;else/* if (ucs < 0x20) */return lib.wc.controlWidth;}// Test for 8-bit control characters.
if(ucs<0xa0)return lib.wc.controlWidth;// Binary search in table of non-spacing characters.
if(lib.wc.isSpace(ucs))return 0;// Binary search in table of wide characters.
return lib.wc.binaryTableSearch_(ucs,lib.wc.unambiguous)?2:1;};/**
* Determine the column width of the given character considering East Asian
* Ambiguous characters.
*
* @param {integer} ucs A unicode character code.
*
* @return {integer} The column width of the given character.
*/lib.wc.charWidthRegardAmbiguous=function(ucs){if(lib.wc.isCjkAmbiguous(ucs))return lib.wc.cjkAmbiguousWidth;return lib.wc.charWidthDisregardAmbiguous(ucs);};/**
* Determine the column width of the given string.
*
* @param {string} str A string.
*
* @return {integer} The column width of the given string.
*/lib.wc.strWidth=function(str){var width,rv=0;for(var i=0;i<str.length;){var codePoint=str.codePointAt(i);width=lib.wc.charWidth(codePoint);if(width<0)return-1;rv+=width;i+=codePoint<=0xffff?1:2;}return rv;};/**
* Get the substring at the given column offset of the given column width.
*
* @param {string} str The string to get substring from.
* @param {integer} start The starting column offset to get substring.
* @param {integer} opt_width The column width of the substring.
*
* @return {string} The substring.
*/lib.wc.substr=function(str,start,opt_width){var startIndex=0;var endIndex,width;// Fun edge case: Normally we associate zero width codepoints (like combining
// characters) with the previous codepoint, so we skip any leading ones while
// including trailing ones. However, if there are zero width codepoints at
// the start of the string, and the substring starts at 0, lets include them
// in the result. This also makes for a simple optimization for a common
// request.
if(start){for(width=0;startIndex<str.length;){var codePoint=str.codePointAt(startIndex);width+=lib.wc.charWidth(codePoint);if(width>start)break;startIndex+=codePoint<=0xffff?1:2;}}if(opt_width!=undefined){for(endIndex=startIndex,width=0;endIndex<str.length;){var _codePoint=str.codePointAt(endIndex);width+=lib.wc.charWidth(_codePoint);if(width>opt_width)break;endIndex+=_codePoint<=0xffff?1:2;}return str.substring(startIndex,endIndex);}return str.substr(startIndex);};/**
* Get substring at the given start and end column offset.
*
* @param {string} str The string to get substring from.
* @param {integer} start The starting column offset.
* @param {integer} end The ending column offset.
*
* @return {string} The substring.
*/lib.wc.substring=function(str,start,end){return lib.wc.substr(str,start,end-start);};lib.resource.add('libdot/changelog/version','text/plain','1.26');lib.resource.add('libdot/changelog/date','text/plain','2019-01-19');// This file was generated by libdot/bin/concat.sh.
// It has been marked read-only for your safety. Rather than
// edit it directly, please modify one of these source files.
//
// hterm/audio/bell.ogg
// hterm/images/icon-96.png
'use strict';lib.resource.add('hterm/audio/bell','audio/ogg;base64','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'+'VbVtzzRl2VRV3RZV1bZl2xZ+V5Z13zNNWRZV1dZNVbV115Z9X9ZtXZg0zTQ1UVRVTRRV1VRV2zZV'+'17Y1UXRVUVVlWVRVWXZlWfdVV9Z9SxRV1VNN2RVVVbZV2fVtVZZ94XRVXVdl2fdVWRZ+W9eF4fZ9'+'4RhV1dZN19V1VZZ9YdZlYbd13yhpmmlqoqiqmiiqqqmqtm2qrq1bouiqoqrKsmeqrqzKsq+rrmzr'+'miiqrqiqsiyqqiyrsqz7qizrtqiquq3KsrCbrqvrtu8LwyzrunCqrq6rsuz7qizruq3rxnHrujB8'+'pinLpqvquqm6um7runHMtm0co6rqvirLwrDKsu/rui+0dSFRVXXdlF3jV2VZ921fd55b94WybTu/'+'rfvKceu60vg5z28cubZtHLNuG7+t+8bzKz9hOI6lZ5q2baqqrZuqq+uybivDrOtCUVV9XZVl3zdd'+'WRdu3zeOW9eNoqrquirLvrDKsjHcxm8cuzAcXds2jlvXnbKtC31jyPcJz2vbxnH7OuP2daOvDAnH'+'jwAAgAEHAIAAE8pAoSErAoA4AQAGIecUUxAqxSB0EFLqIKRUMQYhc05KxRyUUEpqIZTUKsYgVI5J'+'yJyTEkpoKZTSUgehpVBKa6GU1lJrsabUYu0gpBZKaS2U0lpqqcbUWowRYxAy56RkzkkJpbQWSmkt'+'c05K56CkDkJKpaQUS0otVsxJyaCj0kFIqaQSU0mptVBKa6WkFktKMbYUW24x1hxKaS2kEltJKcYU'+'U20txpojxiBkzknJnJMSSmktlNJa5ZiUDkJKmYOSSkqtlZJSzJyT0kFIqYOOSkkptpJKTKGU1kpK'+'sYVSWmwx1pxSbDWU0lpJKcaSSmwtxlpbTLV1EFoLpbQWSmmttVZraq3GUEprJaUYS0qxtRZrbjHm'+'GkppraQSW0mpxRZbji3GmlNrNabWam4x5hpbbT3WmnNKrdbUUo0txppjbb3VmnvvIKQWSmktlNJi'+'ai3G1mKtoZTWSiqxlZJabDHm2lqMOZTSYkmpxZJSjC3GmltsuaaWamwx5ppSi7Xm2nNsNfbUWqwt'+'xppTS7XWWnOPufVWAADAgAMAQIAJZaDQkJUAQBQAAEGIUs5JaRByzDkqCULMOSepckxCKSlVzEEI'+'JbXOOSkpxdY5CCWlFksqLcVWaykptRZrLQAAoMABACDABk2JxQEKDVkJAEQBACDGIMQYhAYZpRiD'+'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'+'m2L/kruPM6Q7oz4tvDQy+bZ3HzOi+gNHA4DZEgA=');lib.resource.add('hterm/images/icon-96','image/png;base64','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'+'YII=');lib.resource.add('hterm/concat/date','text/plain','Sun, 28 Apr 2019 13:36:40 +0000');lib.resource.add('hterm/changelog/version','text/plain','1.84');lib.resource.add('hterm/changelog/date','text/plain','2019-01-19');lib.resource.add('hterm/git/HEAD','text/plain','251d68966c9b2e32e2c127f5ce99653849e58520');// This file was generated by libdot/bin/concat.sh.
// It has been marked read-only for your safety. Rather than
// edit it directly, please modify one of these source files.
//
// hterm/js/hterm.js
// hterm/js/hterm_accessibility_reader.js
// hterm/js/hterm_contextmenu.js
// hterm/js/hterm_frame.js
// hterm/js/hterm_keyboard.js
// hterm/js/hterm_keyboard_bindings.js
// hterm/js/hterm_keyboard_keymap.js
// hterm/js/hterm_keyboard_keypattern.js
// hterm/js/hterm_options.js
// hterm/js/hterm_parser.js
// hterm/js/hterm_parser_identifiers.js
// hterm/js/hterm_preference_manager.js
// hterm/js/hterm_pubsub.js
// hterm/js/hterm_screen.js
// hterm/js/hterm_scrollport.js
// hterm/js/hterm_terminal.js
// hterm/js/hterm_terminal_io.js
// hterm/js/hterm_text_attributes.js
// hterm/js/hterm_vt.js
// hterm/js/hterm_vt_character_map.js
// hterm/audio/bell.ogg
// hterm/images/icon-96.png
'use strict';// SOURCE FILE: hterm/js/hterm.js
// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @fileoverview Declares the hterm.* namespace and some basic shared utilities
* that are too small to deserve dedicated files.
*/var hterm={};/**
* The type of window hosting hterm.
*
* This is set as part of hterm.init(). The value is invalid until
* initialization completes.
*/hterm.windowType=null;/**
* The OS we're running under.
*
* Used when setting up OS-specific behaviors.
*
* This is set as part of hterm.init(). The value is invalid until
* initialization completes.
*/hterm.os=null;/**
* Warning message to display in the terminal when browser zoom is enabled.
*
* You can replace it with your own localized message.
*/hterm.zoomWarningMessage='ZOOM != 100%';/**
* Brief overlay message displayed when text is copied to the clipboard.
*
* By default it is the unicode BLACK SCISSORS character, but you can
* replace it with your own localized message.
*
* This is only displayed when the 'enable-clipboard-notice' preference
* is enabled.
*/hterm.notifyCopyMessage="\u2702";/**
* Text shown in a desktop notification for the terminal
* bell. \u226a is a unicode EIGHTH NOTE, %(title) will
* be replaced by the terminal title.
*/hterm.desktopNotificationTitle="\u266A %(title) \u266A";/**
* The hterm init function, registered with lib.registerInit().
*
* This is called during lib.init().
*
* @param {function} onInit The function lib.init() wants us to invoke when
* initialization is complete.
*/lib.registerInit('hterm',function(onInit){function initOs(os){hterm.os=os;onInit();}function initMessageManager(){lib.i18n.getAcceptLanguages(function(languages){if(!hterm.messageManager)hterm.messageManager=new lib.MessageManager(languages);// If OS detection fails, then we'll still set the value to something.
// The OS logic in hterm tends to be best effort anyways.
lib.f.getOs().then(initOs).catch(initOs);});}function onWindow(window){hterm.windowType=window.type;initMessageManager();}function onTab(tab){if(tab&&window.chrome){chrome.windows.get(tab.windowId,null,onWindow);}else{// TODO(rginda): This is where we end up for a v1 app's background page.
// Maybe windowType = 'none' would be more appropriate, or something.
hterm.windowType='normal';initMessageManager();}}if(!hterm.defaultStorage){if(window.chrome&&chrome.storage&&chrome.storage.sync){hterm.defaultStorage=new lib.Storage.Chrome(chrome.storage.sync);}else{hterm.defaultStorage=new lib.Storage.Local();}}// The chrome.tabs API is not supported in packaged apps, and detecting if
// you're a packaged app is a little awkward.
var isPackagedApp=false;if(window.chrome&&chrome.runtime&&chrome.runtime.getManifest){var manifest=chrome.runtime.getManifest();isPackagedApp=manifest.app&&manifest.app.background;}if(isPackagedApp){// Packaged apps are never displayed in browser tabs.
setTimeout(onWindow.bind(null,{type:'popup'}),0);}else{if(window.chrome&&chrome.tabs){// The getCurrent method gets the tab that is "currently running", not the
// topmost or focused tab.
chrome.tabs.getCurrent(onTab);}else{setTimeout(onWindow.bind(null,{type:'normal'}),0);}}});/**
* Return decimal { width, height } for a given dom node.
*/hterm.getClientSize=function(dom){return dom.getBoundingClientRect();};/**
* Return decimal width for a given dom node.
*/hterm.getClientWidth=function(dom){return dom.getBoundingClientRect().width;};/**
* Return decimal height for a given dom node.
*/hterm.getClientHeight=function(dom){return dom.getBoundingClientRect().height;};/**
* Copy the specified text to the system clipboard.
*
* We'll create selections on demand based on the content to copy.
*
* @param {HTMLDocument} document The document with the selection to copy.
* @param {string} str The string data to copy out.
*/hterm.copySelectionToClipboard=function(document,str){// Request permission if need be.
var requestPermission=function requestPermission(){// Use the Permissions API if available.
if(navigator.permissions&&navigator.permissions.query){return navigator.permissions.query({name:'clipboard-write'}).then(function(status){var checkState=function checkState(resolve,reject){switch(status.state){case'granted':return resolve();case'denied':return reject();default:// Wait for the user to approve/disprove.
return new Promise(function(resolve,reject){status.onchange=function(){return checkState(resolve,reject);};});}};return new Promise(checkState);})// If the platform doesn't support "clipboard-write", or is denied,
// we move on to the copying step anyways.
.catch(function(){return Promise.resolve();});}else{// No permissions API, so resolve right away.
return Promise.resolve();}};// Write to the clipboard.
var writeClipboard=function writeClipboard(){// Use the Clipboard API if available.
if(navigator.clipboard&&navigator.clipboard.writeText){// If this fails (perhaps due to focus changing windows), fallback to the
// legacy copy method.
return navigator.clipboard.writeText(str).catch(execCommand);}else{// No Clipboard API, so use the old execCommand style.
return execCommand();}};// Write to the clipboard using the legacy execCommand method.
// TODO: Once we can rely on the Clipboard API everywhere, we can simplify
// this a lot by deleting the custom selection logic.
var execCommand=function execCommand(){var copySource=document.createElement('pre');copySource.id='hterm:copy-to-clipboard-source';copySource.textContent=str;copySource.style.cssText='-webkit-user-select: text;'+'-moz-user-select: text;'+'position: absolute;'+'top: -99px';document.body.appendChild(copySource);var selection=document.getSelection();var anchorNode=selection.anchorNode;var anchorOffset=selection.anchorOffset;var focusNode=selection.focusNode;var focusOffset=selection.focusOffset;// FF sometimes throws NS_ERROR_FAILURE exceptions when we make this call.
// Catch it because a failure here leaks the copySource node.
// https://bugzilla.mozilla.org/show_bug.cgi?id=1178676
try{selection.selectAllChildren(copySource);}catch(ex){}try{document.execCommand('copy');}catch(firefoxException){}// Ignore this. FF throws an exception if there was an error, even
// though the spec says just return false.
// IE doesn't support selection.extend. This means that the selection won't
// return on IE.
if(selection.extend){// When running in the test harness, we won't have any related nodes.
if(anchorNode){selection.collapse(anchorNode,anchorOffset);}if(focusNode){selection.extend(focusNode,focusOffset);}}copySource.parentNode.removeChild(copySource);// Since execCommand is synchronous, resolve right away.
return Promise.resolve();};// Kick it all off!
return requestPermission().then(writeClipboard);};/**
* Paste the system clipboard into the element with focus.
*
* Note: In Chrome/Firefox app/extension environments, you'll need the
* "clipboardRead" permission. In other environments, this might always
* fail as the browser frequently blocks access for security reasons.
*
* @param {HTMLDocument} The document to paste into.
* @return {boolean} True if the paste succeeded.
*/hterm.pasteFromClipboard=function(document){try{return document.execCommand('paste');}catch(firefoxException){// Ignore this. FF 40 and older would incorrectly throw an exception if
// there was an error instead of returning false.
return false;}};/**
* Return a formatted message in the current locale.
*
* @param {string} name The name of the message to return.
* @param {Array<string>=} args The message arguments, if required.
* @param {string=} string The default message text.
* @return {string} The localized message.
*/hterm.msg=function(name){var args=arguments.length>1&&arguments[1]!==undefined?arguments[1]:[];var string=arguments.length>2?arguments[2]:undefined;return hterm.messageManager.get('HTERM_'+name,args,string);};/**
* Create a new notification.
*
* @param {Object} params Various parameters for the notification.
* @param {string} params.title The title (defaults to the window's title).
* @param {string} params.body The message body (main text).
*/hterm.notify=function(params){var def=function def(curr,fallback){return curr!==undefined?curr:fallback;};if(params===undefined||params===null)params={};// Merge the user's choices with the default settings. We don't take it
// directly in case it was stuffed with excess junk.
var options={'body':params.body,'icon':def(params.icon,lib.resource.getDataUrl('hterm/images/icon-96'))};var title=def(params.title,window.document.title);if(!title)title='hterm';title=lib.f.replaceVars(hterm.desktopNotificationTitle,{'title':title});var n=new Notification(title,options);n.onclick=function(){window.focus();this.close();};return n;};/**
* Launches url in a new tab.
*
* @param {string} url URL to launch in a new tab.
*/hterm.openUrl=function(url){if(window.chrome&&chrome.browser&&chrome.browser.openTab){// For Chrome v2 apps, we need to use this API to properly open windows.
chrome.browser.openTab({'url':url});}else{var win=lib.f.openWindow(url,'_blank');win.focus();}};/**
* Constructor for a hterm.Size record.
*
* Instances of this class have public read/write members for width and height.
*
* @param {integer} width The width of this record.
* @param {integer} height The height of this record.
*/hterm.Size=function(width,height){this.width=width;this.height=height;};/**
* Adjust the width and height of this record.
*
* @param {integer} width The new width of this record.
* @param {integer} height The new height of this record.
*/hterm.Size.prototype.resize=function(width,height){this.width=width;this.height=height;};/**
* Return a copy of this record.
*
* @return {hterm.Size} A new hterm.Size instance with the same width and
* height.
*/hterm.Size.prototype.clone=function(){return new hterm.Size(this.width,this.height);};/**
* Set the height and width of this instance based on another hterm.Size.
*
* @param {hterm.Size} that The object to copy from.
*/hterm.Size.prototype.setTo=function(that){this.width=that.width;this.height=that.height;};/**
* Test if another hterm.Size instance is equal to this one.
*
* @param {hterm.Size} that The other hterm.Size instance.
* @return {boolean} True if both instances have the same width/height, false
* otherwise.
*/hterm.Size.prototype.equals=function(that){return this.width==that.width&&this.height==that.height;};/**
* Return a string representation of this instance.
*
* @return {string} A string that identifies the width and height of this
* instance.
*/hterm.Size.prototype.toString=function(){return'[hterm.Size: '+this.width+', '+this.height+']';};/**
* Constructor for a hterm.RowCol record.
*
* Instances of this class have public read/write members for row and column.
*
* This class includes an 'overflow' bit which is use to indicate that an
* attempt has been made to move the cursor column passed the end of the
* screen. When this happens we leave the cursor column set to the last column
* of the screen but set the overflow bit. In this state cursor movement
* happens normally, but any attempt to print new characters causes a cr/lf
* first.
*
* @param {integer} row The row of this record.
* @param {integer} column The column of this record.
* @param {boolean} opt_overflow Optional boolean indicating that the RowCol
* has overflowed.
*/hterm.RowCol=function(row,column,opt_overflow){this.row=row;this.column=column;this.overflow=!!opt_overflow;};/**
* Adjust the row and column of this record.
*
* @param {integer} row The new row of this record.
* @param {integer} column The new column of this record.
* @param {boolean} opt_overflow Optional boolean indicating that the RowCol
* has overflowed.
*/hterm.RowCol.prototype.move=function(row,column,opt_overflow){this.row=row;this.column=column;this.overflow=!!opt_overflow;};/**
* Return a copy of this record.
*
* @return {hterm.RowCol} A new hterm.RowCol instance with the same row and
* column.
*/hterm.RowCol.prototype.clone=function(){return new hterm.RowCol(this.row,this.column,this.overflow);};/**
* Set the row and column of this instance based on another hterm.RowCol.
*
* @param {hterm.RowCol} that The object to copy from.
*/hterm.RowCol.prototype.setTo=function(that){this.row=that.row;this.column=that.column;this.overflow=that.overflow;};/**
* Test if another hterm.RowCol instance is equal to this one.
*
* @param {hterm.RowCol} that The other hterm.RowCol instance.
* @return {boolean} True if both instances have the same row/column, false
* otherwise.
*/hterm.RowCol.prototype.equals=function(that){return this.row==that.row&&this.column==that.column&&this.overflow==that.overflow;};/**
* Return a string representation of this instance.
*
* @return {string} A string that identifies the row and column of this
* instance.
*/hterm.RowCol.prototype.toString=function(){return'[hterm.RowCol: '+this.row+', '+this.column+', '+this.overflow+']';};// SOURCE FILE: hterm/js/hterm_accessibility_reader.js
// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* AccessibilityReader responsible for rendering command output for AT.
*
* Renders command output for Assistive Technology using a live region. We don't
* use the visible rows of the terminal for rendering command output to the
* screen reader because the rendered content may be different from what we want
* read out by a screen reader. For example, we may not actually render every
* row of a large piece of output to the screen as it wouldn't be performant.
* But we want the screen reader to read it all out in order.
*
* @param {HTMLDivElement} div The div element where the live region should be
* added.
*/hterm.AccessibilityReader=function(div){this.document_=div.ownerDocument;// The live region element to add text to.
var liveRegion=this.document_.createElement('div');liveRegion.id='hterm:accessibility-live-region';liveRegion.style.cssText="position: absolute;\n width: 0; height: 0;\n overflow: hidden;\n left: 0; top: 0;";div.appendChild(liveRegion);// Whether command output should be rendered for Assistive Technology.
// This isn't always enabled because it has an impact on performance.
this.accessibilityEnabled=false;// This live element is used for command output.
this.liveElement_=this.document_.createElement('p');this.liveElement_.setAttribute('aria-live','polite');this.liveElement_.setAttribute('aria-label','');liveRegion.appendChild(this.liveElement_);// This live element is used for speaking out the current screen when
// navigating through the scrollback buffer. It will interrupt existing
// announcements.
this.assertiveLiveElement_=this.document_.createElement('p');this.assertiveLiveElement_.setAttribute('aria-live','assertive');this.assertiveLiveElement_.setAttribute('aria-label','');liveRegion.appendChild(this.assertiveLiveElement_);// A queue of updates to announce.
this.queue_=[];// A timer which tracks when next to add items to the live region. null when
// not running. This is used to combine updates that occur in a small window,
// as well as to avoid too much output being added to the live region in one
// go which can cause the renderer to hang.
this.nextReadTimer_=null;// This is set to true if the cursor is about to update position on the
// screen. i.e. beforeCursorChange has been called but not afterCursorChange.
this.cursorIsChanging_=false;// This tracks changes that would be added to queue_ while the cursor is
// changing. This is done so that we can decide to discard these changes if
// we announce something as a result of the cursor change.
this.cursorChangeQueue_=[];// The string of text on the row that the cursor was last on. Only valid while
// cursorIsChanging_ is true.
this.lastCursorRowString_=null;// The row that the cursor was last on. Only valid while cursorIsChanging_ is
// true.
this.lastCursorRow_=null;// The column that the cursor was last on. Only valid while cursorIsChanging_
// is true.
this.lastCursorColumn_=null;// True if a keypress has been performed since the last cursor change.
this.hasUserGesture=false;};/**
* Delay in ms to use for merging strings to output.
*
* We merge strings together to avoid hanging the terminal and to ensure that
* aria updates make it to the screen reader. We want this to be short so
* there's not a big delay between typing/executing commands and hearing output.
*
* @constant
* @type {integer}
*/hterm.AccessibilityReader.DELAY=50;/**
* Enable accessibility-friendly features that have a performance impact.
*
* @param {boolean} enabled Whether to enable accessibility-friendly features.
*/hterm.AccessibilityReader.prototype.setAccessibilityEnabled=function(enabled){if(!enabled){this.clear();}this.accessibilityEnabled=enabled;};/**
* Decorate the document where the terminal <x-screen> resides. This is needed
* for listening to keystrokes on the screen.
*
* @param {HTMLDocument} doc The document where the <x-screen> resides.
*/hterm.AccessibilityReader.prototype.decorate=function(doc){var _this5=this;var handlers=['keydown','keypress','keyup','textInput'];handlers.forEach(function(handler){doc.addEventListener(handler,function(){_this5.hasUserGesture=true;});});};/**
* This should be called before the cursor on the screen is about to get
* updated. This allows cursor changes to be tracked and related notifications
* to be announced.
*
* @param {string} cursorRowString The text in the row that the cursor is
* currently on.
* @param {integer} cursorRow The index of the row that the cursor is currently
* on, including rows in the scrollback buffer.
* @param {integer} cursorColumn The index of the column that the cursor is
* currently on.
*/hterm.AccessibilityReader.prototype.beforeCursorChange=function(cursorRowString,cursorRow,cursorColumn){// If accessibility is enabled we don't announce selection changes as these
// can have a performance impact.
if(!this.accessibilityEnabled){return;}// If there is no user gesture that can be tied to the cursor change, we
// don't want to announce anything.
if(!this.hasUserGesture||this.cursorIsChanging_){return;}this.cursorIsChanging_=true;this.lastCursorRowString_=cursorRowString;this.lastCursorRow_=cursorRow;this.lastCursorColumn_=cursorColumn;};/**
* This should be called after the cursor on the screen has been updated. Note
* that several updates to the cursor may have happened between
* beforeCursorChange and afterCursorChange.
*
* This allows cursor changes to be tracked and related notifications to be
* announced.
*
* @param {string} cursorRowString The text in the row that the cursor is
* currently on.
* @param {integer} cursorRow The index of the row that the cursor is currently
* on, including rows in the scrollback buffer.
* @param {integer} cursorColumn The index of the column that the cursor is
* currently on.
*/hterm.AccessibilityReader.prototype.afterCursorChange=function(cursorRowString,cursorRow,cursorColumn){// This can happen if clear() is called midway through a cursor change.
if(!this.cursorIsChanging_){return;}this.cursorIsChanging_=false;if(!this.announceAction_(cursorRowString,cursorRow,cursorColumn)){// If we don't announce a special action, we re-queue all the output that
// was queued during the selection change.
for(var i=0;i<this.cursorChangeQueue_.length;++i){this.announce(this.cursorChangeQueue_[i]);}}this.cursorChangeQueue_=[];this.lastCursorRowString_=null;this.lastCursorRow_=null;this.lastCursorColumn_=null;this.hasUserGesture=false;};/**
* Announce the command output.
*
* @param {string} str The string to announce using a live region.
*/hterm.AccessibilityReader.prototype.announce=function(str){if(!this.accessibilityEnabled){return;}// If the cursor is in the middle of changing, we queue up the output
// separately as we may not want it to be announced if it's part of a cursor
// change announcement.
if(this.cursorIsChanging_){this.cursorChangeQueue_.push(str);return;}// Don't append newlines to the queue if the queue is empty. It won't have any
// impact.
if(str=='\n'&&this.queue_.length>0){this.queue_.push('');// We don't need to trigger an announcement on newlines because they won't
// change the existing content that's output.
return;}if(this.queue_.length==0){this.queue_.push(str);}else{// We put a space between strings that appear on the same line.
// TODO(raymes): We should check the location on the row and not add a space
// if the strings are joined together.
var padding='';if(this.queue_[this.queue_.length-1].length!=0){padding=' ';}this.queue_[this.queue_.length-1]+=padding+str;}// If we've already scheduled text being added to the live region, wait for it
// to happen.
if(this.nextReadTimer_){return;}// If there's only one item in the queue, we may get other text being added
// very soon after. In that case, wait a small delay so we can merge the
// related strings.
if(this.queue_.length==1){this.nextReadTimer_=setTimeout(this.addToLiveRegion_.bind(this),hterm.AccessibilityReader.DELAY);}else{throw new Error('Expected only one item in queue_ or nextReadTimer_ to be running.');}};/**
* Voice an announcement that will interrupt other announcements.
*
* @param {string} str The string to announce using a live region.
*/hterm.AccessibilityReader.prototype.assertiveAnnounce=function(str){if(this.hasUserGesture&&str==' '){str=hterm.msg('SPACE_CHARACTER',[],'Space');}// If the same string is announced twice, an attribute change won't be
// registered and the screen reader won't know that the string has changed.
// So we slightly change the string to ensure that the attribute change gets
// registered.
str=str.trim();if(str==this.assertiveLiveElement_.getAttribute('aria-label')){str='\n'+str;}this.clear();this.assertiveLiveElement_.setAttribute('aria-label',str);};/**
* Add a newline to the text that will be announced to the live region.
*/hterm.AccessibilityReader.prototype.newLine=function(){this.announce('\n');};/**
* Clear the live region and any in-flight announcements.
*/hterm.AccessibilityReader.prototype.clear=function(){this.liveElement_.setAttribute('aria-label','');this.assertiveLiveElement_.setAttribute('aria-label','');clearTimeout(this.nextReadTimer_);this.nextReadTimer_=null;this.queue_=[];this.cursorIsChanging_=false;this.cursorChangeQueue_=[];this.lastCursorRowString_=null;this.lastCursorRow_=null;this.lastCursorColumn_=null;this.hasUserGesture=false;};/**
* This will announce an action that is related to a cursor change, for example
* when the user deletes a character we want the character deleted to be
* announced. Similarly, when the user moves the cursor along the line, we want
* the characters selected to be announced.
*
* Note that this function is a heuristic. Because of the nature of terminal
* emulators, we can't distinguish input and output, which means we don't really
* know what output is the result of a keypress and what isn't. Also in some
* terminal applications certain announcements may make sense whereas others may
* not. This function should try to account for the most common cases.
*
* @param {string} cursorRowString The text in the row that the cursor is
* currently on.
* @param {integer} cursorRow The index of the row that the cursor is currently
* on, including rows in the scrollback buffer.
* @param {integer} cursorColumn The index of the column that the cursor is
* currently on.
*/hterm.AccessibilityReader.prototype.announceAction_=function(cursorRowString,cursorRow,cursorColumn){// If the cursor changes rows, we don't announce anything at present.
if(this.lastCursorRow_!=cursorRow){return false;}// The case when the row of text hasn't changed at all.
if(this.lastCursorRowString_==cursorRowString){// Moving the cursor along the line. We check that no significant changes
// have been queued. If they have, it may not just be a cursor movement and
// it may be better to read those out.
if(this.lastCursorColumn_!=cursorColumn&&this.cursorChangeQueue_.join('').trim()==''){// Announce the text between the old cursor position and the new one.
var start=Math.min(this.lastCursorColumn_,cursorColumn);var len=Math.abs(cursorColumn-this.lastCursorColumn_);this.assertiveAnnounce(lib.wc.substr(this.lastCursorRowString_,start,len));return true;}return false;}// The case when the row of text has changed.
if(this.lastCursorRowString_!=cursorRowString){// Spacebar. We manually announce this character since the screen reader may
// not announce the whitespace in a live region.
if(this.lastCursorColumn_+1==cursorColumn){if(lib.wc.substr(cursorRowString,cursorColumn-1,1)==' '&&this.cursorChangeQueue_.length>0&&this.cursorChangeQueue_[0]==' '){this.assertiveAnnounce(' ');return true;}}// Backspace and deletion.
// The position of the characters deleted is right after the current
// position of the cursor in the case of backspace and delete.
var cursorDeleted=cursorColumn;// Check that the current row string is shorter than the previous. Also
// check that the start of the strings (up to the cursor) match.
if(lib.wc.strWidth(cursorRowString)<=lib.wc.strWidth(this.lastCursorRowString_)&&lib.wc.substr(this.lastCursorRowString_,0,cursorDeleted)==lib.wc.substr(cursorRowString,0,cursorDeleted)){// Find the length of the current row string ignoring space characters.
// These may be inserted at the end of the string when deleting characters
// so they should be ignored.
var lengthOfCurrentRow=lib.wc.strWidth(cursorRowString);for(;lengthOfCurrentRow>0;--lengthOfCurrentRow){if(lengthOfCurrentRow==cursorDeleted||lib.wc.substr(cursorRowString,lengthOfCurrentRow-1,1)!=' '){break;}}var numCharsDeleted=lib.wc.strWidth(this.lastCursorRowString_)-lengthOfCurrentRow;// Check that the end of the strings match.
var lengthOfEndOfString=lengthOfCurrentRow-cursorDeleted;var endOfLastRowString=lib.wc.substr(this.lastCursorRowString_,cursorDeleted+numCharsDeleted,lengthOfEndOfString);var endOfCurrentRowString=lib.wc.substr(cursorRowString,cursorDeleted,lengthOfEndOfString);if(endOfLastRowString==endOfCurrentRowString){var deleted=lib.wc.substr(this.lastCursorRowString_,cursorDeleted,numCharsDeleted);if(deleted!=''){this.assertiveAnnounce(deleted);return true;}}}return false;}return false;};/**
* Add text from queue_ to the live region.
*
*/hterm.AccessibilityReader.prototype.addToLiveRegion_=function(){this.nextReadTimer_=null;var str=this.queue_.join('\n').trim();// If the same string is announced twice, an attribute change won't be
// registered and the screen reader won't know that the string has changed.
// So we slightly change the string to ensure that the attribute change gets
// registered.
if(str==this.liveElement_.getAttribute('aria-label')){str='\n'+str;}this.liveElement_.setAttribute('aria-label',str);this.queue_=[];};// SOURCE FILE: hterm/js/hterm_contextmenu.js
// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @fileoverview Context menu handling.
*/ /**
* Manage the context menu usually shown when right clicking.
*/hterm.ContextMenu=function(){// The document that contains this context menu.
this.document_=null;// The generated context menu (i.e. HTML elements).
this.element_=null;// The structured menu (i.e. JS objects).
this.menu_=[];};/**
* Constant to add a separator to the context menu.
*/hterm.ContextMenu.SEPARATOR={};/**
* Bind context menu to a specific document element.
*
* @param {HTMLDocument} document The document to use when creating elements.
*/hterm.ContextMenu.prototype.setDocument=function(document){if(this.element_){this.element_.remove();this.element_=null;}this.document_=document;this.regenerate_();this.document_.body.appendChild(this.element_);};/**
* Regenerate the HTML elements based on internal menu state.
*/hterm.ContextMenu.prototype.regenerate_=function(){var _this6=this;if(!this.element_){this.element_=this.document_.createElement('menu');this.element_.id='hterm:context-menu';this.element_.style.cssText="\n display: none;\n border: solid 1px;\n position: absolute;\n ";}else{this.hide();}// Clear out existing menu entries.
while(this.element_.firstChild){this.element_.removeChild(this.element_.firstChild);}this.menu_.forEach(function(_ref){var _ref2=_slicedToArray(_ref,2),name=_ref2[0],action=_ref2[1];var menuitem=_this6.document_.createElement('menuitem');if(name===hterm.ContextMenu.SEPARATOR){menuitem.innerHTML='<hr>';menuitem.className='separator';}else{menuitem.innerText=name;menuitem.addEventListener('mousedown',function(e){e.preventDefault();action(e);});}_this6.element_.appendChild(menuitem);});};/**
* Set all the entries in the context menu.
*
* This is an array of arrays. The first element in the array is the string to
* display while the second element is the function to call.
*
* The first element may also be the SEPARATOR constant to add a separator.
*
* This resets all existing menu entries.
*
* @param {Array<Array<string, function(Event)>>} items The menu entries.
*/hterm.ContextMenu.prototype.setItems=function(items){this.menu_=items;this.regenerate_();};/**
* Show the context menu.
*
* The event is used to determine where to show the menu.
*
* If no menu entries are defined, then nothing will be shown.
*
* @param {Event} e The event triggering this display.
* @param {hterm.Terminal=} terminal The terminal object to get style info from.
*/hterm.ContextMenu.prototype.show=function(e,terminal){// If there are no menu entries, then don't try to show anything.
if(this.menu_.length==0){return;}// If we have the terminal, sync the style preferences over.
if(terminal){this.element_.style.backgroundColor=terminal.getBackgroundColor();this.element_.style.color=terminal.getForegroundColor();this.element_.style.fontSize=terminal.getFontSize();this.element_.style.fontFamily=terminal.getFontFamily();}this.element_.style.top="".concat(e.clientY,"px");this.element_.style.left="".concat(e.clientX,"px");var docSize=hterm.getClientSize(this.document_.body);this.element_.style.display='block';// We can't calculate sizes until after it's displayed.
var eleSize=hterm.getClientSize(this.element_);// Make sure the menu isn't clipped outside of the current element.
var minY=Math.max(0,docSize.height-eleSize.height);var minX=Math.max(0,docSize.width-eleSize.width);if(minY<e.clientY){this.element_.style.top="".concat(minY,"px");}if(minX<e.clientX){this.element_.style.left="".concat(minX,"px");}};/**
* Hide the context menu.
*/hterm.ContextMenu.prototype.hide=function(){if(!this.element_){return;}this.element_.style.display='none';};// SOURCE FILE: hterm/js/hterm_frame.js
// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* First draft of the interface between the terminal and a third party dialog.
*
* This is rough. It's just the terminal->dialog layer. To complete things
* we'll also need a command->terminal layer. That will have to facilitate
* command->terminal->dialog or direct command->dialog communication.
*
* I imagine this class will change significantly when that happens.
*/ /**
* Construct a new frame for the given terminal.
*
* @param terminal {hterm.Terminal} The parent terminal object.
* @param url {String} The url to load in the frame.
* @param opt_options {Object} Optional options for the frame. Not implemented.
*/hterm.Frame=function(terminal,url,opt_options){this.terminal_=terminal;this.div_=terminal.div_;this.url=url;this.options=opt_options||{};this.iframe_=null;this.container_=null;this.messageChannel_=null;};/**
* Handle messages from the iframe.
*/hterm.Frame.prototype.onMessage_=function(e){switch(e.data.name){case'ipc-init-ok':// We get this response after we send them ipc-init and they finish.
this.sendTerminalInfo_();return;case'terminal-info-ok':// We get this response after we send them terminal-info and they finish.
// Show the finished frame, and then rebind our message handler to the
// callback below.
this.container_.style.display='flex';this.postMessage('visible');this.messageChannel_.port1.onmessage=this.onMessage.bind(this);this.onLoad();return;default:console.log('Unknown message from frame:',e.data);return;}};/**
* Clients could override this, I guess.
*
* It doesn't support multiple listeners, but I'm not sure that would make sense
* here. It's probably better to speak directly to our parents.
*/hterm.Frame.prototype.onMessage=function(){};/**
* Handle iframe onLoad event.
*/hterm.Frame.prototype.onLoad_=function(){this.messageChannel_=new MessageChannel();this.messageChannel_.port1.onmessage=this.onMessage_.bind(this);this.messageChannel_.port1.start();this.iframe_.contentWindow.postMessage({name:'ipc-init',argv:[{messagePort:this.messageChannel_.port2}]},this.url,[this.messageChannel_.port2]);};/**
* Clients may override this.
*/hterm.Frame.prototype.onLoad=function(){};/**
* Sends the terminal-info message to the iframe.
*/hterm.Frame.prototype.sendTerminalInfo_=function(){lib.i18n.getAcceptLanguages(function(languages){this.postMessage('terminal-info',[{acceptLanguages:languages,foregroundColor:this.terminal_.getForegroundColor(),backgroundColor:this.terminal_.getBackgroundColor(),cursorColor:this.terminal_.getCursorColor(),fontSize:this.terminal_.getFontSize(),fontFamily:this.terminal_.getFontFamily(),baseURL:lib.f.getURL('/')}]);}.bind(this));};/**
* User clicked the close button on the frame decoration.
*/hterm.Frame.prototype.onCloseClicked_=function(){this.close();};/**
* Close this frame.
*/hterm.Frame.prototype.close=function(){if(!this.container_||!this.container_.parentNode)return;this.container_.parentNode.removeChild(this.container_);this.onClose();};/**
* Clients may override this.
*/hterm.Frame.prototype.onClose=function(){};/**
* Send a message to the iframe.
*/hterm.Frame.prototype.postMessage=function(name,argv){if(!this.messageChannel_)throw new Error('Message channel is not set up.');this.messageChannel_.port1.postMessage({name:name,argv:argv});};/**
* Show the UI for this frame.
*
* The iframe src is not loaded until this method is called.
*/hterm.Frame.prototype.show=function(){var self=this;function opt(name,defaultValue){if(name in self.options)return self.options[name];return defaultValue;}var self=this;if(this.container_&&this.container_.parentNode){console.error('Frame already visible');return;}var headerHeight='16px';var divSize=hterm.getClientSize(this.div_);var width=opt('width',640);var height=opt('height',480);var left=(divSize.width-width)/2;var top=(divSize.height-height)/2;var document=this.terminal_.document_;var container=this.container_=document.createElement('div');container.style.cssText='position: absolute;'+'display: none;'+'flex-direction: column;'+'top: 10%;'+'left: 4%;'+'width: 90%;'+'height: 80%;'+'min-height: 20%;'+'max-height: 80%;'+'box-shadow: 0 0 2px '+this.terminal_.getForegroundColor()+';'+'border: 2px '+this.terminal_.getForegroundColor()+' solid;';if(false){// No use for the close button, so no use for the window header either.
var header=document.createElement('div');header.style.cssText='display: flex;'+'justify-content: flex-end;'+'height: '+headerHeight+';'+'background-color: '+this.terminal_.getForegroundColor()+';'+'color: '+this.terminal_.getBackgroundColor()+';'+'font-size: 16px;'+'font-family: '+this.terminal_.getFontFamily();container.appendChild(header);var button=document.createElement('div');button.setAttribute('role','button');button.style.cssText='margin-top: -3px;'+'margin-right: 3px;'+'cursor: pointer;';button.textContent="\u2A2F";button.addEventListener('click',this.onCloseClicked_.bind(this));header.appendChild(button);}var iframe=this.iframe_=document.createElement('iframe');iframe.onload=this.onLoad_.bind(this);iframe.style.cssText='display: flex;'+'flex: 1;'+'width: 100%';iframe.setAttribute('src',this.url);iframe.setAttribute('seamless',true);container.appendChild(iframe);this.div_.appendChild(container);};// SOURCE FILE: hterm/js/hterm_keyboard.js
// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* Keyboard handler.
*
* Consumes onKey* events and invokes onVTKeystroke on the associated
* hterm.Terminal object.
*
* See also: [XTERM] as referenced in vt.js.
*
* @param {hterm.Terminal} The Terminal object associated with this keyboard.
*/hterm.Keyboard=function(terminal){// The parent vt interpreter.
this.terminal=terminal;// The element we're currently capturing keyboard events for.
this.keyboardElement_=null;// The event handlers we are interested in, and their bound callbacks, saved
// so they can be uninstalled with removeEventListener, when required.
this.handlers_=[['focusout',this.onFocusOut_.bind(this)],['keydown',this.onKeyDown_.bind(this)],['keypress',this.onKeyPress_.bind(this)],['keyup',this.onKeyUp_.bind(this)],['textInput',this.onTextInput_.bind(this)]];/**
* The current key map.
*/this.keyMap=new hterm.Keyboard.KeyMap(this);this.bindings=new hterm.Keyboard.Bindings(this);/**
* none: Disable any AltGr related munging.
* ctrl-alt: Assume Ctrl+Alt means AltGr.
* left-alt: Assume left Alt means AltGr.
* right-alt: Assume right Alt means AltGr.
*/this.altGrMode='none';/**
* If true, Shift-Insert will fall through to the browser as a paste.
* If false, the keystroke will be sent to the host.
*/this.shiftInsertPaste=true;/**
* If true, home/end will control the terminal scrollbar and shift home/end
* will send the VT keycodes. If false then home/end sends VT codes and
* shift home/end scrolls.
*/this.homeKeysScroll=false;/**
* Same as above, except for page up/page down.
*/this.pageKeysScroll=false;/**
* If true, Ctrl-Plus/Minus/Zero controls zoom.
* If false, Ctrl-Shift-Plus/Minus/Zero controls zoom, Ctrl-Minus sends ^_,
* Ctrl-Plus/Zero do nothing.
*/this.ctrlPlusMinusZeroZoom=true;/**
* Ctrl+C copies if true, sends ^C to host if false.
* Ctrl+Shift+C sends ^C to host if true, copies if false.
*/this.ctrlCCopy=false;/**
* Ctrl+V pastes if true, sends ^V to host if false.
* Ctrl+Shift+V sends ^V to host if true, pastes if false.
*/this.ctrlVPaste=false;/**
* Enable/disable application keypad.
*
* This changes the way numeric keys are sent from the keyboard.
*/this.applicationKeypad=false;/**
* Enable/disable the application cursor mode.
*
* This changes the way cursor keys are sent from the keyboard.
*/this.applicationCursor=false;/**
* If true, the backspace should send BS ('\x08', aka ^H). Otherwise
* the backspace key should send '\x7f'.
*/this.backspaceSendsBackspace=false;/**
* Set whether the meta key sends a leading escape or not.
*/this.metaSendsEscape=true;/**
* Set whether meta-V gets passed to host.
*/this.passMetaV=true;/**
* Controls how the alt key is handled.
*
* escape....... Send an ESC prefix.
* 8-bit........ Add 128 to the unshifted character as in xterm.
* browser-key.. Wait for the keypress event and see what the browser says.
* (This won't work well on platforms where the browser
* performs a default action for some alt sequences.)
*
* This setting only matters when alt is distinct from meta (altIsMeta is
* false.)
*/this.altSendsWhat='escape';/**
* Set whether the alt key acts as a meta key, instead of producing 8-bit
* characters.
*
* True to enable, false to disable, null to autodetect based on platform.
*/this.altIsMeta=false;/**
* If true, tries to detect DEL key events that are from alt-backspace on
* Chrome OS vs from a true DEL key press.
*
* Background: At the time of writing, on Chrome OS, alt-backspace is mapped
* to DEL. Some users may be happy with this, but others may be frustrated
* that it's impossible to do meta-backspace. If the user enables this pref,
* we use a trick to tell a true DEL keypress from alt-backspace: on
* alt-backspace, we will see the alt key go down, then get a DEL keystroke
* that indicates that alt is not pressed. See https://crbug.com/174410 .
*/this.altBackspaceIsMetaBackspace=false;/**
* Used to keep track of the current alt-key state, which is necessary for
* the altBackspaceIsMetaBackspace preference above and for the altGrMode
* preference. This is a bitmap with where bit positions correspond to the
* "location" property of the key event.
*/this.altKeyPressed=0;/**
* If true, Chrome OS media keys will be mapped to their F-key equivalent.
* E.g. "Back" will be mapped to F1. If false, Chrome will handle the keys.
*/this.mediaKeysAreFKeys=false;/**
* Holds the previous setting of altSendsWhat when DECSET 1039 is used. When
* DECRST 1039 is used, altSendsWhat is changed back to this and this is
* nulled out.
*/this.previousAltSendsWhat_=null;};/**
* Special handling for keyCodes in a keyboard layout.
*/hterm.Keyboard.KeyActions={/**
* Call preventDefault and stopPropagation for this key event and nothing
* else.
*/CANCEL:Symbol('CANCEL'),/**
* This performs the default terminal action for the key. If used in the
* 'normal' action and the the keystroke represents a printable key, the
* character will be sent to the host. If used in one of the modifier
* actions, the terminal will perform the normal action after (possibly)
* altering it.
*
* - If the normal sequence starts with CSI, the sequence will be adjusted
* to include the modifier parameter as described in [XTERM] in the final
* table of the "PC-Style Function Keys" section.
*
* - If the control key is down and the key represents a printable character,
* and the uppercase version of the unshifted keycap is between
* 64 (ASCII '@') and 95 (ASCII '_'), then the uppercase version of the
* unshifted keycap minus 64 is sent. This makes '^@' send '\x00' and
* '^_' send '\x1f'. (Note that one higher that 0x1f is 0x20, which is
* the first printable ASCII value.)
*
* - If the alt key is down and the key represents a printable character then
* the value of the character is shifted up by 128.
*
* - If meta is down and configured to send an escape, '\x1b' will be sent
* before the normal action is performed.
*/DEFAULT:Symbol('DEFAULT'),/**
* Causes the terminal to opt out of handling the key event, instead letting
* the browser deal with it.
*/PASS:Symbol('PASS'),/**
* Insert the first or second character of the keyCap, based on e.shiftKey.
* The key will be handled in onKeyDown, and e.preventDefault() will be
* called.
*
* It is useful for a modified key action, where it essentially strips the
* modifier while preventing the browser from reacting to the key.
*/STRIP:Symbol('STRIP')};/**
* Capture keyboard events sent to the associated element.
*
* This enables the keyboard. Captured events are consumed by this class
* and will not perform their default action or bubble to other elements.
*
* Passing a null element will uninstall the keyboard handlers.
*
* @param {HTMLElement} element The element whose events should be captured, or
* null to disable the keyboard.
*/hterm.Keyboard.prototype.installKeyboard=function(element){if(element==this.keyboardElement_)return;if(element&&this.keyboardElement_)this.installKeyboard(null);for(var i=0;i<this.handlers_.length;i++){var handler=this.handlers_[i];if(element){element.addEventListener(handler[0],handler[1]);}else{this.keyboardElement_.removeEventListener(handler[0],handler[1]);}}this.keyboardElement_=element;};/**
* Disable keyboard event capture.
*
* This will allow the browser to process key events normally.
*/hterm.Keyboard.prototype.uninstallKeyboard=function(){this.installKeyboard(null);};/**
* Handle onTextInput events.
*
* These are generated when using IMEs, Virtual Keyboards (VKs), compose keys,
* Unicode input, etc...
*/hterm.Keyboard.prototype.onTextInput_=function(e){if(!e.data)return;// Just pass the generated buffer straight down. No need for us to split it
// up or otherwise parse it ahead of times.
this.terminal.onVTKeystroke(e.data);};/**
* Handle onKeyPress events.
*
* TODO(vapier): Drop this event entirely and only use keydown.
*/hterm.Keyboard.prototype.onKeyPress_=function(e){// FF doesn't set keyCode reliably in keypress events. Stick to the which
// field here until we can move to keydown entirely.
var key=String.fromCharCode(e.which).toLowerCase();if((e.ctrlKey||e.metaKey)&&(key=='c'||key=='v')){// On FF the key press (not key down) event gets fired for copy/paste.
// Let it fall through for the default browser behavior.
return;}if(e.keyCode==9/* Tab */){// On FF, a key press event will be fired in addition of key down for the
// Tab key if key down isn't handled. This would only happen if a custom
// PASS binding has been created and therefore this should be handled by the
// browser.
return;}if(e.altKey&&this.altSendsWhat=='browser-key'&&e.charCode==0){// If we got here because we were expecting the browser to handle an
// alt sequence but it didn't do it, then we might be on an OS without
// an enabled IME system. In that case we fall back to xterm-like
// behavior.
//
// This happens here only as a fallback. Typically these platforms should
// set altSendsWhat to either 'escape' or '8-bit'.
var ch=String.fromCharCode(e.keyCode);if(!e.shiftKey)ch=ch.toLowerCase();}else if(e.charCode>=32){ch=e.charCode;}if(ch)this.terminal.onVTKeystroke(String.fromCharCode(ch));e.preventDefault();e.stopPropagation();};/**
* Prevent default handling for non-ctrl-shifted event.
*
* When combined with Chrome permission 'app.window.fullscreen.overrideEsc',
* and called for both key down and key up events,
* the ESC key remains usable within fullscreen Chrome app windows.
*/hterm.Keyboard.prototype.preventChromeAppNonCtrlShiftDefault_=function(e){if(!window.chrome||!window.chrome.app||!window.chrome.app.window)return;if(!e.ctrlKey||!e.shiftKey)e.preventDefault();};hterm.Keyboard.prototype.onFocusOut_=function(e){this.altKeyPressed=0;};hterm.Keyboard.prototype.onKeyUp_=function(e){if(e.keyCode==18)this.altKeyPressed=this.altKeyPressed&~(1<<e.location-1);if(e.keyCode==27)this.preventChromeAppNonCtrlShiftDefault_(e);};/**
* Handle onKeyDown events.
*/hterm.Keyboard.prototype.onKeyDown_=function(e){if(e.keyCode==18)this.altKeyPressed=this.altKeyPressed|1<<e.location-1;if(e.keyCode==27)this.preventChromeAppNonCtrlShiftDefault_(e);var keyDef=this.keyMap.keyDefs[e.keyCode];if(!keyDef){// If this key hasn't been explicitly registered, fall back to the unknown
// key mapping (keyCode == 0), and then automatically register it to avoid
// any further warnings here.
console.warn("No definition for key ".concat(e.key," (keyCode ").concat(e.keyCode,")"));keyDef=this.keyMap.keyDefs[0];this.keyMap.addKeyDef(e.keyCode,keyDef);}// The type of action we're going to use.
var resolvedActionType=null;var self=this;function getAction(name){// Get the key action for the given action name. If the action is a
// function, dispatch it. If the action defers to the normal action,
// resolve that instead.
resolvedActionType=name;var action=keyDef[name];if(typeof action=='function')action=action.apply(self.keyMap,[e,keyDef]);if(action===DEFAULT&&name!='normal')action=getAction('normal');return action;}// Note that we use the triple-equals ('===') operator to test equality for
// these constants, in order to distinguish usage of the constant from usage
// of a literal string that happens to contain the same bytes.
var CANCEL=hterm.Keyboard.KeyActions.CANCEL;var DEFAULT=hterm.Keyboard.KeyActions.DEFAULT;var PASS=hterm.Keyboard.KeyActions.PASS;var STRIP=hterm.Keyboard.KeyActions.STRIP;var control=e.ctrlKey;var alt=this.altIsMeta?false:e.altKey;var meta=this.altIsMeta?e.altKey||e.metaKey:e.metaKey;// In the key-map, we surround the keyCap for non-printables in "[...]"
var isPrintable=!/^\[\w+\]$/.test(keyDef.keyCap);switch(this.altGrMode){case'ctrl-alt':if(isPrintable&&control&&alt){// ctrl-alt-printable means altGr. We clear out the control and
// alt modifiers and wait to see the charCode in the keydown event.
control=false;alt=false;}break;case'right-alt':if(isPrintable&&this.terminal.keyboard.altKeyPressed&2){control=false;alt=false;}break;case'left-alt':if(isPrintable&&this.terminal.keyboard.altKeyPressed&1){control=false;alt=false;}break;}var action;if(control){action=getAction('control');}else if(alt){action=getAction('alt');}else if(meta){action=getAction('meta');}else{action=getAction('normal');}// If e.maskShiftKey was set (during getAction) it means the shift key is
// already accounted for in the action, and we should not act on it any
// further. This is currently only used for Ctrl-Shift-Tab, which should send
// "CSI Z", not "CSI 1 ; 2 Z".
var shift=!e.maskShiftKey&&e.shiftKey;var keyDown={keyCode:e.keyCode,shift:e.shiftKey,// not `var shift` from above.
ctrl:control,alt:alt,meta:meta};var binding=this.bindings.getBinding(keyDown);if(binding){// Clear out the modifier bits so we don't try to munge the sequence
// further.
shift=control=alt=meta=false;resolvedActionType='normal';action=binding.action;if(typeof action=='function')action=action.call(this,this.terminal,keyDown);}if(alt&&this.altSendsWhat=='browser-key'&&action==DEFAULT){// When altSendsWhat is 'browser-key', we wait for the keypress event.
// In keypress, the browser should have set the event.charCode to the
// appropriate character.
// TODO(rginda): Character compositions will need some black magic.
action=PASS;}if(action===PASS||action===DEFAULT&&!(control||alt||meta)){// If this key is supposed to be handled by the browser, or it is an
// unmodified key with the default action, then exit this event handler.
// If it's an unmodified key, it'll be handled in onKeyPress where we
// can tell for sure which ASCII code to insert.
//
// This block needs to come before the STRIP test, otherwise we'll strip
// the modifier and think it's ok to let the browser handle the keypress.
// The browser won't know we're trying to ignore the modifiers and might
// perform some default action.
return;}if(action===STRIP){alt=control=false;action=keyDef.normal;if(typeof action=='function')action=action.apply(this.keyMap,[e,keyDef]);if(action==DEFAULT&&keyDef.keyCap.length==2)action=keyDef.keyCap.substr(shift?1:0,1);}e.preventDefault();e.stopPropagation();if(action===CANCEL)return;if(action!==DEFAULT&&typeof action!='string'){console.warn('Invalid action: '+JSON.stringify(action));return;}// Strip the modifier that is associated with the action, since we assume that
// modifier has already been accounted for in the action.
if(resolvedActionType=='control'){control=false;}else if(resolvedActionType=='alt'){alt=false;}else if(resolvedActionType=='meta'){meta=false;}if(typeof action=='string'&&action.substr(0,2)=='\x1b['&&(alt||control||shift||meta)){// The action is an escape sequence that and it was triggered in the
// presence of a keyboard modifier, we may need to alter the action to
// include the modifier before sending it.
// The math is funky but aligns w/xterm.
var imod=1;if(shift)imod+=1;if(alt)imod+=2;if(control)imod+=4;if(meta)imod+=8;var mod=';'+imod;if(action.length==3){// Some of the CSI sequences have zero parameters unless modified.
action='\x1b[1'+mod+action.substr(2,1);}else{// Others always have at least one parameter.
action=action.substr(0,action.length-1)+mod+action.substr(action.length-1);}}else{if(action===DEFAULT){action=keyDef.keyCap.substr(shift?1:0,1);if(control){var unshifted=keyDef.keyCap.substr(0,1);var code=unshifted.charCodeAt(0);if(code>=64&&code<=95){action=String.fromCharCode(code-64);}}}if(alt&&this.altSendsWhat=='8-bit'&&action.length==1){var code=action.charCodeAt(0)+128;action=String.fromCharCode(code);}// We respect alt/metaSendsEscape even if the keymap action was a literal
// string. Otherwise, every overridden alt/meta action would have to
// check alt/metaSendsEscape.
if(alt&&this.altSendsWhat=='escape'||meta&&this.metaSendsEscape){action='\x1b'+action;}}this.terminal.onVTKeystroke(action);};// SOURCE FILE: hterm/js/hterm_keyboard_bindings.js
// Copyright (c) 2015 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* A mapping from hterm.Keyboard.KeyPattern to an action.
*
* TODO(rginda): For now this bindings code is only used for user overrides.
* hterm.Keyboard.KeyMap still handles all of the built-in key mappings.
* It'd be nice if we migrated that over to be hterm.Keyboard.Bindings based.
*/hterm.Keyboard.Bindings=function(){this.bindings_={};};/**
* Remove all bindings.
*/hterm.Keyboard.Bindings.prototype.clear=function(){this.bindings_={};};/**
* Add a new binding.
*
* Internal API that assumes parsed objects as inputs.
* See the public addBinding for more details.
*
* @param {hterm.Keyboard.KeyPattern} keyPattern
* @param {string|function|hterm.Keyboard.KeyAction} action
*/hterm.Keyboard.Bindings.prototype.addBinding_=function(keyPattern,action){var binding=null;var list=this.bindings_[keyPattern.keyCode];if(list){for(var i=0;i<list.length;i++){if(list[i].keyPattern.matchKeyPattern(keyPattern)){binding=list[i];break;}}}if(binding){binding.action=action;}else{binding={keyPattern:keyPattern,action:action};if(!list){this.bindings_[keyPattern.keyCode]=[binding];}else{this.bindings_[keyPattern.keyCode].push(binding);list.sort(function(a,b){return hterm.Keyboard.KeyPattern.sortCompare(a.keyPattern,b.keyPattern);});}}};/**
* Add a new binding.
*
* If a binding for the keyPattern already exists it will be overridden.
*
* More specific keyPatterns take precedence over those with wildcards. Given
* bindings for "Ctrl-A" and "Ctrl-*-A", and a "Ctrl-A" keydown, the "Ctrl-A"
* binding will match even if "Ctrl-*-A" was created last.
*
* If action is a string, it will be passed through hterm.Parser.parseKeyAction.
*
* For example:
* // Will replace Ctrl-P keystrokes with the string "hiya!".
* addBinding('Ctrl-P', "'hiya!'");
* // Will cancel the keystroke entirely (make it do nothing).
* addBinding('Alt-D', hterm.Keyboard.KeyActions.CANCEL);
* // Will execute the code and return the action.
* addBinding('Ctrl-T', function() {
* console.log('Got a T!');
* return hterm.Keyboard.KeyActions.PASS;
* });
*
* @param {string|hterm.Keyboard.KeyPattern} keyPattern
* @param {string|function|hterm.Keyboard.KeyAction} action
*/hterm.Keyboard.Bindings.prototype.addBinding=function(key,action){// If we're given a hterm.Keyboard.KeyPattern object, pass it down.
if(typeof key!='string'){this.addBinding_(key,action);return;}// Here we treat key as a string.
var p=new hterm.Parser();p.reset(key);var sequence;try{sequence=p.parseKeySequence();}catch(ex){console.error(ex);return;}if(!p.isComplete()){console.error(p.error('Expected end of sequence: '+sequence));return;}// If action is a string, parse it. Otherwise assume it's callable.
if(typeof action=='string'){p.reset(action);try{action=p.parseKeyAction();}catch(ex){console.error(ex);return;}}if(!p.isComplete()){console.error(p.error('Expected end of sequence: '+sequence));return;}this.addBinding_(new hterm.Keyboard.KeyPattern(sequence),action);};/**
* Add multiple bindings at a time using a map of {string: string, ...}
*
* This uses hterm.Parser to parse the maps key into KeyPatterns, and the
* map values into {string|function|KeyAction}.
*
* For example:
* {
* // Will replace Ctrl-P keystrokes with the string "hiya!".
* 'Ctrl-P': "'hiya!'",
* // Will cancel the keystroke entirely (make it do nothing).
* 'Alt-D': hterm.Keyboard.KeyActions.CANCEL,
* }
*
* @param {Object} map
*/hterm.Keyboard.Bindings.prototype.addBindings=function(map){for(var key in map){this.addBinding(key,map[key]);}};/**
* Return the binding that is the best match for the given keyDown record,
* or null if there is no match.
*
* @param {Object} keyDown An object with a keyCode property and zero or
* more boolean properties representing key modifiers. These property names
* must match those defined in hterm.Keyboard.KeyPattern.modifiers.
*/hterm.Keyboard.Bindings.prototype.getBinding=function(keyDown){var list=this.bindings_[keyDown.keyCode];if(!list)return null;for(var i=0;i<list.length;i++){var binding=list[i];if(binding.keyPattern.matchKeyDown(keyDown))return binding;}return null;};// SOURCE FILE: hterm/js/hterm_keyboard_keymap.js
// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* The default key map for hterm.
*
* Contains a mapping of keyCodes to keyDefs (aka key definitions). The key
* definition tells the hterm.Keyboard class how to handle keycodes.
*
* This should work for most cases, as the printable characters get handled
* in the keypress event. In that case, even if the keycap is wrong in the
* key map, the correct character should be sent.
*
* Different layouts, such as Dvorak should work with this keymap, as those
* layouts typically move keycodes around on the keyboard without disturbing
* the actual keycaps.
*
* There may be issues with control keys on non-US keyboards or with keyboards
* that very significantly from the expectations here, in which case we may
* have to invent new key maps.
*
* The sequences defined in this key map come from [XTERM] as referenced in
* vt.js, starting with the section titled "Alt and Meta Keys".
*/hterm.Keyboard.KeyMap=function(keyboard){this.keyboard=keyboard;this.keyDefs={};this.reset();};/**
* Add a single key definition.
*
* The definition is an object containing the following fields: 'keyCap',
* 'normal', 'control', 'alt', and 'meta'.
*
* - keyCap is a string identifying the key on the keyboard. For printable
* keys, the key cap should be exactly two characters, starting with the
* unshifted version. For example, 'aA', 'bB', '1!' and '=+'. For
* non-printable the key cap should be surrounded in square braces, as in
* '[INS]', '[LEFT]'. By convention, non-printable keycaps are in uppercase
* but this is not a strict requirement.
*
* - Normal is the action that should be performed when the key is pressed
* in the absence of any modifier. See below for the supported actions.
*
* - Control is the action that should be performed when the key is pressed
* along with the control modifier. See below for the supported actions.
*
* - Alt is the action that should be performed when the key is pressed
* along with the alt modifier. See below for the supported actions.
*
* - Meta is the action that should be performed when the key is pressed
* along with the meta modifier. See below for the supported actions.
*
* Actions can be one of the hterm.Keyboard.KeyActions as documented below,
* a literal string, or an array. If the action is a literal string then
* the string is sent directly to the host. If the action is an array it
* is taken to be an escape sequence that may be altered by modifier keys.
* The second-to-last element of the array will be overwritten with the
* state of the modifier keys, as specified in the final table of "PC-Style
* Function Keys" from [XTERM].
*/hterm.Keyboard.KeyMap.prototype.addKeyDef=function(keyCode,def){if(keyCode in this.keyDefs)console.warn('Duplicate keyCode: '+keyCode);this.keyDefs[keyCode]=def;};/**
* Add multiple key definitions in a single call.
*
* This function takes the key definitions as variable argument list. Each
* argument is the key definition specified as an array.
*
* (If the function took everything as one big hash we couldn't detect
* duplicates, and there would be a lot more typing involved.)
*
* Each key definition should have 6 elements: (keyCode, keyCap, normal action,
* control action, alt action and meta action). See KeyMap.addKeyDef for the
* meaning of these elements.
*/hterm.Keyboard.KeyMap.prototype.addKeyDefs=function(var_args){for(var i=0;i<arguments.length;i++){this.addKeyDef(arguments[i][0],{keyCap:arguments[i][1],normal:arguments[i][2],control:arguments[i][3],alt:arguments[i][4],meta:arguments[i][5]});}};/**
* Set up the default state for this keymap.
*/hterm.Keyboard.KeyMap.prototype.reset=function(){this.keyDefs={};var self=this;// This function is used by the "macro" functions below. It makes it
// possible to use the call() macro as an argument to any other macro.
function resolve(action,e,k){if(typeof action=='function')return action.apply(self,[e,k]);return action;}// If not application keypad a, else b. The keys that care about
// application keypad ignore it when the key is modified.
function ak(a,b){return function(e,k){var action=e.shiftKey||e.ctrlKey||e.altKey||e.metaKey||!self.keyboard.applicationKeypad?a:b;return resolve(action,e,k);};}// If mod or not application cursor a, else b. The keys that care about
// application cursor ignore it when the key is modified.
function ac(a,b){return function(e,k){var action=e.shiftKey||e.ctrlKey||e.altKey||e.metaKey||!self.keyboard.applicationCursor?a:b;return resolve(action,e,k);};}// If not backspace-sends-backspace keypad a, else b.
function bs(a,b){return function(e,k){var action=!self.keyboard.backspaceSendsBackspace?a:b;return resolve(action,e,k);};}// If not e.shiftKey a, else b.
function sh(a,b){return function(e,k){var action=!e.shiftKey?a:b;e.maskShiftKey=true;return resolve(action,e,k);};}// If not e.altKey a, else b.
function alt(a,b){return function(e,k){var action=!e.altKey?a:b;return resolve(action,e,k);};}// If no modifiers a, else b.
function mod(a,b){return function(e,k){var action=!(e.shiftKey||e.ctrlKey||e.altKey||e.metaKey)?a:b;return resolve(action,e,k);};}// Compute a control character for a given character.
function ctl(ch){return String.fromCharCode(ch.charCodeAt(0)-64);}// Call a method on the keymap instance.
function c(m){return function(e,k){return this[m](e,k);};}// Ignore if not trapping media keys.
function med(fn){return function(e,k){if(!self.keyboard.mediaKeysAreFKeys){// Block Back, Forward, and Reload keys to avoid navigating away from
// the current page.
return e.keyCode==166||e.keyCode==167||e.keyCode==168?hterm.Keyboard.KeyActions.CANCEL:hterm.Keyboard.KeyActions.PASS;}return resolve(fn,e,k);};}// Browser-specific differences.
if(window.navigator&&navigator.userAgent){if(navigator.userAgent.includes('Firefox')){// Firefox defines some keys uniquely. No other browser defines these is
// this way. Some even conflict. The keyCode field isn't well documented
// as it isn't standardized. At some point we should switch to "key".
// https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode
// http://unixpapa.com/js/key.html
var keycapMute=181;// Mute
var keycapVolDn=182;// Volume Down
var keycapVolUp=183;// Volume Up
var keycapSC=59;// ;:
var keycapEP=61;// =+
var keycapMU=173;// -_
this.addKeyDefs(// Firefox Italian +*.
[171,'+*',DEFAULT,c('onPlusMinusZero_'),DEFAULT,c('onPlusMinusZero_')]);}else{// All other browsers use these mappings.
var keycapMute=173;// Mute
var keycapVolDn=174;// Volume Down
var keycapVolUp=175;// Volume Up
var keycapSC=186;// ;:
var keycapEP=187;// =+
var keycapMU=189;// -_
}}var ESC='\x1b';var CSI='\x1b[';var SS3='\x1bO';var CANCEL=hterm.Keyboard.KeyActions.CANCEL;var DEFAULT=hterm.Keyboard.KeyActions.DEFAULT;var PASS=hterm.Keyboard.KeyActions.PASS;var STRIP=hterm.Keyboard.KeyActions.STRIP;this.addKeyDefs(// These fields are: [keycode, keycap, normal, control, alt, meta]
// The browser sends the keycode 0 for some keys. We'll just assume it's
// going to do the right thing by default for those keys.
[0,'[UNKNOWN]',PASS,PASS,PASS,PASS],// First row.
// These bindings match xterm for lack of a better standard. The emitted
// values might look like they're skipping values, but it's what xterm does.
// https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-PC-Style-Function-Keys
[27,'[ESC]',ESC,DEFAULT,DEFAULT,DEFAULT],[112,'[F1]',mod(SS3+'P',CSI+'P'),DEFAULT,CSI+"23~",DEFAULT],[113,'[F2]',mod(SS3+'Q',CSI+'Q'),DEFAULT,CSI+"24~",DEFAULT],[114,'[F3]',mod(SS3+'R',CSI+'R'),DEFAULT,CSI+"25~",DEFAULT],[115,'[F4]',mod(SS3+'S',CSI+'S'),DEFAULT,CSI+"26~",DEFAULT],[116,'[F5]',CSI+'15~',DEFAULT,CSI+"28~",DEFAULT],[117,'[F6]',CSI+'17~',DEFAULT,CSI+"29~",DEFAULT],[118,'[F7]',CSI+'18~',DEFAULT,CSI+"31~",DEFAULT],[119,'[F8]',CSI+'19~',DEFAULT,CSI+"32~",DEFAULT],[120,'[F9]',CSI+'20~',DEFAULT,CSI+"33~",DEFAULT],[121,'[F10]',CSI+'21~',DEFAULT,CSI+"34~",DEFAULT],[122,'[F11]',c('onF11_'),DEFAULT,CSI+"42~",DEFAULT],[123,'[F12]',CSI+'24~',DEFAULT,CSI+"43~",DEFAULT],// Second row.
[192,'`~',DEFAULT,sh(ctl('@'),ctl('^')),DEFAULT,PASS],[49,'1!',DEFAULT,c('onCtrlNum_'),c('onAltNum_'),c('onMetaNum_')],[50,'2@',DEFAULT,c('onCtrlNum_'),c('onAltNum_'),c('onMetaNum_')],[51,'3#',DEFAULT,c('onCtrlNum_'),c('onAltNum_'),c('onMetaNum_')],[52,'4$',DEFAULT,c('onCtrlNum_'),c('onAltNum_'),c('onMetaNum_')],[53,'5%',DEFAULT,c('onCtrlNum_'),c('onAltNum_'),c('onMetaNum_')],[54,'6^',DEFAULT,c('onCtrlNum_'),c('onAltNum_'),c('onMetaNum_')],[55,'7&',DEFAULT,c('onCtrlNum_'),c('onAltNum_'),c('onMetaNum_')],[56,'8*',DEFAULT,c('onCtrlNum_'),c('onAltNum_'),c('onMetaNum_')],[57,'9(',DEFAULT,c('onCtrlNum_'),c('onAltNum_'),c('onMetaNum_')],[48,'0)',DEFAULT,c('onPlusMinusZero_'),c('onAltNum_'),c('onPlusMinusZero_')],[keycapMU,'-_',DEFAULT,c('onPlusMinusZero_'),DEFAULT,c('onPlusMinusZero_')],[keycapEP,'=+',DEFAULT,c('onPlusMinusZero_'),DEFAULT,c('onPlusMinusZero_')],[8,'[BKSP]',bs('\x7f','\b'),bs('\b','\x7f'),DEFAULT,DEFAULT],// Third row.
[9,'[TAB]',sh('\t',CSI+'Z'),STRIP,PASS,DEFAULT],[81,'qQ',DEFAULT,ctl('Q'),DEFAULT,DEFAULT],[87,'wW',DEFAULT,ctl('W'),DEFAULT,DEFAULT],[69,'eE',DEFAULT,ctl('E'),DEFAULT,DEFAULT],[82,'rR',DEFAULT,ctl('R'),DEFAULT,DEFAULT],[84,'tT',DEFAULT,ctl('T'),DEFAULT,DEFAULT],[89,'yY',DEFAULT,ctl('Y'),DEFAULT,DEFAULT],[85,'uU',DEFAULT,ctl('U'),DEFAULT,DEFAULT],[73,'iI',DEFAULT,ctl('I'),DEFAULT,DEFAULT],[79,'oO',DEFAULT,ctl('O'),DEFAULT,DEFAULT],[80,'pP',DEFAULT,ctl('P'),DEFAULT,DEFAULT],[219,'[{',DEFAULT,ctl('['),DEFAULT,DEFAULT],[221,']}',DEFAULT,ctl(']'),DEFAULT,DEFAULT],[220,'\\|',DEFAULT,ctl('\\'),DEFAULT,DEFAULT],// Fourth row. (We let Ctrl-Shift-J pass for Chrome DevTools.)
[20,'[CAPS]',PASS,PASS,PASS,DEFAULT],[65,'aA',DEFAULT,ctl('A'),DEFAULT,DEFAULT],[83,'sS',DEFAULT,ctl('S'),DEFAULT,DEFAULT],[68,'dD',DEFAULT,ctl('D'),DEFAULT,DEFAULT],[70,'fF',DEFAULT,ctl('F'),DEFAULT,DEFAULT],[71,'gG',DEFAULT,ctl('G'),DEFAULT,DEFAULT],[72,'hH',DEFAULT,ctl('H'),DEFAULT,DEFAULT],[74,'jJ',DEFAULT,sh(ctl('J'),PASS),DEFAULT,DEFAULT],[75,'kK',DEFAULT,sh(ctl('K'),c('onClear_')),DEFAULT,DEFAULT],[76,'lL',DEFAULT,sh(ctl('L'),PASS),DEFAULT,DEFAULT],[keycapSC,';:',DEFAULT,STRIP,DEFAULT,DEFAULT],[222,'\'"',DEFAULT,STRIP,DEFAULT,DEFAULT],[13,'[ENTER]','\r',CANCEL,CANCEL,DEFAULT],// Fifth row. This includes the copy/paste shortcuts. On some
// platforms it's Ctrl-C/V, on others it's Meta-C/V. We assume either
// Ctrl-C/Meta-C should pass to the browser when there is a selection,
// and Ctrl-Shift-V/Meta-*-V should always pass to the browser (since
// these seem to be recognized as paste too).
[16,'[SHIFT]',PASS,PASS,PASS,DEFAULT],[90,'zZ',DEFAULT,ctl('Z'),DEFAULT,DEFAULT],[88,'xX',DEFAULT,ctl('X'),DEFAULT,DEFAULT],[67,'cC',DEFAULT,c('onCtrlC_'),DEFAULT,c('onMetaC_')],[86,'vV',DEFAULT,c('onCtrlV_'),DEFAULT,c('onMetaV_')],[66,'bB',DEFAULT,sh(ctl('B'),PASS),DEFAULT,sh(DEFAULT,PASS)],[78,'nN',DEFAULT,c('onCtrlN_'),DEFAULT,c('onMetaN_')],[77,'mM',DEFAULT,ctl('M'),DEFAULT,DEFAULT],[188,',<',DEFAULT,alt(STRIP,PASS),DEFAULT,DEFAULT],[190,'.>',DEFAULT,alt(STRIP,PASS),DEFAULT,DEFAULT],[191,'/?',DEFAULT,sh(ctl('_'),ctl('?')),DEFAULT,DEFAULT],// Sixth and final row.
[17,'[CTRL]',PASS,PASS,PASS,PASS],[18,'[ALT]',PASS,PASS,PASS,PASS],[91,'[LAPL]',PASS,PASS,PASS,PASS],[32,' ',DEFAULT,ctl('@'),DEFAULT,DEFAULT],[92,'[RAPL]',PASS,PASS,PASS,PASS],[93,'[RMENU]',PASS,PASS,PASS,PASS],// These things.
[42,'[PRTSCR]',PASS,PASS,PASS,PASS],[145,'[SCRLK]',PASS,PASS,PASS,PASS],[19,'[BREAK]',PASS,PASS,PASS,PASS],// The block of six keys above the arrows.
[45,'[INSERT]',c('onKeyInsert_'),DEFAULT,DEFAULT,DEFAULT],[36,'[HOME]',c('onKeyHome_'),DEFAULT,DEFAULT,DEFAULT],[33,'[PGUP]',c('onKeyPageUp_'),DEFAULT,DEFAULT,DEFAULT],[46,'[DEL]',c('onKeyDel_'),DEFAULT,DEFAULT,DEFAULT],[35,'[END]',c('onKeyEnd_'),DEFAULT,DEFAULT,DEFAULT],[34,'[PGDOWN]',c('onKeyPageDown_'),DEFAULT,DEFAULT,DEFAULT],// Arrow keys. When unmodified they respect the application cursor state,
// otherwise they always send the CSI codes.
[38,'[UP]',c('onKeyArrowUp_'),DEFAULT,DEFAULT,DEFAULT],[40,'[DOWN]',c('onKeyArrowDown_'),DEFAULT,DEFAULT,DEFAULT],[39,'[RIGHT]',ac(CSI+'C',SS3+'C'),DEFAULT,DEFAULT,DEFAULT],[37,'[LEFT]',ac(CSI+'D',SS3+'D'),DEFAULT,DEFAULT,DEFAULT],[144,'[NUMLOCK]',PASS,PASS,PASS,PASS],// On Apple keyboards, the NumLock key is a Clear key. It also tends to be
// what KP5 sends when numlock is off. Not clear if we could do anything
// useful with it, so just pass it along.
[12,'[CLEAR]',PASS,PASS,PASS,PASS],// With numlock off, the keypad generates the same key codes as the arrows
// and 'block of six' for some keys, and null key codes for the rest.
// Keypad with numlock on generates unique key codes...
[96,'[KP0]',DEFAULT,DEFAULT,DEFAULT,DEFAULT],[97,'[KP1]',DEFAULT,DEFAULT,DEFAULT,DEFAULT],[98,'[KP2]',DEFAULT,DEFAULT,DEFAULT,DEFAULT],[99,'[KP3]',DEFAULT,DEFAULT,DEFAULT,DEFAULT],[100,'[KP4]',DEFAULT,DEFAULT,DEFAULT,DEFAULT],[101,'[KP5]',DEFAULT,DEFAULT,DEFAULT,DEFAULT],[102,'[KP6]',DEFAULT,DEFAULT,DEFAULT,DEFAULT],[103,'[KP7]',DEFAULT,DEFAULT,DEFAULT,DEFAULT],[104,'[KP8]',DEFAULT,DEFAULT,DEFAULT,DEFAULT],[105,'[KP9]',DEFAULT,DEFAULT,DEFAULT,DEFAULT],[107,'[KP+]',DEFAULT,c('onPlusMinusZero_'),DEFAULT,c('onPlusMinusZero_')],[109,'[KP-]',DEFAULT,c('onPlusMinusZero_'),DEFAULT,c('onPlusMinusZero_')],[106,'[KP*]',DEFAULT,DEFAULT,DEFAULT,DEFAULT],[111,'[KP/]',DEFAULT,DEFAULT,DEFAULT,DEFAULT],[110,'[KP.]',DEFAULT,DEFAULT,DEFAULT,DEFAULT]);// OS-specific differences.
if(hterm.os=='cros'){this.addKeyDefs(// Chrome OS keyboard top row. The media-keys-are-fkeys preference allows
// users to make these always behave as function keys (see those bindings
// above for more details).
[166,'[BACK]',med(mod(SS3+'P',CSI+'P')),DEFAULT,CSI+'23~',DEFAULT],// F1
[167,'[FWD]',med(mod(SS3+'Q',CSI+'Q')),DEFAULT,CSI+'24~',DEFAULT],// F2
[168,'[RELOAD]',med(mod(SS3+'R',CSI+'R')),DEFAULT,CSI+'25~',DEFAULT],// F3
[183,'[FSCR]',med(mod(SS3+'S',CSI+'S')),DEFAULT,CSI+'26~',DEFAULT],// F4
[182,'[WINS]',med(CSI+'15~'),DEFAULT,CSI+'28~',DEFAULT],// F5
[216,'[BRIT-]',med(CSI+'17~'),DEFAULT,CSI+'29~',DEFAULT],// F6
[217,'[BRIT+]',med(CSI+'18~'),DEFAULT,CSI+'31~',DEFAULT],// F7
[173,'[MUTE]',med(CSI+'19~'),DEFAULT,CSI+'32~',DEFAULT],// F8
[174,'[VOL-]',med(CSI+'20~'),DEFAULT,CSI+'33~',DEFAULT],// F9
[175,'[VOL+]',med(CSI+'21~'),DEFAULT,CSI+'34~',DEFAULT],// F10
// We could make this into F11, but it'd be a bit weird. Chrome allows us
// to see this and react, but it doesn't actually allow us to block or
// cancel it, so it makes the screen flash/lock still.
[152,'[POWER]',DEFAULT,DEFAULT,DEFAULT,DEFAULT],// The Pixelbook has a slightly different layout. This means half the keys
// above are off by one. https://crbug.com/807513
[179,'[PLAY]',med(CSI+'18~'),DEFAULT,CSI+'31~',DEFAULT],// F7
// The settings / hamburgers / three hot dogs / menu / whatever-it's-called.
[154,'[DOGS]',med(CSI+'23~'),DEFAULT,CSI+'42~',DEFAULT],// F11
// We don't use this for anything, but keep it from popping up by default.
[153,'[ASSIST]',DEFAULT,DEFAULT,DEFAULT,DEFAULT]);}};/**
* Either allow the paste or send a key sequence.
*/hterm.Keyboard.KeyMap.prototype.onKeyInsert_=function(e){if(this.keyboard.shiftInsertPaste&&e.shiftKey)return hterm.Keyboard.KeyActions.PASS;return'\x1b[2~';};/**
* Either scroll the scrollback buffer or send a key sequence.
*/hterm.Keyboard.KeyMap.prototype.onKeyHome_=function(e){if(!this.keyboard.homeKeysScroll^e.shiftKey){if(e.altey||e.ctrlKey||e.shiftKey||!this.keyboard.applicationCursor){return'\x1b[H';}return'\x1bOH';}this.keyboard.terminal.scrollHome();return hterm.Keyboard.KeyActions.CANCEL;};/**
* Either scroll the scrollback buffer or send a key sequence.
*/hterm.Keyboard.KeyMap.prototype.onKeyEnd_=function(e){if(!this.keyboard.homeKeysScroll^e.shiftKey){if(e.altKey||e.ctrlKey||e.shiftKey||!this.keyboard.applicationCursor){return'\x1b[F';}return'\x1bOF';}this.keyboard.terminal.scrollEnd();return hterm.Keyboard.KeyActions.CANCEL;};/**
* Either scroll the scrollback buffer or send a key sequence.
*/hterm.Keyboard.KeyMap.prototype.onKeyPageUp_=function(e){if(!this.keyboard.pageKeysScroll^e.shiftKey)return'\x1b[5~';this.keyboard.terminal.scrollPageUp();return hterm.Keyboard.KeyActions.CANCEL;};/**
* Either send a true DEL, or sub in meta-backspace.
*
* On Chrome OS, if we know the alt key is down, but we get a DEL event that
* claims that the alt key is not pressed, we know the DEL was a synthetic
* one from a user that hit alt-backspace. Based on a user pref, we can sub
* in meta-backspace in this case.
*/hterm.Keyboard.KeyMap.prototype.onKeyDel_=function(e){if(this.keyboard.altBackspaceIsMetaBackspace&&this.keyboard.altKeyPressed&&!e.altKey)return'\x1b\x7f';return'\x1b[3~';};/**
* Either scroll the scrollback buffer or send a key sequence.
*/hterm.Keyboard.KeyMap.prototype.onKeyPageDown_=function(e){if(!this.keyboard.pageKeysScroll^e.shiftKey)return'\x1b[6~';this.keyboard.terminal.scrollPageDown();return hterm.Keyboard.KeyActions.CANCEL;};/**
* Either scroll the scrollback buffer or send a key sequence.
*/hterm.Keyboard.KeyMap.prototype.onKeyArrowUp_=function(e){if(!this.keyboard.applicationCursor&&e.shiftKey){this.keyboard.terminal.scrollLineUp();return hterm.Keyboard.KeyActions.CANCEL;}return e.shiftKey||e.ctrlKey||e.altKey||e.metaKey||!this.keyboard.applicationCursor?'\x1b[A':'\x1bOA';};/**
* Either scroll the scrollback buffer or send a key sequence.
*/hterm.Keyboard.KeyMap.prototype.onKeyArrowDown_=function(e){if(!this.keyboard.applicationCursor&&e.shiftKey){this.keyboard.terminal.scrollLineDown();return hterm.Keyboard.KeyActions.CANCEL;}return e.shiftKey||e.ctrlKey||e.altKey||e.metaKey||!this.keyboard.applicationCursor?'\x1b[B':'\x1bOB';};/**
* Clear the primary/alternate screens and the scrollback buffer.
*/hterm.Keyboard.KeyMap.prototype.onClear_=function(e,keyDef){this.keyboard.terminal.wipeContents();return hterm.Keyboard.KeyActions.CANCEL;};/**
* Handle F11 behavior (fullscreen) when not in a window.
*
* It would be nice to use the Fullscreen API, but the UX is slightly different
* a bad way: the Escape key is automatically registered for exiting. If we let
* the browser handle F11 directly though, we still get to capture Escape.
*/hterm.Keyboard.KeyMap.prototype.onF11_=function(e,keyDef){if(hterm.windowType!='popup')return hterm.Keyboard.KeyActions.PASS;else return'\x1b[23~';};/**
* Either pass Ctrl-1..9 to the browser or send them to the host.
*
* Note that Ctrl-1 and Ctrl-9 don't actually have special sequences mapped
* to them in xterm or gnome-terminal. The range is really Ctrl-2..8, but
* we handle 1..9 since Chrome treats the whole range special.
*/hterm.Keyboard.KeyMap.prototype.onCtrlNum_=function(e,keyDef){// Compute a control character for a given character.
function ctl(ch){return String.fromCharCode(ch.charCodeAt(0)-64);}if(this.keyboard.terminal.passCtrlNumber&&!e.shiftKey)return hterm.Keyboard.KeyActions.PASS;switch(keyDef.keyCap.substr(0,1)){case'1':return'1';case'2':return ctl('@');case'3':return ctl('[');case'4':return ctl('\\');case'5':return ctl(']');case'6':return ctl('^');case'7':return ctl('_');case'8':return'\x7f';case'9':return'9';}};/**
* Either pass Alt-1..9 to the browser or send them to the host.
*/hterm.Keyboard.KeyMap.prototype.onAltNum_=function(e,keyDef){if(this.keyboard.terminal.passAltNumber&&!e.shiftKey)return hterm.Keyboard.KeyActions.PASS;return hterm.Keyboard.KeyActions.DEFAULT;};/**
* Either pass Meta-1..9 to the browser or send them to the host.
*/hterm.Keyboard.KeyMap.prototype.onMetaNum_=function(e,keyDef){if(this.keyboard.terminal.passMetaNumber&&!e.shiftKey)return hterm.Keyboard.KeyActions.PASS;return hterm.Keyboard.KeyActions.DEFAULT;};/**
* Either send a ^C or interpret the keystroke as a copy command.
*/hterm.Keyboard.KeyMap.prototype.onCtrlC_=function(e,keyDef){var selection=this.keyboard.terminal.getDocument().getSelection();if(!selection.isCollapsed){if(this.keyboard.ctrlCCopy&&!e.shiftKey){// Ctrl-C should copy if there is a selection, send ^C otherwise.
// Perform the copy by letting the browser handle Ctrl-C. On most
// browsers, this is the *only* way to place text on the clipboard from
// the 'drive-by' web.
if(this.keyboard.terminal.clearSelectionAfterCopy){setTimeout(selection.collapseToEnd.bind(selection),50);}return hterm.Keyboard.KeyActions.PASS;}if(!this.keyboard.ctrlCCopy&&e.shiftKey){// Ctrl-Shift-C should copy if there is a selection, send ^C otherwise.
// Perform the copy manually. This only works in situations where
// document.execCommand('copy') is allowed.
if(this.keyboard.terminal.clearSelectionAfterCopy){setTimeout(selection.collapseToEnd.bind(selection),50);}this.keyboard.terminal.copySelectionToClipboard();return hterm.Keyboard.KeyActions.CANCEL;}}return'\x03';};/**
* Either send a ^N or open a new window to the same location.
*/hterm.Keyboard.KeyMap.prototype.onCtrlN_=function(e,keyDef){if(e.shiftKey){lib.f.openWindow(document.location.href,'','chrome=no,close=yes,resize=yes,scrollbars=yes,'+'minimizable=yes,width='+window.innerWidth+',height='+window.innerHeight);return hterm.Keyboard.KeyActions.CANCEL;}return'\x0e';};/**
* Either send a ^V or issue a paste command.
*
* The default behavior is to paste if the user presses Ctrl-Shift-V, and send
* a ^V if the user presses Ctrl-V. This can be flipped with the
* 'ctrl-v-paste' preference.
*
*/hterm.Keyboard.KeyMap.prototype.onCtrlV_=function(e,keyDef){if(!e.shiftKey&&this.keyboard.ctrlVPaste||e.shiftKey&&!this.keyboard.ctrlVPaste){// We try to do the pasting ourselves as not all browsers/OSs bind Ctrl-V to
// pasting. Notably, on macOS, Ctrl-V/Ctrl-Shift-V do nothing.
// However, this might run into web restrictions, so if it fails, we still
// fallback to the letting the native behavior (hopefully) save us.
if(this.keyboard.terminal.paste())return hterm.Keyboard.KeyActions.CANCEL;else return hterm.Keyboard.KeyActions.PASS;}return'\x16';};/**
* Either the default action or open a new window to the same location.
*/hterm.Keyboard.KeyMap.prototype.onMetaN_=function(e,keyDef){if(e.shiftKey){lib.f.openWindow(document.location.href,'','chrome=no,close=yes,resize=yes,scrollbars=yes,'+'minimizable=yes,width='+window.outerWidth+',height='+window.outerHeight);return hterm.Keyboard.KeyActions.CANCEL;}return hterm.Keyboard.KeyActions.DEFAULT;};/**
* Either send a Meta-C or allow the browser to interpret the keystroke as a
* copy command.
*
* If there is no selection, or if the user presses Meta-Shift-C, then we'll
* transmit an '\x1b' (if metaSendsEscape is on) followed by 'c' or 'C'.
*
* If there is a selection, we defer to the browser. In this case we clear out
* the selection so the user knows we heard them, and also to give them a
* chance to send a Meta-C by just hitting the key again.
*/hterm.Keyboard.KeyMap.prototype.onMetaC_=function(e,keyDef){var document=this.keyboard.terminal.getDocument();if(e.shiftKey||document.getSelection().isCollapsed){// If the shift key is being held, or there is no document selection, send
// a Meta-C. The keyboard code will add the ESC if metaSendsEscape is true,
// we just have to decide between 'c' and 'C'.
return keyDef.keyCap.substr(e.shiftKey?1:0,1);}// Otherwise let the browser handle it as a copy command.
if(this.keyboard.terminal.clearSelectionAfterCopy){setTimeout(function(){document.getSelection().collapseToEnd();},50);}return hterm.Keyboard.KeyActions.PASS;};/**
* Either PASS or DEFAULT Meta-V, depending on preference.
*
* Always PASS Meta-Shift-V to allow browser to interpret the keystroke as
* a paste command.
*/hterm.Keyboard.KeyMap.prototype.onMetaV_=function(e,keyDef){if(e.shiftKey)return hterm.Keyboard.KeyActions.PASS;return this.keyboard.passMetaV?hterm.Keyboard.KeyActions.PASS:hterm.Keyboard.KeyActions.DEFAULT;};/**
* Handle font zooming.
*
* The browser's built-in zoom has a bit of an issue at certain zoom levels.
* At some magnifications, the measured height of a row of text differs from
* the height that was explicitly set.
*
* We override the browser zoom keys to change the ScrollPort's font size to
* avoid the issue.
*/hterm.Keyboard.KeyMap.prototype.onPlusMinusZero_=function(e,keyDef){if(!(this.keyboard.ctrlPlusMinusZeroZoom^e.shiftKey)){// If ctrl-PMZ controls zoom and the shift key is pressed, or
// ctrl-shift-PMZ controls zoom and this shift key is not pressed,
// then we want to send the control code instead of affecting zoom.
if(keyDef.keyCap=='-_')return'\x1f';// ^_
// Only ^_ is valid, the other sequences have no meaning.
return hterm.Keyboard.KeyActions.CANCEL;}if(this.keyboard.terminal.getZoomFactor()!=1){// If we're not at 1:1 zoom factor, let the Ctrl +/-/0 keys control the
// browser zoom, so it's easier to for the user to get back to 100%.
return hterm.Keyboard.KeyActions.PASS;}var cap=keyDef.keyCap.substr(0,1);if(cap=='0'){this.keyboard.terminal.setFontSize(0);}else{var size=this.keyboard.terminal.getFontSize();if(cap=='-'||keyDef.keyCap=='[KP-]'){size-=1;}else{size+=1;}this.keyboard.terminal.setFontSize(size);}return hterm.Keyboard.KeyActions.CANCEL;};// SOURCE FILE: hterm/js/hterm_keyboard_keypattern.js
// Copyright (c) 2015 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* A record of modifier bits and keycode used to define a key binding.
*
* The modifier names are enumerated in the static KeyPattern.modifiers
* property below. Each modifier can be true, false, or "*". True means
* the modifier key must be present, false means it must not, and "*" means
* it doesn't matter.
*/hterm.Keyboard.KeyPattern=function(spec){this.wildcardCount=0;this.keyCode=spec.keyCode;hterm.Keyboard.KeyPattern.modifiers.forEach(function(mod){this[mod]=spec[mod]||false;if(this[mod]=='*')this.wildcardCount++;}.bind(this));};/**
* Valid modifier names.
*/hterm.Keyboard.KeyPattern.modifiers=['shift','ctrl','alt','meta'];/**
* A compare callback for Array.prototype.sort().
*
* The bindings code wants to be sure to search through the strictest key
* patterns first, so that loosely defined patterns have a lower priority than
* exact patterns.
*
* @param {hterm.Keyboard.KeyPattern} a
* @param {hterm.Keyboard.KeyPattern} b
*/hterm.Keyboard.KeyPattern.sortCompare=function(a,b){if(a.wildcardCount<b.wildcardCount)return-1;if(a.wildcardCount>b.wildcardCount)return 1;return 0;};/**
* Private method used to match this key pattern against other key patterns
* or key down events.
*
* @param {Object} The object to match.
* @param {boolean} True if we should ignore wildcards. Useful when you want
* to perform and exact match against another key pattern.
*/hterm.Keyboard.KeyPattern.prototype.match_=function(obj,exactMatch){if(this.keyCode!=obj.keyCode)return false;var rv=true;hterm.Keyboard.KeyPattern.modifiers.forEach(function(mod){var modValue=mod in obj?obj[mod]:false;if(!rv||!exactMatch&&this[mod]=='*'||this[mod]==modValue)return;rv=false;}.bind(this));return rv;};/**
* Return true if the given keyDown object is a match for this key pattern.
*
* @param {Object} keyDown An object with a keyCode property and zero or
* more boolean properties representing key modifiers. These property names
* must match those defined in hterm.Keyboard.KeyPattern.modifiers.
*/hterm.Keyboard.KeyPattern.prototype.matchKeyDown=function(keyDown){return this.match_(keyDown,false);};/**
* Return true if the given hterm.Keyboard.KeyPattern is exactly the same as
* this one.
*
* @param {hterm.Keyboard.KeyPattern}
*/hterm.Keyboard.KeyPattern.prototype.matchKeyPattern=function(keyPattern){return this.match_(keyPattern,true);};// SOURCE FILE: hterm/js/hterm_options.js
// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @fileoverview This file implements the hterm.Options class,
* which stores current operating conditions for the terminal. This object is
* used instead of a series of parameters to allow saving/restoring of cursor
* conditions easily, and to provide an easy place for common configuration
* options.
*
* Original code by Cory Maccarrone.
*/ /**
* Constructor for the hterm.Options class, optionally acting as a copy
* constructor.
*
* The defaults are as defined in http://www.vt100.net/docs/vt510-rm/DECSTR
* except that we enable autowrap (wraparound) by default since that seems to
* be what xterm does.
*
* @param {hterm.Options=} opt_copy Optional instance to copy.
* @constructor
*/hterm.Options=function(opt_copy){// All attributes in this class are public to allow easy access by the
// terminal.
this.wraparound=opt_copy?opt_copy.wraparound:true;this.reverseWraparound=opt_copy?opt_copy.reverseWraparound:false;this.originMode=opt_copy?opt_copy.originMode:false;this.autoCarriageReturn=opt_copy?opt_copy.autoCarriageReturn:false;this.cursorVisible=opt_copy?opt_copy.cursorVisible:true;this.cursorBlink=opt_copy?opt_copy.cursorBlink:false;this.insertMode=opt_copy?opt_copy.insertMode:false;this.reverseVideo=opt_copy?opt_copy.reverseVideo:false;this.bracketedPaste=opt_copy?opt_copy.bracketedPaste:false;};// SOURCE FILE: hterm/js/hterm_parser.js
// Copyright (c) 2015 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @constructor
* Parses the key definition syntax used for user keyboard customizations.
*/hterm.Parser=function(){/**
* @type {string} The source string.
*/this.source='';/**
* @type {number} The current position.
*/this.pos=0;/**
* @type {string?} The character at the current position.
*/this.ch=null;};hterm.Parser.prototype.error=function(message){return new Error('Parse error at '+this.pos+': '+message);};hterm.Parser.prototype.isComplete=function(){return this.pos==this.source.length;};hterm.Parser.prototype.reset=function(source,opt_pos){this.source=source;this.pos=opt_pos||0;this.ch=source.substr(0,1);};/**
* Parse a key sequence.
*
* A key sequence is zero or more of the key modifiers defined in
* hterm.Parser.identifiers.modifierKeys followed by a key code. Key
* codes can be an integer or an identifier from
* hterm.Parser.identifiers.keyCodes. Modifiers and keyCodes should be joined
* by the dash character.
*
* An asterisk "*" can be used to indicate that the unspecified modifiers
* are optional.
*
* For example:
* A: Matches only an unmodified "A" character.
* 65: Same as above.
* 0x41: Same as above.
* Ctrl-A: Matches only Ctrl-A.
* Ctrl-65: Same as above.
* Ctrl-0x41: Same as above.
* Ctrl-Shift-A: Matches only Ctrl-Shift-A.
* Ctrl-*-A: Matches Ctrl-A, as well as any other key sequence that includes
* at least the Ctrl and A keys.
*
* @return {Object} An object with shift, ctrl, alt, meta, keyCode
* properties.
*/hterm.Parser.prototype.parseKeySequence=function(){var rv={keyCode:null};for(var k in hterm.Parser.identifiers.modifierKeys){rv[hterm.Parser.identifiers.modifierKeys[k]]=false;}while(this.pos<this.source.length){this.skipSpace();var token=this.parseToken();if(token.type=='integer'){rv.keyCode=token.value;}else if(token.type=='identifier'){var ucValue=token.value.toUpperCase();if(ucValue in hterm.Parser.identifiers.modifierKeys&&hterm.Parser.identifiers.modifierKeys.hasOwnProperty(ucValue)){var mod=hterm.Parser.identifiers.modifierKeys[ucValue];if(rv[mod]&&rv[mod]!='*')throw this.error('Duplicate modifier: '+token.value);rv[mod]=true;}else if(ucValue in hterm.Parser.identifiers.keyCodes&&hterm.Parser.identifiers.keyCodes.hasOwnProperty(ucValue)){rv.keyCode=hterm.Parser.identifiers.keyCodes[ucValue];}else{throw this.error('Unknown key: '+token.value);}}else if(token.type=='symbol'){if(token.value=='*'){for(var id in hterm.Parser.identifiers.modifierKeys){var p=hterm.Parser.identifiers.modifierKeys[id];if(!rv[p])rv[p]='*';}}else{throw this.error('Unexpected symbol: '+token.value);}}else{throw this.error('Expected integer or identifier');}this.skipSpace();if(this.ch!='-')break;if(rv.keyCode!=null)throw this.error('Extra definition after target key');this.advance(1);}if(rv.keyCode==null)throw this.error('Missing target key');return rv;};hterm.Parser.prototype.parseKeyAction=function(){this.skipSpace();var token=this.parseToken();if(token.type=='string')return token.value;if(token.type=='identifier'){if(token.value in hterm.Parser.identifiers.actions&&hterm.Parser.identifiers.actions.hasOwnProperty(token.value))return hterm.Parser.identifiers.actions[token.value];throw this.error('Unknown key action: '+token.value);}throw this.error('Expected string or identifier');};hterm.Parser.prototype.peekString=function(){return this.ch=='\''||this.ch=='"';};hterm.Parser.prototype.peekIdentifier=function(){return this.ch.match(/[a-z_]/i);};hterm.Parser.prototype.peekInteger=function(){return this.ch.match(/[0-9]/);};hterm.Parser.prototype.parseToken=function(){if(this.ch=='*'){var rv={type:'symbol',value:this.ch};this.advance(1);return rv;}if(this.peekIdentifier())return{type:'identifier',value:this.parseIdentifier()};if(this.peekString())return{type:'string',value:this.parseString()};if(this.peekInteger())return{type:'integer',value:this.parseInteger()};throw this.error('Unexpected token');};hterm.Parser.prototype.parseIdentifier=function(){if(!this.peekIdentifier())throw this.error('Expected identifier');return this.parsePattern(/[a-z0-9_]+/ig);};hterm.Parser.prototype.parseInteger=function(){var base=10;if(this.ch=='0'&&this.pos<this.source.length-1&&this.source.substr(this.pos+1,1)=='x'){return parseInt(this.parsePattern(/0x[0-9a-f]+/gi));}return parseInt(this.parsePattern(/\d+/g));};/**
* Parse a single or double quoted string.
*
* The current position should point at the initial quote character. Single
* quoted strings will be treated literally, double quoted will process escapes.
*
* TODO(rginda): Variable interpolation.
*
* @param {ParseState} parseState
* @param {string} quote A single or double-quote character.
* @return {string}
*/hterm.Parser.prototype.parseString=function(){var result='';var quote=this.ch;if(quote!='"'&"e!='\'')throw this.error('String expected');this.advance(1);var re=new RegExp('[\\\\'+quote+']','g');while(this.pos<this.source.length){re.lastIndex=this.pos;if(!re.exec(this.source))throw this.error('Unterminated string literal');result+=this.source.substring(this.pos,re.lastIndex-1);this.advance(re.lastIndex-this.pos-1);if(quote=='"'&&this.ch=='\\'){this.advance(1);result+=this.parseEscape();continue;}if(quote=='\''&&this.ch=='\\'){result+=this.ch;this.advance(1);continue;}if(this.ch==quote){this.advance(1);return result;}}throw this.error('Unterminated string literal');};/**
* Parse an escape code from the current position (which should point to
* the first character AFTER the leading backslash.)
*
* @return {string}
*/hterm.Parser.prototype.parseEscape=function(){var map={'"':'"','\'':'\'','\\':'\\','a':'\x07','b':'\x08','e':'\x1b','f':'\x0c','n':'\x0a','r':'\x0d','t':'\x09','v':'\x0b','x':function x(){var value=this.parsePattern(/[a-z0-9]{2}/ig);return String.fromCharCode(parseInt(value,16));},'u':function u(){var value=this.parsePattern(/[a-z0-9]{4}/ig);return String.fromCharCode(parseInt(value,16));}};if(!(this.ch in map&&map.hasOwnProperty(this.ch)))throw this.error('Unknown escape: '+this.ch);var value=map[this.ch];this.advance(1);if(typeof value=='function')value=value.call(this);return value;};/**
* Parse the given pattern starting from the current position.
*
* @param {RegExp} pattern A pattern representing the characters to span. MUST
* include the "global" RegExp flag.
* @return {string}
*/hterm.Parser.prototype.parsePattern=function(pattern){if(!pattern.global)throw this.error('Internal error: Span patterns must be global');pattern.lastIndex=this.pos;var ary=pattern.exec(this.source);if(!ary||pattern.lastIndex-ary[0].length!=this.pos)throw this.error('Expected match for: '+pattern);this.pos=pattern.lastIndex-1;this.advance(1);return ary[0];};/**
* Advance the current position.
*
* @param {number} count
*/hterm.Parser.prototype.advance=function(count){this.pos+=count;this.ch=this.source.substr(this.pos,1);};/**
* @param {string=} opt_expect A list of valid non-whitespace characters to
* terminate on.
* @return {void}
*/hterm.Parser.prototype.skipSpace=function(opt_expect){if(!/\s/.test(this.ch))return;var re=/\s+/gm;re.lastIndex=this.pos;var source=this.source;if(re.exec(source))this.pos=re.lastIndex;this.ch=this.source.substr(this.pos,1);if(opt_expect){if(this.ch.indexOf(opt_expect)==-1){throw this.error('Expected one of '+opt_expect+', found: '+this.ch);}}};// SOURCE FILE: hterm/js/hterm_parser_identifiers.js
// Copyright (c) 2015 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* Collections of identifier for hterm.Parser.
*/hterm.Parser.identifiers={};/**
* Modifier key names used when defining key sequences.
*
* These are upper case so we can normalize the user input and be forgiving.
* "CTRL-A" and "Ctrl-A" and "ctrl-a" are all accepted.
*
* Note: Names here cannot overlap with hterm.Parser.identifiers.keyCodes.
*/hterm.Parser.identifiers.modifierKeys={SHIFT:'shift',CTRL:'ctrl',// Common alias.
CONTROL:'ctrl',ALT:'alt',META:'meta'};/**
* Key codes useful when defining key sequences.
*
* Punctuation is mostly left out of this list because they can move around
* based on keyboard locale and browser.
*
* In a key sequence like "Ctrl-ESC", the ESC comes from this list of
* identifiers. It is equivalent to "Ctrl-27" and "Ctrl-0x1b".
*
* These are upper case so we can normalize the user input and be forgiving.
* "Ctrl-ESC" and "Ctrl-Esc" an "Ctrl-esc" are all accepted.
*
* We also include common aliases for the same key. "Esc" and "Escape" are the
* same key.
*
* Note: Names here cannot overlap with hterm.Parser.identifiers.modifierKeys.
*/hterm.Parser.identifiers.keyCodes={// Top row.
ESCAPE:27,ESC:27,F1:112,F2:113,F3:114,F4:115,F5:116,F6:117,F7:118,F8:119,F9:120,F10:121,F11:122,F12:123,// Row two.
ONE:49,TWO:50,THREE:51,FOUR:52,FIVE:53,SIX:54,SEVEN:55,EIGHT:56,NINE:57,ZERO:48,BACKSPACE:8,BKSP:8,BS:8,// Row three.
TAB:9,Q:81,W:87,E:69,R:82,T:84,Y:89,U:85,I:73,O:79,P:80,// Row four.
CAPS_LOCK:20,CAPSLOCK:20,CAPS:20,A:65,S:83,D:68,F:70,G:71,H:72,J:74,K:75,L:76,// We map enter and return together even though enter should really be 10
// because most people don't know or care about the history here. Plus,
// most keyboards/programs map them together already. If they really want
// to bind them differently, they can also use the numeric value.
ENTER:13,ENT:13,RETURN:13,RET:13,// Row five.
Z:90,X:88,C:67,V:86,B:66,N:78,M:77,// Etc.
SPACE:32,SP:32,PRINT_SCREEN:42,PRTSC:42,SCROLL_LOCK:145,SCRLK:145,BREAK:19,BRK:19,INSERT:45,INS:45,HOME:36,PAGE_UP:33,PGUP:33,DELETE:46,DEL:46,END:35,PAGE_DOWN:34,PGDOWN:34,PGDN:34,UP:38,DOWN:40,RIGHT:39,LEFT:37,NUMLOCK:144,// Keypad
KP0:96,KP1:97,KP2:98,KP3:99,KP4:100,KP5:101,KP6:102,KP7:103,KP8:104,KP9:105,KP_PLUS:107,KP_ADD:107,KP_MINUS:109,KP_SUBTRACT:109,KP_STAR:106,KP_MULTIPLY:106,KP_DIVIDE:111,KP_DECIMAL:110,KP_PERIOD:110,// Chrome OS media keys
NAVIGATE_BACK:166,NAVIGATE_FORWARD:167,RELOAD:168,FULL_SCREEN:183,WINDOW_OVERVIEW:182,BRIGHTNESS_UP:216,BRIGHTNESS_DOWN:217};/**
* Identifiers for use in key actions.
*/hterm.Parser.identifiers.actions={/**
* Prevent the browser and operating system from handling the event.
*/CANCEL:hterm.Keyboard.KeyActions.CANCEL,/**
* Wait for a "keypress" event, send the keypress charCode to the host.
*/DEFAULT:hterm.Keyboard.KeyActions.DEFAULT,/**
* Let the browser or operating system handle the key.
*/PASS:hterm.Keyboard.KeyActions.PASS,/**
* Scroll the terminal one line up.
*/scrollLineUp:function scrollLineUp(terminal){terminal.scrollLineUp();return hterm.Keyboard.KeyActions.CANCEL;},/**
* Scroll the terminal one line down.
*/scrollLineDown:function scrollLineDown(terminal){terminal.scrollLineDown();return hterm.Keyboard.KeyActions.CANCEL;},/**
* Scroll the terminal one page up.
*/scrollPageUp:function scrollPageUp(terminal){terminal.scrollPageUp();return hterm.Keyboard.KeyActions.CANCEL;},/**
* Scroll the terminal one page down.
*/scrollPageDown:function scrollPageDown(terminal){terminal.scrollPageDown();return hterm.Keyboard.KeyActions.CANCEL;},/**
* Scroll the terminal to the top.
*/scrollToTop:function scrollToTop(terminal){terminal.scrollHome();return hterm.Keyboard.KeyActions.CANCEL;},/**
* Scroll the terminal to the bottom.
*/scrollToBottom:function scrollToBottom(terminal){terminal.scrollEnd();return hterm.Keyboard.KeyActions.CANCEL;},/**
* Clear the active screen and move the cursor to (0,0).
*/clearScreen:function clearScreen(terminal){terminal.clearHome();return hterm.Keyboard.KeyActions.CANCEL;},/**
* Clear the scrollback buffer.
*/clearScrollback:function clearScrollback(terminal){terminal.clearScrollback();return hterm.Keyboard.KeyActions.CANCEL;},/**
* Clear the terminal and scrollback buffer and move the cursor to (0,0).
*/clearTerminal:function clearTerminal(terminal){terminal.wipeContents();return hterm.Keyboard.KeyActions.CANCEL;},/**
* Perform a full terminal reset.
*/fullReset:function fullReset(terminal){terminal.reset();return hterm.Keyboard.KeyActions.CANCEL;},/**
* Perform a soft terminal reset.
*/softReset:function softReset(terminal){terminal.softReset();return hterm.Keyboard.KeyActions.CANCEL;}};// SOURCE FILE: hterm/js/hterm_preference_manager.js
// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* PreferenceManager subclass managing global NaSSH preferences.
*
* This is currently just an ordered list of known connection profiles.
*/hterm.PreferenceManager=function(profileId){var _this7=this;lib.PreferenceManager.call(this,hterm.defaultStorage,hterm.PreferenceManager.prefix_+profileId);Object.entries(hterm.PreferenceManager.defaultPreferences).forEach(function(_ref3){var _ref4=_slicedToArray(_ref3,2),key=_ref4[0],entry=_ref4[1];_this7.definePreference(key,entry['default']);});};/**
* The storage key prefix to namespace the preferences.
*/hterm.PreferenceManager.prefix_='/hterm/profiles/';/**
* List all the defined profiles.
*
* @param {function(Array<string>)} callback Called with the list of profiles.
*/hterm.PreferenceManager.listProfiles=function(callback){hterm.defaultStorage.getItems(null,function(items){var profiles={};for(var _i3=0,_Object$keys=Object.keys(items);_i3<_Object$keys.length;_i3++){var key=_Object$keys[_i3];if(key.startsWith(hterm.PreferenceManager.prefix_)){// Turn "/hterm/profiles/foo/bar/cow" to "foo/bar/cow".
var subKey=key.slice(hterm.PreferenceManager.prefix_.length);// Turn "foo/bar/cow" into "foo".
profiles[subKey.split('/',1)[0]]=true;}}callback(Object.keys(profiles));});};hterm.PreferenceManager.categories={};hterm.PreferenceManager.categories.Keyboard='Keyboard';hterm.PreferenceManager.categories.Appearance='Appearance';hterm.PreferenceManager.categories.CopyPaste='CopyPaste';hterm.PreferenceManager.categories.Sounds='Sounds';hterm.PreferenceManager.categories.Scrolling='Scrolling';hterm.PreferenceManager.categories.Encoding='Encoding';hterm.PreferenceManager.categories.Extensions='Extensions';hterm.PreferenceManager.categories.Miscellaneous='Miscellaneous';/**
* List of categories, ordered by display order (top to bottom)
*/hterm.PreferenceManager.categoryDefinitions=[{id:hterm.PreferenceManager.categories.Appearance,text:'Appearance (fonts, colors, images)'},{id:hterm.PreferenceManager.categories.CopyPaste,text:'Copy & Paste'},{id:hterm.PreferenceManager.categories.Encoding,text:'Encoding'},{id:hterm.PreferenceManager.categories.Keyboard,text:'Keyboard'},{id:hterm.PreferenceManager.categories.Scrolling,text:'Scrolling'},{id:hterm.PreferenceManager.categories.Sounds,text:'Sounds'},{id:hterm.PreferenceManager.categories.Extensions,text:'Extensions'},{id:hterm.PreferenceManager.categories.Miscellaneous,text:'Miscellaneous'}];/**
* Internal helper to create a default preference object.
*
* @param {hterm.PreferenceManager.categories} category The pref category.
* @param {string} name The user readable name/title.
* @param {Object} defaultValue The default pref value.
* @param {Object} type The type for this pref (or an array for enums).
* @param {string} help The user readable help text.
* @return {Object} The default pref object.
*/hterm.PreferenceManager.definePref_=function(name,category,defaultValue,type,help){return{'name':name,'category':category,'default':defaultValue,'type':type,'help':help};};hterm.PreferenceManager.defaultPreferences={'alt-gr-mode':hterm.PreferenceManager.definePref_('AltGr key mode',hterm.PreferenceManager.categories.Keyboard,null,[null,'none','ctrl-alt','left-alt','right-alt'],"Select an AltGr detection heuristic.\n"+"\n"+"'null': Autodetect based on navigator.language:\n"+" 'en-us' => 'none', else => 'right-alt'\n"+"'none': Disable any AltGr related munging.\n"+"'ctrl-alt': Assume Ctrl+Alt means AltGr.\n"+"'left-alt': Assume left Alt means AltGr.\n"+"'right-alt': Assume right Alt means AltGr."),'alt-backspace-is-meta-backspace':hterm.PreferenceManager.definePref_('Alt-Backspace is Meta-Backspace',hterm.PreferenceManager.categories.Keyboard,false,'bool',"If set, undoes the Chrome OS Alt-Backspace->DEL remap, so that "+"Alt-Backspace indeed is Alt-Backspace."),'alt-is-meta':hterm.PreferenceManager.definePref_('Treat Alt key as Meta key',hterm.PreferenceManager.categories.Keyboard,false,'bool',"Whether the Alt key acts as a Meta key or as a distinct Alt key."),'alt-sends-what':hterm.PreferenceManager.definePref_('Alt key modifier handling',hterm.PreferenceManager.categories.Keyboard,'escape',['escape','8-bit','browser-key'],"Controls how the Alt key is handled.\n"+"\n"+" escape: Send an ESC prefix.\n"+" 8-bit: Add 128 to the typed character as in xterm.\n"+" browser-key: Wait for the keypress event and see what the browser\n"+" says. (This won't work well on platforms where the browser\n"+" performs a default action for some Alt sequences.)"),'audible-bell-sound':hterm.PreferenceManager.definePref_('Alert bell sound (URI)',hterm.PreferenceManager.categories.Sounds,'lib-resource:hterm/audio/bell','url',"URL of the terminal bell sound. Empty string for no audible bell."),'desktop-notification-bell':hterm.PreferenceManager.definePref_('Create desktop notifications for alert bells',hterm.PreferenceManager.categories.Sounds,false,'bool',"If true, terminal bells in the background will create a Web "+"Notification. https://www.w3.org/TR/notifications/\n"+"\n"+"Displaying notifications requires permission from the user. When this "+"option is set to true, hterm will attempt to ask the user for "+"permission if necessary. Browsers may not show this permission "+"request if it was not triggered by a user action.\n"+"\n"+"Chrome extensions with the \"notifications\" permission have permission "+"to display notifications."),'background-color':hterm.PreferenceManager.definePref_('Background color',hterm.PreferenceManager.categories.Appearance,'rgb(16, 16, 16)','color',"The background color for text with no other color attributes."),'background-image':hterm.PreferenceManager.definePref_('Background image',hterm.PreferenceManager.categories.Appearance,'','string',"CSS value of the background image. Empty string for no image.\n"+"\n"+"For example:\n"+" url(https://goo.gl/anedTK)\n"+" linear-gradient(top bottom, blue, red)"),'background-size':hterm.PreferenceManager.definePref_('Background image size',hterm.PreferenceManager.categories.Appearance,'','string',"CSS value of the background image size."),'background-position':hterm.PreferenceManager.definePref_('Background image position',hterm.PreferenceManager.categories.Appearance,'','string',"CSS value of the background image position.\n"+"\n"+"For example:\n"+" 10% 10%\n"+" center"),'backspace-sends-backspace':hterm.PreferenceManager.definePref_('Backspace key behavior',hterm.PreferenceManager.categories.Keyboard,false,'bool',"If true, the backspace should send BS ('\\x08', aka ^H). Otherwise "+"the backspace key should send '\\x7f'."),'character-map-overrides':hterm.PreferenceManager.definePref_('Character map overrides',hterm.PreferenceManager.categories.Appearance,null,'value',"This is specified as an object. It is a sparse array, where each "+"property is the character set code and the value is an object that is "+"a sparse array itself. In that sparse array, each property is the "+"received character and the value is the displayed character.\n"+"\n"+"For example:\n"+" {\"0\":{\"+\":\"\\u2192\",\",\":\"\\u2190\",\"-\":\"\\u2191\",\".\":\"\\u2193\", "+"\"0\":\"\\u2588\"}}"),'close-on-exit':hterm.PreferenceManager.definePref_('Close window on exit',hterm.PreferenceManager.categories.Miscellaneous,true,'bool',"Whether to close the window when the command finishes executing."),'cursor-blink':hterm.PreferenceManager.definePref_('Cursor blink',hterm.PreferenceManager.categories.Appearance,false,'bool',"Whether the text cursor blinks by default. This can be toggled at "+"runtime via terminal escape sequences."),'cursor-blink-cycle':hterm.PreferenceManager.definePref_('Cursor blink rate',hterm.PreferenceManager.categories.Appearance,[1000,500],'value',"The text cursor blink rate in milliseconds.\n"+"\n"+"A two element array, the first of which is how long the text cursor "+"should be on, second is how long it should be off."),'cursor-color':hterm.PreferenceManager.definePref_('Text cursor color',hterm.PreferenceManager.categories.Appearance,'rgba(255, 0, 0, 0.5)','color',"The color of the visible text cursor."),'color-palette-overrides':hterm.PreferenceManager.definePref_('Initial color palette',hterm.PreferenceManager.categories.Appearance,null,'value',"Override colors in the default palette.\n"+"\n"+"This can be specified as an array or an object. If specified as an "+"object it is assumed to be a sparse array, where each property "+"is a numeric index into the color palette.\n"+"\n"+"Values can be specified as almost any CSS color value. This "+"includes #RGB, #RRGGBB, rgb(...), rgba(...), and any color names "+"that are also part of the standard X11 rgb.txt file.\n"+"\n"+"You can use 'null' to specify that the default value should be not "+"be changed. This is useful for skipping a small number of indices "+"when the value is specified as an array.\n"+"\n"+"For example, these both set color index 1 to blue:\n"+" {1: \"#0000ff\"}\n"+" [null, \"#0000ff\"]"),'copy-on-select':hterm.PreferenceManager.definePref_('Automatically copy selected content',hterm.PreferenceManager.categories.CopyPaste,true,'bool',"Automatically copy mouse selection to the clipboard."),'use-default-window-copy':hterm.PreferenceManager.definePref_('Let the browser handle text copying',hterm.PreferenceManager.categories.CopyPaste,false,'bool',"Whether to use the default browser/OS's copy behavior.\n"+"\n"+"Allow the browser/OS to handle the copy event directly which might "+"improve compatibility with some systems (where copying doesn't work "+"at all), but makes the text selection less robust.\n"+"\n"+"For example, long lines that were automatically line wrapped will "+"be copied with the newlines still in them."),'clear-selection-after-copy':hterm.PreferenceManager.definePref_('Automatically clear text selection',hterm.PreferenceManager.categories.CopyPaste,true,'bool',"Whether to clear the selection after copying."),'ctrl-plus-minus-zero-zoom':hterm.PreferenceManager.definePref_('Ctrl-+/-/0 zoom behavior',hterm.PreferenceManager.categories.Keyboard,true,'bool',"If true, Ctrl-Plus/Minus/Zero controls zoom.\n"+"If false, Ctrl-Shift-Plus/Minus/Zero controls zoom, Ctrl-Minus sends "+"^_, Ctrl-Plus/Zero do nothing."),'ctrl-c-copy':hterm.PreferenceManager.definePref_('Ctrl-C copy behavior',hterm.PreferenceManager.categories.Keyboard,false,'bool',"Ctrl-C copies if true, send ^C to host if false.\n"+"Ctrl-Shift-C sends ^C to host if true, copies if false."),'ctrl-v-paste':hterm.PreferenceManager.definePref_('Ctrl-V paste behavior',hterm.PreferenceManager.categories.Keyboard,false,'bool',"Ctrl-V pastes if true, send ^V to host if false.\n"+"Ctrl-Shift-V sends ^V to host if true, pastes if false."),'east-asian-ambiguous-as-two-column':hterm.PreferenceManager.definePref_('East Asian Ambiguous use two columns',hterm.PreferenceManager.categories.Keyboard,false,'bool',"Whether East Asian Ambiguous characters have two column width."),'enable-8-bit-control':hterm.PreferenceManager.definePref_('Support non-UTF-8 C1 control characters',hterm.PreferenceManager.categories.Keyboard,false,'bool',"True to enable 8-bit control characters, false to ignore them.\n"+"\n"+"We'll respect the two-byte versions of these control characters "+"regardless of this setting."),'enable-bold':hterm.PreferenceManager.definePref_('Bold text behavior',hterm.PreferenceManager.categories.Appearance,null,'tristate',"If true, use bold weight font for text with the bold/bright "+"attribute. False to use the normal weight font. Null to autodetect."),'enable-bold-as-bright':hterm.PreferenceManager.definePref_('Use bright colors with bold text',hterm.PreferenceManager.categories.Appearance,true,'bool',"If true, use bright colors (8-15 on a 16 color palette) for any text "+"with the bold attribute. False otherwise."),'enable-blink':hterm.PreferenceManager.definePref_('Enable blinking text',hterm.PreferenceManager.categories.Appearance,true,'bool',"If true, respect the blink attribute. False to ignore it."),'enable-clipboard-notice':hterm.PreferenceManager.definePref_('Show notification when copying content',hterm.PreferenceManager.categories.CopyPaste,true,'bool',"Whether to show a message in the terminal when the host writes to the "+"clipboard."),'enable-clipboard-write':hterm.PreferenceManager.definePref_('Allow remote clipboard writes',hterm.PreferenceManager.categories.CopyPaste,true,'bool',"Allow the remote host to write directly to the local system "+"clipboard.\n"+"Read access is never granted regardless of this setting.\n"+"\n"+"This is used to control access to features like OSC-52."),'enable-dec12':hterm.PreferenceManager.definePref_('Allow changing of text cursor blinking',hterm.PreferenceManager.categories.Miscellaneous,false,'bool',"Respect the host's attempt to change the text cursor blink status "+"using DEC Private Mode 12."),'enable-csi-j-3':hterm.PreferenceManager.definePref_('Allow clearing of scrollback buffer (CSI-J-3)',hterm.PreferenceManager.categories.Miscellaneous,true,'bool',"Whether CSI-J (Erase Display) mode 3 may clear the terminal "+"scrollback buffer.\n"+"\n"+"Enabling this by default is safe."),'environment':hterm.PreferenceManager.definePref_('Environment variables',hterm.PreferenceManager.categories.Miscellaneous,{// Signal ncurses based apps to use UTF-8 output instead of legacy
// drawing modes (which only work in ISO-2022 mode). Since hterm is
// always UTF-8, this shouldn't cause problems.
'NCURSES_NO_UTF8_ACS':'1','TERM':'xterm-256color',// Set this env var that a bunch of mainstream terminal emulators set
// to indicate we support true colors.
// https://gist.github.com/XVilka/8346728
'COLORTERM':'truecolor'},'value',"The initial set of environment variables, as an object."),'font-family':hterm.PreferenceManager.definePref_('Text font family',hterm.PreferenceManager.categories.Appearance,'"DejaVu Sans Mono", "Noto Sans Mono", "Everson Mono", FreeMono, '+'Menlo, Terminal, monospace','string',"Default font family for the terminal text."),'font-size':hterm.PreferenceManager.definePref_('Text font size',hterm.PreferenceManager.categories.Appearance,15,'int',"The default font size in pixels."),'font-smoothing':hterm.PreferenceManager.definePref_('Text font smoothing',hterm.PreferenceManager.categories.Appearance,'antialiased','string',"CSS font-smoothing property."),'foreground-color':hterm.PreferenceManager.definePref_('Text color',hterm.PreferenceManager.categories.Appearance,'rgb(240, 240, 240)','color',"The foreground color for text with no other color attributes."),'hide-mouse-while-typing':hterm.PreferenceManager.definePref_('Hide mouse cursor while typing',hterm.PreferenceManager.categories.Keyboard,null,'tristate',"Whether to automatically hide the mouse cursor when typing. "+"By default, autodetect whether the platform/OS handles this.\n"+"\n"+"Note: Some operating systems may override this setting and thus you "+"might not be able to always disable it."),'home-keys-scroll':hterm.PreferenceManager.definePref_('Home/End key scroll behavior',hterm.PreferenceManager.categories.Keyboard,false,'bool',"If true, Home/End controls the terminal scrollbar and Shift-Home/"+"Shift-End are sent to the remote host. If false, then Home/End are "+"sent to the remote host and Shift-Home/Shift-End scrolls."),'keybindings':hterm.PreferenceManager.definePref_('Keyboard bindings/shortcuts',hterm.PreferenceManager.categories.Keyboard,null,'value',"A map of key sequence to key actions. Key sequences include zero or "+"more modifier keys followed by a key code. Key codes can be decimal "+"or hexadecimal numbers, or a key identifier. Key actions can be "+"specified as a string to send to the host, or an action identifier. "+"For a full explanation of the format, see https://goo.gl/LWRndr.\n"+"\n"+"Sample keybindings:\n"+"{\n"+" \"Ctrl-Alt-K\": \"clearTerminal\",\n"+" \"Ctrl-Shift-L\": \"PASS\",\n"+" \"Ctrl-H\": \"'Hello World'\"\n"+"}"),'media-keys-are-fkeys':hterm.PreferenceManager.definePref_('Media keys are Fkeys',hterm.PreferenceManager.categories.Keyboard,false,'bool',"If true, convert media keys to their Fkey equivalent. If false, let "+"the browser handle the keys."),'meta-sends-escape':hterm.PreferenceManager.definePref_('Meta key modifier handling',hterm.PreferenceManager.categories.Keyboard,true,'bool',"Send an ESC prefix when pressing a key while holding the Meta key.\n"+"\n"+"For example, when enabled, pressing Meta-K will send ^[k as if you "+"typed Escape then k. When disabled, only k will be sent."),'mouse-right-click-paste':hterm.PreferenceManager.definePref_('Mouse right clicks paste content',hterm.PreferenceManager.categories.CopyPaste,true,'bool',"Paste on right mouse button clicks.\n"+"\n"+"This option is independent of the \"mouse-paste-button\" setting.\n"+"\n"+"Note: This will handle left & right handed mice correctly."),'mouse-paste-button':hterm.PreferenceManager.definePref_('Mouse button paste',hterm.PreferenceManager.categories.CopyPaste,null,[null,0,1,2,3,4,5,6],"Mouse paste button, or null to autodetect.\n"+"\n"+"For autodetect, we'll use the middle mouse button for non-X11 "+"platforms (including Chrome OS). On X11, we'll use the right mouse "+"button (since the native window manager should paste via the middle "+"mouse button).\n"+"\n"+"0 == left (primary) button.\n"+"1 == middle (auxiliary) button.\n"+"2 == right (secondary) button.\n"+"\n"+"This option is independent of the setting for right-click paste.\n"+"\n"+"Note: This will handle left & right handed mice correctly."),'word-break-match-left':hterm.PreferenceManager.definePref_('Automatic selection halting (to the left)',hterm.PreferenceManager.categories.CopyPaste,'[^\\s\\[\\](){}<>"\'\\^!@#$%&*,;:`]','string',"Regular expression to halt matching to the left (start) of a "+"selection.\n"+"\n"+"Normally this is a character class to reject specific characters.\n"+"We allow \"~\" and \".\" by default as paths frequently start with those."),'word-break-match-right':hterm.PreferenceManager.definePref_('Automatic selection halting (to the right)',hterm.PreferenceManager.categories.CopyPaste,'[^\\s\\[\\](){}<>"\'\\^!@#$%&*,;:~.`]','string',"Regular expression to halt matching to the right (end) of a "+"selection.\n"+"\n"+"Normally this is a character class to reject specific characters."),'word-break-match-middle':hterm.PreferenceManager.definePref_('Word break characters',hterm.PreferenceManager.categories.CopyPaste,'[^\\s\\[\\](){}<>"\'\\^]*','string',"Regular expression to match all the characters in the middle.\n"+"\n"+"Normally this is a character class to reject specific characters.\n"+"\n"+"Used to expand the selection surrounding the starting point."),'page-keys-scroll':hterm.PreferenceManager.definePref_('Page Up/Down key scroll behavior',hterm.PreferenceManager.categories.Keyboard,false,'bool',"If true, Page Up/Page Down controls the terminal scrollbar and "+"Shift-Page Up/Shift-Page Down are sent to the remote host. If false, "+"then Page Up/Page Down are sent to the remote host and Shift-Page Up/"+"Shift-Page Down scrolls."),'pass-alt-number':hterm.PreferenceManager.definePref_('Pass Alt-1..9 key behavior',hterm.PreferenceManager.categories.Keyboard,null,'tristate',"Whether Alt-1..9 is passed to the browser.\n"+"\n"+"This is handy when running hterm in a browser tab, so that you don't "+"lose Chrome's \"switch to tab\" keyboard accelerators. When not running "+"in a tab it's better to send these keys to the host so they can be "+"used in vim or emacs.\n"+"\n"+"If true, Alt-1..9 will be handled by the browser. If false, Alt-1..9 "+"will be sent to the host. If null, autodetect based on browser "+"platform and window type."),'pass-ctrl-number':hterm.PreferenceManager.definePref_('Pass Ctrl-1..9 key behavior',hterm.PreferenceManager.categories.Keyboard,null,'tristate',"Whether Ctrl-1..9 is passed to the browser.\n"+"\n"+"This is handy when running hterm in a browser tab, so that you don't "+"lose Chrome's \"switch to tab\" keyboard accelerators. When not running "+"in a tab it's better to send these keys to the host so they can be "+"used in vim or emacs.\n"+"\n"+"If true, Ctrl-1..9 will be handled by the browser. If false, "+"Ctrl-1..9 will be sent to the host. If null, autodetect based on "+"browser platform and window type."),'pass-meta-number':hterm.PreferenceManager.definePref_('Pass Meta-1..9 key behavior',hterm.PreferenceManager.categories.Keyboard,null,'tristate',"Whether Meta-1..9 is passed to the browser.\n"+"\n"+"This is handy when running hterm in a browser tab, so that you don't "+"lose Chrome's \"switch to tab\" keyboard accelerators. When not running "+"in a tab it's better to send these keys to the host so they can be "+"used in vim or emacs.\n"+"\n"+"If true, Meta-1..9 will be handled by the browser. If false, "+"Meta-1..9 will be sent to the host. If null, autodetect based on "+"browser platform and window type."),'pass-meta-v':hterm.PreferenceManager.definePref_('Pass Meta-V key behavior',hterm.PreferenceManager.categories.Keyboard,true,'bool',"Whether Meta-V gets passed to host."),'paste-on-drop':hterm.PreferenceManager.definePref_('Allow drag & drop to paste',hterm.PreferenceManager.categories.CopyPaste,true,'bool',"If true, Drag and dropped text will paste into terminal.\n"+"If false, dropped text will be ignored."),'receive-encoding':hterm.PreferenceManager.definePref_('Receive encoding',hterm.PreferenceManager.categories.Encoding,'utf-8',['utf-8','raw'],"Set the expected encoding for data received from the host.\n"+"If the encodings do not match, visual bugs are likely to be "+"observed.\n"+"\n"+"Valid values are 'utf-8' and 'raw'."),'scroll-on-keystroke':hterm.PreferenceManager.definePref_('Scroll to bottom after keystroke',hterm.PreferenceManager.categories.Scrolling,true,'bool',"Whether to scroll to the bottom on any keystroke."),'scroll-on-output':hterm.PreferenceManager.definePref_('Scroll to bottom after new output',hterm.PreferenceManager.categories.Scrolling,false,'bool',"Whether to scroll to the bottom on terminal output."),'scrollbar-visible':hterm.PreferenceManager.definePref_('Scrollbar visibility',hterm.PreferenceManager.categories.Scrolling,true,'bool',"The vertical scrollbar mode."),'scroll-wheel-may-send-arrow-keys':hterm.PreferenceManager.definePref_('Emulate arrow keys with scroll wheel',hterm.PreferenceManager.categories.Scrolling,false,'bool',"When using the alternative screen buffer, and DECCKM (Application "+"Cursor Keys) is active, mouse wheel scroll events will emulate arrow "+"keys.\n"+"\n"+"It can be temporarily disabled by holding the Shift key.\n"+"\n"+"This frequently comes up when using pagers (less) or reading man "+"pages or text editors (vi/nano) or using screen/tmux."),'scroll-wheel-move-multiplier':hterm.PreferenceManager.definePref_('Mouse scroll wheel multiplier',hterm.PreferenceManager.categories.Scrolling,1,'int',"The multiplier for scroll wheel events when measured in pixels.\n"+"\n"+"Alters how fast the page scrolls."),'terminal-encoding':hterm.PreferenceManager.definePref_('Terminal encoding',hterm.PreferenceManager.categories.Encoding,'utf-8',['iso-2022','utf-8','utf-8-locked'],"The default terminal encoding (DOCS).\n"+"\n"+"ISO-2022 enables character map translations (like graphics maps).\n"+"UTF-8 disables support for those.\n"+"\n"+"The locked variant means the encoding cannot be changed at runtime "+"via terminal escape sequences.\n"+"\n"+"You should stick with UTF-8 unless you notice broken rendering with "+"legacy applications."),'shift-insert-paste':hterm.PreferenceManager.definePref_('Shift-Insert paste',hterm.PreferenceManager.categories.Keyboard,true,'bool',"Whether Shift-Insert is used for pasting or is sent to the remote host."),'user-css':hterm.PreferenceManager.definePref_('Custom CSS (URI)',hterm.PreferenceManager.categories.Appearance,'','url',"URL of user stylesheet to include in the terminal document."),'user-css-text':hterm.PreferenceManager.definePref_('Custom CSS (inline text)',hterm.PreferenceManager.categories.Appearance,'','multiline-string',"Custom CSS text for styling the terminal."),'allow-images-inline':hterm.PreferenceManager.definePref_('Allow inline image display',hterm.PreferenceManager.categories.Extensions,null,'tristate',"Whether to allow the remote host to display images in the terminal.\n"+"\n"+"By default, we prompt until a choice is made.")};hterm.PreferenceManager.prototype=Object.create(lib.PreferenceManager.prototype);hterm.PreferenceManager.constructor=hterm.PreferenceManager;// SOURCE FILE: hterm/js/hterm_pubsub.js
// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* Utility class used to add publish/subscribe/unsubscribe functionality to
* an existing object.
*/hterm.PubSub=function(){this.observers_={};};/**
* Add publish, subscribe, and unsubscribe methods to an existing object.
*
* No other properties of the object are touched, so there is no need to
* worry about clashing private properties.
*
* @param {Object} obj The object to add this behavior to.
*/hterm.PubSub.addBehavior=function(obj){var pubsub=new hterm.PubSub();for(var m in hterm.PubSub.prototype){obj[m]=hterm.PubSub.prototype[m].bind(pubsub);}};/**
* Subscribe to be notified of messages about a subject.
*
* @param {string} subject The subject to subscribe to.
* @param {function(Object)} callback The function to invoke for notifications.
*/hterm.PubSub.prototype.subscribe=function(subject,callback){if(!(subject in this.observers_))this.observers_[subject]=[];this.observers_[subject].push(callback);};/**
* Unsubscribe from a subject.
*
* @param {string} subject The subject to unsubscribe from.
* @param {function(Object)} callback A callback previously registered via
* subscribe().
*/hterm.PubSub.prototype.unsubscribe=function(subject,callback){var list=this.observers_[subject];if(!list)throw'Invalid subject: '+subject;var i=list.indexOf(callback);if(i<0)throw'Not subscribed: '+subject;list.splice(i,1);};/**
* Publish a message about a subject.
*
* Subscribers (and the optional final callback) are invoked asynchronously.
* This method will return before anyone is actually notified.
*
* @param {string} subject The subject to publish about.
* @param {Object} e An arbitrary object associated with this notification.
* @param {function(Object)} opt_lastCallback An optional function to call after
* all subscribers have been notified.
*/hterm.PubSub.prototype.publish=function(subject,e,opt_lastCallback){function notifyList(i){// Set this timeout before invoking the callback, so we don't have to
// concern ourselves with exceptions.
if(i<list.length-1)setTimeout(notifyList,0,i+1);list[i](e);}var list=this.observers_[subject];if(list){// Copy the list, in case it changes while we're notifying.
list=[].concat(list);}if(opt_lastCallback){if(list){list.push(opt_lastCallback);}else{list=[opt_lastCallback];}}if(list)setTimeout(notifyList,0,0);};// SOURCE FILE: hterm/js/hterm_screen.js
// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @fileoverview This class represents a single terminal screen full of text.
*
* It maintains the current cursor position and has basic methods for text
* insert and overwrite, and adding or removing rows from the screen.
*
* This class has no knowledge of the scrollback buffer.
*
* The number of rows on the screen is determined only by the number of rows
* that the caller inserts into the screen. If a caller wants to ensure a
* constant number of rows on the screen, it's their responsibility to remove a
* row for each row inserted.
*
* The screen width, in contrast, is enforced locally.
*
*
* In practice...
* - The hterm.Terminal class holds two hterm.Screen instances. One for the
* primary screen and one for the alternate screen.
*
* - The html.Screen class only cares that rows are HTMLElements. In the
* larger context of hterm, however, the rows happen to be displayed by an
* hterm.ScrollPort and have to follow a few rules as a result. Each
* row must be rooted by the custom HTML tag 'x-row', and each must have a
* rowIndex property that corresponds to the index of the row in the context
* of the scrollback buffer. These invariants are enforced by hterm.Terminal
* because that is the class using the hterm.Screen in the context of an
* hterm.ScrollPort.
*/ /**
* Create a new screen instance.
*
* The screen initially has no rows and a maximum column count of 0.
*
* @param {integer} opt_columnCount The maximum number of columns for this
* screen. See insertString() and overwriteString() for information about
* what happens when too many characters are added too a row. Defaults to
* 0 if not provided.
*/hterm.Screen=function(opt_columnCount){/**
* Public, read-only access to the rows in this screen.
*/this.rowsArray=[];// The max column width for this screen.
this.columnCount_=opt_columnCount||80;// The current color, bold, underline and blink attributes.
this.textAttributes=new hterm.TextAttributes(window.document);// Current zero-based cursor coordinates.
this.cursorPosition=new hterm.RowCol(0,0);// Saved state used by DECSC and related settings. This is only for saving
// and restoring specific state, not for the current/active state.
this.cursorState_=new hterm.Screen.CursorState(this);// The node containing the row that the cursor is positioned on.
this.cursorRowNode_=null;// The node containing the span of text that the cursor is positioned on.
this.cursorNode_=null;// The offset in column width into cursorNode_ where the cursor is positioned.
this.cursorOffset_=null;// Regexes for expanding word selections.
this.wordBreakMatchLeft=null;this.wordBreakMatchRight=null;this.wordBreakMatchMiddle=null;};/**
* Return the screen size as an hterm.Size object.
*
* @return {hterm.Size} hterm.Size object representing the current number
* of rows and columns in this screen.
*/hterm.Screen.prototype.getSize=function(){return new hterm.Size(this.columnCount_,this.rowsArray.length);};/**
* Return the current number of rows in this screen.
*
* @return {integer} The number of rows in this screen.
*/hterm.Screen.prototype.getHeight=function(){return this.rowsArray.length;};/**
* Return the current number of columns in this screen.
*
* @return {integer} The number of columns in this screen.
*/hterm.Screen.prototype.getWidth=function(){return this.columnCount_;};/**
* Set the maximum number of columns per row.
*
* @param {integer} count The maximum number of columns per row.
*/hterm.Screen.prototype.setColumnCount=function(count){this.columnCount_=count;if(this.cursorPosition.column>=count)this.setCursorPosition(this.cursorPosition.row,count-1);};/**
* Remove the first row from the screen and return it.
*
* @return {HTMLElement} The first row in this screen.
*/hterm.Screen.prototype.shiftRow=function(){return this.shiftRows(1)[0];};/**
* Remove rows from the top of the screen and return them as an array.
*
* @param {integer} count The number of rows to remove.
* @return {Array.<HTMLElement>} The selected rows.
*/hterm.Screen.prototype.shiftRows=function(count){return this.rowsArray.splice(0,count);};/**
* Insert a row at the top of the screen.
*
* @param {HTMLElement} row The row to insert.
*/hterm.Screen.prototype.unshiftRow=function(row){this.rowsArray.splice(0,0,row);};/**
* Insert rows at the top of the screen.
*
* @param {Array.<HTMLElement>} rows The rows to insert.
*/hterm.Screen.prototype.unshiftRows=function(rows){this.rowsArray.unshift.apply(this.rowsArray,rows);};/**
* Remove the last row from the screen and return it.
*
* @return {HTMLElement} The last row in this screen.
*/hterm.Screen.prototype.popRow=function(){return this.popRows(1)[0];};/**
* Remove rows from the bottom of the screen and return them as an array.
*
* @param {integer} count The number of rows to remove.
* @return {Array.<HTMLElement>} The selected rows.
*/hterm.Screen.prototype.popRows=function(count){return this.rowsArray.splice(this.rowsArray.length-count,count);};/**
* Insert a row at the bottom of the screen.
*
* @param {HTMLElement} row The row to insert.
*/hterm.Screen.prototype.pushRow=function(row){this.rowsArray.push(row);};/**
* Insert rows at the bottom of the screen.
*
* @param {Array.<HTMLElement>} rows The rows to insert.
*/hterm.Screen.prototype.pushRows=function(rows){rows.push.apply(this.rowsArray,rows);};/**
* Insert a row at the specified row of the screen.
*
* @param {integer} index The index to insert the row.
* @param {HTMLElement} row The row to insert.
*/hterm.Screen.prototype.insertRow=function(index,row){this.rowsArray.splice(index,0,row);};/**
* Insert rows at the specified row of the screen.
*
* @param {integer} index The index to insert the rows.
* @param {Array.<HTMLElement>} rows The rows to insert.
*/hterm.Screen.prototype.insertRows=function(index,rows){for(var i=0;i<rows.length;i++){this.rowsArray.splice(index+i,0,rows[i]);}};/**
* Remove a row from the screen and return it.
*
* @param {integer} index The index of the row to remove.
* @return {HTMLElement} The selected row.
*/hterm.Screen.prototype.removeRow=function(index){return this.rowsArray.splice(index,1)[0];};/**
* Remove rows from the bottom of the screen and return them as an array.
*
* @param {integer} index The index to start removing rows.
* @param {integer} count The number of rows to remove.
* @return {Array.<HTMLElement>} The selected rows.
*/hterm.Screen.prototype.removeRows=function(index,count){return this.rowsArray.splice(index,count);};/**
* Invalidate the current cursor position.
*
* This sets this.cursorPosition to (0, 0) and clears out some internal
* data.
*
* Attempting to insert or overwrite text while the cursor position is invalid
* will raise an obscure exception.
*/hterm.Screen.prototype.invalidateCursorPosition=function(){this.cursorPosition.move(0,0);this.cursorRowNode_=null;this.cursorNode_=null;this.cursorOffset_=null;};/**
* Clear the contents of the cursor row.
*/hterm.Screen.prototype.clearCursorRow=function(){this.cursorRowNode_.innerHTML='';this.cursorRowNode_.removeAttribute('line-overflow');this.cursorOffset_=0;this.cursorPosition.column=0;this.cursorPosition.overflow=false;var text;if(this.textAttributes.isDefault()){text='';}else{text=lib.f.getWhitespace(this.columnCount_);}// We shouldn't honor inverse colors when clearing an area, to match
// xterm's back color erase behavior.
var inverse=this.textAttributes.inverse;this.textAttributes.inverse=false;this.textAttributes.syncColors();var node=this.textAttributes.createContainer(text);this.cursorRowNode_.appendChild(node);this.cursorNode_=node;this.textAttributes.inverse=inverse;this.textAttributes.syncColors();};/**
* Mark the current row as having overflowed to the next line.
*
* The line overflow state is used when converting a range of rows into text.
* It makes it possible to recombine two or more overflow terminal rows into
* a single line.
*
* This is distinct from the cursor being in the overflow state. Cursor
* overflow indicates that printing at the cursor position will commit a
* line overflow, unless it is preceded by a repositioning of the cursor
* to a non-overflow state.
*/hterm.Screen.prototype.commitLineOverflow=function(){this.cursorRowNode_.setAttribute('line-overflow',true);};/**
* Relocate the cursor to a give row and column.
*
* @param {integer} row The zero based row.
* @param {integer} column The zero based column.
*/hterm.Screen.prototype.setCursorPosition=function(row,column){if(!this.rowsArray.length){console.warn('Attempt to set cursor position on empty screen.');return;}if(row>=this.rowsArray.length){console.error('Row out of bounds: '+row);row=this.rowsArray.length-1;}else if(row<0){console.error('Row out of bounds: '+row);row=0;}if(column>=this.columnCount_){console.error('Column out of bounds: '+column);column=this.columnCount_-1;}else if(column<0){console.error('Column out of bounds: '+column);column=0;}this.cursorPosition.overflow=false;var rowNode=this.rowsArray[row];var node=rowNode.firstChild;if(!node){node=rowNode.ownerDocument.createTextNode('');rowNode.appendChild(node);}var currentColumn=0;if(rowNode==this.cursorRowNode_){if(column>=this.cursorPosition.column-this.cursorOffset_){node=this.cursorNode_;currentColumn=this.cursorPosition.column-this.cursorOffset_;}}else{this.cursorRowNode_=rowNode;}this.cursorPosition.move(row,column);while(node){var offset=column-currentColumn;var width=hterm.TextAttributes.nodeWidth(node);if(!node.nextSibling||width>offset){this.cursorNode_=node;this.cursorOffset_=offset;return;}currentColumn+=width;node=node.nextSibling;}};/**
* Set the provided selection object to be a caret selection at the current
* cursor position.
*/hterm.Screen.prototype.syncSelectionCaret=function(selection){try{selection.collapse(this.cursorNode_,this.cursorOffset_);}catch(firefoxIgnoredException){// FF can throw an exception if the range is off, rather than just not
// performing the collapse.
}};/**
* Split a single node into two nodes at the given offset.
*
* For example:
* Given the DOM fragment '<div><span>Hello World</span></div>', call splitNode_
* passing the span and an offset of 6. This would modify the fragment to
* become: '<div><span>Hello </span><span>World</span></div>'. If the span
* had any attributes they would have been copied to the new span as well.
*
* The to-be-split node must have a container, so that the new node can be
* placed next to it.
*
* @param {HTMLNode} node The node to split.
* @param {integer} offset The offset into the node where the split should
* occur.
*/hterm.Screen.prototype.splitNode_=function(node,offset){var afterNode=node.cloneNode(false);var textContent=node.textContent;node.textContent=hterm.TextAttributes.nodeSubstr(node,0,offset);afterNode.textContent=lib.wc.substr(textContent,offset);if(afterNode.textContent)node.parentNode.insertBefore(afterNode,node.nextSibling);if(!node.textContent)node.parentNode.removeChild(node);};/**
* Ensure that text is clipped and the cursor is clamped to the column count.
*/hterm.Screen.prototype.maybeClipCurrentRow=function(){var width=hterm.TextAttributes.nodeWidth(this.cursorRowNode_);if(width<=this.columnCount_){// Current row does not need clipping, but may need clamping.
if(this.cursorPosition.column>=this.columnCount_){this.setCursorPosition(this.cursorPosition.row,this.columnCount_-1);this.cursorPosition.overflow=true;}return;}// Save off the current column so we can maybe restore it later.
var currentColumn=this.cursorPosition.column;// Move the cursor to the final column.
this.setCursorPosition(this.cursorPosition.row,this.columnCount_-1);// Remove any text that partially overflows.
width=hterm.TextAttributes.nodeWidth(this.cursorNode_);if(this.cursorOffset_<width-1){this.cursorNode_.textContent=hterm.TextAttributes.nodeSubstr(this.cursorNode_,0,this.cursorOffset_+1);}// Remove all nodes after the cursor.
var rowNode=this.cursorRowNode_;var node=this.cursorNode_.nextSibling;while(node){rowNode.removeChild(node);node=this.cursorNode_.nextSibling;}if(currentColumn<this.columnCount_){// If the cursor was within the screen before we started then restore its
// position.
this.setCursorPosition(this.cursorPosition.row,currentColumn);}else{// Otherwise leave it at the the last column in the overflow state.
this.cursorPosition.overflow=true;}};/**
* Insert a string at the current character position using the current
* text attributes.
*
* You must call maybeClipCurrentRow() after in order to clip overflowed
* text and clamp the cursor.
*
* It is also up to the caller to properly maintain the line overflow state
* using hterm.Screen..commitLineOverflow().
*/hterm.Screen.prototype.insertString=function(str){var wcwidth=arguments.length>1&&arguments[1]!==undefined?arguments[1]:undefined;var cursorNode=this.cursorNode_;var cursorNodeText=cursorNode.textContent;this.cursorRowNode_.removeAttribute('line-overflow');// We may alter the width of the string by prepending some missing
// whitespaces, so we need to record the string width ahead of time.
if(wcwidth===undefined)wcwidth=lib.wc.strWidth(str);// No matter what, before this function exits the cursor column will have
// moved this much.
this.cursorPosition.column+=wcwidth;// Local cache of the cursor offset.
var offset=this.cursorOffset_;// Reverse offset is the offset measured from the end of the string.
// Zero implies that the cursor is at the end of the cursor node.
var reverseOffset=hterm.TextAttributes.nodeWidth(cursorNode)-offset;if(reverseOffset<0){// A negative reverse offset means the cursor is positioned past the end
// of the characters on this line. We'll need to insert the missing
// whitespace.
var ws=lib.f.getWhitespace(-reverseOffset);// This whitespace should be completely unstyled. Underline, background
// color, and strikethrough would be visible on whitespace, so we can't use
// one of those spans to hold the text.
if(!(this.textAttributes.underline||this.textAttributes.strikethrough||this.textAttributes.background||this.textAttributes.wcNode||!this.textAttributes.asciiNode||this.textAttributes.tileData!=null)){// Best case scenario, we can just pretend the spaces were part of the
// original string.
str=ws+str;}else if(cursorNode.nodeType==Node.TEXT_NODE||!(cursorNode.wcNode||!cursorNode.asciiNode||cursorNode.tileNode||cursorNode.style.textDecoration||cursorNode.style.textDecorationStyle||cursorNode.style.textDecorationLine||cursorNode.style.backgroundColor)){// Second best case, the current node is able to hold the whitespace.
cursorNode.textContent=cursorNodeText+=ws;}else{// Worst case, we have to create a new node to hold the whitespace.
var wsNode=cursorNode.ownerDocument.createTextNode(ws);this.cursorRowNode_.insertBefore(wsNode,cursorNode.nextSibling);this.cursorNode_=cursorNode=wsNode;this.cursorOffset_=offset=-reverseOffset;cursorNodeText=ws;}// We now know for sure that we're at the last character of the cursor node.
reverseOffset=0;}if(this.textAttributes.matchesContainer(cursorNode)){// The new text can be placed directly in the cursor node.
if(reverseOffset==0){cursorNode.textContent=cursorNodeText+str;}else if(offset==0){cursorNode.textContent=str+cursorNodeText;}else{cursorNode.textContent=hterm.TextAttributes.nodeSubstr(cursorNode,0,offset)+str+hterm.TextAttributes.nodeSubstr(cursorNode,offset);}this.cursorOffset_+=wcwidth;return;}// The cursor node is the wrong style for the new text. If we're at the
// beginning or end of the cursor node, then the adjacent node is also a
// potential candidate.
if(offset==0){// At the beginning of the cursor node, the check the previous sibling.
var previousSibling=cursorNode.previousSibling;if(previousSibling&&this.textAttributes.matchesContainer(previousSibling)){previousSibling.textContent+=str;this.cursorNode_=previousSibling;this.cursorOffset_=lib.wc.strWidth(previousSibling.textContent);return;}var newNode=this.textAttributes.createContainer(str);this.cursorRowNode_.insertBefore(newNode,cursorNode);this.cursorNode_=newNode;this.cursorOffset_=wcwidth;return;}if(reverseOffset==0){// At the end of the cursor node, the check the next sibling.
var nextSibling=cursorNode.nextSibling;if(nextSibling&&this.textAttributes.matchesContainer(nextSibling)){nextSibling.textContent=str+nextSibling.textContent;this.cursorNode_=nextSibling;this.cursorOffset_=lib.wc.strWidth(str);return;}var newNode=this.textAttributes.createContainer(str);this.cursorRowNode_.insertBefore(newNode,nextSibling);this.cursorNode_=newNode;// We specifically need to include any missing whitespace here, since it's
// going in a new node.
this.cursorOffset_=hterm.TextAttributes.nodeWidth(newNode);return;}// Worst case, we're somewhere in the middle of the cursor node. We'll
// have to split it into two nodes and insert our new container in between.
this.splitNode_(cursorNode,offset);var newNode=this.textAttributes.createContainer(str);this.cursorRowNode_.insertBefore(newNode,cursorNode.nextSibling);this.cursorNode_=newNode;this.cursorOffset_=wcwidth;};/**
* Overwrite the text at the current cursor position.
*
* You must call maybeClipCurrentRow() after in order to clip overflowed
* text and clamp the cursor.
*
* It is also up to the caller to properly maintain the line overflow state
* using hterm.Screen..commitLineOverflow().
*/hterm.Screen.prototype.overwriteString=function(str){var wcwidth=arguments.length>1&&arguments[1]!==undefined?arguments[1]:undefined;var maxLength=this.columnCount_-this.cursorPosition.column;if(!maxLength)return;if(wcwidth===undefined)wcwidth=lib.wc.strWidth(str);if(this.textAttributes.matchesContainer(this.cursorNode_)&&this.cursorNode_.textContent.substr(this.cursorOffset_)==str){// This overwrite would be a no-op, just move the cursor and return.
this.cursorOffset_+=wcwidth;this.cursorPosition.column+=wcwidth;return;}this.deleteChars(Math.min(wcwidth,maxLength));this.insertString(str,wcwidth);};/**
* Forward-delete one or more characters at the current cursor position.
*
* Text to the right of the deleted characters is shifted left. Only affects
* characters on the same row as the cursor.
*
* @param {integer} count The column width of characters to delete. This is
* clamped to the column width minus the cursor column.
* @return {integer} The column width of the characters actually deleted.
*/hterm.Screen.prototype.deleteChars=function(count){var node=this.cursorNode_;var offset=this.cursorOffset_;var currentCursorColumn=this.cursorPosition.column;count=Math.min(count,this.columnCount_-currentCursorColumn);if(!count)return 0;var rv=count;var startLength,endLength;while(node&&count){// Sanity check so we don't loop forever, but we don't also go quietly.
if(count<0){console.error("Deleting ".concat(rv," chars went negative: ").concat(count));break;}startLength=hterm.TextAttributes.nodeWidth(node);node.textContent=hterm.TextAttributes.nodeSubstr(node,0,offset)+hterm.TextAttributes.nodeSubstr(node,offset+count);endLength=hterm.TextAttributes.nodeWidth(node);// Deal with splitting wide characters. There are two ways: we could delete
// the first column or the second column. In both cases, we delete the wide
// character and replace one of the columns with a space (since the other
// was deleted). If there are more chars to delete, the next loop will pick
// up the slack.
if(node.wcNode&&offset<startLength&&(endLength&&startLength==endLength||!endLength&&offset==1)){// No characters were deleted when there should be. We're probably trying
// to delete one column width from a wide character node. We remove the
// wide character node here and replace it with a single space.
var spaceNode=this.textAttributes.createContainer(' ');node.parentNode.insertBefore(spaceNode,offset?node:node.nextSibling);node.textContent='';endLength=0;count-=1;}else count-=startLength-endLength;var nextNode=node.nextSibling;if(endLength==0&&node!=this.cursorNode_){node.parentNode.removeChild(node);}node=nextNode;offset=0;}// Remove this.cursorNode_ if it is an empty non-text node.
if(this.cursorNode_.nodeType!=Node.TEXT_NODE&&!this.cursorNode_.textContent){var cursorNode=this.cursorNode_;if(cursorNode.previousSibling){this.cursorNode_=cursorNode.previousSibling;this.cursorOffset_=hterm.TextAttributes.nodeWidth(cursorNode.previousSibling);}else if(cursorNode.nextSibling){this.cursorNode_=cursorNode.nextSibling;this.cursorOffset_=0;}else{var emptyNode=this.cursorRowNode_.ownerDocument.createTextNode('');this.cursorRowNode_.appendChild(emptyNode);this.cursorNode_=emptyNode;this.cursorOffset_=0;}this.cursorRowNode_.removeChild(cursorNode);}return rv;};/**
* Finds first X-ROW of a line containing specified X-ROW.
* Used to support line overflow.
*
* @param {Node} row X-ROW to begin search for first row of line.
* @return {Node} The X-ROW that is at the beginning of the line.
**/hterm.Screen.prototype.getLineStartRow_=function(row){while(row.previousSibling&&row.previousSibling.hasAttribute('line-overflow')){row=row.previousSibling;}return row;};/**
* Gets text of a line beginning with row.
* Supports line overflow.
*
* @param {Node} row First X-ROW of line.
* @return {string} Text content of line.
**/hterm.Screen.prototype.getLineText_=function(row){var rowText="";while(row){rowText+=row.textContent;if(row.hasAttribute('line-overflow')){row=row.nextSibling;}else{break;}}return rowText;};/**
* Returns X-ROW that is ancestor of the node.
*
* @param {Node} node Node to get X-ROW ancestor for.
* @return {Node} X-ROW ancestor of node, or null if not found.
**/hterm.Screen.prototype.getXRowAncestor_=function(node){while(node){if(node.nodeName==='X-ROW')break;node=node.parentNode;}return node;};/**
* Returns position within line of character at offset within node.
* Supports line overflow.
*
* @param {Node} row X-ROW at beginning of line.
* @param {Node} node Node to get position of.
* @param {integer} offset Offset into node.
*
* @return {integer} Position within line of character at offset within node.
**/hterm.Screen.prototype.getPositionWithOverflow_=function(row,node,offset){if(!node)return-1;var ancestorRow=this.getXRowAncestor_(node);if(!ancestorRow)return-1;var position=0;while(ancestorRow!=row){position+=hterm.TextAttributes.nodeWidth(row);if(row.hasAttribute('line-overflow')&&row.nextSibling){row=row.nextSibling;}else{return-1;}}return position+this.getPositionWithinRow_(row,node,offset);};/**
* Returns position within row of character at offset within node.
* Does not support line overflow.
*
* @param {Node} row X-ROW to get position within.
* @param {Node} node Node to get position for.
* @param {integer} offset Offset within node to get position for.
* @return {integer} Position within row of character at offset within node.
**/hterm.Screen.prototype.getPositionWithinRow_=function(row,node,offset){if(node.parentNode!=row){// If we traversed to the top node, then there's nothing to find here.
if(node.parentNode==null)return-1;return this.getPositionWithinRow_(node.parentNode,node,offset)+this.getPositionWithinRow_(row,node.parentNode,0);}var position=0;for(var i=0;i<row.childNodes.length;i++){var currentNode=row.childNodes[i];if(currentNode==node)return position+offset;position+=hterm.TextAttributes.nodeWidth(currentNode);}return-1;};/**
* Returns the node and offset corresponding to position within line.
* Supports line overflow.
*
* @param {Node} row X-ROW at beginning of line.
* @param {integer} position Position within line to retrieve node and offset.
* @return {Array} Two element array containing node and offset respectively.
**/hterm.Screen.prototype.getNodeAndOffsetWithOverflow_=function(row,position){while(row&&position>hterm.TextAttributes.nodeWidth(row)){if(row.hasAttribute('line-overflow')&&row.nextSibling){position-=hterm.TextAttributes.nodeWidth(row);row=row.nextSibling;}else{return-1;}}return this.getNodeAndOffsetWithinRow_(row,position);};/**
* Returns the node and offset corresponding to position within row.
* Does not support line overflow.
*
* @param {Node} row X-ROW to get position within.
* @param {integer} position Position within row to retrieve node and offset.
* @return {Array} Two element array containing node and offset respectively.
**/hterm.Screen.prototype.getNodeAndOffsetWithinRow_=function(row,position){for(var i=0;i<row.childNodes.length;i++){var node=row.childNodes[i];var nodeTextWidth=hterm.TextAttributes.nodeWidth(node);if(position<=nodeTextWidth){if(node.nodeName==='SPAN'){/** Drill down to node contained by SPAN. **/return this.getNodeAndOffsetWithinRow_(node,position);}else{return[node,position];}}position-=nodeTextWidth;}return null;};/**
* Returns the node and offset corresponding to position within line.
* Supports line overflow.
*
* @param {Node} row X-ROW at beginning of line.
* @param {integer} start Start position of range within line.
* @param {integer} end End position of range within line.
* @param {Range} range Range to modify.
**/hterm.Screen.prototype.setRange_=function(row,start,end,range){var startNodeAndOffset=this.getNodeAndOffsetWithOverflow_(row,start);if(startNodeAndOffset==null)return;var endNodeAndOffset=this.getNodeAndOffsetWithOverflow_(row,end);if(endNodeAndOffset==null)return;range.setStart(startNodeAndOffset[0],startNodeAndOffset[1]);range.setEnd(endNodeAndOffset[0],endNodeAndOffset[1]);};/**
* Expands selection to surrounding string with word break matches.
*
* @param {Selection} selection Selection to expand.
* @param {string} leftMatch left word break match.
* @param {string} rightMatch right word break match.
* @param {string} insideMatch inside word break match.
*/hterm.Screen.prototype.expandSelectionWithWordBreakMatches_=function(selection,leftMatch,rightMatch,insideMatch){if(!selection)return;var range=selection.getRangeAt(0);if(!range||range.toString().match(/\s/))return;var rowElement=this.getXRowAncestor_(range.startContainer);if(!rowElement)return;var row=this.getLineStartRow_(rowElement);if(!row)return;var startPosition=this.getPositionWithOverflow_(row,range.startContainer,range.startOffset);if(startPosition==-1)return;var endPosition=this.getPositionWithOverflow_(row,range.endContainer,range.endOffset);if(endPosition==-1)return;//Move start to the left.
var rowText=this.getLineText_(row);var lineUpToRange=lib.wc.substring(rowText,0,endPosition);var leftRegularExpression=new RegExp(leftMatch+insideMatch+"$");var expandedStart=lineUpToRange.search(leftRegularExpression);if(expandedStart==-1||expandedStart>startPosition)return;//Move end to the right.
var lineFromRange=lib.wc.substring(rowText,startPosition,lib.wc.strWidth(rowText));var rightRegularExpression=new RegExp("^"+insideMatch+rightMatch);var found=lineFromRange.match(rightRegularExpression);if(!found)return;var expandedEnd=startPosition+lib.wc.strWidth(found[0]);if(expandedEnd==-1||expandedEnd<endPosition)return;this.setRange_(row,expandedStart,expandedEnd,range);selection.addRange(range);};/**
* Expands selection to surrounding string using the user's settings.
*
* @param {Selection} selection Selection to expand.
*/hterm.Screen.prototype.expandSelection=function(selection){this.expandSelectionWithWordBreakMatches_(selection,this.wordBreakMatchLeft,this.wordBreakMatchRight,this.wordBreakMatchMiddle);};/**
* Expands selection to surrounding URL using a set of fixed match settings.
*
* @param {Selection} selection Selection to expand.
*/hterm.Screen.prototype.expandSelectionForUrl=function(selection){this.expandSelectionWithWordBreakMatches_(selection,"[^\\s\\[\\](){}<>\"'\\^!@#$%&*,;:`]","[^\\s\\[\\](){}<>\"'\\^!@#$%&*,;:~.`]","[^\\s\\[\\](){}<>\"'\\^]*");};/**
* Save the current cursor state to the corresponding screens.
*
* @param {hterm.VT} vt The VT object to read graphic codeset details from.
*/hterm.Screen.prototype.saveCursorAndState=function(vt){this.cursorState_.save(vt);};/**
* Restore the saved cursor state in the corresponding screens.
*
* @param {hterm.VT} vt The VT object to write graphic codeset details to.
*/hterm.Screen.prototype.restoreCursorAndState=function(vt){this.cursorState_.restore(vt);};/**
* Track all the things related to the current "cursor".
*
* The set of things saved & restored here is defined by DEC:
* https://vt100.net/docs/vt510-rm/DECSC.html
* - Cursor position
* - Character attributes set by the SGR command
* - Character sets (G0, G1, G2, or G3) currently in GL and GR
* - Wrap flag (autowrap or no autowrap)
* - State of origin mode (DECOM)
* - Selective erase attribute
* - Any single shift 2 (SS2) or single shift 3 (SS3) functions sent
*
* These are done on a per-screen basis.
*/hterm.Screen.CursorState=function(screen){this.screen_=screen;this.cursor=null;this.textAttributes=null;this.GL=this.GR=this.G0=this.G1=this.G2=this.G3=null;};/**
* Save all the cursor state.
*
* @param {hterm.VT} vt The VT object to read graphic codeset details from.
*/hterm.Screen.CursorState.prototype.save=function(vt){this.cursor=vt.terminal.saveCursor();this.textAttributes=this.screen_.textAttributes.clone();this.GL=vt.GL;this.GR=vt.GR;this.G0=vt.G0;this.G1=vt.G1;this.G2=vt.G2;this.G3=vt.G3;};/**
* Restore the previously saved cursor state.
*
* @param {hterm.VT} vt The VT object to write graphic codeset details to.
*/hterm.Screen.CursorState.prototype.restore=function(vt){vt.terminal.restoreCursor(this.cursor);// Cursor restore includes char attributes (bold/etc...), but does not change
// the color palette (which are a terminal setting).
var tattrs=this.textAttributes.clone();tattrs.colorPalette=this.screen_.textAttributes.colorPalette;tattrs.syncColors();this.screen_.textAttributes=tattrs;vt.GL=this.GL;vt.GR=this.GR;vt.G0=this.G0;vt.G1=this.G1;vt.G2=this.G2;vt.G3=this.G3;};// SOURCE FILE: hterm/js/hterm_scrollport.js
// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* A 'viewport' view of fixed-height rows with support for selection and
* copy-to-clipboard.
*
* 'Viewport' in this case means that only the visible rows are in the DOM.
* If the rowProvider has 100,000 rows, but the ScrollPort is only 25 rows
* tall, then only 25 dom nodes are created. The ScrollPort will ask the
* RowProvider to create new visible rows on demand as they are scrolled in
* to the visible area.
*
* This viewport is designed so that select and copy-to-clipboard still works,
* even when all or part of the selection is scrolled off screen.
*
* Note that the X11 mouse clipboard does not work properly when all or part
* of the selection is off screen. It would be difficult to fix this without
* adding significant overhead to pathologically large selection cases.
*
* The RowProvider should return rows rooted by the custom tag name 'x-row'.
* This ensures that we can quickly assign the correct display height
* to the rows with css.
*
* @param {RowProvider} rowProvider An object capable of providing rows as
* raw text or row nodes.
*/hterm.ScrollPort=function(rowProvider){hterm.PubSub.addBehavior(this);this.rowProvider_=rowProvider;// SWAG the character size until we can measure it.
this.characterSize=new hterm.Size(10,10);// DOM node used for character measurement.
this.ruler_=null;this.selection=new hterm.ScrollPort.Selection(this);// A map of rowIndex => rowNode for each row that is drawn as part of a
// pending redraw_() call. Null if there is no pending redraw_ call.
this.currentRowNodeCache_=null;// A map of rowIndex => rowNode for each row that was drawn as part of the
// previous redraw_() call.
this.previousRowNodeCache_={};// Used during scroll events to detect when the underlying cause is a resize.
this.lastScreenWidth_=null;this.lastScreenHeight_=null;// True if the user should be allowed to select text in the terminal.
// This is disabled when the host requests mouse drag events so that we don't
// end up with two notions of selection.
this.selectionEnabled_=true;// The last row count returned by the row provider, re-populated during
// syncScrollHeight().
this.lastRowCount_=0;// The scroll wheel pixel delta multiplier to increase/decrease
// the scroll speed of mouse wheel events. See: https://goo.gl/sXelnq
this.scrollWheelMultiplier_=1;// The last touch events we saw to support touch based scrolling. Indexed
// by touch identifier since we can have more than one touch active.
this.lastTouch_={};/**
* True if the last scroll caused the scrollport to show the final row.
*/this.isScrolledEnd=true;/**
* A guess at the current scrollbar width, fixed in resize().
*/this.currentScrollbarWidthPx=16;/**
* Whether the ctrl-v key on the screen should paste.
*/this.ctrlVPaste=false;/**
* Whether to paste on dropped text.
*/this.pasteOnDrop=true;this.div_=null;this.document_=null;// Collection of active timeout handles.
this.timeouts_={};this.observers_={};this.DEBUG_=false;};/**
* Proxy for the native selection object which understands how to walk up the
* DOM to find the containing row node and sort out which comes first.
*
* @param {hterm.ScrollPort} scrollPort The parent hterm.ScrollPort instance.
*/hterm.ScrollPort.Selection=function(scrollPort){this.scrollPort_=scrollPort;/**
* The row containing the start of the selection.
*
* This may be partially or fully selected. It may be the selection anchor
* or the focus, but its rowIndex is guaranteed to be less-than-or-equal-to
* that of the endRow.
*
* If only one row is selected then startRow == endRow. If there is no
* selection or the selection is collapsed then startRow == null.
*/this.startRow=null;/**
* The row containing the end of the selection.
*
* This may be partially or fully selected. It may be the selection anchor
* or the focus, but its rowIndex is guaranteed to be greater-than-or-equal-to
* that of the startRow.
*
* If only one row is selected then startRow == endRow. If there is no
* selection or the selection is collapsed then startRow == null.
*/this.endRow=null;/**
* True if startRow != endRow.
*/this.isMultiline=null;/**
* True if the selection is just a point rather than a range.
*/this.isCollapsed=null;};/**
* Given a list of DOM nodes and a container, return the DOM node that
* is first according to a depth-first search.
*
* Returns null if none of the children are found.
*/hterm.ScrollPort.Selection.prototype.findFirstChild=function(parent,childAry){var node=parent.firstChild;while(node){if(childAry.indexOf(node)!=-1)return node;if(node.childNodes.length){var rv=this.findFirstChild(node,childAry);if(rv)return rv;}node=node.nextSibling;}return null;};/**
* Synchronize this object with the current DOM selection.
*
* This is a one-way synchronization, the DOM selection is copied to this
* object, not the other way around.
*/hterm.ScrollPort.Selection.prototype.sync=function(){var self=this;// The dom selection object has no way to tell which nodes come first in
// the document, so we have to figure that out.
//
// This function is used when we detect that the "anchor" node is first.
function anchorFirst(){self.startRow=anchorRow;self.startNode=selection.anchorNode;self.startOffset=selection.anchorOffset;self.endRow=focusRow;self.endNode=selection.focusNode;self.endOffset=selection.focusOffset;}// This function is used when we detect that the "focus" node is first.
function focusFirst(){self.startRow=focusRow;self.startNode=selection.focusNode;self.startOffset=selection.focusOffset;self.endRow=anchorRow;self.endNode=selection.anchorNode;self.endOffset=selection.anchorOffset;}var selection=this.scrollPort_.getDocument().getSelection();this.startRow=null;this.endRow=null;this.isMultiline=null;this.isCollapsed=!selection||selection.isCollapsed;if(!selection){return;}// Usually collapsed selections wouldn't be interesting, however screen
// readers will set a collapsed selection as they navigate through the DOM.
// It is important to preserve these nodes in the DOM as scrolling happens
// so that screen reader navigation isn't cleared.
var accessibilityEnabled=this.scrollPort_.accessibilityReader_&&this.scrollPort_.accessibilityReader_.accessibilityEnabled;if(this.isCollapsed&&!accessibilityEnabled){return;}var anchorRow=selection.anchorNode;while(anchorRow&&anchorRow.nodeName!='X-ROW'){anchorRow=anchorRow.parentNode;}if(!anchorRow){// Don't set a selection if it's not a row node that's selected.
return;}var focusRow=selection.focusNode;while(focusRow&&focusRow.nodeName!='X-ROW'){focusRow=focusRow.parentNode;}if(!focusRow){// Don't set a selection if it's not a row node that's selected.
return;}if(anchorRow.rowIndex<focusRow.rowIndex){anchorFirst();}else if(anchorRow.rowIndex>focusRow.rowIndex){focusFirst();}else if(selection.focusNode==selection.anchorNode){if(selection.anchorOffset<selection.focusOffset){anchorFirst();}else{focusFirst();}}else{// The selection starts and ends in the same row, but isn't contained all
// in a single node.
var firstNode=this.findFirstChild(anchorRow,[selection.anchorNode,selection.focusNode]);if(!firstNode)throw new Error('Unexpected error syncing selection.');if(firstNode==selection.anchorNode){anchorFirst();}else{focusFirst();}}this.isMultiline=anchorRow.rowIndex!=focusRow.rowIndex;};/**
* Turn a div into this hterm.ScrollPort.
*/hterm.ScrollPort.prototype.decorate=function(div,callback){var _this8=this;this.div_=div;this.iframe_=div.ownerDocument.createElement('iframe');this.iframe_.style.cssText='border: 0;'+'height: 100%;'+'position: absolute;'+'width: 100%';div.appendChild(this.iframe_);var onLoad=function onLoad(){_this8.paintIframeContents_();if(callback){callback();}};// Insert Iframe content asynchronously in FF. Otherwise when the frame's
// load event fires in FF it clears out the content of the iframe.
if('mozInnerScreenX'in window){// detect a FF only property
this.iframe_.addEventListener('load',function(){return onLoad();});}else{onLoad();}};/**
* Initialises the content of this.iframe_. This needs to be done asynchronously
* in FF after the Iframe's load event has fired.
* @private
*/hterm.ScrollPort.prototype.paintIframeContents_=function(){var _this9=this;this.iframe_.contentWindow.addEventListener('resize',this.onResize_.bind(this));var doc=this.document_=this.iframe_.contentDocument;doc.body.style.cssText='margin: 0px;'+'padding: 0px;'+'height: 100%;'+'width: 100%;'+'overflow: hidden;'+'cursor: var(--hterm-mouse-cursor-style);'+'-webkit-user-select: none;'+'-moz-user-select: none;';var metaCharset=doc.createElement('meta');metaCharset.setAttribute('charset','utf-8');doc.head.appendChild(metaCharset);if(this.DEBUG_){// When we're debugging we add padding to the body so that the offscreen
// elements are visible.
this.document_.body.style.paddingTop=this.document_.body.style.paddingBottom='calc(var(--hterm-charsize-height) * 3)';}var style=doc.createElement('style');style.textContent='x-row {'+' display: block;'+' height: var(--hterm-charsize-height);'+' line-height: var(--hterm-charsize-height);'+'}';doc.head.appendChild(style);this.userCssLink_=doc.createElement('link');this.userCssLink_.setAttribute('rel','stylesheet');this.userCssText_=doc.createElement('style');doc.head.appendChild(this.userCssText_);// TODO(rginda): Sorry, this 'screen_' isn't the same thing as hterm.Screen
// from screen.js. I need to pick a better name for one of them to avoid
// the collision.
// We make this field editable even though we don't actually allow anything
// to be edited here so that Chrome will do the right thing with virtual
// keyboards and IMEs. But make sure we turn off all the input helper logic
// that doesn't make sense here, and might inadvertently mung or save input.
// Some of these attributes are standard while others are browser specific,
// but should be safely ignored by other browsers.
this.screen_=doc.createElement('x-screen');this.screen_.setAttribute('contenteditable','true');this.screen_.setAttribute('spellcheck','false');this.screen_.setAttribute('autocomplete','off');this.screen_.setAttribute('autocorrect','off');this.screen_.setAttribute('autocapitalize','none');// In some ways the terminal behaves like a text box but not in all ways. It
// is not editable in the same ways a text box is editable and the content we
// want to be read out by a screen reader does not always align with the edits
// (selection changes) that happen in the terminal window. Use the log role so
// that the screen reader doesn't treat it like a text box and announce all
// selection changes. The announcements that we want spoken are generated
// by a separate live region, which gives more control over what will be
// spoken.
this.screen_.setAttribute('role','log');this.screen_.setAttribute('aria-live','off');this.screen_.setAttribute('aria-roledescription','Terminal');// Set aria-readonly to indicate to the screen reader that the text on the
// screen is not modifiable by the html cursor. It may be modifiable by
// sending input to the application running in the terminal, but this is
// orthogonal to the DOM's notion of modifiable.
this.screen_.setAttribute('aria-readonly','true');this.screen_.setAttribute('tabindex','-1');this.screen_.style.cssText='caret-color: transparent;'+'display: block;'+'font-family: monospace;'+'font-size: 15px;'+'font-variant-ligatures: none;'+'height: 100%;'+'overflow-y: scroll; overflow-x: hidden;'+'white-space: pre;'+'width: 100%;'+'outline: none !important';doc.body.appendChild(this.screen_);this.screen_.addEventListener('scroll',this.onScroll_.bind(this));this.screen_.addEventListener('wheel',this.onScrollWheel_.bind(this));this.screen_.addEventListener('touchstart',this.onTouch_.bind(this));this.screen_.addEventListener('touchmove',this.onTouch_.bind(this));this.screen_.addEventListener('touchend',this.onTouch_.bind(this));this.screen_.addEventListener('touchcancel',this.onTouch_.bind(this));this.screen_.addEventListener('copy',this.onCopy_.bind(this));this.screen_.addEventListener('paste',this.onPaste_.bind(this));this.screen_.addEventListener('drop',this.onDragAndDrop_.bind(this));doc.body.addEventListener('keydown',this.onBodyKeyDown_.bind(this));// Add buttons to make accessible scrolling through terminal history work
// well. These are positioned off-screen until they are selected, at which
// point they are moved on-screen.
var scrollButtonHeight=30;var scrollButtonBorder=1;var scrollButtonTotalHeight=scrollButtonHeight+2*scrollButtonBorder;var scrollButtonStyle="right: 0px;\n position:fixed;\n z-index: 1;\n text-align: center;\n cursor: pointer;\n height: ".concat(scrollButtonHeight,"px;\n width: 110px;\n line-height: ").concat(scrollButtonHeight,"px;\n border-width: ").concat(scrollButtonBorder,"px;\n border-style: solid;\n font-weight: bold;");// Note: we use a <div> rather than a <button> because we don't want it to be
// focusable. If it's focusable this interferes with the contenteditable
// focus.
this.scrollUpButton_=this.document_.createElement('div');this.scrollUpButton_.id='hterm:a11y:page-up';this.scrollUpButton_.innerText=hterm.msg('BUTTON_PAGE_UP',[],'Page up');this.scrollUpButton_.setAttribute('role','button');this.scrollUpButton_.style.cssText=scrollButtonStyle;this.scrollUpButton_.style.top=-scrollButtonTotalHeight+'px';this.scrollUpButton_.addEventListener('click',this.scrollPageUp.bind(this));this.scrollDownButton_=this.document_.createElement('div');this.scrollDownButton_.id='hterm:a11y:page-down';this.scrollDownButton_.innerText=hterm.msg('BUTTON_PAGE_DOWN',[],'Page down');this.scrollDownButton_.setAttribute('role','button');this.scrollDownButton_.style.cssText=scrollButtonStyle;this.scrollDownButton_.style.bottom=-scrollButtonTotalHeight+'px';this.scrollDownButton_.addEventListener('click',this.scrollPageDown.bind(this));// We only allow the scroll buttons to display after a delay, otherwise the
// page up button can flash onto the screen during the intial change in focus.
// This seems to be because it is the first element inside the <x-screen>
// element, which will get focussed on page load.
this.allowScrollButtonsToDisplay_=false;setTimeout(function(){_this9.allowScrollButtonsToDisplay_=true;},500);this.document_.addEventListener('selectionchange',function(){_this9.selection.sync();if(!_this9.allowScrollButtonsToDisplay_)return;var accessibilityEnabled=_this9.accessibilityReader_&&_this9.accessibilityReader_.accessibilityEnabled;var selection=_this9.document_.getSelection();var selectedElement;if(selection.anchorNode&&selection.anchorNode.parentElement){selectedElement=selection.anchorNode.parentElement;}if(accessibilityEnabled&&selectedElement==_this9.scrollUpButton_){_this9.scrollUpButton_.style.top='0px';}else{_this9.scrollUpButton_.style.top=-scrollButtonTotalHeight+'px';}if(accessibilityEnabled&&selectedElement==_this9.scrollDownButton_){_this9.scrollDownButton_.style.bottom='0px';}else{_this9.scrollDownButton_.style.bottom=-scrollButtonTotalHeight+'px';}});this.screen_.appendChild(this.scrollUpButton_);// This is the main container for the fixed rows.
this.rowNodes_=doc.createElement('div');this.rowNodes_.id='hterm:row-nodes';this.rowNodes_.style.cssText='display: block;'+'position: fixed;'+'overflow: hidden;'+'-webkit-user-select: text;'+'-moz-user-select: text;';this.screen_.appendChild(this.rowNodes_);this.screen_.appendChild(this.scrollDownButton_);// Two nodes to hold offscreen text during the copy event.
this.topSelectBag_=doc.createElement('x-select-bag');this.topSelectBag_.style.cssText='display: block;'+'overflow: hidden;'+'height: var(--hterm-charsize-height);'+'white-space: pre;';this.bottomSelectBag_=this.topSelectBag_.cloneNode();// Nodes above the top fold and below the bottom fold are hidden. They are
// only used to hold rows that are part of the selection but are currently
// scrolled off the top or bottom of the visible range.
this.topFold_=doc.createElement('x-fold');this.topFold_.id='hterm:top-fold-for-row-selection';this.topFold_.style.cssText='display: block;';this.rowNodes_.appendChild(this.topFold_);this.bottomFold_=this.topFold_.cloneNode();this.bottomFold_.id='hterm:bottom-fold-for-row-selection';this.rowNodes_.appendChild(this.bottomFold_);// This hidden div accounts for the vertical space that would be consumed by
// all the rows in the buffer if they were visible. It's what causes the
// scrollbar to appear on the 'x-screen', and it moves within the screen when
// the scrollbar is moved.
//
// It is set 'visibility: hidden' to keep the browser from trying to include
// it in the selection when a user 'drag selects' upwards (drag the mouse to
// select and scroll at the same time). Without this, the selection gets
// out of whack.
this.scrollArea_=doc.createElement('div');this.scrollArea_.id='hterm:scrollarea';this.scrollArea_.style.cssText='visibility: hidden';this.screen_.appendChild(this.scrollArea_);// This svg element is used to detect when the browser is zoomed. It must be
// placed in the outermost document for currentScale to be correct.
// TODO(rginda): This means that hterm nested in an iframe will not correctly
// detect browser zoom level. We should come up with a better solution.
// Note: This must be http:// else Chrome cannot create the element correctly.
var xmlns='http://www.w3.org/2000/svg';this.svg_=this.div_.ownerDocument.createElementNS(xmlns,'svg');this.svg_.id='hterm:zoom-detector';this.svg_.setAttribute('xmlns',xmlns);this.svg_.setAttribute('version','1.1');this.svg_.style.cssText='position: absolute;'+'top: 0;'+'left: 0;'+'visibility: hidden';// We send focus to this element just before a paste happens, so we can
// capture the pasted text and forward it on to someone who cares.
this.pasteTarget_=doc.createElement('textarea');this.pasteTarget_.id='hterm:ctrl-v-paste-target';this.pasteTarget_.setAttribute('tabindex','-1');this.pasteTarget_.setAttribute('aria-hidden','true');this.pasteTarget_.style.cssText='position: absolute;'+'height: 1px;'+'width: 1px;'+'left: 0px; '+'bottom: 0px;'+'opacity: 0';this.pasteTarget_.contentEditable=true;this.screen_.appendChild(this.pasteTarget_);this.pasteTarget_.addEventListener('textInput',this.handlePasteTargetTextInput_.bind(this));this.resize();};/**
* Set the AccessibilityReader object to use to announce page scroll updates.
*
* @param {hterm.AccessibilityReader} accessibilityReader for announcing page
* scroll updates.
*/hterm.ScrollPort.prototype.setAccessibilityReader=function(accessibilityReader){this.accessibilityReader_=accessibilityReader;};/**
* Scroll the terminal one page up (minus one line) relative to the current
* position.
*/hterm.ScrollPort.prototype.scrollPageUp=function(){if(this.getTopRowIndex()==0){return;}var i=this.getTopRowIndex();this.scrollRowToTop(i-this.visibleRowCount+1);this.assertiveAnnounce_();};/**
* Scroll the terminal one page down (minus one line) relative to the current
* position.
*/hterm.ScrollPort.prototype.scrollPageDown=function(){if(this.isScrolledEnd){return;}var i=this.getTopRowIndex();this.scrollRowToTop(i+this.visibleRowCount-1);this.assertiveAnnounce_();};/**
* Select the font-family and font-smoothing for this scrollport.
*
* @param {string} fontFamily Value of the CSS 'font-family' to use for this
* scrollport. Should be a monospace font.
* @param {string} opt_smoothing Optional value for '-webkit-font-smoothing'.
* Defaults to an empty string if not specified.
*/hterm.ScrollPort.prototype.setFontFamily=function(fontFamily,opt_smoothing){this.screen_.style.fontFamily=fontFamily;if(opt_smoothing){this.screen_.style.webkitFontSmoothing=opt_smoothing;}else{this.screen_.style.webkitFontSmoothing='';}this.syncCharacterSize();};hterm.ScrollPort.prototype.getFontFamily=function(){return this.screen_.style.fontFamily;};/**
* Set a custom stylesheet to include in the scrollport.
*
* Defaults to null, meaning no custom css is loaded. Set it back to null or
* the empty string to remove a previously applied custom css.
*/hterm.ScrollPort.prototype.setUserCssUrl=function(url){if(url){this.userCssLink_.setAttribute('href',url);if(!this.userCssLink_.parentNode)this.document_.head.appendChild(this.userCssLink_);}else if(this.userCssLink_.parentNode){this.document_.head.removeChild(this.userCssLink_);}};hterm.ScrollPort.prototype.setUserCssText=function(text){this.userCssText_.textContent=text;};hterm.ScrollPort.prototype.focus=function(){this.iframe_.focus();this.screen_.focus();this.publish('focus');};hterm.ScrollPort.prototype.getForegroundColor=function(){return this.screen_.style.color;};hterm.ScrollPort.prototype.setForegroundColor=function(color){this.screen_.style.color=color;this.scrollUpButton_.style.backgroundColor=color;this.scrollDownButton_.style.backgroundColor=color;};hterm.ScrollPort.prototype.getBackgroundColor=function(){return this.screen_.style.backgroundColor;};hterm.ScrollPort.prototype.setBackgroundColor=function(color){this.screen_.style.backgroundColor=color;this.scrollUpButton_.style.color=color;this.scrollDownButton_.style.color=color;};hterm.ScrollPort.prototype.setBackgroundImage=function(image){this.screen_.style.backgroundImage=image;};hterm.ScrollPort.prototype.setBackgroundSize=function(size){this.screen_.style.backgroundSize=size;};hterm.ScrollPort.prototype.setBackgroundPosition=function(position){this.screen_.style.backgroundPosition=position;};hterm.ScrollPort.prototype.setCtrlVPaste=function(ctrlVPaste){this.ctrlVPaste=ctrlVPaste;};hterm.ScrollPort.prototype.setPasteOnDrop=function(pasteOnDrop){this.pasteOnDrop=pasteOnDrop;};/**
* Get the usable size of the scrollport screen.
*
* The width will not include the scrollbar width.
*/hterm.ScrollPort.prototype.getScreenSize=function(){var size=hterm.getClientSize(this.screen_);return{height:size.height,width:size.width-this.currentScrollbarWidthPx};};/**
* Get the usable width of the scrollport screen.
*
* This the widget width minus scrollbar width.
*/hterm.ScrollPort.prototype.getScreenWidth=function(){return this.getScreenSize().width;};/**
* Get the usable height of the scrollport screen.
*/hterm.ScrollPort.prototype.getScreenHeight=function(){return this.getScreenSize().height;};/**
* Return the document that holds the visible rows of this hterm.ScrollPort.
*/hterm.ScrollPort.prototype.getDocument=function(){return this.document_;};/**
* Returns the x-screen element that holds the rows of this hterm.ScrollPort.
*/hterm.ScrollPort.prototype.getScreenNode=function(){return this.screen_;};/**
* Clear out any cached rowNodes.
*/hterm.ScrollPort.prototype.resetCache=function(){this.currentRowNodeCache_=null;this.previousRowNodeCache_={};};/**
* Change the current rowProvider.
*
* This will clear the row cache and cause a redraw.
*
* @param {Object} rowProvider An object capable of providing the rows
* in this hterm.ScrollPort.
*/hterm.ScrollPort.prototype.setRowProvider=function(rowProvider){this.resetCache();this.rowProvider_=rowProvider;this.scheduleRedraw();};/**
* Inform the ScrollPort that the root DOM nodes for some or all of the visible
* rows are no longer valid.
*
* Specifically, this should be called if this.rowProvider_.getRowNode() now
* returns an entirely different node than it did before. It does not
* need to be called if the content of a row node is the only thing that
* changed.
*
* This skips some of the overhead of a full redraw, but should not be used
* in cases where the scrollport has been scrolled, or when the row count has
* changed.
*/hterm.ScrollPort.prototype.invalidate=function(){var node=this.topFold_.nextSibling;while(node!=this.bottomFold_){var nextSibling=node.nextSibling;node.parentElement.removeChild(node);node=nextSibling;}this.previousRowNodeCache_=null;var topRowIndex=this.getTopRowIndex();var bottomRowIndex=this.getBottomRowIndex(topRowIndex);this.drawVisibleRows_(topRowIndex,bottomRowIndex);};hterm.ScrollPort.prototype.scheduleInvalidate=function(){if(this.timeouts_.invalidate)return;var self=this;this.timeouts_.invalidate=setTimeout(function(){delete self.timeouts_.invalidate;self.invalidate();},0);};/**
* Set the font size of the ScrollPort.
*/hterm.ScrollPort.prototype.setFontSize=function(px){this.screen_.style.fontSize=px+'px';this.syncCharacterSize();};/**
* Return the current font size of the ScrollPort.
*/hterm.ScrollPort.prototype.getFontSize=function(){return parseInt(this.screen_.style.fontSize);};/**
* Measure the size of a single character in pixels.
*
* @param {string} opt_weight The font weight to measure, or 'normal' if
* omitted.
* @return {hterm.Size} A new hterm.Size object.
*/hterm.ScrollPort.prototype.measureCharacterSize=function(opt_weight){// Number of lines used to average the height of a single character.
var numberOfLines=100;// Number of chars per line used to average the width of a single character.
var lineLength=100;if(!this.ruler_){this.ruler_=this.document_.createElement('div');this.ruler_.id='hterm:ruler-character-size';this.ruler_.style.cssText='position: absolute;'+'top: 0;'+'left: 0;'+'visibility: hidden;'+'height: auto !important;'+'width: auto !important;';// We need to put the text in a span to make the size calculation
// work properly in Firefox
this.rulerSpan_=this.document_.createElement('span');this.rulerSpan_.id='hterm:ruler-span-workaround';this.rulerSpan_.innerHTML=('X'.repeat(lineLength)+'\r').repeat(numberOfLines);this.ruler_.appendChild(this.rulerSpan_);this.rulerBaseline_=this.document_.createElement('span');this.rulerSpan_.id='hterm:ruler-baseline';// We want to collapse it on the baseline
this.rulerBaseline_.style.fontSize='0px';this.rulerBaseline_.textContent='X';}this.rulerSpan_.style.fontWeight=opt_weight||'';this.rowNodes_.appendChild(this.ruler_);var rulerSize=hterm.getClientSize(this.rulerSpan_);var size=new hterm.Size(rulerSize.width/lineLength,rulerSize.height/numberOfLines);this.ruler_.appendChild(this.rulerBaseline_);size.baseline=this.rulerBaseline_.offsetTop;this.ruler_.removeChild(this.rulerBaseline_);this.rowNodes_.removeChild(this.ruler_);this.div_.ownerDocument.body.appendChild(this.svg_);size.zoomFactor=this.svg_.currentScale;this.div_.ownerDocument.body.removeChild(this.svg_);return size;};/**
* Synchronize the character size.
*
* This will re-measure the current character size and adjust the height
* of an x-row to match.
*/hterm.ScrollPort.prototype.syncCharacterSize=function(){this.characterSize=this.measureCharacterSize();this.resize();};/**
* Reset dimensions and visible row count to account for a change in the
* dimensions of the 'x-screen'.
*/hterm.ScrollPort.prototype.resize=function(){this.currentScrollbarWidthPx=hterm.getClientWidth(this.screen_)-this.screen_.clientWidth;this.syncScrollHeight();this.syncRowNodesDimensions_();var self=this;this.publish('resize',{scrollPort:this},function(){self.scrollRowToBottom(self.rowProvider_.getRowCount());self.scheduleRedraw();});};/**
* Announce text content on the current screen for the screen reader.
*/hterm.ScrollPort.prototype.assertiveAnnounce_=function(){if(!this.accessibilityReader_){return;}var topRow=this.getTopRowIndex();var bottomRow=this.getBottomRowIndex(topRow);var percentScrolled=100*topRow/Math.max(1,this.rowProvider_.getRowCount()-this.visibleRowCount);percentScrolled=Math.min(100,Math.round(percentScrolled));var currentScreenContent=hterm.msg('ANNOUNCE_CURRENT_SCREEN_HEADER',[percentScrolled],'$1% scrolled,');currentScreenContent+='\n';for(var i=topRow;i<=bottomRow;++i){var node=this.fetchRowNode_(i);currentScreenContent+=node.textContent+'\n';}this.accessibilityReader_.assertiveAnnounce(currentScreenContent);};/**
* Set the position and size of the row nodes element.
*/hterm.ScrollPort.prototype.syncRowNodesDimensions_=function(){var screenSize=this.getScreenSize();this.lastScreenWidth_=screenSize.width;this.lastScreenHeight_=screenSize.height;// We don't want to show a partial row because it would be distracting
// in a terminal, so we floor any fractional row count.
this.visibleRowCount=lib.f.smartFloorDivide(screenSize.height,this.characterSize.height);// Then compute the height of our integral number of rows.
var visibleRowsHeight=this.visibleRowCount*this.characterSize.height;// Then the difference between the screen height and total row height needs to
// be made up for as top margin. We need to record this value so it
// can be used later to determine the topRowIndex.
this.visibleRowTopMargin=0;this.visibleRowBottomMargin=screenSize.height-visibleRowsHeight;this.topFold_.style.marginBottom=this.visibleRowTopMargin+'px';var topFoldOffset=0;var node=this.topFold_.previousSibling;while(node){topFoldOffset+=hterm.getClientHeight(node);node=node.previousSibling;}// Set the dimensions of the visible rows container.
this.rowNodes_.style.width=screenSize.width+'px';this.rowNodes_.style.height=visibleRowsHeight+topFoldOffset+'px';this.rowNodes_.style.left=this.screen_.offsetLeft+'px';this.rowNodes_.style.top=this.screen_.offsetTop-topFoldOffset+'px';};hterm.ScrollPort.prototype.syncScrollHeight=function(){// Resize the scroll area to appear as though it contains every row.
this.lastRowCount_=this.rowProvider_.getRowCount();this.scrollArea_.style.height=this.characterSize.height*this.lastRowCount_+this.visibleRowTopMargin+this.visibleRowBottomMargin+'px';};/**
* Schedule a redraw to happen asynchronously.
*
* If this method is called multiple times before the redraw has a chance to
* run only one redraw occurs.
*/hterm.ScrollPort.prototype.scheduleRedraw=function(){if(this.timeouts_.redraw)return;var self=this;this.timeouts_.redraw=setTimeout(function(){delete self.timeouts_.redraw;self.redraw_();},0);};/**
* Update the state of scroll up/down buttons.
*
* If the viewport is at the top or bottom row of output, these buttons will
* be made transparent and clicking them shouldn't scroll any further.
*/hterm.ScrollPort.prototype.updateScrollButtonState_=function(){var setButton=function setButton(button,disabled){button.setAttribute('aria-disabled',disabled?'true':'false');button.style.opacity=disabled?0.5:1;};setButton(this.scrollUpButton_,this.getTopRowIndex()==0);setButton(this.scrollDownButton_,this.isScrolledEnd);};/**
* Redraw the current hterm.ScrollPort based on the current scrollbar position.
*
* When redrawing, we are careful to make sure that the rows that start or end
* the current selection are not touched in any way. Doing so would disturb
* the selection, and cleaning up after that would cause flashes at best and
* incorrect selection at worst. Instead, we modify the DOM around these nodes.
* We even stash the selection start/end outside of the visible area if
* they are not supposed to be visible in the hterm.ScrollPort.
*/hterm.ScrollPort.prototype.redraw_=function(){this.resetSelectBags_();this.selection.sync();this.syncScrollHeight();this.currentRowNodeCache_={};var topRowIndex=this.getTopRowIndex();var bottomRowIndex=this.getBottomRowIndex(topRowIndex);this.drawTopFold_(topRowIndex);this.drawBottomFold_(bottomRowIndex);this.drawVisibleRows_(topRowIndex,bottomRowIndex);this.syncRowNodesDimensions_();this.previousRowNodeCache_=this.currentRowNodeCache_;this.currentRowNodeCache_=null;this.isScrolledEnd=this.getTopRowIndex()+this.visibleRowCount>=this.lastRowCount_;this.updateScrollButtonState_();};/**
* Ensure that the nodes above the top fold are as they should be.
*
* If the selection start and/or end nodes are above the visible range
* of this hterm.ScrollPort then the dom will be adjusted so that they appear
* before the top fold (the first x-fold element, aka this.topFold).
*
* If not, the top fold will be the first element.
*
* It is critical that this method does not move the selection nodes. Doing
* so would clear the current selection. Instead, the rest of the DOM is
* adjusted around them.
*/hterm.ScrollPort.prototype.drawTopFold_=function(topRowIndex){if(!this.selection.startRow||this.selection.startRow.rowIndex>=topRowIndex){// Selection is entirely below the top fold, just make sure the fold is
// the first child.
if(this.rowNodes_.firstChild!=this.topFold_)this.rowNodes_.insertBefore(this.topFold_,this.rowNodes_.firstChild);return;}if(!this.selection.isMultiline||this.selection.endRow.rowIndex>=topRowIndex){// Only the startRow is above the fold.
if(this.selection.startRow.nextSibling!=this.topFold_)this.rowNodes_.insertBefore(this.topFold_,this.selection.startRow.nextSibling);}else{// Both rows are above the fold.
if(this.selection.endRow.nextSibling!=this.topFold_){this.rowNodes_.insertBefore(this.topFold_,this.selection.endRow.nextSibling);}// Trim any intermediate lines.
while(this.selection.startRow.nextSibling!=this.selection.endRow){this.rowNodes_.removeChild(this.selection.startRow.nextSibling);}}while(this.rowNodes_.firstChild!=this.selection.startRow){this.rowNodes_.removeChild(this.rowNodes_.firstChild);}};/**
* Ensure that the nodes below the bottom fold are as they should be.
*
* If the selection start and/or end nodes are below the visible range
* of this hterm.ScrollPort then the dom will be adjusted so that they appear
* after the bottom fold (the second x-fold element, aka this.bottomFold).
*
* If not, the bottom fold will be the last element.
*
* It is critical that this method does not move the selection nodes. Doing
* so would clear the current selection. Instead, the rest of the DOM is
* adjusted around them.
*/hterm.ScrollPort.prototype.drawBottomFold_=function(bottomRowIndex){if(!this.selection.endRow||this.selection.endRow.rowIndex<=bottomRowIndex){// Selection is entirely above the bottom fold, just make sure the fold is
// the last child.
if(this.rowNodes_.lastChild!=this.bottomFold_)this.rowNodes_.appendChild(this.bottomFold_);return;}if(!this.selection.isMultiline||this.selection.startRow.rowIndex<=bottomRowIndex){// Only the endRow is below the fold.
if(this.bottomFold_.nextSibling!=this.selection.endRow)this.rowNodes_.insertBefore(this.bottomFold_,this.selection.endRow);}else{// Both rows are below the fold.
if(this.bottomFold_.nextSibling!=this.selection.startRow){this.rowNodes_.insertBefore(this.bottomFold_,this.selection.startRow);}// Trim any intermediate lines.
while(this.selection.startRow.nextSibling!=this.selection.endRow){this.rowNodes_.removeChild(this.selection.startRow.nextSibling);}}while(this.rowNodes_.lastChild!=this.selection.endRow){this.rowNodes_.removeChild(this.rowNodes_.lastChild);}};/**
* Ensure that the rows between the top and bottom folds are as they should be.
*
* This method assumes that drawTopFold_() and drawBottomFold_() have already
* run, and that they have left any visible selection row (selection start
* or selection end) between the folds.
*
* It recycles DOM nodes from the previous redraw where possible, but will ask
* the rowSource to make new nodes if necessary.
*
* It is critical that this method does not move the selection nodes. Doing
* so would clear the current selection. Instead, the rest of the DOM is
* adjusted around them.
*/hterm.ScrollPort.prototype.drawVisibleRows_=function(topRowIndex,bottomRowIndex){var self=this;// Keep removing nodes, starting with currentNode, until we encounter
// targetNode. Throws on failure.
function removeUntilNode(currentNode,targetNode){while(currentNode!=targetNode){if(!currentNode)throw'Did not encounter target node';if(currentNode==self.bottomFold_)throw'Encountered bottom fold before target node';var deadNode=currentNode;currentNode=currentNode.nextSibling;deadNode.parentNode.removeChild(deadNode);}}// Shorthand for things we're going to use a lot.
var selectionStartRow=this.selection.startRow;var selectionEndRow=this.selection.endRow;var bottomFold=this.bottomFold_;// The node we're examining during the current iteration.
var node=this.topFold_.nextSibling;var targetDrawCount=Math.min(this.visibleRowCount,this.rowProvider_.getRowCount());for(var drawCount=0;drawCount<targetDrawCount;drawCount++){var rowIndex=topRowIndex+drawCount;if(node==bottomFold){// We've hit the bottom fold, we need to insert a new row.
var newNode=this.fetchRowNode_(rowIndex);if(!newNode){console.log("Couldn't fetch row index: "+rowIndex);break;}this.rowNodes_.insertBefore(newNode,node);continue;}if(node.rowIndex==rowIndex){// This node is in the right place, move along.
node=node.nextSibling;continue;}if(selectionStartRow&&selectionStartRow.rowIndex==rowIndex){// The selection start row is supposed to be here, remove nodes until
// we find it.
removeUntilNode(node,selectionStartRow);node=selectionStartRow.nextSibling;continue;}if(selectionEndRow&&selectionEndRow.rowIndex==rowIndex){// The selection end row is supposed to be here, remove nodes until
// we find it.
removeUntilNode(node,selectionEndRow);node=selectionEndRow.nextSibling;continue;}if(node==selectionStartRow||node==selectionEndRow){// We encountered the start/end of the selection, but we don't want it
// yet. Insert a new row instead.
var newNode=this.fetchRowNode_(rowIndex);if(!newNode){console.log("Couldn't fetch row index: "+rowIndex);break;}this.rowNodes_.insertBefore(newNode,node);continue;}// There is nothing special about this node, but it's in our way. Replace
// it with the node that should be here.
var newNode=this.fetchRowNode_(rowIndex);if(!newNode){console.log("Couldn't fetch row index: "+rowIndex);break;}if(node==newNode){node=node.nextSibling;continue;}this.rowNodes_.insertBefore(newNode,node);if(!newNode.nextSibling)debugger;this.rowNodes_.removeChild(node);node=newNode.nextSibling;}if(node!=this.bottomFold_)removeUntilNode(node,bottomFold);};/**
* Empty out both select bags and remove them from the document.
*
* These nodes hold the text between the start and end of the selection
* when that text is otherwise off screen. They are filled out in the
* onCopy_ event.
*/hterm.ScrollPort.prototype.resetSelectBags_=function(){if(this.topSelectBag_.parentNode){this.topSelectBag_.textContent='';this.topSelectBag_.parentNode.removeChild(this.topSelectBag_);}if(this.bottomSelectBag_.parentNode){this.bottomSelectBag_.textContent='';this.bottomSelectBag_.parentNode.removeChild(this.bottomSelectBag_);}};/**
* Place a row node in the cache of visible nodes.
*
* This method may only be used during a redraw_.
*/hterm.ScrollPort.prototype.cacheRowNode_=function(rowNode){this.currentRowNodeCache_[rowNode.rowIndex]=rowNode;};/**
* Fetch the row node for the given index.
*
* This will return a node from the cache if possible, or will request one
* from the RowProvider if not.
*
* If a redraw_ is in progress the row will be added to the current cache.
*/hterm.ScrollPort.prototype.fetchRowNode_=function(rowIndex){var node;if(this.previousRowNodeCache_&&rowIndex in this.previousRowNodeCache_){node=this.previousRowNodeCache_[rowIndex];}else{node=this.rowProvider_.getRowNode(rowIndex);}if(this.currentRowNodeCache_)this.cacheRowNode_(node);return node;};/**
* Select all rows in the viewport.
*/hterm.ScrollPort.prototype.selectAll=function(){var firstRow;if(this.topFold_.nextSibling.rowIndex!=0){while(this.topFold_.previousSibling){this.rowNodes_.removeChild(this.topFold_.previousSibling);}firstRow=this.fetchRowNode_(0);this.rowNodes_.insertBefore(firstRow,this.topFold_);this.syncRowNodesDimensions_();}else{firstRow=this.topFold_.nextSibling;}var lastRowIndex=this.rowProvider_.getRowCount()-1;var lastRow;if(this.bottomFold_.previousSibling.rowIndex!=lastRowIndex){while(this.bottomFold_.nextSibling){this.rowNodes_.removeChild(this.bottomFold_.nextSibling);}lastRow=this.fetchRowNode_(lastRowIndex);this.rowNodes_.appendChild(lastRow);}else{lastRow=this.bottomFold_.previousSibling.rowIndex;}var selection=this.document_.getSelection();selection.collapse(firstRow,0);selection.extend(lastRow,lastRow.childNodes.length);this.selection.sync();};/**
* Return the maximum scroll position in pixels.
*/hterm.ScrollPort.prototype.getScrollMax_=function(e){return hterm.getClientHeight(this.scrollArea_)+this.visibleRowTopMargin+this.visibleRowBottomMargin-hterm.getClientHeight(this.screen_);};/**
* Scroll the given rowIndex to the top of the hterm.ScrollPort.
*
* @param {integer} rowIndex Index of the target row.
*/hterm.ScrollPort.prototype.scrollRowToTop=function(rowIndex){this.syncScrollHeight();this.isScrolledEnd=rowIndex+this.visibleRowCount>=this.lastRowCount_;var scrollTop=rowIndex*this.characterSize.height+this.visibleRowTopMargin;var scrollMax=this.getScrollMax_();if(scrollTop>scrollMax)scrollTop=scrollMax;if(this.screen_.scrollTop==scrollTop)return;this.screen_.scrollTop=scrollTop;this.scheduleRedraw();};/**
* Scroll the given rowIndex to the bottom of the hterm.ScrollPort.
*
* @param {integer} rowIndex Index of the target row.
*/hterm.ScrollPort.prototype.scrollRowToBottom=function(rowIndex){this.syncScrollHeight();this.isScrolledEnd=rowIndex+this.visibleRowCount>=this.lastRowCount_;var scrollTop=rowIndex*this.characterSize.height+this.visibleRowTopMargin+this.visibleRowBottomMargin;scrollTop-=this.visibleRowCount*this.characterSize.height;if(scrollTop<0)scrollTop=0;if(this.screen_.scrollTop==scrollTop)return;this.screen_.scrollTop=scrollTop;};/**
* Return the row index of the first visible row.
*
* This is based on the scroll position. If a redraw_ is in progress this
* returns the row that *should* be at the top.
*/hterm.ScrollPort.prototype.getTopRowIndex=function(){return Math.round(this.screen_.scrollTop/this.characterSize.height);};/**
* Return the row index of the last visible row.
*
* This is based on the scroll position. If a redraw_ is in progress this
* returns the row that *should* be at the bottom.
*/hterm.ScrollPort.prototype.getBottomRowIndex=function(topRowIndex){return topRowIndex+this.visibleRowCount-1;};/**
* Handler for scroll events.
*
* The onScroll event fires when scrollArea's scrollTop property changes. This
* may be due to the user manually move the scrollbar, or a programmatic change.
*/hterm.ScrollPort.prototype.onScroll_=function(e){var screenSize=this.getScreenSize();if(screenSize.width!=this.lastScreenWidth_||screenSize.height!=this.lastScreenHeight_){// This event may also fire during a resize (but before the resize event!).
// This happens when the browser moves the scrollbar as part of the resize.
// In these cases, we want to ignore the scroll event and let onResize
// handle things. If we don't, then we end up scrolling to the wrong
// position after a resize.
this.resize();return;}this.redraw_();this.publish('scroll',{scrollPort:this});};/**
* Clients can override this if they want to hear scrollwheel events.
*
* Clients may call event.preventDefault() if they want to keep the scrollport
* from also handling the events.
*/hterm.ScrollPort.prototype.onScrollWheel=function(e){};/**
* Handler for scroll-wheel events.
*
* The onScrollWheel event fires when the user moves their scrollwheel over this
* hterm.ScrollPort. Because the frontmost element in the hterm.ScrollPort is
* a fixed position DIV, the scroll wheel does nothing by default. Instead, we
* have to handle it manually.
*/hterm.ScrollPort.prototype.onScrollWheel_=function(e){this.onScrollWheel(e);if(e.defaultPrevented)return;// Figure out how far this event wants us to scroll.
var delta=this.scrollWheelDelta(e);var top=this.screen_.scrollTop-delta.y;if(top<0)top=0;var scrollMax=this.getScrollMax_();if(top>scrollMax)top=scrollMax;if(top!=this.screen_.scrollTop){// Moving scrollTop causes a scroll event, which triggers the redraw.
this.screen_.scrollTop=top;// Only preventDefault when we've actually scrolled. If there's nothing
// to scroll we want to pass the event through so Chrome can detect the
// overscroll.
e.preventDefault();}};/**
* Calculate how far a wheel event should scroll.
*
* This normalizes the browser's concept of a scroll (pixels, lines, etc...)
* into a standard pixel distance.
*
* @param {WheelEvent} e The mouse wheel event to process.
* @return {Object} The x & y of how far (in pixels) to scroll.
*/hterm.ScrollPort.prototype.scrollWheelDelta=function(e){var delta={x:0,y:0};switch(e.deltaMode){case WheelEvent.DOM_DELTA_PIXEL:delta.x=e.deltaX*this.scrollWheelMultiplier_;delta.y=e.deltaY*this.scrollWheelMultiplier_;break;case WheelEvent.DOM_DELTA_LINE:delta.x=e.deltaX*this.characterSize.width;delta.y=e.deltaY*this.characterSize.height;break;case WheelEvent.DOM_DELTA_PAGE:delta.x=e.deltaX*this.characterSize.width*this.screen_.getWidth();delta.y=e.deltaY*this.characterSize.height*this.screen_.getHeight();break;}// The Y sign is inverted from what we would expect: up/down are
// negative/positive respectively. The X sign is sane though: left/right
// are negative/positive respectively.
delta.y*=-1;return delta;};/**
* Clients can override this if they want to hear touch events.
*
* Clients may call event.preventDefault() if they want to keep the scrollport
* from also handling the events.
*/hterm.ScrollPort.prototype.onTouch=function(e){};/**
* Handler for touch events.
*/hterm.ScrollPort.prototype.onTouch_=function(e){this.onTouch(e);if(e.defaultPrevented)return;// Extract the fields from the Touch event that we need. If we saved the
// event directly, it has references to other objects (like x-row) that
// might stick around for a long time. This way we only have small objects
// in our lastTouch_ state.
var scrubTouch=function scrubTouch(t){return{id:t.identifier,y:t.clientY,x:t.clientX};};var i,touch;switch(e.type){case'touchstart':// Workaround focus bug on CrOS if possible.
// TODO(vapier): Drop this once https://crbug.com/919222 is fixed.
if(hterm.os=='cros'&&window.chrome&&chrome.windows){chrome.windows.getCurrent(function(win){if(!win.focused){chrome.windows.update(win.id,{focused:true});}});}// Save the current set of touches.
for(i=0;i<e.changedTouches.length;++i){touch=scrubTouch(e.changedTouches[i]);this.lastTouch_[touch.id]=touch;}break;case'touchcancel':case'touchend':// Throw away existing touches that we're finished with.
for(i=0;i<e.changedTouches.length;++i){delete this.lastTouch_[e.changedTouches[i].identifier];}break;case'touchmove':// Walk all of the touches in this one event and merge all of their
// changes into one delta. This lets multiple fingers scroll faster.
var delta=0;for(i=0;i<e.changedTouches.length;++i){touch=scrubTouch(e.changedTouches[i]);delta+=this.lastTouch_[touch.id].y-touch.y;this.lastTouch_[touch.id]=touch;}// Invert to match the touchscreen scrolling direction of browser windows.
delta*=-1;var top=this.screen_.scrollTop-delta;if(top<0)top=0;var scrollMax=this.getScrollMax_();if(top>scrollMax)top=scrollMax;if(top!=this.screen_.scrollTop){// Moving scrollTop causes a scroll event, which triggers the redraw.
this.screen_.scrollTop=top;}break;}// To disable gestures or anything else interfering with our scrolling.
e.preventDefault();};/**
* Handler for resize events.
*
* The browser will resize us such that the top row stays at the top, but we
* prefer to the bottom row to stay at the bottom.
*/hterm.ScrollPort.prototype.onResize_=function(e){// Re-measure, since onResize also happens for browser zoom changes.
this.syncCharacterSize();};/**
* Clients can override this if they want to hear copy events.
*
* Clients may call event.preventDefault() if they want to keep the scrollport
* from also handling the events.
*/hterm.ScrollPort.prototype.onCopy=function(e){};/**
* Handler for copy-to-clipboard events.
*
* If some or all of the selected rows are off screen we may need to fill in
* the rows between selection start and selection end. This handler determines
* if we're missing some of the selected text, and if so populates one or both
* of the "select bags" with the missing text.
*/hterm.ScrollPort.prototype.onCopy_=function(e){this.onCopy(e);if(e.defaultPrevented)return;this.resetSelectBags_();this.selection.sync();if(this.selection.isCollapsed||this.selection.endRow.rowIndex-this.selection.startRow.rowIndex<2){return;}var topRowIndex=this.getTopRowIndex();var bottomRowIndex=this.getBottomRowIndex(topRowIndex);if(this.selection.startRow.rowIndex<topRowIndex){// Start of selection is above the top fold.
var endBackfillIndex;if(this.selection.endRow.rowIndex<topRowIndex){// Entire selection is above the top fold.
endBackfillIndex=this.selection.endRow.rowIndex;}else{// Selection extends below the top fold.
endBackfillIndex=this.topFold_.nextSibling.rowIndex;}this.topSelectBag_.textContent=this.rowProvider_.getRowsText(this.selection.startRow.rowIndex+1,endBackfillIndex);this.rowNodes_.insertBefore(this.topSelectBag_,this.selection.startRow.nextSibling);this.syncRowNodesDimensions_();}if(this.selection.endRow.rowIndex>bottomRowIndex){// Selection ends below the bottom fold.
var startBackfillIndex;if(this.selection.startRow.rowIndex>bottomRowIndex){// Entire selection is below the bottom fold.
startBackfillIndex=this.selection.startRow.rowIndex+1;}else{// Selection starts above the bottom fold.
startBackfillIndex=this.bottomFold_.previousSibling.rowIndex+1;}this.bottomSelectBag_.textContent=this.rowProvider_.getRowsText(startBackfillIndex,this.selection.endRow.rowIndex);this.rowNodes_.insertBefore(this.bottomSelectBag_,this.selection.endRow);}};/**
* Focuses on the paste target on a ctrl-v keydown event, as in
* FF a content editable element must be focused before the paste event.
*/hterm.ScrollPort.prototype.onBodyKeyDown_=function(e){if(!this.ctrlVPaste)return;if((e.ctrlKey||e.metaKey)&&e.keyCode==86/* 'V' */)this.pasteTarget_.focus();};/**
* Handle a paste event on the the ScrollPort's screen element.
*
* TODO: Handle ClipboardData.files transfers. https://crbug.com/433581.
*/hterm.ScrollPort.prototype.onPaste_=function(e){this.pasteTarget_.focus();var self=this;setTimeout(function(){self.publish('paste',{text:self.pasteTarget_.value});self.pasteTarget_.value='';self.focus();},0);};/**
* Handles a textInput event on the paste target. Stops this from
* propagating as we want this to be handled in the onPaste_ method.
*/hterm.ScrollPort.prototype.handlePasteTargetTextInput_=function(e){e.stopPropagation();};/**
* Handle a drop event on the the ScrollPort's screen element.
*
* By default we try to copy in the structured format (HTML/whatever).
* The shift key can select plain text though.
*
* TODO: Handle DataTransfer.files transfers. https://crbug.com/433581.
*
* @param {DragEvent} e The drag event that fired us.
*/hterm.ScrollPort.prototype.onDragAndDrop_=function(e){if(!this.pasteOnDrop)return;e.preventDefault();var data;var format;// If the shift key active, try to find a "rich" text source (but not plain
// text). e.g. text/html is OK.
if(e.shiftKey){e.dataTransfer.types.forEach(function(t){if(!format&&t!='text/plain'&&t.startsWith('text/'))format=t;});// If we found a non-plain text source, try it out first.
if(format)data=e.dataTransfer.getData(format);}// If we haven't loaded anything useful, fall back to plain text.
if(!data)data=e.dataTransfer.getData('text/plain');if(data)this.publish('paste',{text:data});};/**
* Set the vertical scrollbar mode of the ScrollPort.
*/hterm.ScrollPort.prototype.setScrollbarVisible=function(state){this.screen_.style.overflowY=state?'scroll':'hidden';};/**
* Set scroll wheel multiplier. This alters how much the screen scrolls on
* mouse wheel events.
*/hterm.ScrollPort.prototype.setScrollWheelMoveMultipler=function(multiplier){this.scrollWheelMultiplier_=multiplier;};// SOURCE FILE: hterm/js/hterm_terminal.js
// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* Constructor for the Terminal class.
*
* A Terminal pulls together the hterm.ScrollPort, hterm.Screen and hterm.VT100
* classes to provide the complete terminal functionality.
*
* There are a number of lower-level Terminal methods that can be called
* directly to manipulate the cursor, text, scroll region, and other terminal
* attributes. However, the primary method is interpret(), which parses VT
* escape sequences and invokes the appropriate Terminal methods.
*
* This class was heavily influenced by Cory Maccarrone's Framebuffer class.
*
* TODO(rginda): Eventually we're going to need to support characters which are
* displayed twice as wide as standard latin characters. This is to support
* CJK (and possibly other character sets).
*
* @param {string} opt_profileId Optional preference profile name. If not
* provided, defaults to 'default'.
*/hterm.Terminal=function(opt_profileId){this.profileId_=null;// Two screen instances.
this.primaryScreen_=new hterm.Screen();this.alternateScreen_=new hterm.Screen();// The "current" screen.
this.screen_=this.primaryScreen_;// The local notion of the screen size. ScreenBuffers also have a size which
// indicates their present size. During size changes, the two may disagree.
// Also, the inactive screen's size is not altered until it is made the active
// screen.
this.screenSize=new hterm.Size(0,0);// The scroll port we'll be using to display the visible rows.
this.scrollPort_=new hterm.ScrollPort(this);this.scrollPort_.subscribe('resize',this.onResize_.bind(this));this.scrollPort_.subscribe('scroll',this.onScroll_.bind(this));this.scrollPort_.subscribe('paste',this.onPaste_.bind(this));this.scrollPort_.subscribe('focus',this.onScrollportFocus_.bind(this));this.scrollPort_.onCopy=this.onCopy_.bind(this);// The div that contains this terminal.
this.div_=null;// The document that contains the scrollPort. Defaulted to the global
// document here so that the terminal is functional even if it hasn't been
// inserted into a document yet, but re-set in decorate().
this.document_=window.document;// The rows that have scrolled off screen and are no longer addressable.
this.scrollbackRows_=[];// Saved tab stops.
this.tabStops_=[];// Keep track of whether default tab stops have been erased; after a TBC
// clears all tab stops, defaults aren't restored on resize until a reset.
this.defaultTabStops=true;// The VT's notion of the top and bottom rows. Used during some VT
// cursor positioning and scrolling commands.
this.vtScrollTop_=null;this.vtScrollBottom_=null;// The DIV element for the visible cursor.
this.cursorNode_=null;// The current cursor shape of the terminal.
this.cursorShape_=hterm.Terminal.cursorShape.BLOCK;// Cursor blink on/off cycle in ms, overwritten by prefs once they're loaded.
this.cursorBlinkCycle_=[100,100];// Pre-bound onCursorBlink_ handler, so we don't have to do this for each
// cursor on/off servicing.
this.myOnCursorBlink_=this.onCursorBlink_.bind(this);// These prefs are cached so we don't have to read from local storage with
// each output and keystroke. They are initialized by the preference manager.
this.backgroundColor_=null;this.foregroundColor_=null;this.scrollOnOutput_=null;this.scrollOnKeystroke_=null;this.scrollWheelArrowKeys_=null;// True if we should override mouse event reporting to allow local selection.
this.defeatMouseReports_=false;// Whether to auto hide the mouse cursor when typing.
this.setAutomaticMouseHiding();// Timer to keep mouse visible while it's being used.
this.mouseHideDelay_=null;// Terminal bell sound.
this.bellAudio_=this.document_.createElement('audio');this.bellAudio_.id='hterm:bell-audio';this.bellAudio_.setAttribute('preload','auto');// The AccessibilityReader object for announcing command output.
this.accessibilityReader_=null;// The context menu object.
this.contextMenu=new hterm.ContextMenu();// All terminal bell notifications that have been generated (not necessarily
// shown).
this.bellNotificationList_=[];// Whether we have permission to display notifications.
this.desktopNotificationBell_=false;// Cursor position and attributes saved with DECSC.
this.savedOptions_={};// The current mode bits for the terminal.
this.options_=new hterm.Options();// Timeouts we might need to clear.
this.timeouts_={};// The VT escape sequence interpreter.
this.vt=new hterm.VT(this);this.saveCursorAndState(true);// The keyboard handler.
this.keyboard=new hterm.Keyboard(this);// General IO interface that can be given to third parties without exposing
// the entire terminal object.
this.io=new hterm.Terminal.IO(this);// True if mouse-click-drag should scroll the terminal.
this.enableMouseDragScroll=true;this.copyOnSelect=null;this.mouseRightClickPaste=null;this.mousePasteButton=null;// Whether to use the default window copy behavior.
this.useDefaultWindowCopy=false;this.clearSelectionAfterCopy=true;this.realizeSize_(80,24);this.setDefaultTabStops();// Whether we allow images to be shown.
this.allowImagesInline=null;this.reportFocus=false;this.setProfile(opt_profileId||'default',function(){this.onTerminalReady();}.bind(this));};/**
* Possible cursor shapes.
*/hterm.Terminal.cursorShape={BLOCK:'BLOCK',BEAM:'BEAM',UNDERLINE:'UNDERLINE'};/**
* Clients should override this to be notified when the terminal is ready
* for use.
*
* The terminal initialization is asynchronous, and shouldn't be used before
* this method is called.
*/hterm.Terminal.prototype.onTerminalReady=function(){};/**
* Default tab with of 8 to match xterm.
*/hterm.Terminal.prototype.tabWidth=8;/**
* Select a preference profile.
*
* This will load the terminal preferences for the given profile name and
* associate subsequent preference changes with the new preference profile.
*
* @param {string} profileId The name of the preference profile. Forward slash
* characters will be removed from the name.
* @param {function} opt_callback Optional callback to invoke when the profile
* transition is complete.
*/hterm.Terminal.prototype.setProfile=function(profileId,opt_callback){this.profileId_=profileId.replace(/\//g,'');var terminal=this;if(this.prefs_)this.prefs_.deactivate();this.prefs_=new hterm.PreferenceManager(this.profileId_);this.prefs_.addObservers(null,{'alt-gr-mode':function altGrMode(v){if(v==null){if(navigator.language.toLowerCase()=='en-us'){v='none';}else{v='right-alt';}}else if(typeof v=='string'){v=v.toLowerCase();}else{v='none';}if(!/^(none|ctrl-alt|left-alt|right-alt)$/.test(v))v='none';terminal.keyboard.altGrMode=v;},'alt-backspace-is-meta-backspace':function altBackspaceIsMetaBackspace(v){terminal.keyboard.altBackspaceIsMetaBackspace=v;},'alt-is-meta':function altIsMeta(v){terminal.keyboard.altIsMeta=v;},'alt-sends-what':function altSendsWhat(v){if(!/^(escape|8-bit|browser-key)$/.test(v))v='escape';terminal.keyboard.altSendsWhat=v;},'audible-bell-sound':function audibleBellSound(v){var ary=v.match(/^lib-resource:(\S+)/);if(ary){terminal.bellAudio_.setAttribute('src',lib.resource.getDataUrl(ary[1]));}else{terminal.bellAudio_.setAttribute('src',v);}},'desktop-notification-bell':function desktopNotificationBell(v){if(v&&Notification){terminal.desktopNotificationBell_=Notification.permission==='granted';if(!terminal.desktopNotificationBell_){// Note: We don't call Notification.requestPermission here because
// Chrome requires the call be the result of a user action (such as an
// onclick handler), and pref listeners are run asynchronously.
//
// A way of working around this would be to display a dialog in the
// terminal with a "click-to-request-permission" button.
console.warn('desktop-notification-bell is true but we do not have '+'permission to display notifications.');}}else{terminal.desktopNotificationBell_=false;}},'background-color':function backgroundColor(v){terminal.setBackgroundColor(v);},'background-image':function backgroundImage(v){terminal.scrollPort_.setBackgroundImage(v);},'background-size':function backgroundSize(v){terminal.scrollPort_.setBackgroundSize(v);},'background-position':function backgroundPosition(v){terminal.scrollPort_.setBackgroundPosition(v);},'backspace-sends-backspace':function backspaceSendsBackspace(v){terminal.keyboard.backspaceSendsBackspace=v;},'character-map-overrides':function characterMapOverrides(v){if(!(v==null||_instanceof(v,Object))){console.warn('Preference character-map-modifications is not an '+'object: '+v);return;}terminal.vt.characterMaps.reset();terminal.vt.characterMaps.setOverrides(v);},'cursor-blink':function cursorBlink(v){terminal.setCursorBlink(!!v);},'cursor-blink-cycle':function cursorBlinkCycle(v){if(_instanceof(v,Array)&&typeof v[0]=='number'&&typeof v[1]=='number'){terminal.cursorBlinkCycle_=v;}else if(typeof v=='number'){terminal.cursorBlinkCycle_=[v,v];}else{// Fast blink indicates an error.
terminal.cursorBlinkCycle_=[100,100];}},'cursor-color':function cursorColor(v){terminal.setCursorColor(v);},'color-palette-overrides':function colorPaletteOverrides(v){if(!(v==null||_instanceof(v,Object)||_instanceof(v,Array))){console.warn('Preference color-palette-overrides is not an array or '+'object: '+v);return;}lib.colors.colorPalette=lib.colors.stockColorPalette.concat();if(v){for(var key in v){var i=parseInt(key);if(isNaN(i)||i<0||i>255){console.log('Invalid value in palette: '+key+': '+v[key]);continue;}if(v[i]){var rgb=lib.colors.normalizeCSS(v[i]);if(rgb)lib.colors.colorPalette[i]=rgb;}}}terminal.primaryScreen_.textAttributes.resetColorPalette();terminal.alternateScreen_.textAttributes.resetColorPalette();},'copy-on-select':function copyOnSelect(v){terminal.copyOnSelect=!!v;},'use-default-window-copy':function useDefaultWindowCopy(v){terminal.useDefaultWindowCopy=!!v;},'clear-selection-after-copy':function clearSelectionAfterCopy(v){terminal.clearSelectionAfterCopy=!!v;},'ctrl-plus-minus-zero-zoom':function ctrlPlusMinusZeroZoom(v){terminal.keyboard.ctrlPlusMinusZeroZoom=v;},'ctrl-c-copy':function ctrlCCopy(v){terminal.keyboard.ctrlCCopy=v;},'ctrl-v-paste':function ctrlVPaste(v){terminal.keyboard.ctrlVPaste=v;terminal.scrollPort_.setCtrlVPaste(v);},'paste-on-drop':function pasteOnDrop(v){terminal.scrollPort_.setPasteOnDrop(v);},'east-asian-ambiguous-as-two-column':function eastAsianAmbiguousAsTwoColumn(v){lib.wc.regardCjkAmbiguous=v;},'enable-8-bit-control':function enable8BitControl(v){terminal.vt.enable8BitControl=!!v;},'enable-bold':function enableBold(v){terminal.syncBoldSafeState();},'enable-bold-as-bright':function enableBoldAsBright(v){terminal.primaryScreen_.textAttributes.enableBoldAsBright=!!v;terminal.alternateScreen_.textAttributes.enableBoldAsBright=!!v;},'enable-blink':function enableBlink(v){terminal.setTextBlink(!!v);},'enable-clipboard-write':function enableClipboardWrite(v){terminal.vt.enableClipboardWrite=!!v;},'enable-dec12':function enableDec12(v){terminal.vt.enableDec12=!!v;},'enable-csi-j-3':function enableCsiJ3(v){terminal.vt.enableCsiJ3=!!v;},'font-family':function fontFamily(v){terminal.syncFontFamily();},'font-size':function fontSize(v){v=parseInt(v);if(v<=0){console.error("Invalid font size: ".concat(v));return;}terminal.setFontSize(v);},'font-smoothing':function fontSmoothing(v){terminal.syncFontFamily();},'foreground-color':function foregroundColor(v){terminal.setForegroundColor(v);},'hide-mouse-while-typing':function hideMouseWhileTyping(v){terminal.setAutomaticMouseHiding(v);},'home-keys-scroll':function homeKeysScroll(v){terminal.keyboard.homeKeysScroll=v;},'keybindings':function keybindings(v){terminal.keyboard.bindings.clear();if(!v)return;if(!_instanceof(v,Object)){console.error('Error in keybindings preference: Expected object');return;}try{terminal.keyboard.bindings.addBindings(v);}catch(ex){console.error('Error in keybindings preference: '+ex);}},'media-keys-are-fkeys':function mediaKeysAreFkeys(v){terminal.keyboard.mediaKeysAreFKeys=v;},'meta-sends-escape':function metaSendsEscape(v){terminal.keyboard.metaSendsEscape=v;},'mouse-right-click-paste':function mouseRightClickPaste(v){terminal.mouseRightClickPaste=v;},'mouse-paste-button':function mousePasteButton(v){terminal.syncMousePasteButton();},'page-keys-scroll':function pageKeysScroll(v){terminal.keyboard.pageKeysScroll=v;},'pass-alt-number':function passAltNumber(v){if(v==null){// Let Alt-1..9 pass to the browser (to control tab switching) on
// non-OS X systems, or if hterm is not opened in an app window.
v=hterm.os!='mac'&&hterm.windowType!='popup';}terminal.passAltNumber=v;},'pass-ctrl-number':function passCtrlNumber(v){if(v==null){// Let Ctrl-1..9 pass to the browser (to control tab switching) on
// non-OS X systems, or if hterm is not opened in an app window.
v=hterm.os!='mac'&&hterm.windowType!='popup';}terminal.passCtrlNumber=v;},'pass-meta-number':function passMetaNumber(v){if(v==null){// Let Meta-1..9 pass to the browser (to control tab switching) on
// OS X systems, or if hterm is not opened in an app window.
v=hterm.os=='mac'&&hterm.windowType!='popup';}terminal.passMetaNumber=v;},'pass-meta-v':function passMetaV(v){terminal.keyboard.passMetaV=v;},'receive-encoding':function receiveEncoding(v){if(!/^(utf-8|raw)$/.test(v)){console.warn('Invalid value for "receive-encoding": '+v);v='utf-8';}terminal.vt.characterEncoding=v;},'scroll-on-keystroke':function scrollOnKeystroke(v){terminal.scrollOnKeystroke_=v;},'scroll-on-output':function scrollOnOutput(v){terminal.scrollOnOutput_=v;},'scrollbar-visible':function scrollbarVisible(v){terminal.setScrollbarVisible(v);},'scroll-wheel-may-send-arrow-keys':function scrollWheelMaySendArrowKeys(v){terminal.scrollWheelArrowKeys_=v;},'scroll-wheel-move-multiplier':function scrollWheelMoveMultiplier(v){terminal.setScrollWheelMoveMultipler(v);},'shift-insert-paste':function shiftInsertPaste(v){terminal.keyboard.shiftInsertPaste=v;},'terminal-encoding':function terminalEncoding(v){terminal.vt.setEncoding(v);},'user-css':function userCss(v){terminal.scrollPort_.setUserCssUrl(v);},'user-css-text':function userCssText(v){terminal.scrollPort_.setUserCssText(v);},'word-break-match-left':function wordBreakMatchLeft(v){terminal.primaryScreen_.wordBreakMatchLeft=v;terminal.alternateScreen_.wordBreakMatchLeft=v;},'word-break-match-right':function wordBreakMatchRight(v){terminal.primaryScreen_.wordBreakMatchRight=v;terminal.alternateScreen_.wordBreakMatchRight=v;},'word-break-match-middle':function wordBreakMatchMiddle(v){terminal.primaryScreen_.wordBreakMatchMiddle=v;terminal.alternateScreen_.wordBreakMatchMiddle=v;},'allow-images-inline':function allowImagesInline(v){terminal.allowImagesInline=v;}});this.prefs_.readStorage(function(){this.prefs_.notifyAll();if(opt_callback)opt_callback();}.bind(this));};/**
* Returns the preferences manager used for configuring this terminal.
*
* @return {hterm.PreferenceManager}
*/hterm.Terminal.prototype.getPrefs=function(){return this.prefs_;};/**
* Enable or disable bracketed paste mode.
*
* @param {boolean} state The value to set.
*/hterm.Terminal.prototype.setBracketedPaste=function(state){this.options_.bracketedPaste=state;};/**
* Set the color for the cursor.
*
* If you want this setting to persist, set it through prefs_, rather than
* with this method.
*
* @param {string=} color The color to set. If not defined, we reset to the
* saved user preference.
*/hterm.Terminal.prototype.setCursorColor=function(color){if(color===undefined)color=this.prefs_.get('cursor-color');this.setCssVar('cursor-color',color);};/**
* Return the current cursor color as a string.
* @return {string}
*/hterm.Terminal.prototype.getCursorColor=function(){return this.getCssVar('cursor-color');};/**
* Enable or disable mouse based text selection in the terminal.
*
* @param {boolean} state The value to set.
*/hterm.Terminal.prototype.setSelectionEnabled=function(state){this.enableMouseDragScroll=state;};/**
* Set the background color.
*
* If you want this setting to persist, set it through prefs_, rather than
* with this method.
*
* @param {string=} color The color to set. If not defined, we reset to the
* saved user preference.
*/hterm.Terminal.prototype.setBackgroundColor=function(color){if(color===undefined)color=this.prefs_.get('background-color');this.backgroundColor_=lib.colors.normalizeCSS(color);this.primaryScreen_.textAttributes.setDefaults(this.foregroundColor_,this.backgroundColor_);this.alternateScreen_.textAttributes.setDefaults(this.foregroundColor_,this.backgroundColor_);this.scrollPort_.setBackgroundColor(color);};/**
* Return the current terminal background color.
*
* Intended for use by other classes, so we don't have to expose the entire
* prefs_ object.
*
* @return {string}
*/hterm.Terminal.prototype.getBackgroundColor=function(){return this.backgroundColor_;};/**
* Set the foreground color.
*
* If you want this setting to persist, set it through prefs_, rather than
* with this method.
*
* @param {string=} color The color to set. If not defined, we reset to the
* saved user preference.
*/hterm.Terminal.prototype.setForegroundColor=function(color){if(color===undefined)color=this.prefs_.get('foreground-color');this.foregroundColor_=lib.colors.normalizeCSS(color);this.primaryScreen_.textAttributes.setDefaults(this.foregroundColor_,this.backgroundColor_);this.alternateScreen_.textAttributes.setDefaults(this.foregroundColor_,this.backgroundColor_);this.scrollPort_.setForegroundColor(color);};/**
* Return the current terminal foreground color.
*
* Intended for use by other classes, so we don't have to expose the entire
* prefs_ object.
*
* @return {string}
*/hterm.Terminal.prototype.getForegroundColor=function(){return this.foregroundColor_;};/**
* Create a new instance of a terminal command and run it with a given
* argument string.
*
* @param {function} commandClass The constructor for a terminal command.
* @param {string} argString The argument string to pass to the command.
*/hterm.Terminal.prototype.runCommandClass=function(commandClass,argString){var environment=this.prefs_.get('environment');if(_typeof(environment)!='object'||environment==null)environment={};var self=this;this.command=new commandClass({argString:argString||'',io:this.io.push(),environment:environment,onExit:function onExit(code){self.io.pop();self.uninstallKeyboard();if(self.prefs_.get('close-on-exit'))window.close();}});this.installKeyboard();this.command.run();};/**
* Returns true if the current screen is the primary screen, false otherwise.
*
* @return {boolean}
*/hterm.Terminal.prototype.isPrimaryScreen=function(){return this.screen_==this.primaryScreen_;};/**
* Install the keyboard handler for this terminal.
*
* This will prevent the browser from seeing any keystrokes sent to the
* terminal.
*/hterm.Terminal.prototype.installKeyboard=function(){this.keyboard.installKeyboard(this.scrollPort_.getDocument().body);};/**
* Uninstall the keyboard handler for this terminal.
*/hterm.Terminal.prototype.uninstallKeyboard=function(){this.keyboard.installKeyboard(null);};/**
* Set a CSS variable.
*
* Normally this is used to set variables in the hterm namespace.
*
* @param {string} name The variable to set.
* @param {string} value The value to assign to the variable.
* @param {string?} opt_prefix The variable namespace/prefix to use.
*/hterm.Terminal.prototype.setCssVar=function(name,value){var opt_prefix=arguments.length>2&&arguments[2]!==undefined?arguments[2]:'--hterm-';this.document_.documentElement.style.setProperty("".concat(opt_prefix).concat(name),value);};/**
* Get a CSS variable.
*
* Normally this is used to get variables in the hterm namespace.
*
* @param {string} name The variable to read.
* @param {string?} opt_prefix The variable namespace/prefix to use.
* @return {string} The current setting for this variable.
*/hterm.Terminal.prototype.getCssVar=function(name){var opt_prefix=arguments.length>1&&arguments[1]!==undefined?arguments[1]:'--hterm-';return this.document_.documentElement.style.getPropertyValue("".concat(opt_prefix).concat(name));};/**
* Set the font size for this terminal.
*
* Call setFontSize(0) to reset to the default font size.
*
* This function does not modify the font-size preference.
*
* @param {number} px The desired font size, in pixels.
*/hterm.Terminal.prototype.setFontSize=function(px){if(px<=0)px=this.prefs_.get('font-size');this.scrollPort_.setFontSize(px);this.setCssVar('charsize-width',this.scrollPort_.characterSize.width+'px');this.setCssVar('charsize-height',this.scrollPort_.characterSize.height+'px');};/**
* Get the current font size.
*
* @return {number}
*/hterm.Terminal.prototype.getFontSize=function(){return this.scrollPort_.getFontSize();};/**
* Get the current font family.
*
* @return {string}
*/hterm.Terminal.prototype.getFontFamily=function(){return this.scrollPort_.getFontFamily();};/**
* Set the CSS "font-family" for this terminal.
*/hterm.Terminal.prototype.syncFontFamily=function(){this.scrollPort_.setFontFamily(this.prefs_.get('font-family'),this.prefs_.get('font-smoothing'));this.syncBoldSafeState();};/**
* Set this.mousePasteButton based on the mouse-paste-button pref,
* autodetecting if necessary.
*/hterm.Terminal.prototype.syncMousePasteButton=function(){var button=this.prefs_.get('mouse-paste-button');if(typeof button=='number'){this.mousePasteButton=button;return;}if(hterm.os!='linux'){this.mousePasteButton=1;// Middle mouse button.
}else{this.mousePasteButton=2;// Right mouse button.
}};/**
* Enable or disable bold based on the enable-bold pref, autodetecting if
* necessary.
*/hterm.Terminal.prototype.syncBoldSafeState=function(){var enableBold=this.prefs_.get('enable-bold');if(enableBold!==null){this.primaryScreen_.textAttributes.enableBold=enableBold;this.alternateScreen_.textAttributes.enableBold=enableBold;return;}var normalSize=this.scrollPort_.measureCharacterSize();var boldSize=this.scrollPort_.measureCharacterSize('bold');var isBoldSafe=normalSize.equals(boldSize);if(!isBoldSafe){console.warn('Bold characters disabled: Size of bold weight differs '+'from normal. Font family is: '+this.scrollPort_.getFontFamily());}this.primaryScreen_.textAttributes.enableBold=isBoldSafe;this.alternateScreen_.textAttributes.enableBold=isBoldSafe;};/**
* Control text blinking behavior.
*
* @param {boolean=} state Whether to enable support for blinking text.
*/hterm.Terminal.prototype.setTextBlink=function(state){if(state===undefined)state=this.prefs_.get('enable-blink');this.setCssVar('blink-node-duration',state?'0.7s':'0');};/**
* Set the mouse cursor style based on the current terminal mode.
*/hterm.Terminal.prototype.syncMouseStyle=function(){this.setCssVar('mouse-cursor-style',this.vt.mouseReport==this.vt.MOUSE_REPORT_DISABLED?'var(--hterm-mouse-cursor-text)':'var(--hterm-mouse-cursor-default)');};/**
* Return a copy of the current cursor position.
*
* @return {hterm.RowCol} The RowCol object representing the current position.
*/hterm.Terminal.prototype.saveCursor=function(){return this.screen_.cursorPosition.clone();};/**
* Return the current text attributes.
*
* @return {string}
*/hterm.Terminal.prototype.getTextAttributes=function(){return this.screen_.textAttributes;};/**
* Set the text attributes.
*
* @param {string} textAttributes The attributes to set.
*/hterm.Terminal.prototype.setTextAttributes=function(textAttributes){this.screen_.textAttributes=textAttributes;};/**
* Return the current browser zoom factor applied to the terminal.
*
* @return {number} The current browser zoom factor.
*/hterm.Terminal.prototype.getZoomFactor=function(){return this.scrollPort_.characterSize.zoomFactor;};/**
* Change the title of this terminal's window.
*
* @param {string} title The title to set.
*/hterm.Terminal.prototype.setWindowTitle=function(title){window.document.title=title;};/**
* Restore a previously saved cursor position.
*
* @param {hterm.RowCol} cursor The position to restore.
*/hterm.Terminal.prototype.restoreCursor=function(cursor){var row=lib.f.clamp(cursor.row,0,this.screenSize.height-1);var column=lib.f.clamp(cursor.column,0,this.screenSize.width-1);this.screen_.setCursorPosition(row,column);if(cursor.column>column||cursor.column==column&&cursor.overflow){this.screen_.cursorPosition.overflow=true;}};/**
* Clear the cursor's overflow flag.
*/hterm.Terminal.prototype.clearCursorOverflow=function(){this.screen_.cursorPosition.overflow=false;};/**
* Save the current cursor state to the corresponding screens.
*
* See the hterm.Screen.CursorState class for more details.
*
* @param {boolean=} both If true, update both screens, else only update the
* current screen.
*/hterm.Terminal.prototype.saveCursorAndState=function(both){if(both){this.primaryScreen_.saveCursorAndState(this.vt);this.alternateScreen_.saveCursorAndState(this.vt);}else this.screen_.saveCursorAndState(this.vt);};/**
* Restore the saved cursor state in the corresponding screens.
*
* See the hterm.Screen.CursorState class for more details.
*
* @param {boolean=} both If true, update both screens, else only update the
* current screen.
*/hterm.Terminal.prototype.restoreCursorAndState=function(both){if(both){this.primaryScreen_.restoreCursorAndState(this.vt);this.alternateScreen_.restoreCursorAndState(this.vt);}else this.screen_.restoreCursorAndState(this.vt);};/**
* Sets the cursor shape
*
* @param {string} shape The shape to set.
*/hterm.Terminal.prototype.setCursorShape=function(shape){this.cursorShape_=shape;this.restyleCursor_();};/**
* Get the cursor shape
*
* @return {string}
*/hterm.Terminal.prototype.getCursorShape=function(){return this.cursorShape_;};/**
* Set the width of the terminal, resizing the UI to match.
*
* @param {number} columnCount
*/hterm.Terminal.prototype.setWidth=function(columnCount){if(columnCount==null){this.div_.style.width='100%';return;}this.div_.style.width=Math.ceil(this.scrollPort_.characterSize.width*columnCount+this.scrollPort_.currentScrollbarWidthPx)+'px';this.realizeSize_(columnCount,this.screenSize.height);this.scheduleSyncCursorPosition_();};/**
* Set the height of the terminal, resizing the UI to match.
*
* @param {number} rowCount The height in rows.
*/hterm.Terminal.prototype.setHeight=function(rowCount){if(rowCount==null){this.div_.style.height='100%';return;}this.div_.style.height=this.scrollPort_.characterSize.height*rowCount+'px';this.realizeSize_(this.screenSize.width,rowCount);this.scheduleSyncCursorPosition_();};/**
* Deal with terminal size changes.
*
* @param {number} columnCount The number of columns.
* @param {number} rowCount The number of rows.
*/hterm.Terminal.prototype.realizeSize_=function(columnCount,rowCount){if(columnCount!=this.screenSize.width)this.realizeWidth_(columnCount);if(rowCount!=this.screenSize.height)this.realizeHeight_(rowCount);// Send new terminal size to plugin.
this.io.onTerminalResize_(columnCount,rowCount);};/**
* Deal with terminal width changes.
*
* This function does what needs to be done when the terminal width changes
* out from under us. It happens here rather than in onResize_() because this
* code may need to run synchronously to handle programmatic changes of
* terminal width.
*
* Relying on the browser to send us an async resize event means we may not be
* in the correct state yet when the next escape sequence hits.
*
* @param {number} columnCount The number of columns.
*/hterm.Terminal.prototype.realizeWidth_=function(columnCount){if(columnCount<=0)throw new Error('Attempt to realize bad width: '+columnCount);var deltaColumns=columnCount-this.screen_.getWidth();this.screenSize.width=columnCount;this.screen_.setColumnCount(columnCount);if(deltaColumns>0){if(this.defaultTabStops)this.setDefaultTabStops(this.screenSize.width-deltaColumns);}else{for(var i=this.tabStops_.length-1;i>=0;i--){if(this.tabStops_[i]<columnCount)break;this.tabStops_.pop();}}this.screen_.setColumnCount(this.screenSize.width);};/**
* Deal with terminal height changes.
*
* This function does what needs to be done when the terminal height changes
* out from under us. It happens here rather than in onResize_() because this
* code may need to run synchronously to handle programmatic changes of
* terminal height.
*
* Relying on the browser to send us an async resize event means we may not be
* in the correct state yet when the next escape sequence hits.
*
* @param {number} rowCount The number of rows.
*/hterm.Terminal.prototype.realizeHeight_=function(rowCount){if(rowCount<=0)throw new Error('Attempt to realize bad height: '+rowCount);var deltaRows=rowCount-this.screen_.getHeight();this.screenSize.height=rowCount;var cursor=this.saveCursor();if(deltaRows<0){// Screen got smaller.
deltaRows*=-1;while(deltaRows){var lastRow=this.getRowCount()-1;if(lastRow-this.scrollbackRows_.length==cursor.row)break;if(this.getRowText(lastRow))break;this.screen_.popRow();deltaRows--;}var ary=this.screen_.shiftRows(deltaRows);this.scrollbackRows_.push.apply(this.scrollbackRows_,ary);// We just removed rows from the top of the screen, we need to update
// the cursor to match.
cursor.row=Math.max(cursor.row-deltaRows,0);}else if(deltaRows>0){// Screen got larger.
if(deltaRows<=this.scrollbackRows_.length){var scrollbackCount=Math.min(deltaRows,this.scrollbackRows_.length);var rows=this.scrollbackRows_.splice(this.scrollbackRows_.length-scrollbackCount,scrollbackCount);this.screen_.unshiftRows(rows);deltaRows-=scrollbackCount;cursor.row+=scrollbackCount;}if(deltaRows)this.appendRows_(deltaRows);}this.setVTScrollRegion(null,null);this.restoreCursor(cursor);};/**
* Scroll the terminal to the top of the scrollback buffer.
*/hterm.Terminal.prototype.scrollHome=function(){this.scrollPort_.scrollRowToTop(0);};/**
* Scroll the terminal to the end.
*/hterm.Terminal.prototype.scrollEnd=function(){this.scrollPort_.scrollRowToBottom(this.getRowCount());};/**
* Scroll the terminal one page up (minus one line) relative to the current
* position.
*/hterm.Terminal.prototype.scrollPageUp=function(){this.scrollPort_.scrollPageUp();};/**
* Scroll the terminal one page down (minus one line) relative to the current
* position.
*/hterm.Terminal.prototype.scrollPageDown=function(){this.scrollPort_.scrollPageDown();};/**
* Scroll the terminal one line up relative to the current position.
*/hterm.Terminal.prototype.scrollLineUp=function(){var i=this.scrollPort_.getTopRowIndex();this.scrollPort_.scrollRowToTop(i-1);};/**
* Scroll the terminal one line down relative to the current position.
*/hterm.Terminal.prototype.scrollLineDown=function(){var i=this.scrollPort_.getTopRowIndex();this.scrollPort_.scrollRowToTop(i+1);};/**
* Clear primary screen, secondary screen, and the scrollback buffer.
*/hterm.Terminal.prototype.wipeContents=function(){this.clearHome(this.primaryScreen_);this.clearHome(this.alternateScreen_);this.clearScrollback();};/**
* Clear scrollback buffer.
*/hterm.Terminal.prototype.clearScrollback=function(){var _this10=this;// Move to the end of the buffer in case the screen was scrolled back.
// We're going to throw it away which would leave the display invalid.
this.scrollEnd();this.scrollbackRows_.length=0;this.scrollPort_.resetCache();[this.primaryScreen_,this.alternateScreen_].forEach(function(screen){var bottom=screen.getHeight();_this10.renumberRows_(0,bottom,screen);});this.syncCursorPosition_();this.scrollPort_.invalidate();};/**
* Full terminal reset.
*
* Perform a full reset to the default values listed in
* https://vt100.net/docs/vt510-rm/RIS.html
*/hterm.Terminal.prototype.reset=function(){var _this11=this;this.vt.reset();this.clearAllTabStops();this.setDefaultTabStops();var resetScreen=function resetScreen(screen){// We want to make sure to reset the attributes before we clear the screen.
// The attributes might be used to initialize default/empty rows.
screen.textAttributes.reset();screen.textAttributes.resetColorPalette();_this11.clearHome(screen);screen.saveCursorAndState(_this11.vt);};resetScreen(this.primaryScreen_);resetScreen(this.alternateScreen_);// Reset terminal options to their default values.
this.options_=new hterm.Options();this.setCursorBlink(!!this.prefs_.get('cursor-blink'));this.setVTScrollRegion(null,null);this.setCursorVisible(true);};/**
* Soft terminal reset.
*
* Perform a soft reset to the default values listed in
* http://www.vt100.net/docs/vt510-rm/DECSTR#T5-9
*/hterm.Terminal.prototype.softReset=function(){var _this12=this;this.vt.reset();// Reset terminal options to their default values.
this.options_=new hterm.Options();// We show the cursor on soft reset but do not alter the blink state.
this.options_.cursorBlink=!!this.timeouts_.cursorBlink;var resetScreen=function resetScreen(screen){// Xterm also resets the color palette on soft reset, even though it doesn't
// seem to be documented anywhere.
screen.textAttributes.reset();screen.textAttributes.resetColorPalette();screen.saveCursorAndState(_this12.vt);};resetScreen(this.primaryScreen_);resetScreen(this.alternateScreen_);// The xterm man page explicitly says this will happen on soft reset.
this.setVTScrollRegion(null,null);// Xterm also shows the cursor on soft reset, but does not alter the blink
// state.
this.setCursorVisible(true);};/**
* Move the cursor forward to the next tab stop, or to the last column
* if no more tab stops are set.
*/hterm.Terminal.prototype.forwardTabStop=function(){var column=this.screen_.cursorPosition.column;for(var i=0;i<this.tabStops_.length;i++){if(this.tabStops_[i]>column){this.setCursorColumn(this.tabStops_[i]);return;}}// xterm does not clear the overflow flag on HT or CHT.
var overflow=this.screen_.cursorPosition.overflow;this.setCursorColumn(this.screenSize.width-1);this.screen_.cursorPosition.overflow=overflow;};/**
* Move the cursor backward to the previous tab stop, or to the first column
* if no previous tab stops are set.
*/hterm.Terminal.prototype.backwardTabStop=function(){var column=this.screen_.cursorPosition.column;for(var i=this.tabStops_.length-1;i>=0;i--){if(this.tabStops_[i]<column){this.setCursorColumn(this.tabStops_[i]);return;}}this.setCursorColumn(1);};/**
* Set a tab stop at the given column.
*
* @param {integer} column Zero based column.
*/hterm.Terminal.prototype.setTabStop=function(column){for(var i=this.tabStops_.length-1;i>=0;i--){if(this.tabStops_[i]==column)return;if(this.tabStops_[i]<column){this.tabStops_.splice(i+1,0,column);return;}}this.tabStops_.splice(0,0,column);};/**
* Clear the tab stop at the current cursor position.
*
* No effect if there is no tab stop at the current cursor position.
*/hterm.Terminal.prototype.clearTabStopAtCursor=function(){var column=this.screen_.cursorPosition.column;var i=this.tabStops_.indexOf(column);if(i==-1)return;this.tabStops_.splice(i,1);};/**
* Clear all tab stops.
*/hterm.Terminal.prototype.clearAllTabStops=function(){this.tabStops_.length=0;this.defaultTabStops=false;};/**
* Set up the default tab stops, starting from a given column.
*
* This sets a tabstop every (column % this.tabWidth) column, starting
* from the specified column, or 0 if no column is provided. It also flags
* future resizes to set them up.
*
* This does not clear the existing tab stops first, use clearAllTabStops
* for that.
*
* @param {integer} opt_start Optional starting zero based starting column, useful
* for filling out missing tab stops when the terminal is resized.
*/hterm.Terminal.prototype.setDefaultTabStops=function(opt_start){var start=opt_start||0;var w=this.tabWidth;// Round start up to a default tab stop.
start=start-1-(start-1)%w+w;for(var i=start;i<this.screenSize.width;i+=w){this.setTabStop(i);}this.defaultTabStops=true;};/**
* Interpret a sequence of characters.
*
* Incomplete escape sequences are buffered until the next call.
*
* @param {string} str Sequence of characters to interpret or pass through.
*/hterm.Terminal.prototype.interpret=function(str){this.scheduleSyncCursorPosition_();this.vt.interpret(str);};/**
* Take over the given DIV for use as the terminal display.
*
* @param {HTMLDivElement} div The div to use as the terminal display.
*/hterm.Terminal.prototype.decorate=function(div){var _this13=this;var charset=div.ownerDocument.characterSet.toLowerCase();if(charset!='utf-8'){console.warn("Document encoding should be set to utf-8, not \"".concat(charset,"\";")+" Add <meta charset='utf-8'/> to your HTML <head> to fix.");}this.div_=div;this.accessibilityReader_=new hterm.AccessibilityReader(div);this.scrollPort_.decorate(div,function(){return _this13.setupScrollPort_();});};/**
* Initialisation of ScrollPort properties which need to be set after its DOM
* has been initialised.
* @private
*/hterm.Terminal.prototype.setupScrollPort_=function(){this.scrollPort_.setBackgroundImage(this.prefs_.get('background-image'));this.scrollPort_.setBackgroundSize(this.prefs_.get('background-size'));this.scrollPort_.setBackgroundPosition(this.prefs_.get('background-position'));this.scrollPort_.setUserCssUrl(this.prefs_.get('user-css'));this.scrollPort_.setUserCssText(this.prefs_.get('user-css-text'));this.scrollPort_.setAccessibilityReader(this.accessibilityReader_);this.div_.focus=this.focus.bind(this);this.setFontSize(this.prefs_.get('font-size'));this.syncFontFamily();this.setScrollbarVisible(this.prefs_.get('scrollbar-visible'));this.setScrollWheelMoveMultipler(this.prefs_.get('scroll-wheel-move-multiplier'));this.document_=this.scrollPort_.getDocument();this.accessibilityReader_.decorate(this.document_);this.document_.body.oncontextmenu=function(){return false;};this.contextMenu.setDocument(this.document_);var onMouse=this.onMouse_.bind(this);var screenNode=this.scrollPort_.getScreenNode();screenNode.addEventListener('mousedown',onMouse);screenNode.addEventListener('mouseup',onMouse);screenNode.addEventListener('mousemove',onMouse);this.scrollPort_.onScrollWheel=onMouse;screenNode.addEventListener('keydown',this.onKeyboardActivity_.bind(this));screenNode.addEventListener('focus',this.onFocusChange_.bind(this,true));// Listen for mousedown events on the screenNode as in FF the focus
// events don't bubble.
screenNode.addEventListener('mousedown',function(){setTimeout(this.onFocusChange_.bind(this,true));}.bind(this));screenNode.addEventListener('blur',this.onFocusChange_.bind(this,false));var style=this.document_.createElement('style');style.textContent='.cursor-node[focus="false"] {'+' box-sizing: border-box;'+' background-color: transparent !important;'+' border-width: 2px;'+' border-style: solid;'+'}'+'menu {'+' margin: 0;'+' padding: 0;'+' cursor: var(--hterm-mouse-cursor-pointer);'+'}'+'menuitem {'+' white-space: nowrap;'+' border-bottom: 1px dashed;'+' display: block;'+' padding: 0.3em 0.3em 0 0.3em;'+'}'+'menuitem.separator {'+' border-bottom: none;'+' height: 0.5em;'+' padding: 0;'+'}'+'menuitem:hover {'+' color: var(--hterm-cursor-color);'+'}'+'.wc-node {'+' display: inline-block;'+' text-align: center;'+' width: calc(var(--hterm-charsize-width) * 2);'+' line-height: var(--hterm-charsize-height);'+'}'+':root {'+' --hterm-charsize-width: '+this.scrollPort_.characterSize.width+'px;'+' --hterm-charsize-height: '+this.scrollPort_.characterSize.height+'px;'+// Default position hides the cursor for when the window is initializing.
' --hterm-cursor-offset-col: -1;'+' --hterm-cursor-offset-row: -1;'+' --hterm-blink-node-duration: 0.7s;'+' --hterm-mouse-cursor-default: default;'+' --hterm-mouse-cursor-text: text;'+' --hterm-mouse-cursor-pointer: pointer;'+' --hterm-mouse-cursor-style: var(--hterm-mouse-cursor-text);'+'}'+'.uri-node:hover {'+' text-decoration: underline;'+' cursor: var(--hterm-mouse-cursor-pointer);'+'}'+'@keyframes blink {'+' from { opacity: 1.0; }'+' to { opacity: 0.0; }'+'}'+'.blink-node {'+' animation-name: blink;'+' animation-duration: var(--hterm-blink-node-duration);'+' animation-iteration-count: infinite;'+' animation-timing-function: ease-in-out;'+' animation-direction: alternate;'+'}';// Insert this stock style as the first node so that any user styles will
// override w/out having to use !important everywhere. The rules above mix
// runtime variables with default ones designed to be overridden by the user,
// but we can wait for a concrete case from the users to determine the best
// way to split the sheet up to before & after the user-css settings.
this.document_.head.insertBefore(style,this.document_.head.firstChild);this.cursorNode_=this.document_.createElement('div');this.cursorNode_.id='hterm:terminal-cursor';this.cursorNode_.className='cursor-node';this.cursorNode_.style.cssText='position: absolute;'+'left: calc(var(--hterm-charsize-width) * var(--hterm-cursor-offset-col));'+'top: calc(var(--hterm-charsize-height) * var(--hterm-cursor-offset-row));'+'display: '+(this.options_.cursorVisible?'':'none')+';'+'width: var(--hterm-charsize-width);'+'height: var(--hterm-charsize-height);'+'background-color: var(--hterm-cursor-color);'+'border-color: var(--hterm-cursor-color);'+'-webkit-transition: opacity, background-color 100ms linear;'+'-moz-transition: opacity, background-color 100ms linear;';this.setCursorColor();this.setCursorBlink(!!this.prefs_.get('cursor-blink'));this.restyleCursor_();this.document_.body.appendChild(this.cursorNode_);// When 'enableMouseDragScroll' is off we reposition this element directly
// under the mouse cursor after a click. This makes Chrome associate
// subsequent mousemove events with the scroll-blocker. Since the
// scroll-blocker is a peer (not a child) of the scrollport, the mousemove
// events do not cause the scrollport to scroll.
//
// It's a hack, but it's the cleanest way I could find.
this.scrollBlockerNode_=this.document_.createElement('div');this.scrollBlockerNode_.id='hterm:mouse-drag-scroll-blocker';this.scrollBlockerNode_.setAttribute('aria-hidden','true');this.scrollBlockerNode_.style.cssText='position: absolute;'+'top: -99px;'+'display: block;'+'width: 10px;'+'height: 10px;';this.document_.body.appendChild(this.scrollBlockerNode_);this.scrollPort_.onScrollWheel=onMouse;['mousedown','mouseup','mousemove','click','dblclick'].forEach(function(event){this.scrollBlockerNode_.addEventListener(event,onMouse);this.cursorNode_.addEventListener(event,onMouse);this.document_.addEventListener(event,onMouse);}.bind(this));this.cursorNode_.addEventListener('mousedown',function(){setTimeout(this.focus.bind(this));}.bind(this));this.setReverseVideo(false);this.scrollPort_.focus();this.scrollPort_.scheduleRedraw();};/**
* Return the HTML document that contains the terminal DOM nodes.
*
* @return {HTMLDocument}
*/hterm.Terminal.prototype.getDocument=function(){return this.document_;};/**
* Focus the terminal.
*/hterm.Terminal.prototype.focus=function(){this.scrollPort_.focus();};/**
* Return the HTML Element for a given row index.
*
* This is a method from the RowProvider interface. The ScrollPort uses
* it to fetch rows on demand as they are scrolled into view.
*
* TODO(rginda): Consider saving scrollback rows as (HTML source, text content)
* pairs to conserve memory.
*
* @param {integer} index The zero-based row index, measured relative to the
* start of the scrollback buffer. On-screen rows will always have the
* largest indices.
* @return {HTMLElement} The 'x-row' element containing for the requested row.
*/hterm.Terminal.prototype.getRowNode=function(index){if(index<this.scrollbackRows_.length)return this.scrollbackRows_[index];var screenIndex=index-this.scrollbackRows_.length;return this.screen_.rowsArray[screenIndex];};/**
* Return the text content for a given range of rows.
*
* This is a method from the RowProvider interface. The ScrollPort uses
* it to fetch text content on demand when the user attempts to copy their
* selection to the clipboard.
*
* @param {integer} start The zero-based row index to start from, measured
* relative to the start of the scrollback buffer. On-screen rows will
* always have the largest indices.
* @param {integer} end The zero-based row index to end on, measured
* relative to the start of the scrollback buffer.
* @return {string} A single string containing the text value of the range of
* rows. Lines will be newline delimited, with no trailing newline.
*/hterm.Terminal.prototype.getRowsText=function(start,end){var ary=[];for(var i=start;i<end;i++){var node=this.getRowNode(i);ary.push(node.textContent);if(i<end-1&&!node.getAttribute('line-overflow'))ary.push('\n');}return ary.join('');};/**
* Return the text content for a given row.
*
* This is a method from the RowProvider interface. The ScrollPort uses
* it to fetch text content on demand when the user attempts to copy their
* selection to the clipboard.
*
* @param {integer} index The zero-based row index to return, measured
* relative to the start of the scrollback buffer. On-screen rows will
* always have the largest indices.
* @return {string} A string containing the text value of the selected row.
*/hterm.Terminal.prototype.getRowText=function(index){var node=this.getRowNode(index);return node.textContent;};/**
* Return the total number of rows in the addressable screen and in the
* scrollback buffer of this terminal.
*
* This is a method from the RowProvider interface. The ScrollPort uses
* it to compute the size of the scrollbar.
*
* @return {integer} The number of rows in this terminal.
*/hterm.Terminal.prototype.getRowCount=function(){return this.scrollbackRows_.length+this.screen_.rowsArray.length;};/**
* Create DOM nodes for new rows and append them to the end of the terminal.
*
* This is the only correct way to add a new DOM node for a row. Notice that
* the new row is appended to the bottom of the list of rows, and does not
* require renumbering (of the rowIndex property) of previous rows.
*
* If you think you want a new blank row somewhere in the middle of the
* terminal, look into moveRows_().
*
* This method does not pay attention to vtScrollTop/Bottom, since you should
* be using moveRows() in cases where they would matter.
*
* The cursor will be positioned at column 0 of the first inserted line.
*
* @param {number} count The number of rows to created.
*/hterm.Terminal.prototype.appendRows_=function(count){var cursorRow=this.screen_.rowsArray.length;var offset=this.scrollbackRows_.length+cursorRow;for(var i=0;i<count;i++){var row=this.document_.createElement('x-row');row.appendChild(this.document_.createTextNode(''));row.rowIndex=offset+i;this.screen_.pushRow(row);}var extraRows=this.screen_.rowsArray.length-this.screenSize.height;if(extraRows>0){var ary=this.screen_.shiftRows(extraRows);Array.prototype.push.apply(this.scrollbackRows_,ary);if(this.scrollPort_.isScrolledEnd)this.scheduleScrollDown_();}if(cursorRow>=this.screen_.rowsArray.length)cursorRow=this.screen_.rowsArray.length-1;this.setAbsoluteCursorPosition(cursorRow,0);};/**
* Relocate rows from one part of the addressable screen to another.
*
* This is used to recycle rows during VT scrolls (those which are driven
* by VT commands, rather than by the user manipulating the scrollbar.)
*
* In this case, the blank lines scrolled into the scroll region are made of
* the nodes we scrolled off. These have their rowIndex properties carefully
* renumbered so as not to confuse the ScrollPort.
*
* @param {number} fromIndex The start index.
* @param {number} count The number of rows to move.
* @param {number} toIndex The destination index.
*/hterm.Terminal.prototype.moveRows_=function(fromIndex,count,toIndex){var ary=this.screen_.removeRows(fromIndex,count);this.screen_.insertRows(toIndex,ary);var start,end;if(fromIndex<toIndex){start=fromIndex;end=toIndex+count;}else{start=toIndex;end=fromIndex+count;}this.renumberRows_(start,end);this.scrollPort_.scheduleInvalidate();};/**
* Renumber the rowIndex property of the given range of rows.
*
* The start and end indices are relative to the screen, not the scrollback.
* Rows in the scrollback buffer cannot be renumbered. Since they are not
* addressable (you can't delete them, scroll them, etc), you should have
* no need to renumber scrollback rows.
*
* @param {number} start The start index.
* @param {number} end The end index.
* @param {hterm.Screen} opt_screen The screen to renumber.
*/hterm.Terminal.prototype.renumberRows_=function(start,end,opt_screen){var screen=opt_screen||this.screen_;var offset=this.scrollbackRows_.length;for(var i=start;i<end;i++){screen.rowsArray[i].rowIndex=offset+i;}};/**
* Print a string to the terminal.
*
* This respects the current insert and wraparound modes. It will add new lines
* to the end of the terminal, scrolling off the top into the scrollback buffer
* if necessary.
*
* The string is *not* parsed for escape codes. Use the interpret() method if
* that's what you're after.
*
* @param{string} str The string to print.
*/hterm.Terminal.prototype.print=function(str){this.scheduleSyncCursorPosition_();// Basic accessibility output for the screen reader.
this.accessibilityReader_.announce(str);var startOffset=0;var strWidth=lib.wc.strWidth(str);// Fun edge case: If the string only contains zero width codepoints (like
// combining characters), we make sure to iterate at least once below.
if(strWidth==0&&str)strWidth=1;while(startOffset<strWidth){if(this.options_.wraparound&&this.screen_.cursorPosition.overflow){this.screen_.commitLineOverflow();this.newLine(true);}var count=strWidth-startOffset;var didOverflow=false;var substr;if(this.screen_.cursorPosition.column+count>=this.screenSize.width){didOverflow=true;count=this.screenSize.width-this.screen_.cursorPosition.column;}if(didOverflow&&!this.options_.wraparound){// If the string overflowed the line but wraparound is off, then the
// last printed character should be the last of the string.
// TODO: This will add to our problems with multibyte UTF-16 characters.
substr=lib.wc.substr(str,startOffset,count-1)+lib.wc.substr(str,strWidth-1);count=strWidth;}else{substr=lib.wc.substr(str,startOffset,count);}var tokens=hterm.TextAttributes.splitWidecharString(substr);for(var i=0;i<tokens.length;i++){this.screen_.textAttributes.wcNode=tokens[i].wcNode;this.screen_.textAttributes.asciiNode=tokens[i].asciiNode;if(this.options_.insertMode){this.screen_.insertString(tokens[i].str,tokens[i].wcStrWidth);}else{this.screen_.overwriteString(tokens[i].str,tokens[i].wcStrWidth);}this.screen_.textAttributes.wcNode=false;this.screen_.textAttributes.asciiNode=true;}this.screen_.maybeClipCurrentRow();startOffset+=count;}if(this.scrollOnOutput_)this.scrollPort_.scrollRowToBottom(this.getRowCount());};/**
* Set the VT scroll region.
*
* This also resets the cursor position to the absolute (0, 0) position, since
* that's what xterm appears to do.
*
* Setting the scroll region to the full height of the terminal will clear
* the scroll region. This is *NOT* what most terminals do. We're explicitly
* going "off-spec" here because it makes `screen` and `tmux` overflow into the
* local scrollback buffer, which means the scrollbars and shift-pgup/pgdn
* continue to work as most users would expect.
*
* @param {integer} scrollTop The zero-based top of the scroll region.
* @param {integer} scrollBottom The zero-based bottom of the scroll region,
* inclusive.
*/hterm.Terminal.prototype.setVTScrollRegion=function(scrollTop,scrollBottom){if(scrollTop==0&&scrollBottom==this.screenSize.height-1){this.vtScrollTop_=null;this.vtScrollBottom_=null;}else{this.vtScrollTop_=scrollTop;this.vtScrollBottom_=scrollBottom;}};/**
* Return the top row index according to the VT.
*
* This will return 0 unless the terminal has been told to restrict scrolling
* to some lower row. It is used for some VT cursor positioning and scrolling
* commands.
*
* @return {integer} The topmost row in the terminal's scroll region.
*/hterm.Terminal.prototype.getVTScrollTop=function(){if(this.vtScrollTop_!=null)return this.vtScrollTop_;return 0;};/**
* Return the bottom row index according to the VT.
*
* This will return the height of the terminal unless the it has been told to
* restrict scrolling to some higher row. It is used for some VT cursor
* positioning and scrolling commands.
*
* @return {integer} The bottom most row in the terminal's scroll region.
*/hterm.Terminal.prototype.getVTScrollBottom=function(){if(this.vtScrollBottom_!=null)return this.vtScrollBottom_;return this.screenSize.height-1;};/**
* Process a '\n' character.
*
* If the cursor is on the final row of the terminal this will append a new
* blank row to the screen and scroll the topmost row into the scrollback
* buffer.
*
* Otherwise, this moves the cursor to column zero of the next row.
*
* @param {boolean=} dueToOverflow Whether the newline is due to wraparound of
* the terminal.
*/hterm.Terminal.prototype.newLine=function(){var dueToOverflow=arguments.length>0&&arguments[0]!==undefined?arguments[0]:false;if(!dueToOverflow)this.accessibilityReader_.newLine();var cursorAtEndOfScreen=this.screen_.cursorPosition.row==this.screen_.rowsArray.length-1;if(this.vtScrollBottom_!=null){// A VT Scroll region is active, we never append new rows.
if(this.screen_.cursorPosition.row==this.vtScrollBottom_){// We're at the end of the VT Scroll Region, perform a VT scroll.
this.vtScrollUp(1);this.setAbsoluteCursorPosition(this.screen_.cursorPosition.row,0);}else if(cursorAtEndOfScreen){// We're at the end of the screen, the only thing to do is put the
// cursor to column 0.
this.setAbsoluteCursorPosition(this.screen_.cursorPosition.row,0);}else{// Anywhere else, advance the cursor row, and reset the column.
this.setAbsoluteCursorPosition(this.screen_.cursorPosition.row+1,0);}}else if(cursorAtEndOfScreen){// We're at the end of the screen. Append a new row to the terminal,
// shifting the top row into the scrollback.
this.appendRows_(1);}else{// Anywhere else in the screen just moves the cursor.
this.setAbsoluteCursorPosition(this.screen_.cursorPosition.row+1,0);}};/**
* Like newLine(), except maintain the cursor column.
*/hterm.Terminal.prototype.lineFeed=function(){var column=this.screen_.cursorPosition.column;this.newLine();this.setCursorColumn(column);};/**
* If autoCarriageReturn is set then newLine(), else lineFeed().
*/hterm.Terminal.prototype.formFeed=function(){if(this.options_.autoCarriageReturn){this.newLine();}else{this.lineFeed();}};/**
* Move the cursor up one row, possibly inserting a blank line.
*
* The cursor column is not changed.
*/hterm.Terminal.prototype.reverseLineFeed=function(){var scrollTop=this.getVTScrollTop();var currentRow=this.screen_.cursorPosition.row;if(currentRow==scrollTop){this.insertLines(1);}else{this.setAbsoluteCursorRow(currentRow-1);}};/**
* Replace all characters to the left of the current cursor with the space
* character.
*
* TODO(rginda): This should probably *remove* the characters (not just replace
* with a space) if there are no characters at or beyond the current cursor
* position.
*/hterm.Terminal.prototype.eraseToLeft=function(){var cursor=this.saveCursor();this.setCursorColumn(0);var count=cursor.column+1;this.screen_.overwriteString(lib.f.getWhitespace(count),count);this.restoreCursor(cursor);};/**
* Erase a given number of characters to the right of the cursor.
*
* The cursor position is unchanged.
*
* If the current background color is not the default background color this
* will insert spaces rather than delete. This is unfortunate because the
* trailing space will affect text selection, but it's difficult to come up
* with a way to style empty space that wouldn't trip up the hterm.Screen
* code.
*
* eraseToRight is ignored in the presence of a cursor overflow. This deviates
* from xterm, but agrees with gnome-terminal and konsole, xfce4-terminal. See
* crbug.com/232390 for details.
*
* @param {number} opt_count The number of characters to erase.
*/hterm.Terminal.prototype.eraseToRight=function(opt_count){if(this.screen_.cursorPosition.overflow)return;var maxCount=this.screenSize.width-this.screen_.cursorPosition.column;var count=opt_count?Math.min(opt_count,maxCount):maxCount;if(this.screen_.textAttributes.background===this.screen_.textAttributes.DEFAULT_COLOR){var cursorRow=this.screen_.rowsArray[this.screen_.cursorPosition.row];if(hterm.TextAttributes.nodeWidth(cursorRow)<=this.screen_.cursorPosition.column+count){this.screen_.deleteChars(count);this.clearCursorOverflow();return;}}var cursor=this.saveCursor();this.screen_.overwriteString(lib.f.getWhitespace(count),count);this.restoreCursor(cursor);this.clearCursorOverflow();};/**
* Erase the current line.
*
* The cursor position is unchanged.
*/hterm.Terminal.prototype.eraseLine=function(){var cursor=this.saveCursor();this.screen_.clearCursorRow();this.restoreCursor(cursor);this.clearCursorOverflow();};/**
* Erase all characters from the start of the screen to the current cursor
* position, regardless of scroll region.
*
* The cursor position is unchanged.
*/hterm.Terminal.prototype.eraseAbove=function(){var cursor=this.saveCursor();this.eraseToLeft();for(var i=0;i<cursor.row;i++){this.setAbsoluteCursorPosition(i,0);this.screen_.clearCursorRow();}this.restoreCursor(cursor);this.clearCursorOverflow();};/**
* Erase all characters from the current cursor position to the end of the
* screen, regardless of scroll region.
*
* The cursor position is unchanged.
*/hterm.Terminal.prototype.eraseBelow=function(){var cursor=this.saveCursor();this.eraseToRight();var bottom=this.screenSize.height-1;for(var i=cursor.row+1;i<=bottom;i++){this.setAbsoluteCursorPosition(i,0);this.screen_.clearCursorRow();}this.restoreCursor(cursor);this.clearCursorOverflow();};/**
* Fill the terminal with a given character.
*
* This methods does not respect the VT scroll region.
*
* @param {string} ch The character to use for the fill.
*/hterm.Terminal.prototype.fill=function(ch){var cursor=this.saveCursor();this.setAbsoluteCursorPosition(0,0);for(var row=0;row<this.screenSize.height;row++){for(var col=0;col<this.screenSize.width;col++){this.setAbsoluteCursorPosition(row,col);this.screen_.overwriteString(ch,1);}}this.restoreCursor(cursor);};/**
* Erase the entire display and leave the cursor at (0, 0).
*
* This does not respect the scroll region.
*
* @param {hterm.Screen} opt_screen Optional screen to operate on. Defaults
* to the current screen.
*/hterm.Terminal.prototype.clearHome=function(opt_screen){var screen=opt_screen||this.screen_;var bottom=screen.getHeight();this.accessibilityReader_.clear();if(bottom==0){// Empty screen, nothing to do.
return;}for(var i=0;i<bottom;i++){screen.setCursorPosition(i,0);screen.clearCursorRow();}screen.setCursorPosition(0,0);};/**
* Erase the entire display without changing the cursor position.
*
* The cursor position is unchanged. This does not respect the scroll
* region.
*
* @param {hterm.Screen} opt_screen Optional screen to operate on. Defaults
* to the current screen.
*/hterm.Terminal.prototype.clear=function(opt_screen){var screen=opt_screen||this.screen_;var cursor=screen.cursorPosition.clone();this.clearHome(screen);screen.setCursorPosition(cursor.row,cursor.column);};/**
* VT command to insert lines at the current cursor row.
*
* This respects the current scroll region. Rows pushed off the bottom are
* lost (they won't show up in the scrollback buffer).
*
* @param {integer} count The number of lines to insert.
*/hterm.Terminal.prototype.insertLines=function(count){var cursorRow=this.screen_.cursorPosition.row;var bottom=this.getVTScrollBottom();count=Math.min(count,bottom-cursorRow);// The moveCount is the number of rows we need to relocate to make room for
// the new row(s). The count is the distance to move them.
var moveCount=bottom-cursorRow-count+1;if(moveCount)this.moveRows_(cursorRow,moveCount,cursorRow+count);for(var i=count-1;i>=0;i--){this.setAbsoluteCursorPosition(cursorRow+i,0);this.screen_.clearCursorRow();}};/**
* VT command to delete lines at the current cursor row.
*
* New rows are added to the bottom of scroll region to take their place. New
* rows are strictly there to take up space and have no content or style.
*
* @param {number} count The number of lines to delete.
*/hterm.Terminal.prototype.deleteLines=function(count){var cursor=this.saveCursor();var top=cursor.row;var bottom=this.getVTScrollBottom();var maxCount=bottom-top+1;count=Math.min(count,maxCount);var moveStart=bottom-count+1;if(count!=maxCount)this.moveRows_(top,count,moveStart);for(var i=0;i<count;i++){this.setAbsoluteCursorPosition(moveStart+i,0);this.screen_.clearCursorRow();}this.restoreCursor(cursor);this.clearCursorOverflow();};/**
* Inserts the given number of spaces at the current cursor position.
*
* The cursor position is not changed.
*
* @param {number} count The number of spaces to insert.
*/hterm.Terminal.prototype.insertSpace=function(count){var cursor=this.saveCursor();var ws=lib.f.getWhitespace(count||1);this.screen_.insertString(ws,ws.length);this.screen_.maybeClipCurrentRow();this.restoreCursor(cursor);this.clearCursorOverflow();};/**
* Forward-delete the specified number of characters starting at the cursor
* position.
*
* @param {integer} count The number of characters to delete.
*/hterm.Terminal.prototype.deleteChars=function(count){var deleted=this.screen_.deleteChars(count);if(deleted&&!this.screen_.textAttributes.isDefault()){var cursor=this.saveCursor();this.setCursorColumn(this.screenSize.width-deleted);this.screen_.insertString(lib.f.getWhitespace(deleted));this.restoreCursor(cursor);}this.clearCursorOverflow();};/**
* Shift rows in the scroll region upwards by a given number of lines.
*
* New rows are inserted at the bottom of the scroll region to fill the
* vacated rows. The new rows not filled out with the current text attributes.
*
* This function does not affect the scrollback rows at all. Rows shifted
* off the top are lost.
*
* The cursor position is not altered.
*
* @param {integer} count The number of rows to scroll.
*/hterm.Terminal.prototype.vtScrollUp=function(count){var cursor=this.saveCursor();this.setAbsoluteCursorRow(this.getVTScrollTop());this.deleteLines(count);this.restoreCursor(cursor);};/**
* Shift rows below the cursor down by a given number of lines.
*
* This function respects the current scroll region.
*
* New rows are inserted at the top of the scroll region to fill the
* vacated rows. The new rows not filled out with the current text attributes.
*
* This function does not affect the scrollback rows at all. Rows shifted
* off the bottom are lost.
*
* @param {integer} count The number of rows to scroll.
*/hterm.Terminal.prototype.vtScrollDown=function(opt_count){var cursor=this.saveCursor();this.setAbsoluteCursorPosition(this.getVTScrollTop(),0);this.insertLines(opt_count);this.restoreCursor(cursor);};/**
* Enable accessibility-friendly features that have a performance impact.
*
* This will generate additional DOM nodes in an aria-live region that will
* cause Assitive Technology to announce the output of the terminal. It also
* enables other features that aid assistive technology. All the features gated
* behind this flag have a performance impact on the terminal which is why they
* are made optional.
*
* @param {boolean} enabled Whether to enable accessibility-friendly features.
*/hterm.Terminal.prototype.setAccessibilityEnabled=function(enabled){this.accessibilityReader_.setAccessibilityEnabled(enabled);};/**
* Set the cursor position.
*
* The cursor row is relative to the scroll region if the terminal has
* 'origin mode' enabled, or relative to the addressable screen otherwise.
*
* @param {integer} row The new zero-based cursor row.
* @param {integer} row The new zero-based cursor column.
*/hterm.Terminal.prototype.setCursorPosition=function(row,column){if(this.options_.originMode){this.setRelativeCursorPosition(row,column);}else{this.setAbsoluteCursorPosition(row,column);}};/**
* Move the cursor relative to its current position.
*
* @param {number} row
* @param {number} column
*/hterm.Terminal.prototype.setRelativeCursorPosition=function(row,column){var scrollTop=this.getVTScrollTop();row=lib.f.clamp(row+scrollTop,scrollTop,this.getVTScrollBottom());column=lib.f.clamp(column,0,this.screenSize.width-1);this.screen_.setCursorPosition(row,column);};/**
* Move the cursor to the specified position.
*
* @param {number} row
* @param {number} column
*/hterm.Terminal.prototype.setAbsoluteCursorPosition=function(row,column){row=lib.f.clamp(row,0,this.screenSize.height-1);column=lib.f.clamp(column,0,this.screenSize.width-1);this.screen_.setCursorPosition(row,column);};/**
* Set the cursor column.
*
* @param {integer} column The new zero-based cursor column.
*/hterm.Terminal.prototype.setCursorColumn=function(column){this.setAbsoluteCursorPosition(this.screen_.cursorPosition.row,column);};/**
* Return the cursor column.
*
* @return {integer} The zero-based cursor column.
*/hterm.Terminal.prototype.getCursorColumn=function(){return this.screen_.cursorPosition.column;};/**
* Set the cursor row.
*
* The cursor row is relative to the scroll region if the terminal has
* 'origin mode' enabled, or relative to the addressable screen otherwise.
*
* @param {integer} row The new cursor row.
*/hterm.Terminal.prototype.setAbsoluteCursorRow=function(row){this.setAbsoluteCursorPosition(row,this.screen_.cursorPosition.column);};/**
* Return the cursor row.
*
* @return {integer} The zero-based cursor row.
*/hterm.Terminal.prototype.getCursorRow=function(){return this.screen_.cursorPosition.row;};/**
* Request that the ScrollPort redraw itself soon.
*
* The redraw will happen asynchronously, soon after the call stack winds down.
* Multiple calls will be coalesced into a single redraw.
*/hterm.Terminal.prototype.scheduleRedraw_=function(){if(this.timeouts_.redraw)return;var self=this;this.timeouts_.redraw=setTimeout(function(){delete self.timeouts_.redraw;self.scrollPort_.redraw_();},0);};/**
* Request that the ScrollPort be scrolled to the bottom.
*
* The scroll will happen asynchronously, soon after the call stack winds down.
* Multiple calls will be coalesced into a single scroll.
*
* This affects the scrollbar position of the ScrollPort, and has nothing to
* do with the VT scroll commands.
*/hterm.Terminal.prototype.scheduleScrollDown_=function(){if(this.timeouts_.scrollDown)return;var self=this;this.timeouts_.scrollDown=setTimeout(function(){delete self.timeouts_.scrollDown;self.scrollPort_.scrollRowToBottom(self.getRowCount());},10);};/**
* Move the cursor up a specified number of rows.
*
* @param {integer} count The number of rows to move the cursor.
*/hterm.Terminal.prototype.cursorUp=function(count){return this.cursorDown(-(count||1));};/**
* Move the cursor down a specified number of rows.
*
* @param {integer} count The number of rows to move the cursor.
*/hterm.Terminal.prototype.cursorDown=function(count){count=count||1;var minHeight=this.options_.originMode?this.getVTScrollTop():0;var maxHeight=this.options_.originMode?this.getVTScrollBottom():this.screenSize.height-1;var row=lib.f.clamp(this.screen_.cursorPosition.row+count,minHeight,maxHeight);this.setAbsoluteCursorRow(row);};/**
* Move the cursor left a specified number of columns.
*
* If reverse wraparound mode is enabled and the previous row wrapped into
* the current row then we back up through the wraparound as well.
*
* @param {integer} count The number of columns to move the cursor.
*/hterm.Terminal.prototype.cursorLeft=function(count){count=count||1;if(count<1)return;var currentColumn=this.screen_.cursorPosition.column;if(this.options_.reverseWraparound){if(this.screen_.cursorPosition.overflow){// If this cursor is in the right margin, consume one count to get it
// back to the last column. This only applies when we're in reverse
// wraparound mode.
count--;this.clearCursorOverflow();if(!count)return;}var newRow=this.screen_.cursorPosition.row;var newColumn=currentColumn-count;if(newColumn<0){newRow=newRow-Math.floor(count/this.screenSize.width)-1;if(newRow<0){// xterm also wraps from row 0 to the last row.
newRow=this.screenSize.height+newRow%this.screenSize.height;}newColumn=this.screenSize.width+newColumn%this.screenSize.width;}this.setCursorPosition(Math.max(newRow,0),newColumn);}else{var newColumn=Math.max(currentColumn-count,0);this.setCursorColumn(newColumn);}};/**
* Move the cursor right a specified number of columns.
*
* @param {integer} count The number of columns to move the cursor.
*/hterm.Terminal.prototype.cursorRight=function(count){count=count||1;if(count<1)return;var column=lib.f.clamp(this.screen_.cursorPosition.column+count,0,this.screenSize.width-1);this.setCursorColumn(column);};/**
* Reverse the foreground and background colors of the terminal.
*
* This only affects text that was drawn with no attributes.
*
* TODO(rginda): Test xterm to see if reverse is respected for text that has
* been drawn with attributes that happen to coincide with the default
* 'no-attribute' colors. My guess is probably not.
*
* @param {boolean} state The state to set.
*/hterm.Terminal.prototype.setReverseVideo=function(state){this.options_.reverseVideo=state;if(state){this.scrollPort_.setForegroundColor(this.prefs_.get('background-color'));this.scrollPort_.setBackgroundColor(this.prefs_.get('foreground-color'));}else{this.scrollPort_.setForegroundColor(this.prefs_.get('foreground-color'));this.scrollPort_.setBackgroundColor(this.prefs_.get('background-color'));}};/**
* Ring the terminal bell.
*
* This will not play the bell audio more than once per second.
*/hterm.Terminal.prototype.ringBell=function(){this.cursorNode_.style.backgroundColor=this.scrollPort_.getForegroundColor();var self=this;setTimeout(function(){self.restyleCursor_();},200);// bellSquelchTimeout_ affects both audio and notification bells.
if(this.bellSquelchTimeout_)return;if(this.bellAudio_.getAttribute('src')){this.bellAudio_.play();this.bellSequelchTimeout_=setTimeout(function(){delete this.bellSquelchTimeout_;}.bind(this),500);}else{delete this.bellSquelchTimeout_;}if(this.desktopNotificationBell_&&!this.document_.hasFocus()){var n=hterm.notify();this.bellNotificationList_.push(n);// TODO: Should we try to raise the window here?
n.onclick=function(){self.closeBellNotifications_();};}};/**
* Set the origin mode bit.
*
* If origin mode is on, certain VT cursor and scrolling commands measure their
* row parameter relative to the VT scroll region. Otherwise, row 0 corresponds
* to the top of the addressable screen.
*
* Defaults to off.
*
* @param {boolean} state True to set origin mode, false to unset.
*/hterm.Terminal.prototype.setOriginMode=function(state){this.options_.originMode=state;this.setCursorPosition(0,0);};/**
* Set the insert mode bit.
*
* If insert mode is on, existing text beyond the cursor position will be
* shifted right to make room for new text. Otherwise, new text overwrites
* any existing text.
*
* Defaults to off.
*
* @param {boolean} state True to set insert mode, false to unset.
*/hterm.Terminal.prototype.setInsertMode=function(state){this.options_.insertMode=state;};/**
* Set the auto carriage return bit.
*
* If auto carriage return is on then a formfeed character is interpreted
* as a newline, otherwise it's the same as a linefeed. The difference boils
* down to whether or not the cursor column is reset.
*
* @param {boolean} state The state to set.
*/hterm.Terminal.prototype.setAutoCarriageReturn=function(state){this.options_.autoCarriageReturn=state;};/**
* Set the wraparound mode bit.
*
* If wraparound mode is on, certain VT commands will allow the cursor to wrap
* to the start of the following row. Otherwise, the cursor is clamped to the
* end of the screen and attempts to write past it are ignored.
*
* Defaults to on.
*
* @param {boolean} state True to set wraparound mode, false to unset.
*/hterm.Terminal.prototype.setWraparound=function(state){this.options_.wraparound=state;};/**
* Set the reverse-wraparound mode bit.
*
* If wraparound mode is off, certain VT commands will allow the cursor to wrap
* to the end of the previous row. Otherwise, the cursor is clamped to column
* 0.
*
* Defaults to off.
*
* @param {boolean} state True to set reverse-wraparound mode, false to unset.
*/hterm.Terminal.prototype.setReverseWraparound=function(state){this.options_.reverseWraparound=state;};/**
* Selects between the primary and alternate screens.
*
* If alternate mode is on, the alternate screen is active. Otherwise the
* primary screen is active.
*
* Swapping screens has no effect on the scrollback buffer.
*
* Each screen maintains its own cursor position.
*
* Defaults to off.
*
* @param {boolean} state True to set alternate mode, false to unset.
*/hterm.Terminal.prototype.setAlternateMode=function(state){var cursor=this.saveCursor();this.screen_=state?this.alternateScreen_:this.primaryScreen_;if(this.screen_.rowsArray.length&&this.screen_.rowsArray[0].rowIndex!=this.scrollbackRows_.length){// If the screen changed sizes while we were away, our rowIndexes may
// be incorrect.
var offset=this.scrollbackRows_.length;var ary=this.screen_.rowsArray;for(var i=0;i<ary.length;i++){ary[i].rowIndex=offset+i;}}this.realizeWidth_(this.screenSize.width);this.realizeHeight_(this.screenSize.height);this.scrollPort_.syncScrollHeight();this.scrollPort_.invalidate();this.restoreCursor(cursor);this.scrollPort_.resize();};/**
* Set the cursor-blink mode bit.
*
* If cursor-blink is on, the cursor will blink when it is visible. Otherwise
* a visible cursor does not blink.
*
* You should make sure to turn blinking off if you're going to dispose of a
* terminal, otherwise you'll leak a timeout.
*
* Defaults to on.
*
* @param {boolean} state True to set cursor-blink mode, false to unset.
*/hterm.Terminal.prototype.setCursorBlink=function(state){this.options_.cursorBlink=state;if(!state&&this.timeouts_.cursorBlink){clearTimeout(this.timeouts_.cursorBlink);delete this.timeouts_.cursorBlink;}if(this.options_.cursorVisible)this.setCursorVisible(true);};/**
* Set the cursor-visible mode bit.
*
* If cursor-visible is on, the cursor will be visible. Otherwise it will not.
*
* Defaults to on.
*
* @param {boolean} state True to set cursor-visible mode, false to unset.
*/hterm.Terminal.prototype.setCursorVisible=function(state){this.options_.cursorVisible=state;if(!state){if(this.timeouts_.cursorBlink){clearTimeout(this.timeouts_.cursorBlink);delete this.timeouts_.cursorBlink;}this.cursorNode_.style.opacity='0';return;}this.syncCursorPosition_();this.cursorNode_.style.opacity='1';if(this.options_.cursorBlink){if(this.timeouts_.cursorBlink)return;this.onCursorBlink_();}else{if(this.timeouts_.cursorBlink){clearTimeout(this.timeouts_.cursorBlink);delete this.timeouts_.cursorBlink;}}};/**
* Synchronizes the visible cursor and document selection with the current
* cursor coordinates.
*
* @return {boolean} True if the cursor is onscreen and synced.
*/hterm.Terminal.prototype.syncCursorPosition_=function(){var topRowIndex=this.scrollPort_.getTopRowIndex();var bottomRowIndex=this.scrollPort_.getBottomRowIndex(topRowIndex);var cursorRowIndex=this.scrollbackRows_.length+this.screen_.cursorPosition.row;var forceSyncSelection=false;if(this.accessibilityReader_.accessibilityEnabled){// Report the new position of the cursor for accessibility purposes.
var cursorColumnIndex=this.screen_.cursorPosition.column;var cursorLineText=this.screen_.rowsArray[this.screen_.cursorPosition.row].innerText;// This will force the selection to be sync'd to the cursor position if the
// user has pressed a key. Generally we would only sync the cursor position
// when selection is collapsed so that if the user has selected something
// we don't clear the selection by moving the selection. However when a
// screen reader is used, it's intuitive for entering a key to move the
// selection to the cursor.
forceSyncSelection=this.accessibilityReader_.hasUserGesture;this.accessibilityReader_.afterCursorChange(cursorLineText,cursorRowIndex,cursorColumnIndex);}if(cursorRowIndex>bottomRowIndex){// Cursor is scrolled off screen, move it outside of the visible area.
this.setCssVar('cursor-offset-row','-1');return false;}if(this.options_.cursorVisible&&this.cursorNode_.style.display=='none'){// Re-display the terminal cursor if it was hidden by the mouse cursor.
this.cursorNode_.style.display='';}// Position the cursor using CSS variable math. If we do the math in JS,
// the float math will end up being more precise than the CSS which will
// cause the cursor tracking to be off.
this.setCssVar('cursor-offset-row',"".concat(cursorRowIndex-topRowIndex," + ")+"".concat(this.scrollPort_.visibleRowTopMargin,"px"));this.setCssVar('cursor-offset-col',this.screen_.cursorPosition.column);this.cursorNode_.setAttribute('title','('+this.screen_.cursorPosition.column+', '+this.screen_.cursorPosition.row+')');// Update the caret for a11y purposes.
var selection=this.document_.getSelection();if(selection&&(selection.isCollapsed||forceSyncSelection)){this.screen_.syncSelectionCaret(selection);}return true;};/**
* Adjusts the style of this.cursorNode_ according to the current cursor shape
* and character cell dimensions.
*/hterm.Terminal.prototype.restyleCursor_=function(){var shape=this.cursorShape_;if(this.cursorNode_.getAttribute('focus')=='false'){// Always show a block cursor when unfocused.
shape=hterm.Terminal.cursorShape.BLOCK;}var style=this.cursorNode_.style;switch(shape){case hterm.Terminal.cursorShape.BEAM:style.height='var(--hterm-charsize-height)';style.backgroundColor='transparent';style.borderBottomStyle=null;style.borderLeftStyle='solid';break;case hterm.Terminal.cursorShape.UNDERLINE:style.height=this.scrollPort_.characterSize.baseline+'px';style.backgroundColor='transparent';style.borderBottomStyle='solid';// correct the size to put it exactly at the baseline
style.borderLeftStyle=null;break;default:style.height='var(--hterm-charsize-height)';style.backgroundColor='var(--hterm-cursor-color)';style.borderBottomStyle=null;style.borderLeftStyle=null;break;}};/**
* Synchronizes the visible cursor with the current cursor coordinates.
*
* The sync will happen asynchronously, soon after the call stack winds down.
* Multiple calls will be coalesced into a single sync. This should be called
* prior to the cursor actually changing position.
*/hterm.Terminal.prototype.scheduleSyncCursorPosition_=function(){if(this.timeouts_.syncCursor)return;if(this.accessibilityReader_.accessibilityEnabled){// Report the previous position of the cursor for accessibility purposes.
var cursorRowIndex=this.scrollbackRows_.length+this.screen_.cursorPosition.row;var cursorColumnIndex=this.screen_.cursorPosition.column;var cursorLineText=this.screen_.rowsArray[this.screen_.cursorPosition.row].innerText;this.accessibilityReader_.beforeCursorChange(cursorLineText,cursorRowIndex,cursorColumnIndex);}var self=this;this.timeouts_.syncCursor=setTimeout(function(){self.syncCursorPosition_();delete self.timeouts_.syncCursor;},0);};/**
* Show or hide the zoom warning.
*
* The zoom warning is a message warning the user that their browser zoom must
* be set to 100% in order for hterm to function properly.
*
* @param {boolean} state True to show the message, false to hide it.
*/hterm.Terminal.prototype.showZoomWarning_=function(state){if(!this.zoomWarningNode_){if(!state)return;this.zoomWarningNode_=this.document_.createElement('div');this.zoomWarningNode_.id='hterm:zoom-warning';this.zoomWarningNode_.style.cssText='color: black;'+'background-color: #ff2222;'+'font-size: large;'+'border-radius: 8px;'+'opacity: 0.75;'+'padding: 0.2em 0.5em 0.2em 0.5em;'+'top: 0.5em;'+'right: 1.2em;'+'position: absolute;'+'-webkit-text-size-adjust: none;'+'-webkit-user-select: none;'+'-moz-text-size-adjust: none;'+'-moz-user-select: none;';this.zoomWarningNode_.addEventListener('click',function(e){this.parentNode.removeChild(this);});}this.zoomWarningNode_.textContent=lib.i18n.replaceReferences(hterm.zoomWarningMessage,[parseInt(this.scrollPort_.characterSize.zoomFactor*100)]);this.zoomWarningNode_.style.fontFamily=this.prefs_.get('font-family');if(state){if(!this.zoomWarningNode_.parentNode)this.div_.parentNode.appendChild(this.zoomWarningNode_);}else if(this.zoomWarningNode_.parentNode){this.zoomWarningNode_.parentNode.removeChild(this.zoomWarningNode_);}};/**
* Show the terminal overlay for a given amount of time.
*
* The terminal overlay appears in inverse video in a large font, centered
* over the terminal. You should probably keep the overlay message brief,
* since it's in a large font and you probably aren't going to check the size
* of the terminal first.
*
* @param {string} msg The text (not HTML) message to display in the overlay.
* @param {number} opt_timeout The amount of time to wait before fading out
* the overlay. Defaults to 1.5 seconds. Pass null to have the overlay
* stay up forever (or until the next overlay).
*/hterm.Terminal.prototype.showOverlay=function(msg,opt_timeout){var _this14=this;if(!this.overlayNode_){if(!this.div_)return;this.overlayNode_=this.document_.createElement('div');this.overlayNode_.style.cssText='border-radius: 15px;'+'font-size: xx-large;'+'opacity: 0.75;'+'padding: 0.2em 0.5em 0.2em 0.5em;'+'position: absolute;'+'-webkit-user-select: none;'+'-webkit-transition: opacity 180ms ease-in;'+'-moz-user-select: none;'+'-moz-transition: opacity 180ms ease-in;';this.overlayNode_.addEventListener('mousedown',function(e){e.preventDefault();e.stopPropagation();},true);}this.overlayNode_.style.color=this.prefs_.get('background-color');this.overlayNode_.style.backgroundColor=this.prefs_.get('foreground-color');this.overlayNode_.style.fontFamily=this.prefs_.get('font-family');this.overlayNode_.textContent=msg;this.overlayNode_.style.opacity='0.75';if(!this.overlayNode_.parentNode)this.div_.appendChild(this.overlayNode_);var divSize=hterm.getClientSize(this.div_);var overlaySize=hterm.getClientSize(this.overlayNode_);this.overlayNode_.style.top=(divSize.height-overlaySize.height)/2+'px';this.overlayNode_.style.left=(divSize.width-overlaySize.width-this.scrollPort_.currentScrollbarWidthPx)/2+'px';if(this.overlayTimeout_)clearTimeout(this.overlayTimeout_);this.accessibilityReader_.assertiveAnnounce(msg);if(opt_timeout===null)return;this.overlayTimeout_=setTimeout(function(){_this14.overlayNode_.style.opacity='0';_this14.overlayTimeout_=setTimeout(function(){return _this14.hideOverlay();},200);},opt_timeout||1500);};/**
* Hide the terminal overlay immediately.
*
* Useful when we show an overlay for an event with an unknown end time.
*/hterm.Terminal.prototype.hideOverlay=function(){if(this.overlayTimeout_)clearTimeout(this.overlayTimeout_);this.overlayTimeout_=null;if(this.overlayNode_.parentNode)this.overlayNode_.parentNode.removeChild(this.overlayNode_);this.overlayNode_.style.opacity='0.75';};/**
* Paste from the system clipboard to the terminal.
*/hterm.Terminal.prototype.paste=function(){return hterm.pasteFromClipboard(this.document_);};/**
* Copy a string to the system clipboard.
*
* Note: If there is a selected range in the terminal, it'll be cleared.
*
* @param {string} str The string to copy.
*/hterm.Terminal.prototype.copyStringToClipboard=function(str){if(this.prefs_.get('enable-clipboard-notice'))setTimeout(this.showOverlay.bind(this,hterm.notifyCopyMessage,500),200);hterm.copySelectionToClipboard(this.document_,str);};/**
* Display an image.
*
* Either URI or buffer or blob fields must be specified.
*
* @param {Object} options The image to display.
* @param {string=} options.name A human readable string for the image.
* @param {string|number=} options.size The size (in bytes).
* @param {boolean=} options.preserveAspectRatio Whether to preserve aspect.
* @param {boolean=} options.inline Whether to display the image inline.
* @param {string|number=} options.width The width of the image.
* @param {string|number=} options.height The height of the image.
* @param {string=} options.align Direction to align the image.
* @param {string=} options.uri The source URI for the image.
* @param {ArrayBuffer=} options.buffer The ArrayBuffer image data.
* @param {Blob=} options.blob The Blob image data.
* @param {string=} options.type The MIME type of the image data.
* @param {function=} onLoad Callback when loading finishes.
* @param {function(Event)=} onError Callback when loading fails.
*/hterm.Terminal.prototype.displayImage=function(options,onLoad,onError){var _this15=this;// Make sure we're actually given a resource to display.
if(options.uri===undefined&&options.buffer===undefined&&options.blob===undefined)return;// Set up the defaults to simplify code below.
if(!options.name)options.name='';// See if the mime type is available. If not, guess from the filename.
// We don't list all possible mime types because the browser can usually
// guess it correctly. So list the ones that need a bit more help.
if(!options.type){var ary=options.name.split('.');var ext=ary[ary.length-1].trim();switch(ext){case'svg':case'svgz':options.type='image/svg+xml';break;}}// Has the user approved image display yet?
if(this.allowImagesInline!==true){this.newLine();var row=this.getRowNode(this.scrollbackRows_.length+this.getCursorRow()-1);if(this.allowImagesInline===false){row.textContent=hterm.msg('POPUP_INLINE_IMAGE_DISABLED',[],'Inline Images Disabled');return;}// Show a prompt.
var button;var span=this.document_.createElement('span');span.innerText=hterm.msg('POPUP_INLINE_IMAGE',[],'Inline Images');span.style.fontWeight='bold';span.style.borderWidth='1px';span.style.borderStyle='dashed';button=this.document_.createElement('span');button.innerText=hterm.msg('BUTTON_BLOCK',[],'block');button.style.marginLeft='1em';button.style.borderWidth='1px';button.style.borderStyle='solid';button.addEventListener('click',function(){_this15.prefs_.set('allow-images-inline',false);});span.appendChild(button);button=this.document_.createElement('span');button.innerText=hterm.msg('BUTTON_ALLOW_SESSION',[],'allow this session');button.style.marginLeft='1em';button.style.borderWidth='1px';button.style.borderStyle='solid';button.addEventListener('click',function(){_this15.allowImagesInline=true;});span.appendChild(button);button=this.document_.createElement('span');button.innerText=hterm.msg('BUTTON_ALLOW_ALWAYS',[],'always allow');button.style.marginLeft='1em';button.style.borderWidth='1px';button.style.borderStyle='solid';button.addEventListener('click',function(){_this15.prefs_.set('allow-images-inline',true);});span.appendChild(button);row.appendChild(span);return;}// See if we should show this object directly, or download it.
if(options.inline){var io=this.io.push();io.showOverlay(hterm.msg('LOADING_RESOURCE_START',[options.name],'Loading $1 ...'),null);// While we're loading the image, eat all the user's input.
io.onVTKeystroke=io.sendString=function(){};// Initialize this new image.
var img=/** @type {!HTMLImageElement} */this.document_.createElement('img');if(options.uri!==undefined){img.src=options.uri;}else if(options.buffer!==undefined){var blob=new Blob([options.buffer],{type:options.type});img.src=URL.createObjectURL(blob);}else{var _blob=new Blob([options.blob],{type:options.type});img.src=URL.createObjectURL(options.blob);}img.title=img.alt=options.name;// Attach the image to the page to let it load/render. It won't stay here.
// This is needed so it's visible and the DOM can calculate the height. If
// the image is hidden or not in the DOM, the height is always 0.
this.document_.body.appendChild(img);// Wait for the image to finish loading before we try moving it to the
// right place in the terminal.
img.onload=function(){// Now that we have the image dimensions, figure out how to show it.
img.style.objectFit=options.preserveAspectRatio?'scale-down':'fill';img.style.maxWidth="".concat(_this15.document_.body.clientWidth,"px");img.style.maxHeight="".concat(_this15.document_.body.clientHeight,"px");// Parse a width/height specification.
var parseDim=function parseDim(dim,maxDim,cssVar){if(!dim||dim=='auto')return'';var ary=dim.match(/^([0-9]+)(px|%)?$/);if(ary){if(ary[2]=='%')return maxDim*parseInt(ary[1])/100+'px';else if(ary[2]=='px')return dim;else return"calc(".concat(dim," * var(").concat(cssVar,"))");}return'';};img.style.width=parseDim(options.width,_this15.document_.body.clientWidth,'--hterm-charsize-width');img.style.height=parseDim(options.height,_this15.document_.body.clientHeight,'--hterm-charsize-height');// Figure out how many rows the image occupies, then add that many.
// XXX: This count will be inaccurate if the font size changes on us.
var padRows=Math.ceil(img.clientHeight/_this15.scrollPort_.characterSize.height);for(var i=0;i<padRows;++i){_this15.newLine();}// Update the max height in case the user shrinks the character size.
img.style.maxHeight="calc(".concat(padRows," * var(--hterm-charsize-height))");// Move the image to the last row. This way when we scroll up, it doesn't
// disappear when the first row gets clipped. It will disappear when we
// scroll down and the last row is clipped ...
_this15.document_.body.removeChild(img);// Create a wrapper node so we can do an absolute in a relative position.
// This helps with rounding errors between JS & CSS counts.
var div=_this15.document_.createElement('div');div.style.position='relative';div.style.textAlign=options.align;img.style.position='absolute';img.style.bottom='calc(0px - var(--hterm-charsize-height))';div.appendChild(img);var row=_this15.getRowNode(_this15.scrollbackRows_.length+_this15.getCursorRow()-1);row.appendChild(div);// Now that the image has been read, we can revoke the source.
if(options.uri===undefined){URL.revokeObjectURL(img.src);}io.hideOverlay();io.pop();if(onLoad)onLoad();};// If we got a malformed image, give up.
img.onerror=function(e){_this15.document_.body.removeChild(img);io.showOverlay(hterm.msg('LOADING_RESOURCE_FAILED',[options.name],'Loading $1 failed'));io.pop();if(onError)onError(e);};}else{// We can't use chrome.downloads.download as that requires "downloads"
// permissions, and that works only in extensions, not apps.
var a=this.document_.createElement('a');if(options.uri!==undefined){a.href=options.uri;}else if(options.buffer!==undefined){var _blob2=new Blob([options.buffer]);a.href=URL.createObjectURL(_blob2);}else{a.href=URL.createObjectURL(options.blob);}a.download=options.name;this.document_.body.appendChild(a);a.click();a.remove();if(options.uri===undefined){URL.revokeObjectURL(a.href);}}};/**
* Returns the selected text, or null if no text is selected.
*
* @return {string|null}
*/hterm.Terminal.prototype.getSelectionText=function(){var selection=this.scrollPort_.selection;selection.sync();if(selection.isCollapsed)return null;// Start offset measures from the beginning of the line.
var startOffset=selection.startOffset;var node=selection.startNode;// If an x-row isn't selected, |node| will be null.
if(!node)return null;if(node.nodeName!='X-ROW'){// If the selection doesn't start on an x-row node, then it must be
// somewhere inside the x-row. Add any characters from previous siblings
// into the start offset.
if(node.nodeName=='#text'&&node.parentNode.nodeName=='SPAN'){// If node is the text node in a styled span, move up to the span node.
node=node.parentNode;}while(node.previousSibling){node=node.previousSibling;startOffset+=hterm.TextAttributes.nodeWidth(node);}}// End offset measures from the end of the line.
var endOffset=hterm.TextAttributes.nodeWidth(selection.endNode)-selection.endOffset;node=selection.endNode;if(node.nodeName!='X-ROW'){// If the selection doesn't end on an x-row node, then it must be
// somewhere inside the x-row. Add any characters from following siblings
// into the end offset.
if(node.nodeName=='#text'&&node.parentNode.nodeName=='SPAN'){// If node is the text node in a styled span, move up to the span node.
node=node.parentNode;}while(node.nextSibling){node=node.nextSibling;endOffset+=hterm.TextAttributes.nodeWidth(node);}}var rv=this.getRowsText(selection.startRow.rowIndex,selection.endRow.rowIndex+1);return lib.wc.substring(rv,startOffset,lib.wc.strWidth(rv)-endOffset);};/**
* Copy the current selection to the system clipboard, then clear it after a
* short delay.
*/hterm.Terminal.prototype.copySelectionToClipboard=function(){var text=this.getSelectionText();if(text!=null)this.copyStringToClipboard(text);};hterm.Terminal.prototype.overlaySize=function(){this.showOverlay(this.screenSize.width+'x'+this.screenSize.height);};/**
* Invoked by hterm.Terminal.Keyboard when a VT keystroke is detected.
*
* @param {string} string The VT string representing the keystroke, in UTF-16.
*/hterm.Terminal.prototype.onVTKeystroke=function(string){if(this.scrollOnKeystroke_)this.scrollPort_.scrollRowToBottom(this.getRowCount());this.io.onVTKeystroke(string);};/**
* Open the selected url.
*/hterm.Terminal.prototype.openSelectedUrl_=function(){var str=this.getSelectionText();// If there is no selection, try and expand wherever they clicked.
if(str==null){this.screen_.expandSelectionForUrl(this.document_.getSelection());str=this.getSelectionText();// If clicking in empty space, return.
if(str==null)return;}// Make sure URL is valid before opening.
if(str.length>2048||str.search(/[\s\[\](){}<>"'\\^`]/)>=0)return;// If the URI isn't anchored, it'll open relative to the extension.
// We have no way of knowing the correct schema, so assume http.
if(str.search('^[a-zA-Z][a-zA-Z0-9+.-]*://')<0){// We have to whitelist a few protocols that lack authorities and thus
// never use the //. Like mailto.
switch(str.split(':',1)[0]){case'mailto':break;default:str='http://'+str;break;}}hterm.openUrl(str);};/**
* Manage the automatic mouse hiding behavior while typing.
*
* @param {boolean=} v Whether to enable automatic hiding.
*/hterm.Terminal.prototype.setAutomaticMouseHiding=function(){var v=arguments.length>0&&arguments[0]!==undefined?arguments[0]:null;// Since Chrome OS & macOS do this by default everywhere, we don't need to.
// Linux & Windows seem to leave this to specific applications to manage.
if(v===null)v=hterm.os!='cros'&&hterm.os!='mac';this.mouseHideWhileTyping_=!!v;};/**
* Handler for monitoring user keyboard activity.
*
* This isn't for processing the keystrokes directly, but for updating any
* state that might toggle based on the user using the keyboard at all.
*
* @param {KeyboardEvent} e The keyboard event that triggered us.
*/hterm.Terminal.prototype.onKeyboardActivity_=function(e){// When the user starts typing, hide the mouse cursor.
if(this.mouseHideWhileTyping_&&!this.mouseHideDelay_)this.setCssVar('mouse-cursor-style','none');};/**
* Add the terminalRow and terminalColumn properties to mouse events and
* then forward on to onMouse().
*
* The terminalRow and terminalColumn properties contain the (row, column)
* coordinates for the mouse event.
*
* @param {Event} e The mouse event to handle.
*/hterm.Terminal.prototype.onMouse_=function(e){var _this16=this;if(e.processedByTerminalHandler_){// We register our event handlers on the document, as well as the cursor
// and the scroll blocker. Mouse events that occur on the cursor or
// scroll blocker will also appear on the document, but we don't want to
// process them twice.
//
// We can't just prevent bubbling because that has other side effects, so
// we decorate the event object with this property instead.
return;}// Consume navigation events. Button 3 is usually "browser back" and
// button 4 is "browser forward" which we don't want to happen.
if(e.button>2){e.preventDefault();// We don't return so click events can be passed to the remote below.
}var reportMouseEvents=!this.defeatMouseReports_&&this.vt.mouseReport!=this.vt.MOUSE_REPORT_DISABLED;e.processedByTerminalHandler_=true;// Handle auto hiding of mouse cursor while typing.
if(this.mouseHideWhileTyping_&&!this.mouseHideDelay_){// Make sure the mouse cursor is visible.
this.syncMouseStyle();// This debounce isn't perfect, but should work well enough for such a
// simple implementation. If the user moved the mouse, we enabled this
// debounce, and then moved the mouse just before the timeout, we wouldn't
// debounce that later movement.
this.mouseHideDelay_=setTimeout(function(){return _this16.mouseHideDelay_=null;},1000);}// One based row/column stored on the mouse event.
e.terminalRow=parseInt((e.clientY-this.scrollPort_.visibleRowTopMargin)/this.scrollPort_.characterSize.height)+1;e.terminalColumn=parseInt(e.clientX/this.scrollPort_.characterSize.width)+1;if(e.type=='mousedown'&&e.terminalColumn>this.screenSize.width){// Mousedown in the scrollbar area.
return;}if(this.options_.cursorVisible&&!reportMouseEvents){// If the cursor is visible and we're not sending mouse events to the
// host app, then we want to hide the terminal cursor when the mouse
// cursor is over top. This keeps the terminal cursor from interfering
// with local text selection.
if(e.terminalRow-1==this.screen_.cursorPosition.row&&e.terminalColumn-1==this.screen_.cursorPosition.column){this.cursorNode_.style.display='none';}else if(this.cursorNode_.style.display=='none'){this.cursorNode_.style.display='';}}if(e.type=='mousedown'){this.contextMenu.hide(e);if(e.altKey||!reportMouseEvents){// If VT mouse reporting is disabled, or has been defeated with
// alt-mousedown, then the mouse will act on the local selection.
this.defeatMouseReports_=true;this.setSelectionEnabled(true);}else{// Otherwise we defer ownership of the mouse to the VT.
this.defeatMouseReports_=false;this.document_.getSelection().collapseToEnd();this.setSelectionEnabled(false);e.preventDefault();}}if(!reportMouseEvents){if(e.type=='dblclick'){this.screen_.expandSelection(this.document_.getSelection());if(this.copyOnSelect)this.copySelectionToClipboard();}if(e.type=='click'&&!e.shiftKey&&(e.ctrlKey||e.metaKey)){// Debounce this event with the dblclick event. If you try to doubleclick
// a URL to open it, Chrome will fire click then dblclick, but we won't
// have expanded the selection text at the first click event.
clearTimeout(this.timeouts_.openUrl);this.timeouts_.openUrl=setTimeout(this.openSelectedUrl_.bind(this),500);return;}if(e.type=='mousedown'){if(e.ctrlKey&&e.button==2/* right button */){e.preventDefault();this.contextMenu.show(e,this);}else if(e.button==this.mousePasteButton||this.mouseRightClickPaste&&e.button==2/* right button */){if(!this.paste())console.warn('Could not paste manually due to web restrictions');}}if(e.type=='mouseup'&&e.button==0&&this.copyOnSelect&&!this.document_.getSelection().isCollapsed){this.copySelectionToClipboard();}if((e.type=='mousemove'||e.type=='mouseup')&&this.scrollBlockerNode_.engaged){// Disengage the scroll-blocker after one of these events.
this.scrollBlockerNode_.engaged=false;this.scrollBlockerNode_.style.top='-99px';}// Emulate arrow key presses via scroll wheel events.
if(this.scrollWheelArrowKeys_&&!e.shiftKey&&this.keyboard.applicationCursor&&!this.isPrimaryScreen()){if(e.type=='wheel'){var delta=this.scrollPort_.scrollWheelDelta(e);// Helper to turn a wheel event delta into a series of key presses.
var deltaToArrows=function deltaToArrows(distance,charSize,arrowPos,arrowNeg){if(distance==0){return'';}// Convert the scroll distance into a number of rows/cols.
var cells=lib.f.smartFloorDivide(Math.abs(distance),charSize);var data='\x1bO'+(distance<0?arrowNeg:arrowPos);return data.repeat(cells);};// The order between up/down and left/right doesn't really matter.
this.io.sendString(// Up/down arrow keys.
deltaToArrows(delta.y,this.scrollPort_.characterSize.height,'A','B')+// Left/right arrow keys.
deltaToArrows(delta.x,this.scrollPort_.characterSize.width,'C','D'));e.preventDefault();}}}else/* if (this.reportMouseEvents) */{if(!this.scrollBlockerNode_.engaged){if(e.type=='mousedown'){// Move the scroll-blocker into place if we want to keep the scrollport
// from scrolling.
this.scrollBlockerNode_.engaged=true;this.scrollBlockerNode_.style.top=e.clientY-5+'px';this.scrollBlockerNode_.style.left=e.clientX-5+'px';}else if(e.type=='mousemove'){// Oh. This means that drag-scroll was disabled AFTER the mouse down,
// in which case it's too late to engage the scroll-blocker.
this.document_.getSelection().collapseToEnd();e.preventDefault();}}this.onMouse(e);}if(e.type=='mouseup'&&this.document_.getSelection().isCollapsed){// Restore this on mouseup in case it was temporarily defeated with a
// alt-mousedown. Only do this when the selection is empty so that
// we don't immediately kill the users selection.
this.defeatMouseReports_=false;}};/**
* Clients should override this if they care to know about mouse events.
*
* The event parameter will be a normal DOM mouse click event with additional
* 'terminalRow' and 'terminalColumn' properties.
*
* @param {Event} e The mouse event to handle.
*/hterm.Terminal.prototype.onMouse=function(e){};/**
* React when focus changes.
*
* @param {boolean} focused True if focused, false otherwise.
*/hterm.Terminal.prototype.onFocusChange_=function(focused){this.cursorNode_.setAttribute('focus',focused);this.restyleCursor_();if(this.reportFocus)this.io.sendString(focused===true?'\x1b[I':'\x1b[O');if(focused===true)this.closeBellNotifications_();};/**
* React when the ScrollPort is scrolled.
*/hterm.Terminal.prototype.onScroll_=function(){this.scheduleSyncCursorPosition_();};/**
* React when text is pasted into the scrollPort.
*
* @param {Event} e The DOM paste event to handle.
*/hterm.Terminal.prototype.onPaste_=function(e){var data=e.text.replace(/\n/mg,'\r');if(this.options_.bracketedPaste){// We strip out most escape sequences as they can cause issues (like
// inserting an \x1b[201~ midstream). We pass through whitespace
// though: 0x08:\b 0x09:\t 0x0a:\n 0x0d:\r.
// This matches xterm behavior.
var filter=function filter(data){return data.replace(/[\x00-\x07\x0b-\x0c\x0e-\x1f]/g,'');};data='\x1b[200~'+filter(data)+'\x1b[201~';}this.io.sendString(data);};/**
* React when the user tries to copy from the scrollPort.
*
* @param {Event} e The DOM copy event.
*/hterm.Terminal.prototype.onCopy_=function(e){if(!this.useDefaultWindowCopy){e.preventDefault();setTimeout(this.copySelectionToClipboard.bind(this),0);}};/**
* React when the ScrollPort is resized.
*
* Note: This function should not directly contain code that alters the internal
* state of the terminal. That kind of code belongs in realizeWidth or
* realizeHeight, so that it can be executed synchronously in the case of a
* programmatic width change.
*/hterm.Terminal.prototype.onResize_=function(){var columnCount=Math.floor(this.scrollPort_.getScreenWidth()/this.scrollPort_.characterSize.width)||0;var rowCount=lib.f.smartFloorDivide(this.scrollPort_.getScreenHeight(),this.scrollPort_.characterSize.height)||0;if(columnCount<=0||rowCount<=0){// We avoid these situations since they happen sometimes when the terminal
// gets removed from the document or during the initial load, and we can't
// deal with that.
// This can also happen if called before the scrollPort calculates the
// character size, meaning we dived by 0 above and default to 0 values.
return;}var isNewSize=columnCount!=this.screenSize.width||rowCount!=this.screenSize.height;// We do this even if the size didn't change, just to be sure everything is
// in sync.
this.realizeSize_(columnCount,rowCount);this.showZoomWarning_(this.scrollPort_.characterSize.zoomFactor!=1);if(isNewSize)this.overlaySize();this.restyleCursor_();this.scheduleSyncCursorPosition_();};/**
* Service the cursor blink timeout.
*/hterm.Terminal.prototype.onCursorBlink_=function(){if(!this.options_.cursorBlink){delete this.timeouts_.cursorBlink;return;}if(this.cursorNode_.getAttribute('focus')=='false'||this.cursorNode_.style.opacity=='0'){this.cursorNode_.style.opacity='1';this.timeouts_.cursorBlink=setTimeout(this.myOnCursorBlink_,this.cursorBlinkCycle_[0]);}else{this.cursorNode_.style.opacity='0';this.timeouts_.cursorBlink=setTimeout(this.myOnCursorBlink_,this.cursorBlinkCycle_[1]);}};/**
* Set the scrollbar-visible mode bit.
*
* If scrollbar-visible is on, the vertical scrollbar will be visible.
* Otherwise it will not.
*
* Defaults to on.
*
* @param {boolean} state True to set scrollbar-visible mode, false to unset.
*/hterm.Terminal.prototype.setScrollbarVisible=function(state){this.scrollPort_.setScrollbarVisible(state);};/**
* Set the scroll wheel move multiplier. This will affect how fast the page
* scrolls on wheel events.
*
* Defaults to 1.
*
* @param {number} multiplier The multiplier to set.
*/hterm.Terminal.prototype.setScrollWheelMoveMultipler=function(multiplier){this.scrollPort_.setScrollWheelMoveMultipler(multiplier);};/**
* Close all web notifications created by terminal bells.
*/hterm.Terminal.prototype.closeBellNotifications_=function(){this.bellNotificationList_.forEach(function(n){n.close();});this.bellNotificationList_.length=0;};/**
* Syncs the cursor position when the scrollport gains focus.
*/hterm.Terminal.prototype.onScrollportFocus_=function(){// If the cursor is offscreen we set selection to the last row on the screen.
var topRowIndex=this.scrollPort_.getTopRowIndex();var bottomRowIndex=this.scrollPort_.getBottomRowIndex(topRowIndex);var selection=this.document_.getSelection();if(!this.syncCursorPosition_()&&selection){selection.collapse(this.getRowNode(bottomRowIndex));}};// SOURCE FILE: hterm/js/hterm_terminal_io.js
// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* Input/Output interface used by commands to communicate with the terminal.
*
* Commands like `nassh` and `crosh` receive an instance of this class as
* part of their argv object. This allows them to write to and read from the
* terminal without exposing them to an entire hterm.Terminal instance.
*
* The active command must override the onVTKeystroke() and sendString() methods
* of this class in order to receive keystrokes and send output to the correct
* destination.
*
* Isolating commands from the terminal provides the following benefits:
* - Provides a mechanism to save and restore onVTKeystroke and sendString
* handlers when invoking subcommands (see the push() and pop() methods).
* - The isolation makes it easier to make changes in Terminal and supporting
* classes without affecting commands.
* - In The Future commands may run in web workers where they would only be able
* to talk to a Terminal instance through an IPC mechanism.
*
* @param {hterm.Terminal}
*/hterm.Terminal.IO=function(terminal){this.terminal_=terminal;// The IO object to restore on IO.pop().
this.previousIO_=null;// Any data this object accumulated while not active.
this.buffered_='';// Decoder to maintain UTF-8 decode state.
this.textDecoder_=new TextDecoder();};/**
* Show the terminal overlay for a given amount of time.
*
* The terminal overlay appears in inverse video in a large font, centered
* over the terminal. You should probably keep the overlay message brief,
* since it's in a large font and you probably aren't going to check the size
* of the terminal first.
*
* @param {string} msg The text (not HTML) message to display in the overlay.
* @param {number} opt_timeout The amount of time to wait before fading out
* the overlay. Defaults to 1.5 seconds. Pass null to have the overlay
* stay up forever (or until the next overlay).
*/hterm.Terminal.IO.prototype.showOverlay=function(message,opt_timeout){this.terminal_.showOverlay(message,opt_timeout);};/**
* Hide the current overlay immediately.
*
* Useful when we show an overlay for an event with an unknown end time.
*/hterm.Terminal.IO.prototype.hideOverlay=function(){this.terminal_.hideOverlay();};/**
* Open an frame in the current terminal window, pointed to the specified
* url.
*
* Eventually we'll probably need size/position/decoration options.
* The user should also be able to move/resize the frame.
*
* @param {string} url The URL to load in the frame.
* @param {Object} opt_options Optional frame options. Not implemented.
*/hterm.Terminal.IO.prototype.createFrame=function(url,opt_options){return new hterm.Frame(this.terminal_,url,opt_options);};/**
* Change the preference profile for the terminal.
*
* @param profileName {string} The name of the preference profile to activate.
*/hterm.Terminal.IO.prototype.setTerminalProfile=function(profileName){this.terminal_.setProfile(profileName);};/**
* Create a new hterm.Terminal.IO instance and make it active on the Terminal
* object associated with this instance.
*
* This is used to pass control of the terminal IO off to a subcommand. The
* IO.pop() method can be used to restore control when the subcommand completes.
*/hterm.Terminal.IO.prototype.push=function(){var io=new hterm.Terminal.IO(this.terminal_);io.keyboardCaptured_=this.keyboardCaptured_;io.columnCount=this.columnCount;io.rowCount=this.rowCount;io.previousIO_=this.terminal_.io;this.terminal_.io=io;return io;};/**
* Restore the Terminal's previous IO object.
*
* We'll flush out any queued data.
*/hterm.Terminal.IO.prototype.pop=function(){this.terminal_.io=this.previousIO_;this.previousIO_.flush();};/**
* Flush accumulated data.
*
* If we're not the active IO, the connected process might still be writing
* data to us, but we won't be displaying it. Flush any buffered data now.
*/hterm.Terminal.IO.prototype.flush=function(){if(this.buffered_){this.terminal_.interpret(this.buffered_);this.buffered_='';}};/**
* Called when data needs to be sent to the current command.
*
* Clients should override this to receive notification of pending data.
*
* @param {string} string The data to send.
*/hterm.Terminal.IO.prototype.sendString=function(string){// Override this.
console.log('Unhandled sendString: '+string);};/**
* Called when a terminal keystroke is detected.
*
* Clients should override this to receive notification of keystrokes.
*
* @param {string} string The VT key sequence.
*/hterm.Terminal.IO.prototype.onVTKeystroke=function(string){// Override this.
console.log('Unobserverd VT keystroke: '+JSON.stringify(string));};hterm.Terminal.IO.prototype.onTerminalResize_=function(width,height){var obj=this;while(obj){obj.columnCount=width;obj.rowCount=height;obj=obj.previousIO_;}this.onTerminalResize(width,height);};/**
* Called when terminal size is changed.
*
* Clients should override this to receive notification of resize.
*
* @param {string|integer} terminal width.
* @param {string|integer} terminal height.
*/hterm.Terminal.IO.prototype.onTerminalResize=function(width,height){// Override this.
};/**
* Write a UTF-8 encoded byte string to the terminal.
*
* @param {string} string The UTF-8 encoded string to print.
*/hterm.Terminal.IO.prototype.writeUTF8=function(string){// We can't use instanceof here on string to see if it's an ArrayBuffer as it
// might be constructed in a different runtime context whose ArrayBuffer was
// not the same. See https://crbug.com/930171#5 for more details.
if(typeof string=='string'){if(this.terminal_.characterEncoding!='raw'){var bytes=lib.codec.stringToCodeUnitArray(string,Uint8Array);string=this.textDecoder_.decode(bytes,{stream:true});}}else{// Handle array buffers & typed arrays by normalizing into a typed array.
var u8=new Uint8Array(string);if(this.terminal_.characterEncoding=='raw'){string=lib.codec.codeUnitArrayToString(u8);}else{string=this.textDecoder_.decode(u8,{stream:true});}}this.print(string);};/**
* Write a UTF-8 encoded byte string to the terminal followed by crlf.
*
* @param {string} string The UTF-8 encoded string to print.
*/hterm.Terminal.IO.prototype.writelnUTF8=function(string){this.writeUTF8(string);// We need to use writeUTF8 to make sure we flush the decoder state.
this.writeUTF8('\r\n');};/**
* Write a UTF-16 JavaScript string to the terminal.
*
* @param {string} string The string to print.
*/hterm.Terminal.IO.prototype.print=hterm.Terminal.IO.prototype.writeUTF16=function(string){// If another process has the foreground IO, buffer new data sent to this IO
// (since it's in the background). When we're made the foreground IO again,
// we'll flush everything.
if(this.terminal_.io!=this){this.buffered_+=string;return;}this.terminal_.interpret(string);};/**
* Print a UTF-16 JavaScript string to the terminal followed by a newline.
*
* @param {string} string The string to print.
*/hterm.Terminal.IO.prototype.println=hterm.Terminal.IO.prototype.writelnUTF16=function(string){this.print(string+'\r\n');};// SOURCE FILE: hterm/js/hterm_text_attributes.js
// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* Constructor for TextAttribute objects.
*
* These objects manage a set of text attributes such as foreground/
* background color, bold, faint, italic, blink, underline, and strikethrough.
*
* TextAttribute instances can be used to construct a DOM container implementing
* the current attributes, or to test an existing DOM container for
* compatibility with the current attributes.
*
* @constructor
* @param {HTMLDocument} document The parent document to use when creating
* new DOM containers.
*/hterm.TextAttributes=function(document){this.document_=document;// These variables contain the source of the color as either:
// SRC_DEFAULT (use context default)
// rgb(...) (true color form)
// number (representing the index from color palette to use)
this.foregroundSource=this.SRC_DEFAULT;this.backgroundSource=this.SRC_DEFAULT;this.underlineSource=this.SRC_DEFAULT;// These properties cache the value in the color table, but foregroundSource
// and backgroundSource contain the canonical values.
this.foreground=this.DEFAULT_COLOR;this.background=this.DEFAULT_COLOR;this.underlineColor=this.DEFAULT_COLOR;this.defaultForeground='rgb(255, 255, 255)';this.defaultBackground='rgb(0, 0, 0)';// Any attributes added here that do not default to falsey (e.g. undefined or
// null) require a bit more care. createContainer has to always attach the
// attribute so matchesContainer can work correctly.
this.bold=false;this.faint=false;this.italic=false;this.blink=false;this.underline=false;this.strikethrough=false;this.inverse=false;this.invisible=false;this.wcNode=false;this.asciiNode=true;this.tileData=null;this.uri=null;this.uriId=null;this.colorPalette=null;this.resetColorPalette();};/**
* If false, we ignore the bold attribute.
*
* This is used for fonts that have a bold version that is a different size
* than the normal weight version.
*/hterm.TextAttributes.prototype.enableBold=true;/**
* If true, use bright colors (if available) for bold text.
*
* This setting is independent of the enableBold setting.
*/hterm.TextAttributes.prototype.enableBoldAsBright=true;/**
* A sentinel constant meaning "whatever the default color is in this context".
*/hterm.TextAttributes.prototype.DEFAULT_COLOR=Symbol('DEFAULT_COLOR');/**
* A constant string used to specify that source color is context default.
*/hterm.TextAttributes.prototype.SRC_DEFAULT=Symbol('SRC_DEFAULT');/**
* The document object which should own the DOM nodes created by this instance.
*
* @param {HTMLDocument} document The parent document.
*/hterm.TextAttributes.prototype.setDocument=function(document){this.document_=document;};/**
* Create a deep copy of this object.
*
* @return {hterm.TextAttributes} A deep copy of this object.
*/hterm.TextAttributes.prototype.clone=function(){var rv=new hterm.TextAttributes(null);for(var key in this){rv[key]=this[key];}rv.colorPalette=this.colorPalette.concat();return rv;};/**
* Reset the current set of attributes.
*
* This does not affect the palette. Use resetColorPalette() for that.
* It also doesn't affect the tile data, it's not meant to.
*/hterm.TextAttributes.prototype.reset=function(){this.foregroundSource=this.SRC_DEFAULT;this.backgroundSource=this.SRC_DEFAULT;this.underlineSource=this.SRC_DEFAULT;this.foreground=this.DEFAULT_COLOR;this.background=this.DEFAULT_COLOR;this.underlineColor=this.DEFAULT_COLOR;this.bold=false;this.faint=false;this.italic=false;this.blink=false;this.underline=false;this.strikethrough=false;this.inverse=false;this.invisible=false;this.wcNode=false;this.asciiNode=true;this.uri=null;this.uriId=null;};/**
* Reset the color palette to the default state.
*/hterm.TextAttributes.prototype.resetColorPalette=function(){this.colorPalette=lib.colors.colorPalette.concat();this.syncColors();};/**
* Reset the color.
*
* @param {integer|string} index The color index in the palette to reset.
*/hterm.TextAttributes.prototype.resetColor=function(index){index=parseInt(index,10);if(isNaN(index)||index>=this.colorPalette.length)return;this.colorPalette[index]=lib.colors.stockColorPalette[index];this.syncColors();};/**
* Test if the current attributes describe unstyled text.
*
* @return {boolean} True if the current attributes describe unstyled text.
*/hterm.TextAttributes.prototype.isDefault=function(){return this.foregroundSource==this.SRC_DEFAULT&&this.backgroundSource==this.SRC_DEFAULT&&!this.bold&&!this.faint&&!this.italic&&!this.blink&&!this.underline&&!this.strikethrough&&!this.inverse&&!this.invisible&&!this.wcNode&&this.asciiNode&&this.tileData==null&&this.uri==null;};/**
* Create a DOM container (a span or a text node) with a style to match the
* current set of attributes.
*
* This method will create a plain text node if the text is unstyled, or
* an HTML span if the text is styled. Due to lack of monospace wide character
* fonts on certain systems (e.g. Chrome OS), we need to put each wide character
* in a span of CSS class '.wc-node' which has double column width.
* Each vt_tiledata tile is also represented by a span with a single
* character, with CSS classes '.tile' and '.tile_<glyph number>'.
*
* @param {string} opt_textContent Optional text content for the new container.
* @return {HTMLNode} An HTML span or text nodes styled to match the current
* attributes.
*/hterm.TextAttributes.prototype.createContainer=function(opt_textContent){if(this.isDefault()){// Only attach attributes where we need an explicit default for the
// matchContainer logic below.
var node=this.document_.createTextNode(opt_textContent);node.asciiNode=true;return node;}var span=this.document_.createElement('span');var style=span.style;var classes=[];if(this.foreground!=this.DEFAULT_COLOR)style.color=this.foreground;if(this.background!=this.DEFAULT_COLOR)style.backgroundColor=this.background;if(this.enableBold&&this.bold)style.fontWeight='bold';if(this.faint)span.faint=true;if(this.italic)style.fontStyle='italic';if(this.blink){classes.push('blink-node');span.blinkNode=true;}var textDecorationLine='';span.underline=this.underline;if(this.underline){textDecorationLine+=' underline';style.textDecorationStyle=this.underline;}if(this.underlineColor!=this.DEFAULT_COLOR)style.textDecorationColor=this.underlineColor;if(this.strikethrough){textDecorationLine+=' line-through';span.strikethrough=true;}if(textDecorationLine)style.textDecorationLine=textDecorationLine;if(this.wcNode){classes.push('wc-node');span.wcNode=true;}span.asciiNode=this.asciiNode;if(this.tileData!=null){classes.push('tile');classes.push('tile_'+this.tileData);span.tileNode=true;}if(opt_textContent)span.textContent=opt_textContent;if(this.uri){classes.push('uri-node');span.uriId=this.uriId;span.title=this.uri;span.addEventListener('click',hterm.openUrl.bind(this,this.uri));}if(classes.length)span.className=classes.join(' ');return span;};/**
* Tests if the provided object (string, span or text node) has the same
* style as this TextAttributes instance.
*
* This indicates that text with these attributes could be inserted directly
* into the target DOM node.
*
* For the purposes of this method, a string is considered a text node.
*
* @param {string|HTMLNode} obj The object to test.
* @return {boolean} True if the provided container has the same style as
* this attributes instance.
*/hterm.TextAttributes.prototype.matchesContainer=function(obj){if(typeof obj=='string'||obj.nodeType==Node.TEXT_NODE)return this.isDefault();var style=obj.style;// We don't want to put multiple characters in a wcNode or a tile.
// See the comments in createContainer.
// For attributes that default to false, we do not require that obj have them
// declared, so always normalize them using !! (to turn undefined into false)
// in the compares below.
return!(this.wcNode||obj.wcNode)&&this.asciiNode==obj.asciiNode&&!(this.tileData!=null||obj.tileNode)&&this.uriId==obj.uriId&&this.foreground==this.DEFAULT_COLOR&&style.color==''&&this.background==this.DEFAULT_COLOR&&style.backgroundColor==''&&this.underlineColor==this.DEFAULT_COLOR&&style.textDecorationColor==''&&(this.enableBold&&this.bold)==!!style.fontWeight&&this.blink==!!obj.blinkNode&&this.italic==!!style.fontStyle&&this.underline==obj.underline&&!!this.strikethrough==!!obj.strikethrough;};hterm.TextAttributes.prototype.setDefaults=function(foreground,background){this.defaultForeground=foreground;this.defaultBackground=background;this.syncColors();};/**
* Updates foreground and background properties based on current indices and
* other state.
*
* @param {string} terminalForeground The terminal foreground color for use as
* inverse text background.
* @param {string} terminalBackground The terminal background color for use as
* inverse text foreground.
*
*/hterm.TextAttributes.prototype.syncColors=function(){var _this17=this;function getBrightIndex(i){if(i<8){// If the color is from the lower half of the ANSI 16, add 8.
return i+8;}// If it's not from the 16 color palette, ignore bold requests. This
// matches the behavior of gnome-terminal.
return i;}// Expand the default color as makes sense.
var getDefaultColor=function getDefaultColor(color,defaultColor){return color==_this17.DEFAULT_COLOR?defaultColor:color;};var foregroundSource=this.foregroundSource;var backgroundSource=this.backgroundSource;if(this.enableBoldAsBright&&this.bold){if(Number.isInteger(foregroundSource)){foregroundSource=getBrightIndex(foregroundSource);}}if(foregroundSource==this.SRC_DEFAULT)this.foreground=this.DEFAULT_COLOR;else if(Number.isInteger(foregroundSource))this.foreground=this.colorPalette[foregroundSource];else this.foreground=foregroundSource;if(this.faint){var colorToMakeFaint=getDefaultColor(this.foreground,this.defaultForeground);this.foreground=lib.colors.mix(colorToMakeFaint,'rgb(0, 0, 0)',0.3333);}if(backgroundSource==this.SRC_DEFAULT)this.background=this.DEFAULT_COLOR;else if(Number.isInteger(backgroundSource))this.background=this.colorPalette[backgroundSource];else this.background=backgroundSource;// Once we've processed the bold-as-bright and faint attributes, swap.
// This matches xterm/gnome-terminal.
if(this.inverse){var swp=getDefaultColor(this.foreground,this.defaultForeground);this.foreground=getDefaultColor(this.background,this.defaultBackground);this.background=swp;}// Process invisible settings last to keep it simple.
if(this.invisible)this.foreground=this.background;if(this.underlineSource==this.SRC_DEFAULT)this.underlineColor=this.DEFAULT_COLOR;else if(Number.isInteger(this.underlineSource))this.underlineColor=this.colorPalette[this.underlineSource];else this.underlineColor=this.underlineSource;};/**
* Static method used to test if the provided objects (strings, spans or
* text nodes) have the same style.
*
* For the purposes of this method, a string is considered a text node.
*
* @param {string|HTMLNode} obj1 An object to test.
* @param {string|HTMLNode} obj2 Another object to test.
* @return {boolean} True if the containers have the same style.
*/hterm.TextAttributes.containersMatch=function(obj1,obj2){if(typeof obj1=='string')return hterm.TextAttributes.containerIsDefault(obj2);if(obj1.nodeType!=obj2.nodeType)return false;if(obj1.nodeType==Node.TEXT_NODE)return true;var style1=obj1.style;var style2=obj2.style;return style1.color==style2.color&&style1.backgroundColor==style2.backgroundColor&&style1.backgroundColor==style2.backgroundColor&&style1.fontWeight==style2.fontWeight&&style1.fontStyle==style2.fontStyle&&style1.textDecoration==style2.textDecoration&&style1.textDecorationColor==style2.textDecorationColor&&style1.textDecorationStyle==style2.textDecorationStyle&&style1.textDecorationLine==style2.textDecorationLine;};/**
* Static method to test if a given DOM container represents unstyled text.
*
* For the purposes of this method, a string is considered a text node.
*
* @param {string|HTMLNode} obj1 An object to test.
* @return {boolean} True if the object is unstyled.
*/hterm.TextAttributes.containerIsDefault=function(obj){return typeof obj=='string'||obj.nodeType==Node.TEXT_NODE;};/**
* Static method to get the column width of a node's textContent.
*
* @param {HTMLElement} node The HTML element to get the width of textContent
* from.
* @return {integer} The column width of the node's textContent.
*/hterm.TextAttributes.nodeWidth=function(node){if(!node.asciiNode){return lib.wc.strWidth(node.textContent);}else{return node.textContent.length;}};/**
* Static method to get the substr of a node's textContent. The start index
* and substr width are computed in column width.
*
* @param {HTMLElement} node The HTML element to get the substr of textContent
* from.
* @param {integer} start The starting offset in column width.
* @param {integer} width The width to capture in column width.
* @return {integer} The extracted substr of the node's textContent.
*/hterm.TextAttributes.nodeSubstr=function(node,start,width){if(!node.asciiNode){return lib.wc.substr(node.textContent,start,width);}else{return node.textContent.substr(start,width);}};/**
* Static method to get the substring based of a node's textContent. The
* start index of end index are computed in column width.
*
* @param {HTMLElement} node The HTML element to get the substr of textContent
* from.
* @param {integer} start The starting offset in column width.
* @param {integer} end The ending offset in column width.
* @return {integer} The extracted substring of the node's textContent.
*/hterm.TextAttributes.nodeSubstring=function(node,start,end){if(!node.asciiNode){return lib.wc.substring(node.textContent,start,end);}else{return node.textContent.substring(start,end);}};/**
* Static method to split a string into contiguous runs of single-width
* characters and runs of double-width characters.
*
* @param {string} str The string to split.
* @return {Array} An array of objects that contain substrings of str, where
* each substring is either a contiguous runs of single-width characters
* or a double-width character. For objects that contain a double-width
* character, its wcNode property is set to true. For objects that contain
* only ASCII content, its asciiNode property is set to true.
*/hterm.TextAttributes.splitWidecharString=function(str){var rv=[];var base=0,length=0,wcStrWidth=0,wcCharWidth;var asciiNode=true;for(var i=0;i<str.length;){var c=str.codePointAt(i);var increment;if(c<128){wcStrWidth+=1;length+=1;increment=1;}else{increment=c<=0xffff?1:2;wcCharWidth=lib.wc.charWidth(c);if(wcCharWidth<=1){wcStrWidth+=wcCharWidth;length+=increment;asciiNode=false;}else{if(length){rv.push({str:str.substr(base,length),asciiNode:asciiNode,wcStrWidth:wcStrWidth});asciiNode=true;wcStrWidth=0;}rv.push({str:str.substr(i,increment),wcNode:true,asciiNode:false,wcStrWidth:2});base=i+increment;length=0;}}i+=increment;}if(length){rv.push({str:str.substr(base,length),asciiNode:asciiNode,wcStrWidth:wcStrWidth});}return rv;};// SOURCE FILE: hterm/js/hterm_vt.js
// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* Constructor for the VT escape sequence interpreter.
*
* The interpreter operates on a terminal object capable of performing cursor
* move operations, painting characters, etc.
*
* This interpreter is intended to be compatible with xterm, though it
* ignores some of the more esoteric escape sequences.
*
* Control sequences are documented in hterm/doc/ControlSequences.md.
*
* @param {hterm.Terminal} terminal Terminal to use with the interpreter.
*/hterm.VT=function(terminal){/**
* The display terminal object associated with this virtual terminal.
*/this.terminal=terminal;terminal.onMouse=this.onTerminalMouse_.bind(this);this.mouseReport=this.MOUSE_REPORT_DISABLED;this.mouseCoordinates=this.MOUSE_COORDINATES_X10;// We only want to report mouse moves between cells, not between pixels.
this.lastMouseDragResponse_=null;// Parse state left over from the last parse. You should use the parseState
// instance passed into your parse routine, rather than reading
// this.parseState_ directly.
this.parseState_=new hterm.VT.ParseState(this.parseUnknown_);// Any "leading modifiers" for the escape sequence, such as '?', ' ', or the
// other modifiers handled in this.parseCSI_.
this.leadingModifier_='';// Any "trailing modifiers". Same character set as a leading modifier,
// except these are found after the numeric arguments.
this.trailingModifier_='';// Whether or not to respect the escape codes for setting terminal width.
this.allowColumnWidthChanges_=false;// The amount of time we're willing to wait for the end of an OSC sequence.
this.oscTimeLimit_=20000;/**
* Whether to accept the 8-bit control characters.
*
* An 8-bit control character is one with the eighth bit set. These
* didn't work on 7-bit terminals so they all have two byte equivalents.
* Most hosts still only use the two-byte versions.
*
* We ignore 8-bit control codes by default. This is in order to avoid
* issues with "accidental" usage of codes that need to be terminated.
* The "accident" usually involves cat'ing binary data.
*/this.enable8BitControl=false;/**
* Whether to allow the OSC 52 sequence to write to the system clipboard.
*/this.enableClipboardWrite=true;/**
* Respect the host's attempt to change the cursor blink status using
* the DEC Private mode 12.
*/this.enableDec12=false;/**
* Respect the host's attempt to clear the scrollback buffer using CSI-J-3.
*/this.enableCsiJ3=true;/**
* The expected encoding method for data received from the host.
*/this.characterEncoding='utf-8';/**
* If true, emit warnings when we encounter a control character or escape
* sequence that we don't recognize or explicitly ignore.
*
* We disable this by default as the console logging can be expensive when
* dumping binary files (e.g. `cat /dev/zero`) to the point where you can't
* recover w/out restarting.
*/this.warnUnimplemented=false;/**
* The set of available character maps (used by G0...G3 below).
*/this.characterMaps=new hterm.VT.CharacterMaps();/**
* The default G0...G3 character maps.
* We default to the US/ASCII map everywhere as that aligns with other
* terminals, and it makes it harder to accidentally switch to the graphics
* character map (Ctrl-N). Any program that wants to use the graphics map
* will usually select it anyways since there's no guarantee what state any
* of the maps are in at any particular time.
*/this.G0=this.G1=this.G2=this.G3=this.characterMaps.getMap('B');/**
* The 7-bit visible character set.
*
* This is a mapping from inbound data to display glyph. The GL set
* contains the 94 bytes from 0x21 to 0x7e.
*
* The default GL set is 'B', US ASCII.
*/this.GL='G0';/**
* The 8-bit visible character set.
*
* This is a mapping from inbound data to display glyph. The GR set
* contains the 94 bytes from 0xa1 to 0xfe.
*/this.GR='G0';/**
* The current encoding of the terminal.
*
* We only support ECMA-35 and UTF-8, so go with a boolean here.
* The encoding can be locked too.
*/this.codingSystemUtf8_=false;this.codingSystemLocked_=false;// Construct a regular expression to match the known one-byte control chars.
// This is used in parseUnknown_ to quickly scan a string for the next
// control character.
this.cc1Pattern_=null;this.updateEncodingState_();};/**
* No mouse events.
*/hterm.VT.prototype.MOUSE_REPORT_DISABLED=0;/**
* DECSET mode 9.
*
* Report mouse down events only.
*/hterm.VT.prototype.MOUSE_REPORT_PRESS=1;/**
* DECSET mode 1000.
*
* Report mouse down/up events only.
*/hterm.VT.prototype.MOUSE_REPORT_CLICK=2;/**
* DECSET mode 1002.
*
* Report mouse down/up and movement while a button is down.
*/hterm.VT.prototype.MOUSE_REPORT_DRAG=3;/**
* DEC mode for X10 coorindates (the default).
*/hterm.VT.prototype.MOUSE_COORDINATES_X10=0;/**
* DEC mode 1005 for UTF-8 coorindates.
*/hterm.VT.prototype.MOUSE_COORDINATES_UTF8=1;/**
* DEC mode 1006 for SGR coorindates.
*/hterm.VT.prototype.MOUSE_COORDINATES_SGR=2;/**
* ParseState constructor.
*
* This object tracks the current state of the parse. It has fields for the
* current buffer, position in the buffer, and the parse function.
*
* @param {function} defaultFunc The default parser function.
* @param {string} opt_buf Optional string to use as the current buffer.
*/hterm.VT.ParseState=function(defaultFunction,opt_buf){this.defaultFunction=defaultFunction;this.buf=opt_buf||null;this.pos=0;this.func=defaultFunction;this.args=[];// Whether any of the arguments in the args array have subarguments.
// e.g. All CSI sequences are integer arguments separated by semi-colons,
// so subarguments are further colon separated.
this.subargs=null;};/**
* Reset the parser function, buffer, and position.
*/hterm.VT.ParseState.prototype.reset=function(opt_buf){this.resetParseFunction();this.resetBuf(opt_buf||'');this.resetArguments();};/**
* Reset the parser function only.
*/hterm.VT.ParseState.prototype.resetParseFunction=function(){this.func=this.defaultFunction;};/**
* Reset the buffer and position only.
*
* @param {string} buf Optional new value for buf, defaults to null.
*/hterm.VT.ParseState.prototype.resetBuf=function(opt_buf){this.buf=typeof opt_buf=='string'?opt_buf:null;this.pos=0;};/**
* Reset the arguments list only.
*
* Typically we reset arguments before parsing a sequence that uses them rather
* than always trying to make sure they're in a good state. This can lead to
* confusion during debugging where args from a previous sequence appear to be
* "sticking around" in other sequences (which in reality don't use args).
*
* @param {string} opt_arg_zero Optional initial value for args[0].
*/hterm.VT.ParseState.prototype.resetArguments=function(opt_arg_zero){this.args.length=0;if(typeof opt_arg_zero!='undefined')this.args[0]=opt_arg_zero;};/**
* Parse an argument as an integer.
*
* This assumes the inputs are already in the proper format. e.g. This won't
* handle non-numeric arguments.
*
* An "0" argument is treated the same as "" which means the default value will
* be applied. This is what most terminal sequences expect.
*
* @param {string} argstr The argument to parse directly.
* @param {number=} defaultValue Default value if argstr is empty.
* @return {number} The parsed value.
*/hterm.VT.ParseState.prototype.parseInt=function(argstr,defaultValue){if(defaultValue===undefined)defaultValue=0;if(argstr){var ret=parseInt(argstr,10);// An argument of zero is treated as the default value.
return ret==0?defaultValue:ret;}return defaultValue;};/**
* Get an argument as an integer.
*
* @param {number} argnum The argument number to retrieve.
* @param {number=} defaultValue Default value if the argument is empty.
* @return {number} The parsed value.
*/hterm.VT.ParseState.prototype.iarg=function(argnum,defaultValue){return this.parseInt(this.args[argnum],defaultValue);};/**
* Check whether an argument has subarguments.
*
* @param {number} argnum The argument number to check.
* @return {number} Whether the argument has subarguments.
*/hterm.VT.ParseState.prototype.argHasSubargs=function(argnum){return this.subargs&&this.subargs[argnum];};/**
* Mark an argument as having subarguments.
*
* @param {number} argnum The argument number that has subarguments.
*/hterm.VT.ParseState.prototype.argSetSubargs=function(argnum){if(this.subargs===null)this.subargs={};this.subargs[argnum]=true;};/**
* Advance the parse position.
*
* @param {integer} count The number of bytes to advance.
*/hterm.VT.ParseState.prototype.advance=function(count){this.pos+=count;};/**
* Return the remaining portion of the buffer without affecting the parse
* position.
*
* @return {string} The remaining portion of the buffer.
*/hterm.VT.ParseState.prototype.peekRemainingBuf=function(){return this.buf.substr(this.pos);};/**
* Return the next single character in the buffer without affecting the parse
* position.
*
* @return {string} The next character in the buffer.
*/hterm.VT.ParseState.prototype.peekChar=function(){return this.buf.substr(this.pos,1);};/**
* Return the next single character in the buffer and advance the parse
* position one byte.
*
* @return {string} The next character in the buffer.
*/hterm.VT.ParseState.prototype.consumeChar=function(){return this.buf.substr(this.pos++,1);};/**
* Return true if the buffer is empty, or the position is past the end.
*/hterm.VT.ParseState.prototype.isComplete=function(){return this.buf==null||this.buf.length<=this.pos;};/**
* Reset the VT back to baseline state.
*/hterm.VT.prototype.reset=function(){this.G0=this.G1=this.G2=this.G3=this.characterMaps.getMap('B');this.GL='G0';this.GR='G0';this.mouseReport=this.MOUSE_REPORT_DISABLED;this.mouseCoordinates=this.MOUSE_COORDINATES_X10;this.lastMouseDragResponse_=null;};/**
* Handle terminal mouse events.
*
* See the "Mouse Tracking" section of [xterm].
*/hterm.VT.prototype.onTerminalMouse_=function(e){// Short circuit a few events to avoid unnecessary processing.
if(this.mouseReport==this.MOUSE_REPORT_DISABLED)return;else if(this.mouseReport!=this.MOUSE_REPORT_DRAG&&e.type=='mousemove')return;// Temporary storage for our response.
var response;// Modifier key state.
var mod=0;if(this.mouseReport!=this.MOUSE_REPORT_PRESS){if(e.shiftKey)mod|=4;if(e.metaKey||this.terminal.keyboard.altIsMeta&&e.altKey)mod|=8;if(e.ctrlKey)mod|=16;}// X & Y coordinate reporting.
var x;var y;// Normally X10 has a limit of 255, but since we only want to emit UTF-8 valid
// streams, we limit ourselves to 127 to avoid setting the 8th bit. If we do
// re-enable this, we should re-enable the hterm_vt_tests.js too.
var limit=127;switch(this.mouseCoordinates){case this.MOUSE_COORDINATES_UTF8:// UTF-8 mode is the same as X10 but with higher limits.
limit=2047;case this.MOUSE_COORDINATES_X10:// X10 reports coordinates by encoding into strings.
x=String.fromCharCode(lib.f.clamp(e.terminalColumn+32,32,limit));y=String.fromCharCode(lib.f.clamp(e.terminalRow+32,32,limit));break;case this.MOUSE_COORDINATES_SGR:// SGR reports coordinates by transmitting the numbers directly.
x=e.terminalColumn;y=e.terminalRow;break;}switch(e.type){case'wheel':// Mouse wheel is treated as button 1 or 2 plus an additional 64.
b=(e.deltaY*-1>0?0:1)+64;b|=mod;if(this.mouseCoordinates==this.MOUSE_COORDINATES_SGR){response="\x1B[<".concat(b,";").concat(x,";").concat(y,"M");}else{// X10 based modes (including UTF8) add 32 for legacy encoding reasons.
response='\x1b[M'+String.fromCharCode(b+32)+x+y;}// Keep the terminal from scrolling.
e.preventDefault();break;case'mousedown':// Buttons are encoded as button number.
var b=Math.min(e.button,2);// X10 based modes (including UTF8) add 32 for legacy encoding reasons.
if(this.mouseCoordinates!=this.MOUSE_COORDINATES_SGR)b+=32;// And mix in the modifier keys.
b|=mod;if(this.mouseCoordinates==this.MOUSE_COORDINATES_SGR)response="\x1B[<".concat(b,";").concat(x,";").concat(y,"M");else response='\x1b[M'+String.fromCharCode(b)+x+y;break;case'mouseup':if(this.mouseReport!=this.MOUSE_REPORT_PRESS){if(this.mouseCoordinates==this.MOUSE_COORDINATES_SGR){// SGR mode can report the released button.
response="\x1B[<".concat(e.button,";").concat(x,";").concat(y,"m");}else{// X10 mode has no indication of which button was released.
response='\x1b[M\x23'+x+y;}}break;case'mousemove':if(this.mouseReport==this.MOUSE_REPORT_DRAG&&e.buttons){// Standard button bits. The XTerm protocol only reports the first
// button press (e.g. if left & right are pressed, right is ignored),
// and it only supports the first three buttons. If none of them are
// pressed, then XTerm flags it as a release. We'll do the same.
// X10 based modes (including UTF8) add 32 for legacy encoding reasons.
b=this.mouseCoordinates==this.MOUSE_COORDINATES_SGR?0:32;// Priority here matches XTerm: left, middle, right.
if(e.buttons&0x1){// Report left button.
b+=0;}else if(e.buttons&0x4){// Report middle button.
b+=1;}else if(e.buttons&0x2){// Report right button.
b+=2;}else{// Release higher buttons.
b+=3;}// Add 32 to indicate mouse motion.
b+=32;// And mix in the modifier keys.
b|=mod;if(this.mouseCoordinates==this.MOUSE_COORDINATES_SGR)response="\x1B[<".concat(b,";").concat(x,";").concat(y,"M");else response='\x1b[M'+String.fromCharCode(b)+x+y;// If we were going to report the same cell because we moved pixels
// within, suppress the report. This is what xterm does and cuts
// down on duplicate messages.
if(this.lastMouseDragResponse_==response)response='';else this.lastMouseDragResponse_=response;}break;case'click':case'dblclick':break;default:console.error('Unknown mouse event: '+e.type,e);break;}if(response)this.terminal.io.sendString(response);};/**
* Interpret a string of characters, displaying the results on the associated
* terminal object.
*
* The buffer will be decoded according to the 'receive-encoding' preference.
*/hterm.VT.prototype.interpret=function(buf){this.parseState_.resetBuf(buf);while(!this.parseState_.isComplete()){var func=this.parseState_.func;var pos=this.parseState_.pos;var buf=this.parseState_.buf;this.parseState_.func.call(this,this.parseState_);if(this.parseState_.func==func&&this.parseState_.pos==pos&&this.parseState_.buf==buf){throw'Parser did not alter the state!';}}};/**
* Set the encoding of the terminal.
*
* @param {string} encoding The name of the encoding to set.
*/hterm.VT.prototype.setEncoding=function(encoding){switch(encoding){default:console.warn('Invalid value for "terminal-encoding": '+encoding);// Fall through.
case'iso-2022':this.codingSystemUtf8_=false;this.codingSystemLocked_=false;break;case'utf-8-locked':this.codingSystemUtf8_=true;this.codingSystemLocked_=true;break;case'utf-8':this.codingSystemUtf8_=true;this.codingSystemLocked_=false;break;}this.updateEncodingState_();};/**
* Refresh internal state when the encoding changes.
*/hterm.VT.prototype.updateEncodingState_=function(){var _this18=this;// If we're in UTF8 mode, don't suport 8-bit escape sequences as we'll never
// see those -- everything should be UTF8!
var cc1=Object.keys(hterm.VT.CC1).filter(function(e){return!_this18.codingSystemUtf8_||e.charCodeAt()<0x80;}).map(function(e){return'\\x'+lib.f.zpad(e.charCodeAt().toString(16),2);}).join('');this.cc1Pattern_=new RegExp("[".concat(cc1,"]"));};/**
* The default parse function.
*
* This will scan the string for the first 1-byte control character (C0/C1
* characters from [CTRL]). Any plain text coming before the code will be
* printed to the terminal, then the control character will be dispatched.
*/hterm.VT.prototype.parseUnknown_=function(parseState){var self=this;function print(str){if(!self.codingSystemUtf8_&&self[self.GL].GL)str=self[self.GL].GL(str);self.terminal.print(str);}// Search for the next contiguous block of plain text.
var buf=parseState.peekRemainingBuf();var nextControl=buf.search(this.cc1Pattern_);if(nextControl==0){// We've stumbled right into a control character.
this.dispatch('CC1',buf.substr(0,1),parseState);parseState.advance(1);return;}if(nextControl==-1){// There are no control characters in this string.
print(buf);parseState.reset();return;}print(buf.substr(0,nextControl));this.dispatch('CC1',buf.substr(nextControl,1),parseState);parseState.advance(nextControl+1);};/**
* Parse a Control Sequence Introducer code and dispatch it.
*
* See [CSI] for some useful information about these codes.
*/hterm.VT.prototype.parseCSI_=function(parseState){var ch=parseState.peekChar();var args=parseState.args;var finishParsing=function finishParsing(){// Resetting the arguments isn't strictly necessary, but it makes debugging
// less confusing (otherwise args will stick around until the next sequence
// that needs arguments).
parseState.resetArguments();// We need to clear subargs since we explicitly set it.
parseState.subargs=null;parseState.resetParseFunction();};if(ch>='@'&&ch<='~'){// This is the final character.
this.dispatch('CSI',this.leadingModifier_+this.trailingModifier_+ch,parseState);finishParsing();}else if(ch==';'){// Parameter delimiter.
if(this.trailingModifier_){// Parameter delimiter after the trailing modifier. That's a paddlin'.
finishParsing();}else{if(!args.length){// They omitted the first param, we need to supply it.
args.push('');}args.push('');}}else if(ch>='0'&&ch<='9'||ch==':'){// Next byte in the current parameter.
if(this.trailingModifier_){// Numeric parameter after the trailing modifier. That's a paddlin'.
finishParsing();}else{if(!args.length){args[0]=ch;}else{args[args.length-1]+=ch;}// Possible sub-parameters.
if(ch==':')parseState.argSetSubargs(args.length-1);}}else if(ch>=' '&&ch<='?'){// Modifier character.
if(!args.length){this.leadingModifier_+=ch;}else{this.trailingModifier_+=ch;}}else if(this.cc1Pattern_.test(ch)){// Control character.
this.dispatch('CC1',ch,parseState);}else{// Unexpected character in sequence, bail out.
finishParsing();}parseState.advance(1);};/**
* Skip over the string until the next String Terminator (ST, 'ESC \') or
* Bell (BEL, '\x07').
*
* The string is accumulated in parseState.args[0]. Make sure to reset the
* arguments (with parseState.resetArguments) before starting the parse.
*
* You can detect that parsing in complete by checking that the parse
* function has changed back to the default parse function.
*
* @return {boolean} If true, parsing is ongoing or complete. If false, we've
* exceeded the max string sequence.
*/hterm.VT.prototype.parseUntilStringTerminator_=function(parseState){var buf=parseState.peekRemainingBuf();var args=parseState.args;// Since we might modify parse state buffer locally, if we want to advance
// the parse state buffer later on, we need to know how many chars we added.
var bufInserted=0;if(!args.length){args[0]='';args[1]=new Date();}else{// If our saved buffer ends with an escape, it's because we were hoping
// it's an ST split across two buffers. Move it from our saved buffer
// to the start of our current buffer for processing anew.
if(args[0].slice(-1)=='\x1b'){args[0]=args[0].slice(0,-1);buf='\x1b'+buf;bufInserted=1;}}var nextTerminator=buf.search(/[\x1b\x07]/);var terminator=buf[nextTerminator];var foundTerminator;// If the next escape we see is not a start of a ST, fall through. This will
// either be invalid (embedded escape), or we'll queue it up (wait for \\).
if(terminator=='\x1b'&&buf[nextTerminator+1]!='\\')foundTerminator=false;else foundTerminator=nextTerminator!=-1;if(!foundTerminator){// No terminator here, have to wait for the next string.
args[0]+=buf;var abortReason;// Special case: If our buffering happens to split the ST (\e\\), we have to
// buffer the content temporarily. So don't reject a trailing escape here,
// instead we let it timeout or be rejected in the next pass.
if(terminator=='\x1b'&&nextTerminator!=buf.length-1)abortReason='embedded escape: '+nextTerminator;if(new Date()-args[1]>this.oscTimeLimit_)abortReason='timeout expired: '+(new Date()-args[1]);if(abortReason){if(this.warnUnimplemented)console.log('parseUntilStringTerminator_: aborting: '+abortReason,args[0]);parseState.reset(args[0]);return false;}parseState.advance(buf.length-bufInserted);return true;}args[0]+=buf.substr(0,nextTerminator);parseState.resetParseFunction();parseState.advance(nextTerminator+(terminator=='\x1b'?2:1)-bufInserted);return true;};/**
* Dispatch to the function that handles a given CC1, ESC, or CSI or VT52 code.
*/hterm.VT.prototype.dispatch=function(type,code,parseState){var handler=hterm.VT[type][code];if(!handler){if(this.warnUnimplemented)console.warn('Unknown '+type+' code: '+JSON.stringify(code));return;}if(handler==hterm.VT.ignore){if(this.warnUnimplemented)console.warn('Ignored '+type+' code: '+JSON.stringify(code));return;}if(parseState.subargs&&!handler.supportsSubargs){if(this.warnUnimplemented)console.warn('Ignored '+type+' code w/subargs: '+JSON.stringify(code));return;}if(type=='CC1'&&code>'\x7f'&&!this.enable8BitControl){// It's kind of a hack to put this here, but...
//
// If we're dispatching a 'CC1' code, and it's got the eighth bit set,
// but we're not supposed to handle 8-bit codes? Just ignore it.
//
// This prevents an errant (DCS, '\x90'), (OSC, '\x9d'), (PM, '\x9e') or
// (APC, '\x9f') from locking up the terminal waiting for its expected
// (ST, '\x9c') or (BEL, '\x07').
console.warn('Ignoring 8-bit control code: 0x'+code.charCodeAt(0).toString(16));return;}handler.apply(this,[parseState,code]);};/**
* Set one of the ANSI defined terminal mode bits.
*
* Invoked in response to SM/RM.
*
* Unexpected and unimplemented values are silently ignored.
*/hterm.VT.prototype.setANSIMode=function(code,state){if(code==4){// Insert Mode (IRM)
this.terminal.setInsertMode(state);}else if(code==20){// Automatic Newline (LNM)
this.terminal.setAutoCarriageReturn(state);}else if(this.warnUnimplemented){console.warn('Unimplemented ANSI Mode: '+code);}};/**
* Set or reset one of the DEC Private modes.
*
* Invoked in response to DECSET/DECRST.
*/hterm.VT.prototype.setDECMode=function(code,state){switch(parseInt(code,10)){case 1:// DECCKM
this.terminal.keyboard.applicationCursor=state;break;case 3:// DECCOLM
if(this.allowColumnWidthChanges_){this.terminal.setWidth(state?132:80);this.terminal.clearHome();this.terminal.setVTScrollRegion(null,null);}break;case 5:// DECSCNM
this.terminal.setReverseVideo(state);break;case 6:// DECOM
this.terminal.setOriginMode(state);break;case 7:// DECAWM
this.terminal.setWraparound(state);break;case 9:// Report on mouse down events only (X10).
this.mouseReport=state?this.MOUSE_REPORT_PRESS:this.MOUSE_REPORT_DISABLED;this.terminal.syncMouseStyle();break;case 12:// Start blinking cursor
if(this.enableDec12)this.terminal.setCursorBlink(state);break;case 25:// DECTCEM
this.terminal.setCursorVisible(state);break;case 30:// Show scrollbar
this.terminal.setScrollbarVisible(state);break;case 40:// Allow 80 - 132 (DECCOLM) Mode
this.terminal.allowColumnWidthChanges_=state;break;case 45:// Reverse-wraparound Mode
this.terminal.setReverseWraparound(state);break;case 67:// Backarrow key sends backspace (DECBKM)
this.terminal.keyboard.backspaceSendsBackspace=state;break;case 1000:// Report on mouse clicks only (X11).
this.mouseReport=state?this.MOUSE_REPORT_CLICK:this.MOUSE_REPORT_DISABLED;this.terminal.syncMouseStyle();break;case 1002:// Report on mouse clicks and drags
this.mouseReport=state?this.MOUSE_REPORT_DRAG:this.MOUSE_REPORT_DISABLED;this.terminal.syncMouseStyle();break;case 1004:// Report on window focus change.
this.terminal.reportFocus=state;break;case 1005:// Extended coordinates in UTF-8 mode.
this.mouseCoordinates=state?this.MOUSE_COORDINATES_UTF8:this.MOUSE_COORDINATES_X10;break;case 1006:// Extended coordinates in SGR mode.
this.mouseCoordinates=state?this.MOUSE_COORDINATES_SGR:this.MOUSE_COORDINATES_X10;break;case 1007:// Enable Alternate Scroll Mode.
this.terminal.scrollWheelArrowKeys_=state;break;case 1010:// Scroll to bottom on tty output
this.terminal.scrollOnOutput=state;break;case 1011:// Scroll to bottom on key press
this.terminal.scrollOnKeystroke=state;break;case 1036:// Send ESC when Meta modifies a key
this.terminal.keyboard.metaSendsEscape=state;break;case 1039:// Send ESC when Alt modifies a key
if(state){if(!this.terminal.keyboard.previousAltSendsWhat_){this.terminal.keyboard.previousAltSendsWhat_=this.terminal.keyboard.altSendsWhat;this.terminal.keyboard.altSendsWhat='escape';}}else if(this.terminal.keyboard.previousAltSendsWhat_){this.terminal.keyboard.altSendsWhat=this.terminal.keyboard.previousAltSendsWhat_;this.terminal.keyboard.previousAltSendsWhat_=null;}break;case 47:// Use Alternate Screen Buffer
case 1047:this.terminal.setAlternateMode(state);break;case 1048:// Save cursor as in DECSC.
if(state)this.terminal.saveCursorAndState();else this.terminal.restoreCursorAndState();break;case 1049:// 1047 + 1048 + clear.
if(state){this.terminal.saveCursorAndState();this.terminal.setAlternateMode(state);this.terminal.clear();}else{this.terminal.setAlternateMode(state);this.terminal.restoreCursorAndState();}break;case 2004:// Bracketed paste mode.
this.terminal.setBracketedPaste(state);break;default:if(this.warnUnimplemented)console.warn('Unimplemented DEC Private Mode: '+code);break;}};/**
* Function shared by control characters and escape sequences that are
* ignored.
*/hterm.VT.ignore=function(){};/**
* Collection of control characters expressed in a single byte.
*
* This includes the characters from the C0 and C1 sets (see [CTRL]) that we
* care about. Two byte versions of the C1 codes are defined in the
* hterm.VT.ESC collection.
*
* The 'CC1' mnemonic here refers to the fact that these are one-byte Control
* Codes. It's only used in this source file and not defined in any of the
* referenced documents.
*/hterm.VT.CC1={};/**
* Collection of two-byte and three-byte sequences starting with ESC.
*/hterm.VT.ESC={};/**
* Collection of CSI (Control Sequence Introducer) sequences.
*
* These sequences begin with 'ESC [', and may take zero or more arguments.
*/hterm.VT.CSI={};/**
* Collection of OSC (Operating System Control) sequences.
*
* These sequences begin with 'ESC ]', followed by a function number and a
* string terminated by either ST or BEL.
*/hterm.VT.OSC={};/**
* Collection of VT52 sequences.
*
* When in VT52 mode, other sequences are disabled.
*/hterm.VT.VT52={};/**
* Null (NUL).
*
* Silently ignored.
*/hterm.VT.CC1['\x00']=hterm.VT.ignore;/**
* Enquiry (ENQ).
*
* Transmit answerback message.
*
* The default answerback message in xterm is an empty string, so we just
* ignore this.
*/hterm.VT.CC1['\x05']=hterm.VT.ignore;/**
* Ring Bell (BEL).
*/hterm.VT.CC1['\x07']=function(){this.terminal.ringBell();};/**
* Backspace (BS).
*
* Move the cursor to the left one character position, unless it is at the
* left margin, in which case no action occurs.
*/hterm.VT.CC1['\x08']=function(){this.terminal.cursorLeft(1);};/**
* Horizontal Tab (HT).
*
* Move the cursor to the next tab stop, or to the right margin if no further
* tab stops are present on the line.
*/hterm.VT.CC1['\x09']=function(){this.terminal.forwardTabStop();};/**
* Line Feed (LF).
*
* This code causes a line feed or a new line operation. See Automatic
* Newline (LNM).
*/hterm.VT.CC1['\x0a']=function(){this.terminal.formFeed();};/**
* Vertical Tab (VT).
*
* Interpreted as LF.
*/hterm.VT.CC1['\x0b']=hterm.VT.CC1['\x0a'];/**
* Form Feed (FF).
*
* Interpreted as LF.
*/hterm.VT.CC1['\x0c']=hterm.VT.CC1['\x0a'];/**
* Carriage Return (CR).
*
* Move cursor to the left margin on the current line.
*/hterm.VT.CC1['\x0d']=function(){this.terminal.setCursorColumn(0);};/**
* Shift Out (SO), aka Lock Shift 0 (LS1).
*
* Invoke G1 character set in GL.
*/hterm.VT.CC1['\x0e']=function(){this.GL='G1';};/**
* Shift In (SI), aka Lock Shift 0 (LS0).
*
* Invoke G0 character set in GL.
*/hterm.VT.CC1['\x0f']=function(){this.GL='G0';};/**
* Transmit On (XON).
*
* Not currently implemented.
*
* TODO(rginda): Implement?
*/hterm.VT.CC1['\x11']=hterm.VT.ignore;/**
* Transmit Off (XOFF).
*
* Not currently implemented.
*
* TODO(rginda): Implement?
*/hterm.VT.CC1['\x13']=hterm.VT.ignore;/**
* Cancel (CAN).
*
* If sent during a control sequence, the sequence is immediately terminated
* and not executed.
*
* It also causes the error character to be displayed.
*/hterm.VT.CC1['\x18']=function(parseState){// If we've shifted in the G1 character set, shift it back out to
// the default character set.
if(this.GL=='G1'){this.GL='G0';}parseState.resetParseFunction();this.terminal.print('?');};/**
* Substitute (SUB).
*
* Interpreted as CAN.
*/hterm.VT.CC1['\x1a']=hterm.VT.CC1['\x18'];/**
* Escape (ESC).
*/hterm.VT.CC1['\x1b']=function(parseState){function parseESC(parseState){var ch=parseState.consumeChar();if(ch=='\x1b')return;this.dispatch('ESC',ch,parseState);if(parseState.func==parseESC)parseState.resetParseFunction();}parseState.func=parseESC;};/**
* Delete (DEL).
*/hterm.VT.CC1['\x7f']=hterm.VT.ignore;// 8 bit control characters and their two byte equivalents, below...
/**
* Index (IND).
*
* Like newline, only keep the X position
*/hterm.VT.CC1['\x84']=hterm.VT.ESC['D']=function(){this.terminal.lineFeed();};/**
* Next Line (NEL).
*
* Like newline, but doesn't add lines.
*/hterm.VT.CC1['\x85']=hterm.VT.ESC['E']=function(){this.terminal.setCursorColumn(0);this.terminal.cursorDown(1);};/**
* Horizontal Tabulation Set (HTS).
*/hterm.VT.CC1['\x88']=hterm.VT.ESC['H']=function(){this.terminal.setTabStop(this.terminal.getCursorColumn());};/**
* Reverse Index (RI).
*
* Move up one line.
*/hterm.VT.CC1['\x8d']=hterm.VT.ESC['M']=function(){this.terminal.reverseLineFeed();};/**
* Single Shift 2 (SS2).
*
* Select of G2 Character Set for the next character only.
*
* Not currently implemented.
*/hterm.VT.CC1['\x8e']=hterm.VT.ESC['N']=hterm.VT.ignore;/**
* Single Shift 3 (SS3).
*
* Select of G3 Character Set for the next character only.
*
* Not currently implemented.
*/hterm.VT.CC1['\x8f']=hterm.VT.ESC['O']=hterm.VT.ignore;/**
* Device Control String (DCS).
*
* Indicate a DCS sequence. See Device-Control functions in [XTERM].
* Not currently implemented.
*
* TODO(rginda): Consider implementing DECRQSS, the rest don't seem applicable.
*/hterm.VT.CC1['\x90']=hterm.VT.ESC['P']=function(parseState){parseState.resetArguments();parseState.func=this.parseUntilStringTerminator_;};/**
* Start of Guarded Area (SPA).
*
* Will not implement.
*/hterm.VT.CC1['\x96']=hterm.VT.ESC['V']=hterm.VT.ignore;/**
* End of Guarded Area (EPA).
*
* Will not implement.
*/hterm.VT.CC1['\x97']=hterm.VT.ESC['W']=hterm.VT.ignore;/**
* Start of String (SOS).
*
* Will not implement.
*/hterm.VT.CC1['\x98']=hterm.VT.ESC['X']=hterm.VT.ignore;/**
* Single Character Introducer (SCI, also DECID).
*
* Return Terminal ID. Obsolete form of 'ESC [ c' (DA).
*/hterm.VT.CC1['\x9a']=hterm.VT.ESC['Z']=function(){this.terminal.io.sendString('\x1b[?1;2c');};/**
* Control Sequence Introducer (CSI).
*
* The lead into most escape sequences. See [CSI].
*/hterm.VT.CC1['\x9b']=hterm.VT.ESC['[']=function(parseState){parseState.resetArguments();this.leadingModifier_='';this.trailingModifier_='';parseState.func=this.parseCSI_;};/**
* String Terminator (ST).
*
* Used to terminate DCS/OSC/PM/APC commands which may take string arguments.
*
* We don't directly handle it here, as it's only used to terminate other
* sequences. See the 'parseUntilStringTerminator_' method.
*/hterm.VT.CC1['\x9c']=hterm.VT.ESC['\\']=hterm.VT.ignore;/**
* Operating System Command (OSC).
*
* Commands relating to the operating system.
*/hterm.VT.CC1['\x9d']=hterm.VT.ESC[']']=function(parseState){parseState.resetArguments();function parseOSC(parseState){if(!this.parseUntilStringTerminator_(parseState)){// The string sequence was too long.
return;}if(parseState.func==parseOSC){// We're not done parsing the string yet.
return;}// We're done.
var ary=parseState.args[0].match(/^(\d+);?(.*)$/);if(ary){parseState.args[0]=ary[2];this.dispatch('OSC',ary[1],parseState);}else{console.warn('Invalid OSC: '+JSON.stringify(parseState.args[0]));}// Resetting the arguments isn't strictly necessary, but it makes debugging
// less confusing (otherwise args will stick around until the next sequence
// that needs arguments).
parseState.resetArguments();}parseState.func=parseOSC;};/**
* Privacy Message (PM).
*
* Will not implement.
*/hterm.VT.CC1['\x9e']=hterm.VT.ESC['^']=function(parseState){parseState.resetArguments();parseState.func=this.parseUntilStringTerminator_;};/**
* Application Program Control (APC).
*
* Will not implement.
*/hterm.VT.CC1['\x9f']=hterm.VT.ESC['_']=function(parseState){parseState.resetArguments();parseState.func=this.parseUntilStringTerminator_;};/**
* ESC \x20 - Unclear to me where these originated, possibly in xterm.
*
* Not currently implemented:
* ESC \x20 F - Select 7 bit escape codes in responses (S7C1T).
* ESC \x20 G - Select 8 bit escape codes in responses (S8C1T).
* NB: We currently assume S7C1T always.
*
* Will not implement:
* ESC \x20 L - Set ANSI conformance level 1.
* ESC \x20 M - Set ANSI conformance level 2.
* ESC \x20 N - Set ANSI conformance level 3.
*/hterm.VT.ESC['\x20']=function(parseState){parseState.func=function(parseState){var ch=parseState.consumeChar();if(this.warnUnimplemented)console.warn('Unimplemented sequence: ESC 0x20 '+ch);parseState.resetParseFunction();};};/**
* DEC 'ESC #' sequences.
*/hterm.VT.ESC['#']=function(parseState){parseState.func=function(parseState){var ch=parseState.consumeChar();if(ch=='8'){// DEC Screen Alignment Test (DECALN).
this.terminal.setCursorPosition(0,0);this.terminal.fill('E');}parseState.resetParseFunction();};};/**
* Designate Other Coding System (DOCS).
*/hterm.VT.ESC['%']=function(parseState){parseState.func=function(parseState){var ch=parseState.consumeChar();// If we've locked the encoding, then just eat the bytes and return.
if(this.codingSystemLocked_){if(ch=='/')parseState.consumeChar();parseState.resetParseFunction();return;}// Process the encoding requests.
switch(ch){case'@':// Switch to ECMA 35.
this.setEncoding('iso-2022');break;case'G':// Switch to UTF-8.
this.setEncoding('utf-8');break;case'/':// One way transition to something else.
ch=parseState.consumeChar();switch(ch){case'G':// UTF-8 Level 1.
case'H':// UTF-8 Level 2.
case'I':// UTF-8 Level 3.
// We treat all UTF-8 levels the same.
this.setEncoding('utf-8-locked');break;default:if(this.warnUnimplemented)console.warn('Unknown ESC % / argument: '+JSON.stringify(ch));break;}break;default:if(this.warnUnimplemented)console.warn('Unknown ESC % argument: '+JSON.stringify(ch));break;}parseState.resetParseFunction();};};/**
* Character Set Selection (SCS).
*
* ESC ( Ps - Set G0 character set (VT100).
* ESC ) Ps - Set G1 character set (VT220).
* ESC * Ps - Set G2 character set (VT220).
* ESC + Ps - Set G3 character set (VT220).
* ESC - Ps - Set G1 character set (VT300).
* ESC . Ps - Set G2 character set (VT300).
* ESC / Ps - Set G3 character set (VT300).
*
* All other sequences are echoed to the terminal.
*/hterm.VT.ESC['(']=hterm.VT.ESC[')']=hterm.VT.ESC['*']=hterm.VT.ESC['+']=hterm.VT.ESC['-']=hterm.VT.ESC['.']=hterm.VT.ESC['/']=function(parseState,code){parseState.func=function(parseState){var ch=parseState.consumeChar();if(ch=='\x1b'){parseState.resetParseFunction();parseState.func();return;}var map=this.characterMaps.getMap(ch);if(map!==undefined){if(code=='('){this.G0=map;}else if(code==')'||code=='-'){this.G1=map;}else if(code=='*'||code=='.'){this.G2=map;}else if(code=='+'||code=='/'){this.G3=map;}}else if(this.warnUnimplemented){console.log('Invalid character set for "'+code+'": '+ch);}parseState.resetParseFunction();};};/**
* Back Index (DECBI).
*
* VT420 and up. Not currently implemented.
*/hterm.VT.ESC['6']=hterm.VT.ignore;/**
* Save Cursor (DECSC).
*/hterm.VT.ESC['7']=function(){this.terminal.saveCursorAndState();};/**
* Restore Cursor (DECRC).
*/hterm.VT.ESC['8']=function(){this.terminal.restoreCursorAndState();};/**
* Forward Index (DECFI).
*
* VT210 and up. Not currently implemented.
*/hterm.VT.ESC['9']=hterm.VT.ignore;/**
* Application keypad (DECKPAM).
*/hterm.VT.ESC['=']=function(){this.terminal.keyboard.applicationKeypad=true;};/**
* Normal keypad (DECKPNM).
*/hterm.VT.ESC['>']=function(){this.terminal.keyboard.applicationKeypad=false;};/**
* Cursor to lower left corner of screen.
*
* Will not implement.
*
* This is only recognized by xterm when the hpLowerleftBugCompat resource is
* set.
*/hterm.VT.ESC['F']=hterm.VT.ignore;/**
* Full Reset (RIS).
*/hterm.VT.ESC['c']=function(){this.terminal.reset();};/**
* Memory lock/unlock.
*
* Will not implement.
*/hterm.VT.ESC['l']=hterm.VT.ESC['m']=hterm.VT.ignore;/**
* Lock Shift 2 (LS2)
*
* Invoke the G2 Character Set as GL.
*/hterm.VT.ESC['n']=function(){this.GL='G2';};/**
* Lock Shift 3 (LS3)
*
* Invoke the G3 Character Set as GL.
*/hterm.VT.ESC['o']=function(){this.GL='G3';};/**
* Lock Shift 2, Right (LS3R)
*
* Invoke the G3 Character Set as GR.
*/hterm.VT.ESC['|']=function(){this.GR='G3';};/**
* Lock Shift 2, Right (LS2R)
*
* Invoke the G2 Character Set as GR.
*/hterm.VT.ESC['}']=function(){this.GR='G2';};/**
* Lock Shift 1, Right (LS1R)
*
* Invoke the G1 Character Set as GR.
*/hterm.VT.ESC['~']=function(){this.GR='G1';};/**
* Change icon name and window title.
*
* We only change the window title.
*/hterm.VT.OSC['0']=function(parseState){this.terminal.setWindowTitle(parseState.args[0]);};/**
* Change window title.
*/hterm.VT.OSC['2']=hterm.VT.OSC['0'];/**
* Set/read color palette.
*/hterm.VT.OSC['4']=function(parseState){// Args come in as a single 'index1;rgb1 ... ;indexN;rgbN' string.
// We split on the semicolon and iterate through the pairs.
var args=parseState.args[0].split(';');var pairCount=parseInt(args.length/2);var colorPalette=this.terminal.getTextAttributes().colorPalette;var responseArray=[];for(var pairNumber=0;pairNumber<pairCount;++pairNumber){var colorIndex=parseInt(args[pairNumber*2]);var colorValue=args[pairNumber*2+1];if(colorIndex>=colorPalette.length)continue;if(colorValue=='?'){// '?' means we should report back the current color value.
colorValue=lib.colors.rgbToX11(colorPalette[colorIndex]);if(colorValue)responseArray.push(colorIndex+';'+colorValue);continue;}colorValue=lib.colors.x11ToCSS(colorValue);if(colorValue)colorPalette[colorIndex]=colorValue;}if(responseArray.length)this.terminal.io.sendString('\x1b]4;'+responseArray.join(';')+'\x07');};/**
* Hyperlinks.
*
* The first argument is optional and colon separated:
* id=<id>
* The second argument is the link itself.
*
* Calling with a non-blank URI starts it. A blank URI stops it.
*
* https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda
*/hterm.VT.OSC['8']=function(parseState){var args=parseState.args[0].split(';');var id=null;var uri=null;if(args.length!=2||args[1].length==0){// Reset link.
}else{// Pull out any colon separated parameters in the first argument.
var params=args[0].split(':');id='';params.forEach(function(param){var idx=param.indexOf('=');if(idx==-1)return;var key=param.slice(0,idx);var value=param.slice(idx+1);switch(key){case'id':id=value;break;default:// Ignore unknown keys.
break;}});// The URI is in the second argument.
uri=args[1];}var attrs=this.terminal.getTextAttributes();attrs.uri=uri;attrs.uriId=id;};/**
* iTerm2 growl notifications.
*/hterm.VT.OSC['9']=function(parseState){// This just dumps the entire string as the message.
hterm.notify({'body':parseState.args[0]});};/**
* Change VT100 text foreground color.
*/hterm.VT.OSC['10']=function(parseState){// Args come in as a single string, but extra args will chain to the following
// OSC sequences.
var args=parseState.args[0].split(';');if(!args)return;var colorArg;var colorX11=lib.colors.x11ToCSS(args.shift());if(colorX11)this.terminal.setForegroundColor(colorX11);if(args.length>0){parseState.args[0]=args.join(';');hterm.VT.OSC['11'].apply(this,[parseState]);}};/**
* Change VT100 text background color.
*/hterm.VT.OSC['11']=function(parseState){// Args come in as a single string, but extra args will chain to the following
// OSC sequences.
var args=parseState.args[0].split(';');if(!args)return;var colorArg;var colorX11=lib.colors.x11ToCSS(args.shift());if(colorX11)this.terminal.setBackgroundColor(colorX11);if(args.length>0){parseState.args[0]=args.join(';');hterm.VT.OSC['12'].apply(this,[parseState]);}};/**
* Change text cursor color.
*/hterm.VT.OSC['12']=function(parseState){// Args come in as a single string, but extra args will chain to the following
// OSC sequences.
var args=parseState.args[0].split(';');if(!args)return;var colorArg;var colorX11=lib.colors.x11ToCSS(args.shift());if(colorX11)this.terminal.setCursorColor(colorX11);/* Note: If we support OSC 13+, we'd chain it here.
if (args.length > 0) {
parseState.args[0] = args.join(';');
hterm.VT.OSC['13'].apply(this, [parseState]);
}
*/};/**
* Set the cursor shape.
*
* Parameter is expected to be in the form "CursorShape=number", where number is
* one of:
*
* 0 - Block
* 1 - I-Beam
* 2 - Underline
*
* This is a bit of a de-facto standard supported by iTerm 2 and Konsole. See
* also: DECSCUSR.
*
* Invalid numbers will restore the cursor to the block shape.
*/hterm.VT.OSC['50']=function(parseState){var args=parseState.args[0].match(/CursorShape=(.)/i);if(!args){console.warn('Could not parse OSC 50 args: '+parseState.args[0]);return;}switch(args[1]){case'1':// CursorShape=1: I-Beam.
this.terminal.setCursorShape(hterm.Terminal.cursorShape.BEAM);break;case'2':// CursorShape=2: Underline.
this.terminal.setCursorShape(hterm.Terminal.cursorShape.UNDERLINE);break;default:// CursorShape=0: Block.
this.terminal.setCursorShape(hterm.Terminal.cursorShape.BLOCK);}};/**
* Set/read system clipboard.
*
* Read is not implemented due to security considerations. A remote app
* that is able to both write and read to the clipboard could essentially
* take over your session.
*
* The clipboard data will be decoded according to the 'receive-encoding'
* preference.
*/hterm.VT.OSC['52']=function(parseState){if(!this.enableClipboardWrite)return;// Args come in as a single 'clipboard;b64-data' string. The clipboard
// parameter is used to select which of the X clipboards to address. Since
// we're not integrating with X, we treat them all the same.
var args=parseState.args[0].match(/^[cps01234567]*;(.*)/);if(!args)return;var data=window.atob(args[1]);if(this.characterEncoding=='utf-8'){var decoder=new TextDecoder();var bytes=lib.codec.stringToCodeUnitArray(data,Uint8Array);data=decoder.decode(bytes);}if(data)this.terminal.copyStringToClipboard(data);};/**
* Reset color palette.
*/hterm.VT.OSC['104']=function(parseState){var attrs=this.terminal.getTextAttributes();// If there are no args, we reset the entire palette.
if(!parseState.args[0]){attrs.resetColorPalette();return;}// Args come in as a single 'index1;index2;...;indexN' string.
// Split on the semicolon and iterate through the colors.
var args=parseState.args[0].split(';');args.forEach(function(c){return attrs.resetColor(c);});};/**
* Reset foreground color.
*/hterm.VT.OSC['110']=function(parseState){this.terminal.setForegroundColor();};/**
* Reset background color.
*/hterm.VT.OSC['111']=function(parseState){this.terminal.setBackgroundColor();};/**
* Reset text cursor color.
*/hterm.VT.OSC['112']=function(parseState){this.terminal.setCursorColor();};/**
* iTerm2 extended sequences.
*
* We only support image display atm.
*/hterm.VT.OSC['1337']=function(parseState){// Args come in as a set of key value pairs followed by data.
// File=name=<base64>;size=123;inline=1:<base64 data>
var args=parseState.args[0].match(/^File=([^:]*):([\s\S]*)$/m);if(!args){if(this.warnUnimplemented)console.log("iTerm2 1337: unsupported sequence: ".concat(args[1]));return;}var options={name:'',size:0,preserveAspectRatio:true,inline:false,width:'auto',height:'auto',align:'left',type:'',buffer:lib.codec.stringToCodeUnitArray(atob(args[2]),Uint8Array).buffer};// Walk the "key=value;" sets.
args[1].split(';').forEach(function(ele){var kv=ele.match(/^([^=]+)=(.*)$/m);if(!kv)return;// Sanitize values nicely.
switch(kv[1]){case'name':try{options.name=window.atob(kv[2]);}catch(e){}break;case'size':try{options.size=parseInt(kv[2]);}catch(e){}break;case'width':options.width=kv[2];break;case'height':options.height=kv[2];break;case'preserveAspectRatio':options.preserveAspectRatio=!(kv[2]=='0');break;case'inline':options.inline=!(kv[2]=='0');break;// hterm-specific keys.
case'align':options.align=kv[2];break;case'type':options.type=kv[2];break;default:// Ignore unknown keys. Don't want remote stuffing our JS env.
break;}});// This is a bit of a hack. If the buffer has data following the image, we
// need to delay processing of it until after we've finished with the image.
// Otherwise while we wait for the the image to load asynchronously, the new
// text data will intermingle with the image.
if(options.inline){var io=this.terminal.io;var queued=parseState.peekRemainingBuf();parseState.advance(queued.length);this.terminal.displayImage(options);io.print(queued);}else this.terminal.displayImage(options);};/**
* URxvt perl modules.
*
* This is the escape system used by rxvt-unicode and its perl modules.
* Obviously we don't support perl or custom modules, so we list a few common
* ones that we find useful.
*
* Technically there is no format here, but most modules obey:
* <module name>;<module args, usually ; delimited>
*/hterm.VT.OSC['777']=function(parseState){var ary;var urxvtMod=parseState.args[0].split(';',1)[0];switch(urxvtMod){case'notify':// Format:
// notify;title;message
var title,message;ary=parseState.args[0].match(/^[^;]+;([^;]*)(;([\s\S]*))?$/);if(ary){title=ary[1];message=ary[3];}hterm.notify({'title':title,'body':message});break;default:console.warn('Unknown urxvt module: '+parseState.args[0]);break;}};/**
* Insert (blank) characters (ICH).
*/hterm.VT.CSI['@']=function(parseState){this.terminal.insertSpace(parseState.iarg(0,1));};/**
* Cursor Up (CUU).
*/hterm.VT.CSI['A']=function(parseState){this.terminal.cursorUp(parseState.iarg(0,1));};/**
* Cursor Down (CUD).
*/hterm.VT.CSI['B']=function(parseState){this.terminal.cursorDown(parseState.iarg(0,1));};/**
* Cursor Forward (CUF).
*/hterm.VT.CSI['C']=function(parseState){this.terminal.cursorRight(parseState.iarg(0,1));};/**
* Cursor Backward (CUB).
*/hterm.VT.CSI['D']=function(parseState){this.terminal.cursorLeft(parseState.iarg(0,1));};/**
* Cursor Next Line (CNL).
*
* This is like Cursor Down, except the cursor moves to the beginning of the
* line as well.
*/hterm.VT.CSI['E']=function(parseState){this.terminal.cursorDown(parseState.iarg(0,1));this.terminal.setCursorColumn(0);};/**
* Cursor Preceding Line (CPL).
*
* This is like Cursor Up, except the cursor moves to the beginning of the
* line as well.
*/hterm.VT.CSI['F']=function(parseState){this.terminal.cursorUp(parseState.iarg(0,1));this.terminal.setCursorColumn(0);};/**
* Cursor Horizontal Absolute (CHA).
*
* Xterm calls this Cursor Character Absolute.
*/hterm.VT.CSI['G']=function(parseState){this.terminal.setCursorColumn(parseState.iarg(0,1)-1);};/**
* Cursor Position (CUP).
*/hterm.VT.CSI['H']=function(parseState){this.terminal.setCursorPosition(parseState.iarg(0,1)-1,parseState.iarg(1,1)-1);};/**
* Cursor Forward Tabulation (CHT).
*/hterm.VT.CSI['I']=function(parseState){var count=parseState.iarg(0,1);count=lib.f.clamp(count,1,this.terminal.screenSize.width);for(var i=0;i<count;i++){this.terminal.forwardTabStop();}};/**
* Erase in Display (ED, DECSED).
*/hterm.VT.CSI['J']=hterm.VT.CSI['?J']=function(parseState,code){var arg=parseState.args[0];if(!arg||arg==0){this.terminal.eraseBelow();}else if(arg==1){this.terminal.eraseAbove();}else if(arg==2){this.terminal.clear();}else if(arg==3){if(this.enableCsiJ3){this.terminal.clearScrollback();}}};/**
* Erase in line (EL, DECSEL).
*/hterm.VT.CSI['K']=hterm.VT.CSI['?K']=function(parseState,code){var arg=parseState.args[0];if(!arg||arg==0){this.terminal.eraseToRight();}else if(arg==1){this.terminal.eraseToLeft();}else if(arg==2){this.terminal.eraseLine();}};/**
* Insert Lines (IL).
*/hterm.VT.CSI['L']=function(parseState){this.terminal.insertLines(parseState.iarg(0,1));};/**
* Delete Lines (DL).
*/hterm.VT.CSI['M']=function(parseState){this.terminal.deleteLines(parseState.iarg(0,1));};/**
* Delete Characters (DCH).
*
* This command shifts the line contents left, starting at the cursor position.
*/hterm.VT.CSI['P']=function(parseState){this.terminal.deleteChars(parseState.iarg(0,1));};/**
* Scroll Up (SU).
*/hterm.VT.CSI['S']=function(parseState){this.terminal.vtScrollUp(parseState.iarg(0,1));};/**
* Scroll Down (SD).
* Also 'Initiate highlight mouse tracking'. Will not implement this part.
*/hterm.VT.CSI['T']=function(parseState){if(parseState.args.length<=1)this.terminal.vtScrollDown(parseState.iarg(0,1));};/**
* Reset one or more features of the title modes to the default value.
*
* ESC [ > Ps T
*
* Normally, "reset" disables the feature. It is possible to disable the
* ability to reset features by compiling a different default for the title
* modes into xterm.
*
* Ps values:
* 0 - Do not set window/icon labels using hexadecimal.
* 1 - Do not query window/icon labels using hexadecimal.
* 2 - Do not set window/icon labels using UTF-8.
* 3 - Do not query window/icon labels using UTF-8.
*
* Will not implement.
*/hterm.VT.CSI['>T']=hterm.VT.ignore;/**
* Erase Characters (ECH).
*/hterm.VT.CSI['X']=function(parseState){this.terminal.eraseToRight(parseState.iarg(0,1));};/**
* Cursor Backward Tabulation (CBT).
*/hterm.VT.CSI['Z']=function(parseState){var count=parseState.iarg(0,1);count=lib.f.clamp(count,1,this.terminal.screenSize.width);for(var i=0;i<count;i++){this.terminal.backwardTabStop();}};/**
* Character Position Absolute (HPA).
*
* Same as Cursor Horizontal Absolute (CHA).
*/hterm.VT.CSI['`']=hterm.VT.CSI['G'];/**
* Character Position Relative (HPR).
*/hterm.VT.CSI['a']=function(parseState){this.terminal.setCursorColumn(this.terminal.getCursorColumn()+parseState.iarg(0,1));};/**
* Repeat the preceding graphic character.
*
* Not currently implemented.
*/hterm.VT.CSI['b']=hterm.VT.ignore;/**
* Send Device Attributes (Primary DA).
*
* TODO(rginda): This is hardcoded to send back 'VT100 with Advanced Video
* Option', but it may be more correct to send a VT220 response once
* we fill out the 'Not currently implemented' parts.
*/hterm.VT.CSI['c']=function(parseState){if(!parseState.args[0]||parseState.args[0]==0){this.terminal.io.sendString('\x1b[?1;2c');}};/**
* Send Device Attributes (Secondary DA).
*
* TODO(rginda): This is hardcoded to send back 'VT100' but it may be more
* correct to send a VT220 response once we fill out more 'Not currently
* implemented' parts.
*/hterm.VT.CSI['>c']=function(parseState){this.terminal.io.sendString('\x1b[>0;256;0c');};/**
* Line Position Absolute (VPA).
*/hterm.VT.CSI['d']=function(parseState){this.terminal.setAbsoluteCursorRow(parseState.iarg(0,1)-1);};/**
* Horizontal and Vertical Position (HVP).
*
* Same as Cursor Position (CUP).
*/hterm.VT.CSI['f']=hterm.VT.CSI['H'];/**
* Tab Clear (TBC).
*/hterm.VT.CSI['g']=function(parseState){if(!parseState.args[0]||parseState.args[0]==0){// Clear tab stop at cursor.
this.terminal.clearTabStopAtCursor(false);}else if(parseState.args[0]==3){// Clear all tab stops.
this.terminal.clearAllTabStops();}};/**
* Set Mode (SM).
*/hterm.VT.CSI['h']=function(parseState){for(var i=0;i<parseState.args.length;i++){this.setANSIMode(parseState.args[i],true);}};/**
* DEC Private Mode Set (DECSET).
*/hterm.VT.CSI['?h']=function(parseState){for(var i=0;i<parseState.args.length;i++){this.setDECMode(parseState.args[i],true);}};/**
* Media Copy (MC).
* Media Copy (MC, DEC Specific).
*
* These commands control the printer. Will not implement.
*/hterm.VT.CSI['i']=hterm.VT.CSI['?i']=hterm.VT.ignore;/**
* Reset Mode (RM).
*/hterm.VT.CSI['l']=function(parseState){for(var i=0;i<parseState.args.length;i++){this.setANSIMode(parseState.args[i],false);}};/**
* DEC Private Mode Reset (DECRST).
*/hterm.VT.CSI['?l']=function(parseState){for(var i=0;i<parseState.args.length;i++){this.setDECMode(parseState.args[i],false);}};/**
* Parse extended SGR 38/48 sequences.
*
* This deals with the various ISO 8613-6 forms, and with legacy xterm forms
* that are common in the wider application world.
*
* @param {hterm.VT.ParseState} parseState The current input state.
* @param {number} i The argument in parseState to start processing.
* @param {hterm.TextAttributes} attrs The current text attributes.
* @return {Object} The skipCount member defines how many arguments to skip
* (i.e. how many were processed), and the color member is the color that
* was successfully processed, or undefined if not.
*/hterm.VT.prototype.parseSgrExtendedColors=function(parseState,i,attrs){var ary;var usedSubargs;if(parseState.argHasSubargs(i)){// The ISO 8613-6 compliant form.
// e.g. 38:[color choice]:[arg1]:[arg2]:...
ary=parseState.args[i].split(':');ary.shift();// Remove "38".
usedSubargs=true;}else if(parseState.argHasSubargs(i+1)){// The xterm form which isn't ISO 8613-6 compliant. Not many emulators
// support this, and others actively do not want to. We'll ignore it so
// at least the rest of the stream works correctly. e.g. 38;2:R:G:B
// We return 0 here so we only skip the "38" ... we can't be confident the
// next arg is actually supposed to be part of it vs a typo where the next
// arg is legit.
return{skipCount:0};}else{// The xterm form which isn't ISO 8613-6 compliant, but many emulators
// support, and many applications rely on.
// e.g. 38;2;R;G;B
ary=parseState.args.slice(i+1);usedSubargs=false;}// Figure out which form to parse.
switch(parseInt(ary[0])){default:// Unknown.
case 0:// Implementation defined. We ignore it.
return{skipCount:0};case 1:{// Transparent color.
// Require ISO 8613-6 form.
if(!usedSubargs)return{skipCount:0};return{color:'rgba(0, 0, 0, 0)',skipCount:0};}case 2:{// RGB color.
// Skip over the color space identifier, if it exists.
var start;if(usedSubargs){// The ISO 8613-6 compliant form:
// 38:2:<color space id>:R:G:B[:...]
// The xterm form isn't ISO 8613-6 compliant.
// 38:2:R:G:B
// Since the ISO 8613-6 form requires at least 5 arguments,
// we can still support the xterm form unambiguously.
if(ary.length==4)start=1;else start=2;}else{// The legacy xterm form: 38;2;R;G;B
start=1;}// We need at least 3 args for RGB. If we don't have them, assume this
// sequence is corrupted, so don't eat anything more.
// We ignore more than 3 args on purpose since ISO 8613-6 defines some,
// and we don't care about them.
if(ary.length<start+3)return{skipCount:0};var r=parseState.parseInt(ary[start+0]);var g=parseState.parseInt(ary[start+1]);var b=parseState.parseInt(ary[start+2]);return{color:"rgb(".concat(r,", ").concat(g,", ").concat(b,")"),skipCount:usedSubargs?0:4};}case 3:{// CMY color.
// No need to support xterm/legacy forms as xterm doesn't support CMY.
if(!usedSubargs)return{skipCount:0};// We need at least 4 args for CMY. If we don't have them, assume
// this sequence is corrupted. We ignore the color space identifier,
// tolerance, etc...
if(ary.length<4)return{skipCount:0};// TODO: See CMYK below.
var c=parseState.parseInt(ary[1]);var m=parseState.parseInt(ary[2]);var y=parseState.parseInt(ary[3]);return{skipCount:0};}case 4:{// CMYK color.
// No need to support xterm/legacy forms as xterm doesn't support CMYK.
if(!usedSubargs)return{skipCount:0};// We need at least 5 args for CMYK. If we don't have them, assume
// this sequence is corrupted. We ignore the color space identifier,
// tolerance, etc...
if(ary.length<5)return{skipCount:0};// TODO: Implement this.
// Might wait until CSS4 is adopted for device-cmyk():
// https://www.w3.org/TR/css-color-4/#cmyk-colors
// Or normalize it to RGB ourselves:
// https://www.w3.org/TR/css-color-4/#cmyk-rgb
var _c=parseState.parseInt(ary[1]);var _m=parseState.parseInt(ary[2]);var _y=parseState.parseInt(ary[3]);var k=parseState.parseInt(ary[4]);return{skipCount:0};}case 5:{// Color palette index.
// If we're short on args, assume this sequence is corrupted, so don't
// eat anything more.
if(ary.length<2)return{skipCount:0};// Support 38:5:P (ISO 8613-6) and 38;5;P (xterm/legacy).
// We also ignore extra args with 38:5:P:[...], but more for laziness.
var ret={skipCount:usedSubargs?0:2};var color=parseState.parseInt(ary[1]);if(color<attrs.colorPalette.length)ret.color=color;return ret;}}};/**
* Character Attributes (SGR).
*
* Iterate through the list of arguments, applying the attribute changes based
* on the argument value...
*/hterm.VT.CSI['m']=function(parseState){var attrs=this.terminal.getTextAttributes();if(!parseState.args.length){attrs.reset();return;}for(var i=0;i<parseState.args.length;i++){// If this argument has subargs (i.e. it has args followed by colons),
// the iarg logic will implicitly truncate that off for us.
var arg=parseState.iarg(i,0);if(arg<30){if(arg==0){// Normal (default).
attrs.reset();}else if(arg==1){// Bold.
attrs.bold=true;}else if(arg==2){// Faint.
attrs.faint=true;}else if(arg==3){// Italic.
attrs.italic=true;}else if(arg==4){// Underline.
if(parseState.argHasSubargs(i)){var uarg=parseState.args[i].split(':')[1];if(uarg==0)attrs.underline=false;else if(uarg==1)attrs.underline='solid';else if(uarg==2)attrs.underline='double';else if(uarg==3)attrs.underline='wavy';else if(uarg==4)attrs.underline='dotted';else if(uarg==5)attrs.underline='dashed';}else{attrs.underline='solid';}}else if(arg==5){// Blink.
attrs.blink=true;}else if(arg==7){// Inverse.
attrs.inverse=true;}else if(arg==8){// Invisible.
attrs.invisible=true;}else if(arg==9){// Crossed out.
attrs.strikethrough=true;}else if(arg==21){// Double underlined.
attrs.underline='double';}else if(arg==22){// Not bold & not faint.
attrs.bold=false;attrs.faint=false;}else if(arg==23){// Not italic.
attrs.italic=false;}else if(arg==24){// Not underlined.
attrs.underline=false;}else if(arg==25){// Not blink.
attrs.blink=false;}else if(arg==27){// Steady.
attrs.inverse=false;}else if(arg==28){// Visible.
attrs.invisible=false;}else if(arg==29){// Not crossed out.
attrs.strikethrough=false;}}else if(arg<50){// Select fore/background color from bottom half of 16 color palette
// or from the 256 color palette or alternative specify color in fully
// qualified rgb(r, g, b) form.
if(arg<38){attrs.foregroundSource=arg-30;}else if(arg==38){var result=this.parseSgrExtendedColors(parseState,i,attrs);if(result.color!==undefined)attrs.foregroundSource=result.color;i+=result.skipCount;}else if(arg==39){attrs.foregroundSource=attrs.SRC_DEFAULT;}else if(arg<48){attrs.backgroundSource=arg-40;}else if(arg==48){var _result=this.parseSgrExtendedColors(parseState,i,attrs);if(_result.color!==undefined)attrs.backgroundSource=_result.color;i+=_result.skipCount;}else{attrs.backgroundSource=attrs.SRC_DEFAULT;}}else if(arg==58){// Underline coloring.
var _result2=this.parseSgrExtendedColors(parseState,i,attrs);if(_result2.color!==undefined)attrs.underlineSource=_result2.color;i+=_result2.skipCount;}else if(arg==59){// Disable underline coloring.
attrs.underlineSource=attrs.SRC_DEFAULT;}else if(arg>=90&&arg<=97){attrs.foregroundSource=arg-90+8;}else if(arg>=100&&arg<=107){attrs.backgroundSource=arg-100+8;}}attrs.setDefaults(this.terminal.getForegroundColor(),this.terminal.getBackgroundColor());};// SGR calls can handle subargs.
hterm.VT.CSI['m'].supportsSubargs=true;/**
* Set xterm-specific keyboard modes.
*
* Will not implement.
*/hterm.VT.CSI['>m']=hterm.VT.ignore;/**
* Device Status Report (DSR, DEC Specific).
*
* 5 - Status Report. Result (OK) is CSI 0 n
* 6 - Report Cursor Position (CPR) [row;column]. Result is CSI r ; c R
*/hterm.VT.CSI['n']=function(parseState){if(parseState.args[0]==5){this.terminal.io.sendString('\x1b0n');}else if(parseState.args[0]==6){var row=this.terminal.getCursorRow()+1;var col=this.terminal.getCursorColumn()+1;this.terminal.io.sendString('\x1b['+row+';'+col+'R');}};/**
* Disable modifiers which may be enabled via CSI['>m'].
*
* Will not implement.
*/hterm.VT.CSI['>n']=hterm.VT.ignore;/**
* Device Status Report (DSR, DEC Specific).
*
* 6 - Report Cursor Position (CPR) [row;column] as CSI ? r ; c R
* 15 - Report Printer status as CSI ? 1 0 n (ready) or
* CSI ? 1 1 n (not ready).
* 25 - Report UDK status as CSI ? 2 0 n (unlocked) or CSI ? 2 1 n (locked).
* 26 - Report Keyboard status as CSI ? 2 7 ; 1 ; 0 ; 0 n (North American).
* The last two parameters apply to VT400 & up, and denote keyboard ready
* and LK01 respectively.
* 53 - Report Locator status as CSI ? 5 3 n Locator available, if compiled-in,
* or CSI ? 5 0 n No Locator, if not.
*/hterm.VT.CSI['?n']=function(parseState){if(parseState.args[0]==6){var row=this.terminal.getCursorRow()+1;var col=this.terminal.getCursorColumn()+1;this.terminal.io.sendString('\x1b['+row+';'+col+'R');}else if(parseState.args[0]==15){this.terminal.io.sendString('\x1b[?11n');}else if(parseState.args[0]==25){this.terminal.io.sendString('\x1b[?21n');}else if(parseState.args[0]==26){this.terminal.io.sendString('\x1b[?12;1;0;0n');}else if(parseState.args[0]==53){this.terminal.io.sendString('\x1b[?50n');}};/**
* This is used by xterm to decide whether to hide the pointer cursor as the
* user types.
*
* Valid values for the parameter:
* 0 - Never hide the pointer.
* 1 - Hide if the mouse tracking mode is not enabled.
* 2 - Always hide the pointer.
*
* If no parameter is given, xterm uses the default, which is 1.
*
* Not currently implemented.
*/hterm.VT.CSI['>p']=hterm.VT.ignore;/**
* Soft terminal reset (DECSTR).
*/hterm.VT.CSI['!p']=function(){this.terminal.softReset();};/**
* Request ANSI Mode (DECRQM).
*
* Not currently implemented.
*/hterm.VT.CSI['$p']=hterm.VT.ignore;hterm.VT.CSI['?$p']=hterm.VT.ignore;/**
* Set conformance level (DECSCL).
*
* Not currently implemented.
*/hterm.VT.CSI['"p']=hterm.VT.ignore;/**
* Load LEDs (DECLL).
*
* Not currently implemented. Could be implemented as virtual LEDs overlaying
* the terminal if anyone cares.
*/hterm.VT.CSI['q']=hterm.VT.ignore;/**
* Set cursor style (DECSCUSR, VT520).
*/hterm.VT.CSI[' q']=function(parseState){var arg=parseState.args[0];if(arg==0||arg==1){this.terminal.setCursorShape(hterm.Terminal.cursorShape.BLOCK);this.terminal.setCursorBlink(true);}else if(arg==2){this.terminal.setCursorShape(hterm.Terminal.cursorShape.BLOCK);this.terminal.setCursorBlink(false);}else if(arg==3){this.terminal.setCursorShape(hterm.Terminal.cursorShape.UNDERLINE);this.terminal.setCursorBlink(true);}else if(arg==4){this.terminal.setCursorShape(hterm.Terminal.cursorShape.UNDERLINE);this.terminal.setCursorBlink(false);}else if(arg==5){this.terminal.setCursorShape(hterm.Terminal.cursorShape.BEAM);this.terminal.setCursorBlink(true);}else if(arg==6){this.terminal.setCursorShape(hterm.Terminal.cursorShape.BEAM);this.terminal.setCursorBlink(false);}else{console.warn('Unknown cursor style: '+arg);}};/**
* Select character protection attribute (DECSCA).
*
* Will not implement.
*/hterm.VT.CSI['"q']=hterm.VT.ignore;/**
* Set Scrolling Region (DECSTBM).
*/hterm.VT.CSI['r']=function(parseState){var args=parseState.args;var scrollTop=args[0]?parseInt(args[0],10)-1:null;var scrollBottom=args[1]?parseInt(args[1],10)-1:null;this.terminal.setVTScrollRegion(scrollTop,scrollBottom);this.terminal.setCursorPosition(0,0);};/**
* Restore DEC Private Mode Values.
*
* Will not implement.
*/hterm.VT.CSI['?r']=hterm.VT.ignore;/**
* Change Attributes in Rectangular Area (DECCARA)
*
* Will not implement.
*/hterm.VT.CSI['$r']=hterm.VT.ignore;/**
* Save cursor (ANSI.SYS)
*/hterm.VT.CSI['s']=function(){this.terminal.saveCursorAndState();};/**
* Save DEC Private Mode Values.
*
* Will not implement.
*/hterm.VT.CSI['?s']=hterm.VT.ignore;/**
* Window manipulation (from dtterm, as well as extensions).
*
* Will not implement.
*/hterm.VT.CSI['t']=hterm.VT.ignore;/**
* Reverse Attributes in Rectangular Area (DECRARA).
*
* Will not implement.
*/hterm.VT.CSI['$t']=hterm.VT.ignore;/**
* Set one or more features of the title modes.
*
* Will not implement.
*/hterm.VT.CSI['>t']=hterm.VT.ignore;/**
* Set warning-bell volume (DECSWBV, VT520).
*
* Will not implement.
*/hterm.VT.CSI[' t']=hterm.VT.ignore;/**
* Restore cursor (ANSI.SYS).
*/hterm.VT.CSI['u']=function(){this.terminal.restoreCursorAndState();};/**
* Set margin-bell volume (DECSMBV, VT520).
*
* Will not implement.
*/hterm.VT.CSI[' u']=hterm.VT.ignore;/**
* Copy Rectangular Area (DECCRA, VT400 and up).
*
* Will not implement.
*/hterm.VT.CSI['$v']=hterm.VT.ignore;/**
* Enable Filter Rectangle (DECEFR).
*
* Will not implement.
*/hterm.VT.CSI['\'w']=hterm.VT.ignore;/**
* Request Terminal Parameters (DECREQTPARM).
*
* Not currently implemented.
*/hterm.VT.CSI['x']=hterm.VT.ignore;/**
* Select Attribute Change Extent (DECSACE).
*
* Will not implement.
*/hterm.VT.CSI['*x']=hterm.VT.ignore;/**
* Fill Rectangular Area (DECFRA), VT420 and up.
*
* Will not implement.
*/hterm.VT.CSI['$x']=hterm.VT.ignore;/**
* vt_tiledata (as used by NAOhack and UnNetHack)
* (see https://nethackwiki.com/wiki/Vt_tiledata for more info)
*
* Implemented as far as we care (start a glyph and end a glyph).
*/hterm.VT.CSI['z']=function(parseState){if(parseState.args.length<1)return;var arg=parseState.args[0];if(arg==0){// Start a glyph (one parameter, the glyph number).
if(parseState.args.length<2)return;this.terminal.getTextAttributes().tileData=parseState.args[1];}else if(arg==1){// End a glyph.
this.terminal.getTextAttributes().tileData=null;}};/**
* Enable Locator Reporting (DECELR).
*
* Not currently implemented.
*/hterm.VT.CSI['\'z']=hterm.VT.ignore;/**
* Erase Rectangular Area (DECERA), VT400 and up.
*
* Will not implement.
*/hterm.VT.CSI['$z']=hterm.VT.ignore;/**
* Select Locator Events (DECSLE).
*
* Not currently implemented.
*/hterm.VT.CSI['\'{']=hterm.VT.ignore;/**
* Request Locator Position (DECRQLP).
*
* Not currently implemented.
*/hterm.VT.CSI['\'|']=hterm.VT.ignore;/**
* Insert Columns (DECIC), VT420 and up.
*
* Will not implement.
*/hterm.VT.CSI['\'}']=hterm.VT.ignore;/**
* Delete P s Columns (DECDC), VT420 and up.
*
* Will not implement.
*/hterm.VT.CSI['\'~']=hterm.VT.ignore;// SOURCE FILE: hterm/js/hterm_vt_character_map.js
// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* Character map object.
*
* Mapping from received to display character, used depending on the active
* VT character set.
*
* GR maps are not currently supported.
*
* @param {string} description A human readable description of this map.
* @param {Object} glmap The GL mapping from input to output characters.
*/hterm.VT.CharacterMap=function(description,glmap){/**
* Short description for this character set, useful for debugging.
*/this.description=description;/**
* The function to call to when this map is installed in GL.
*/this.GL=null;// Always keep an unmodified reference to the map.
// This allows us to sanely reset back to the original state.
this.glmapBase_=glmap;// Now sync the internal state as needed.
this.sync_();};/**
* Internal helper for resyncing internal state.
*
* Used when the mappings change.
*
* @param {Object?} opt_glmap Additional mappings to overlay on top of the
* base mapping.
*/hterm.VT.CharacterMap.prototype.sync_=function(opt_glmap){var _this19=this;// If there are no maps, then reset the state back.
if(!this.glmapBase_&&!opt_glmap){this.GL=null;delete this.glmap_;delete this.glre_;return;}// Set the the GL mapping. If we're given a custom mapping, then create a
// new object to hold the merged map. This way we can cleanly reset back.
if(opt_glmap)this.glmap_=Object.assign({},this.glmapBase_,opt_glmap);else this.glmap_=this.glmapBase_;var glchars=Object.keys(this.glmap_).map(function(key){return'\\x'+lib.f.zpad(key.charCodeAt(0).toString(16));});this.glre_=new RegExp('['+glchars.join('')+']','g');this.GL=function(str){return str.replace(_this19.glre_,function(ch){return _this19.glmap_[ch];});};};/**
* Reset map back to original mappings (discarding runtime updates).
*
* Specifically, any calls to setOverrides will be discarded.
*/hterm.VT.CharacterMap.prototype.reset=function(){// If we haven't been given a custom mapping, then there's nothing to reset.
if(this.glmap_!==this.glmapBase_)this.sync_();};/**
* Merge custom changes to this map.
*
* The input map need not duplicate the existing mappings as it is merged with
* the existing base map (what was created with). Subsequent calls to this
* will throw away previous override settings.
*
* @param {Object} glmap The custom map to override existing mappings.
*/hterm.VT.CharacterMap.prototype.setOverrides=function(glmap){this.sync_(glmap);};/**
* Return a copy of this mapping.
*
* @return {hterm.VT.CharacterMap} A new hterm.VT.CharacterMap instance.
*/hterm.VT.CharacterMap.prototype.clone=function(){var map=new hterm.VT.CharacterMap(this.description,this.glmapBase_);if(this.glmap_!==this.glmapBase_)map.setOverrides(this.glmap_);return map;};/**
* Table of character maps.
*/hterm.VT.CharacterMaps=function(){this.maps_=hterm.VT.CharacterMaps.DefaultMaps;// Always keep an unmodified reference to the map.
// This allows us to sanely reset back to the original state.
this.mapsBase_=this.maps_;};/**
* Look up a previously registered map.
*
* @param {String} name The name of the map to lookup.
* @return {hterm.VT.CharacterMap} The map, if it's been registered.
*/hterm.VT.CharacterMaps.prototype.getMap=function(name){if(this.maps_.hasOwnProperty(name))return this.maps_[name];else return undefined;};/**
* Register a new map.
*
* Any previously registered maps by this name will be discarded.
*
* @param {String} name The name of the map.
* @param {hterm.VT.CharacterMap} map The map to register.
*/hterm.VT.CharacterMaps.prototype.addMap=function(name,map){if(this.maps_===this.mapsBase_)this.maps_=Object.assign({},this.mapsBase_);this.maps_[name]=map;};/**
* Reset the table and all its maps back to original state.
*/hterm.VT.CharacterMaps.prototype.reset=function(){if(this.maps_!==hterm.VT.CharacterMaps.DefaultMaps)this.maps_=hterm.VT.CharacterMaps.DefaultMaps;};/**
* Merge custom changes to this table.
*
* @param {Object} maps A set of hterm.VT.CharacterMap objects.
*/hterm.VT.CharacterMaps.prototype.setOverrides=function(maps){if(this.maps_===this.mapsBase_)this.maps_=Object.assign({},this.mapsBase_);for(var name in maps){var map=this.getMap(name);if(map!==undefined){this.maps_[name]=map.clone();this.maps_[name].setOverrides(maps[name]);}else this.addMap(name,new hterm.VT.CharacterMap('user '+name,maps[name]));}};/**
* The default set of supported character maps.
*/hterm.VT.CharacterMaps.DefaultMaps={};/**
* VT100 Graphic character map.
* http://vt100.net/docs/vt220-rm/table2-4.html
*/hterm.VT.CharacterMaps.DefaultMaps['0']=new hterm.VT.CharacterMap('graphic',{'\x60':"\u25C6",// ` -> diamond
'\x61':"\u2592",// a -> grey-box
'\x62':"\u2409",// b -> h/t
'\x63':"\u240C",// c -> f/f
'\x64':"\u240D",// d -> c/r
'\x65':"\u240A",// e -> l/f
'\x66':"\xB0",// f -> degree
'\x67':"\xB1",// g -> +/-
'\x68':"\u2424",// h -> n/l
'\x69':"\u240B",// i -> v/t
'\x6a':"\u2518",// j -> bottom-right
'\x6b':"\u2510",// k -> top-right
'\x6c':"\u250C",// l -> top-left
'\x6d':"\u2514",// m -> bottom-left
'\x6e':"\u253C",// n -> line-cross
'\x6f':"\u23BA",// o -> scan1
'\x70':"\u23BB",// p -> scan3
'\x71':"\u2500",// q -> scan5
'\x72':"\u23BC",// r -> scan7
'\x73':"\u23BD",// s -> scan9
'\x74':"\u251C",// t -> left-tee
'\x75':"\u2524",// u -> right-tee
'\x76':"\u2534",// v -> bottom-tee
'\x77':"\u252C",// w -> top-tee
'\x78':"\u2502",// x -> vertical-line
'\x79':"\u2264",// y -> less-equal
'\x7a':"\u2265",// z -> greater-equal
'\x7b':"\u03C0",// { -> pi
'\x7c':"\u2260",// | -> not-equal
'\x7d':"\xA3",// } -> british-pound
'\x7e':"\xB7"// ~ -> dot
});/**
* British character map.
* http://vt100.net/docs/vt220-rm/table2-5.html
*/hterm.VT.CharacterMaps.DefaultMaps['A']=new hterm.VT.CharacterMap('british',{'\x23':"\xA3"// # -> british-pound
});/**
* US ASCII map, no changes.
*/hterm.VT.CharacterMaps.DefaultMaps['B']=new hterm.VT.CharacterMap('us',null);/**
* Dutch character map.
* http://vt100.net/docs/vt220-rm/table2-6.html
*/hterm.VT.CharacterMaps.DefaultMaps['4']=new hterm.VT.CharacterMap('dutch',{'\x23':"\xA3",// # -> british-pound
'\x40':"\xBE",// @ -> 3/4
'\x5b':"\u0132",// [ -> 'ij' ligature (xterm goes with \u00ff?)
'\x5c':"\xBD",// \ -> 1/2
'\x5d':"|",// ] -> vertical bar
'\x7b':"\xA8",// { -> two dots
'\x7c':"f",// | -> f
'\x7d':"\xBC",// } -> 1/4
'\x7e':"\xB4"// ~ -> acute
});/**
* Finnish character map.
* http://vt100.net/docs/vt220-rm/table2-7.html
*/hterm.VT.CharacterMaps.DefaultMaps['C']=hterm.VT.CharacterMaps.DefaultMaps['5']=new hterm.VT.CharacterMap('finnish',{'\x5b':"\xC4",// [ -> 'A' umlaut
'\x5c':"\xD6",// \ -> 'O' umlaut
'\x5d':"\xC5",// ] -> 'A' ring
'\x5e':"\xDC",// ~ -> 'u' umlaut
'\x60':"\xE9",// ` -> 'e' acute
'\x7b':"\xE4",// { -> 'a' umlaut
'\x7c':"\xF6",// | -> 'o' umlaut
'\x7d':"\xE5",// } -> 'a' ring
'\x7e':"\xFC"// ~ -> 'u' umlaut
});/**
* French character map.
* http://vt100.net/docs/vt220-rm/table2-8.html
*/hterm.VT.CharacterMaps.DefaultMaps['R']=new hterm.VT.CharacterMap('french',{'\x23':"\xA3",// # -> british-pound
'\x40':"\xE0",// @ -> 'a' grave
'\x5b':"\xB0",// [ -> ring
'\x5c':"\xE7",// \ -> 'c' cedilla
'\x5d':"\xA7",// ] -> section symbol (double s)
'\x7b':"\xE9",// { -> 'e' acute
'\x7c':"\xF9",// | -> 'u' grave
'\x7d':"\xE8",// } -> 'e' grave
'\x7e':"\xA8"// ~ -> umlaut
});/**
* French Canadian character map.
* http://vt100.net/docs/vt220-rm/table2-9.html
*/hterm.VT.CharacterMaps.DefaultMaps['Q']=new hterm.VT.CharacterMap('french canadian',{'\x40':"\xE0",// @ -> 'a' grave
'\x5b':"\xE2",// [ -> 'a' circumflex
'\x5c':"\xE7",// \ -> 'c' cedilla
'\x5d':"\xEA",// ] -> 'e' circumflex
'\x5e':"\xEE",// ^ -> 'i' circumflex
'\x60':"\xF4",// ` -> 'o' circumflex
'\x7b':"\xE9",// { -> 'e' acute
'\x7c':"\xF9",// | -> 'u' grave
'\x7d':"\xE8",// } -> 'e' grave
'\x7e':"\xFB"// ~ -> 'u' circumflex
});/**
* German character map.
* http://vt100.net/docs/vt220-rm/table2-10.html
*/hterm.VT.CharacterMaps.DefaultMaps['K']=new hterm.VT.CharacterMap('german',{'\x40':"\xA7",// @ -> section symbol (double s)
'\x5b':"\xC4",// [ -> 'A' umlaut
'\x5c':"\xD6",// \ -> 'O' umlaut
'\x5d':"\xDC",// ] -> 'U' umlaut
'\x7b':"\xE4",// { -> 'a' umlaut
'\x7c':"\xF6",// | -> 'o' umlaut
'\x7d':"\xFC",// } -> 'u' umlaut
'\x7e':"\xDF"// ~ -> eszett
});/**
* Italian character map.
* http://vt100.net/docs/vt220-rm/table2-11.html
*/hterm.VT.CharacterMaps.DefaultMaps['Y']=new hterm.VT.CharacterMap('italian',{'\x23':"\xA3",// # -> british-pound
'\x40':"\xA7",// @ -> section symbol (double s)
'\x5b':"\xB0",// [ -> ring
'\x5c':"\xE7",// \ -> 'c' cedilla
'\x5d':"\xE9",// ] -> 'e' acute
'\x60':"\xF9",// ` -> 'u' grave
'\x7b':"\xE0",// { -> 'a' grave
'\x7c':"\xF2",// | -> 'o' grave
'\x7d':"\xE8",// } -> 'e' grave
'\x7e':"\xEC"// ~ -> 'i' grave
});/**
* Norwegian/Danish character map.
* http://vt100.net/docs/vt220-rm/table2-12.html
*/hterm.VT.CharacterMaps.DefaultMaps['E']=hterm.VT.CharacterMaps.DefaultMaps['6']=new hterm.VT.CharacterMap('norwegian/danish',{'\x40':"\xC4",// @ -> 'A' umlaut
'\x5b':"\xC6",// [ -> 'AE' ligature
'\x5c':"\xD8",// \ -> 'O' stroke
'\x5d':"\xC5",// ] -> 'A' ring
'\x5e':"\xDC",// ^ -> 'U' umlaut
'\x60':"\xE4",// ` -> 'a' umlaut
'\x7b':"\xE6",// { -> 'ae' ligature
'\x7c':"\xF8",// | -> 'o' stroke
'\x7d':"\xE5",// } -> 'a' ring
'\x7e':"\xFC"// ~ -> 'u' umlaut
});/**
* Spanish character map.
* http://vt100.net/docs/vt220-rm/table2-13.html
*/hterm.VT.CharacterMaps.DefaultMaps['Z']=new hterm.VT.CharacterMap('spanish',{'\x23':"\xA3",// # -> british-pound
'\x40':"\xA7",// @ -> section symbol (double s)
'\x5b':"\xA1",// [ -> '!' inverted
'\x5c':"\xD1",// \ -> 'N' tilde
'\x5d':"\xBF",// ] -> '?' inverted
'\x7b':"\xB0",// { -> ring
'\x7c':"\xF1",// | -> 'n' tilde
'\x7d':"\xE7"// } -> 'c' cedilla
});/**
* Swedish character map.
* http://vt100.net/docs/vt220-rm/table2-14.html
*/hterm.VT.CharacterMaps.DefaultMaps['7']=hterm.VT.CharacterMaps.DefaultMaps['H']=new hterm.VT.CharacterMap('swedish',{'\x40':"\xC9",// @ -> 'E' acute
'\x5b':"\xC4",// [ -> 'A' umlaut
'\x5c':"\xD6",// \ -> 'O' umlaut
'\x5d':"\xC5",// ] -> 'A' ring
'\x5e':"\xDC",// ^ -> 'U' umlaut
'\x60':"\xE9",// ` -> 'e' acute
'\x7b':"\xE4",// { -> 'a' umlaut
'\x7c':"\xF6",// | -> 'o' umlaut
'\x7d':"\xE5",// } -> 'a' ring
'\x7e':"\xFC"// ~ -> 'u' umlaut
});/**
* Swiss character map.
* http://vt100.net/docs/vt220-rm/table2-15.html
*/hterm.VT.CharacterMaps.DefaultMaps['=']=new hterm.VT.CharacterMap('swiss',{'\x23':"\xF9",// # -> 'u' grave
'\x40':"\xE0",// @ -> 'a' grave
'\x5b':"\xE9",// [ -> 'e' acute
'\x5c':"\xE7",// \ -> 'c' cedilla
'\x5d':"\xEA",// ] -> 'e' circumflex
'\x5e':"\xEE",// ^ -> 'i' circumflex
'\x5f':"\xE8",// _ -> 'e' grave
'\x60':"\xF4",// ` -> 'o' circumflex
'\x7b':"\xE4",// { -> 'a' umlaut
'\x7c':"\xF6",// | -> 'o' umlaut
'\x7d':"\xFC",// } -> 'u' umlaut
'\x7e':"\xFB"// ~ -> 'u' circumflex
});lib.resource.add('hterm/audio/bell','audio/ogg;base64','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'+'VbVtzzRl2VRV3RZV1bZl2xZ+V5Z13zNNWRZV1dZNVbV115Z9X9ZtXZg0zTQ1UVRVTRRV1VRV2zZV'+'17Y1UXRVUVVlWVRVWXZlWfdVV9Z9SxRV1VNN2RVVVbZV2fVtVZZ94XRVXVdl2fdVWRZ+W9eF4fZ9'+'4RhV1dZN19V1VZZ9YdZlYbd13yhpmmlqoqiqmiiqqqmqtm2qrq1bouiqoqrKsmeqrqzKsq+rrmzr'+'miiqrqiqsiyqqiyrsqz7qizrtqiquq3KsrCbrqvrtu8LwyzrunCqrq6rsuz7qizruq3rxnHrujB8'+'pinLpqvquqm6um7runHMtm0co6rqvirLwrDKsu/rui+0dSFRVXXdlF3jV2VZ921fd55b94WybTu/'+'rfvKceu60vg5z28cubZtHLNuG7+t+8bzKz9hOI6lZ5q2baqqrZuqq+uybivDrOtCUVV9XZVl3zdd'+'WRdu3zeOW9eNoqrquirLvrDKsjHcxm8cuzAcXds2jlvXnbKtC31jyPcJz2vbxnH7OuP2daOvDAnH'+'jwAAgAEHAIAAE8pAoSErAoA4AQAGIecUUxAqxSB0EFLqIKRUMQYhc05KxRyUUEpqIZTUKsYgVI5J'+'yJyTEkpoKZTSUgehpVBKa6GU1lJrsabUYu0gpBZKaS2U0lpqqcbUWowRYxAy56RkzkkJpbQWSmkt'+'c05K56CkDkJKpaQUS0otVsxJyaCj0kFIqaQSU0mptVBKa6WkFktKMbYUW24x1hxKaS2kEltJKcYU'+'U20txpojxiBkzknJnJMSSmktlNJa5ZiUDkJKmYOSSkqtlZJSzJyT0kFIqYOOSkkptpJKTKGU1kpK'+'sYVSWmwx1pxSbDWU0lpJKcaSSmwtxlpbTLV1EFoLpbQWSmmttVZraq3GUEprJaUYS0qxtRZrbjHm'+'GkppraQSW0mpxRZbji3GmlNrNabWam4x5hpbbT3WmnNKrdbUUo0txppjbb3VmnvvIKQWSmktlNJi'+'ai3G1mKtoZTWSiqxlZJabDHm2lqMOZTSYkmpxZJSjC3GmltsuaaWamwx5ppSi7Xm2nNsNfbUWqwt'+'xppTS7XWWnOPufVWAADAgAMAQIAJZaDQkJUAQBQAAEGIUs5JaRByzDkqCULMOSepckxCKSlVzEEI'+'JbXOOSkpxdY5CCWlFksqLcVWaykptRZrLQAAoMABACDABk2JxQEKDVkJAEQBACDGIMQYhAYZpRiD'+'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'+'m2L/kruPM6Q7oz4tvDQy+bZ3HzOi+gNHA4DZEgA=');lib.resource.add('hterm/images/icon-96','image/png;base64','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'+'YII=');lib.resource.add('hterm/concat/date','text/plain','Sun, 28 Apr 2019 13:36:40 +0000');lib.resource.add('hterm/changelog/version','text/plain','1.84');lib.resource.add('hterm/changelog/date','text/plain','2019-01-19');lib.resource.add('hterm/git/HEAD','text/plain','251d68966c9b2e32e2c127f5ce99653849e58520');