|  |  | @ -9,6 +9,46 @@ const SEQ_SET_ATTRS = 4 | 
			
		
	
		
		
			
				
					
					|  |  |  | const SEQ_SET_FG = 5 |  |  |  | const SEQ_SET_FG = 5 | 
			
		
	
		
		
			
				
					
					|  |  |  | const SEQ_SET_BG = 6 |  |  |  | const SEQ_SET_BG = 6 | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | function du (str) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   return str.codePointAt(0) - 1 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | /* eslint-disable no-multi-spaces */ | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | const TOPIC_SCREEN_OPTS  = 'O' | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | const TOPIC_CONTENT      = 'S' | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | const TOPIC_TITLE        = 'T' | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | const TOPIC_BUTTONS      = 'B' | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | const TOPIC_CURSOR       = 'C' | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | const TOPIC_INTERNAL     = 'D' | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | const TOPIC_BELL         = '!' | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | const OPT_CURSOR_VISIBLE   = (1 << 0) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | const OPT_DEBUGBAR         = (1 << 1) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | const OPT_CURSORS_ALT_MODE = (1 << 2) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | const OPT_NUMPAD_ALT_MODE  = (1 << 3) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | const OPT_FN_ALT_MODE      = (1 << 4) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | const OPT_CLICK_TRACKING   = (1 << 5) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | const OPT_MOVE_TRACKING    = (1 << 6) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | const OPT_SHOW_BUTTONS     = (1 << 7) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | const OPT_SHOW_CONFIG_LINKS = (1 << 8) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // const OPT_CURSOR_SHAPE   = (7 << 9)
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | const OPT_CRLF_MODE        = (1 << 12) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | const OPT_BRACKETED_PASTE  = (1 << 13) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | const OPT_REVERSE_VIDEO    = (1 << 14) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | const ATTR_FG        = (1 << 0)  // 1 if not using default background color (ignore cell bg) - color extension bit
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | const ATTR_BG        = (1 << 1)  // 1 if not using default foreground color (ignore cell fg) - color extension bit
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | const ATTR_BOLD      = (1 << 2)  // Bold font
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | const ATTR_UNDERLINE = (1 << 3)  // Underline decoration
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | const ATTR_INVERSE   = (1 << 4)  // Invert colors - this is useful so we can clear then with SGR manipulation commands
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | const ATTR_BLINK     = (1 << 5)  // Blinking
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | const ATTR_ITALIC    = (1 << 6)  // Italic font
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | const ATTR_STRIKE    = (1 << 7)  // Strike-through decoration
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | const ATTR_OVERLINE  = (1 << 8)  // Over-line decoration
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | const ATTR_FAINT     = (1 << 9)  // Faint foreground color (reduced alpha)
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | const ATTR_FRAKTUR   = (1 << 10) // Fraktur font (unicode substitution)
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | /* eslint-enable no-multi-spaces */ | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | module.exports = class ScreenParser { |  |  |  | module.exports = class ScreenParser { | 
			
		
	
		
		
			
				
					
					|  |  |  |   constructor (screen) { |  |  |  |   constructor (screen) { | 
			
		
	
		
		
			
				
					
					|  |  |  |     this.screen = screen |  |  |  |     this.screen = screen | 
			
		
	
	
		
		
			
				
					|  |  | @ -16,77 +56,78 @@ module.exports = class ScreenParser { | 
			
		
	
		
		
			
				
					
					|  |  |  |     // true if TermScreen#load was called at least once
 |  |  |  |     // true if TermScreen#load was called at least once
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     this.contentLoaded = false |  |  |  |     this.contentLoaded = false | 
			
		
	
		
		
			
				
					
					|  |  |  |   } |  |  |  |   } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   /** |  |  |  |   /** | 
			
		
	
		
		
			
				
					
					|  |  |  |    * Parses the content of an `S` message and schedules a draw |  |  |  |    * Hide the warning message about failed data load | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |    * @param {string} str - the message content |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |    */ |  |  |  |    */ | 
			
		
	
		
		
			
				
					
					|  |  |  |   loadContent (str) { |  |  |  |   hideLoadFailedMsg () { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     // current index
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     let i = 0 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     let strArray = Array.from ? Array.from(str) : str.split('') |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     // Uncomment to capture screen content for the demo page
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     // console.log(JSON.stringify(`S${str}`))
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     if (!this.contentLoaded) { |  |  |  |     if (!this.contentLoaded) { | 
			
		
	
		
		
			
				
					
					|  |  |  |       let errmsg = qs('#load-failed') |  |  |  |       let errmsg = qs('#load-failed') | 
			
		
	
		
		
			
				
					
					|  |  |  |       if (errmsg) errmsg.parentNode.removeChild(errmsg) |  |  |  |       if (errmsg) errmsg.parentNode.removeChild(errmsg) | 
			
		
	
		
		
			
				
					
					|  |  |  |       this.contentLoaded = true |  |  |  |       this.contentLoaded = true | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     // window size
 |  |  |  |   loadUpdate (str) { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     const newHeight = strArray[i++].codePointAt(0) - 1 |  |  |  |     console.log(`update ${str}`) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     const newWidth = strArray[i++].codePointAt(0) - 1 |  |  |  |     // current index
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     const resized = (this.screen.window.height !== newHeight) || (this.screen.window.width !== newWidth) |  |  |  |     let ci = 0 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     this.screen.window.height = newHeight |  |  |  |     let strArray = Array.from ? Array.from(str) : str.split('') | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     this.screen.window.width = newWidth |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     // cursor position
 |  |  |  |     let text | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     let [cursorY, cursorX] = [ |  |  |  |     let resized = false | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |       strArray[i++].codePointAt(0) - 1, |  |  |  |     const topics = du(strArray[ci++]) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |       strArray[i++].codePointAt(0) - 1 |  |  |  |     // this.screen.cursor.hanging = !!(attributes & (1 << 1))
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     ] |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     let cursorMoved = (cursorX !== this.screen.cursor.x || cursorY !== this.screen.cursor.y) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     this.screen.cursor.x = cursorX |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     this.screen.cursor.y = cursorY |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     if (cursorMoved) { |  |  |  |     while (ci < strArray.length) { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |       this.screen.renderer.resetCursorBlink() |  |  |  |       const topic = strArray[ci++] | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |       this.screen.emit('cursor-moved') |  |  |  |       console.log(`topic ${topic}`) | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       if (topic === TOPIC_SCREEN_OPTS) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         const newHeight = du(strArray[ci++]) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         const newWidth = du(strArray[ci++]) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         const theme = du(strArray[ci++]) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         const defFg = du(strArray[ci++]) | (du(strArray[ci++]) << 12) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         const defBg = du(strArray[ci++]) | (du(strArray[ci++]) << 12) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         const attributes = du(strArray[ci++]) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         // themeing
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         if (theme >= 0 && theme < themes.length) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |           this.screen.renderer.palette = themes[theme] | 
			
		
	
		
		
			
				
					
					|  |  |  |         } |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         this.screen.renderer.setDefaultColors(defFg, defBg) | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     // attributes
 |  |  |  |         // apply size
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     let attributes = strArray[i++].codePointAt(0) - 1 |  |  |  |         resized = (this.screen.window.height !== newHeight) || (this.screen.window.width !== newWidth) | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         this.screen.window.height = newHeight | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         this.screen.window.width = newWidth | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     this.screen.cursor.visible = !!(attributes & 1) |  |  |  |         // process attributes
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     this.screen.cursor.hanging = !!(attributes & (1 << 1)) |  |  |  |         this.screen.cursor.visible = !!(attributes & OPT_CURSOR_VISIBLE) | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         this.screen.input.setAlts( |  |  |  |         this.screen.input.setAlts( | 
			
		
	
		
		
			
				
					
					|  |  |  |       !!(attributes & (1 << 2)), // cursors alt
 |  |  |  |           !!(attributes & OPT_CURSORS_ALT_MODE), | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |       !!(attributes & (1 << 3)), // numpad alt
 |  |  |  |           !!(attributes & OPT_NUMPAD_ALT_MODE), | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |       !!(attributes & (1 << 4)), // fn keys alt
 |  |  |  |           !!(attributes & OPT_FN_ALT_MODE), | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |       !!(attributes & (1 << 12)) // crlf mode
 |  |  |  |           !!(attributes & OPT_CRLF_MODE) | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |         ) |  |  |  |         ) | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     let trackMouseClicks = !!(attributes & (1 << 5)) |  |  |  |         const trackMouseClicks = !!(attributes & OPT_CLICK_TRACKING) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     let trackMouseMovement = !!(attributes & (1 << 6)) |  |  |  |         const trackMouseMovement = !!(attributes & OPT_MOVE_TRACKING) | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         // 0 - Block blink     2 - Block steady (1 is unused)
 |  |  |  |         // 0 - Block blink     2 - Block steady (1 is unused)
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         // 3 - Underline blink 4 - Underline steady
 |  |  |  |         // 3 - Underline blink 4 - Underline steady
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         // 5 - I-bar blink     6 - I-bar steady
 |  |  |  |         // 5 - I-bar blink     6 - I-bar steady
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         let cursorShape = (attributes >> 9) & 0x07 |  |  |  |         let cursorShape = (attributes >> 9) & 0x07 | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         // if it's not zero, decrement such that the two most significant bits
 |  |  |  |         // if it's not zero, decrement such that the two most significant bits
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         // are the type and the least significant bit is the blink state
 |  |  |  |         // are the type and the least significant bit is the blink state
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         if (cursorShape > 0) cursorShape-- |  |  |  |         if (cursorShape > 0) cursorShape-- | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |         const cursorStyle = cursorShape >> 1 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     let cursorStyle = cursorShape >> 1 |  |  |  |         const cursorBlinking = !(cursorShape & 1) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     let cursorBlinking = !(cursorShape & 1) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |         if (cursorStyle === 0) this.screen.cursor.style = 'block' |  |  |  |         if (cursorStyle === 0) this.screen.cursor.style = 'block' | 
			
		
	
		
		
			
				
					
					|  |  |  |         else if (cursorStyle === 1) this.screen.cursor.style = 'line' |  |  |  |         else if (cursorStyle === 1) this.screen.cursor.style = 'line' | 
			
		
	
		
		
			
				
					
					|  |  |  |         else if (cursorStyle === 2) this.screen.cursor.style = 'bar' |  |  |  |         else if (cursorStyle === 2) this.screen.cursor.style = 'bar' | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         if (this.screen.cursor.blinking !== cursorBlinking) { |  |  |  |         if (this.screen.cursor.blinking !== cursorBlinking) { | 
			
		
	
		
		
			
				
					
					|  |  |  |           this.screen.cursor.blinking = cursorBlinking |  |  |  |           this.screen.cursor.blinking = cursorBlinking | 
			
		
	
		
		
			
				
					
					|  |  |  |           this.screen.renderer.resetCursorBlink() |  |  |  |           this.screen.renderer.resetCursorBlink() | 
			
		
	
	
		
		
			
				
					|  |  | @ -100,14 +141,108 @@ module.exports = class ScreenParser { | 
			
		
	
		
		
			
				
					
					|  |  |  |           movement: trackMouseMovement |  |  |  |           movement: trackMouseMovement | 
			
		
	
		
		
			
				
					
					|  |  |  |         } |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     let showButtons = !!(attributes & (1 << 7)) |  |  |  |         const showButtons = !!(attributes & OPT_SHOW_BUTTONS) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     let showConfigLinks = !!(attributes & (1 << 8)) |  |  |  |         const showConfigLinks = !!(attributes & OPT_SHOW_CONFIG_LINKS) | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         $('.x-term-conf-btn').toggleClass('hidden', !showConfigLinks) |  |  |  |         $('.x-term-conf-btn').toggleClass('hidden', !showConfigLinks) | 
			
		
	
		
		
			
				
					
					|  |  |  |         $('#action-buttons').toggleClass('hidden', !showButtons) |  |  |  |         $('#action-buttons').toggleClass('hidden', !showButtons) | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     this.screen.bracketedPaste = !!(attributes & (1 << 13)) |  |  |  |         this.screen.bracketedPaste = !!(attributes & OPT_BRACKETED_PASTE) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     this.screen.reverseVideo = !!(attributes & (1 << 14)) |  |  |  |         this.screen.reverseVideo = !!(attributes & OPT_REVERSE_VIDEO) | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         const debugbar = !!(attributes & OPT_DEBUGBAR) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         // TODO do something with debugbar
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       } else if (topic === TOPIC_CURSOR) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         // cursor position
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         const [cursorY, cursorX] = [ | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |           strArray[ci++].codePointAt(0) - 1, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |           strArray[ci++].codePointAt(0) - 1 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         ] | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         const hanging = du(strArray[ci++]) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         const cursorMoved = ( | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |           hanging !== this.screen.cursor.hanging || | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |           cursorX !== this.screen.cursor.x || | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |           cursorY !== this.screen.cursor.y) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         this.screen.cursor.x = cursorX | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         this.screen.cursor.y = cursorY | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         this.screen.cursor.hanging = hanging | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         if (cursorMoved) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |           this.screen.renderer.resetCursorBlink() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |           this.screen.emit('cursor-moved') | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       } else if (topic === TOPIC_TITLE) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         // TODO optimize this
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         text = '' | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         while (ci < strArray.length) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |           let c = strArray[ci++] | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |           if (c !== '\x01') { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             text += c | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |           } else { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             break | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |           } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         qs('#screen-title').textContent = text | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         if (text.length === 0) text = 'Terminal' | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         qs('title').textContent = `${text} :: ESPTerm` | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       } else if (topic === TOPIC_BUTTONS) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         // TODO optimize this
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         const count = du(strArray[ci++]) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         let buttons = [] | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         for (let j = 0; j < count; j++) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |           text = '' | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |           while (ci < strArray.length) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             let c = strArray[ci++] | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             if (c === '\x01') break | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             text += c | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |           } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |           buttons.push(text) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         $('#action-buttons button').forEach((button, i) => { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |           let label = buttons[i].trim() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |           // if empty string, use the "dim" effect and put nbsp instead to
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |           // stretch the button vertically
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |           button.innerHTML = label.length ? $.htmlEscape(label) : ' ' | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |           button.style.opacity = label.length ? 1 : 0.2 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         }) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       } else if (topic === TOPIC_BELL) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         this.screen.beep() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       } else if (topic === TOPIC_INTERNAL) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         // debug info
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         const flags = du(strArray[ci++]) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         const cursorAttrs = du(strArray[ci++]) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         const regionStart = du(strArray[ci++]) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         const regionEnd = du(strArray[ci++]) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         const charsetGx = du(strArray[ci++]) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         const charsetG0 = strArray[ci++] | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         const charsetG1 = strArray[ci++] | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         const freeHeap = du(strArray[ci++]) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         const numClients = du(strArray[ci++]) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         // TODO do something with those
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       } else if (topic === TOPIC_CONTENT) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         const window_y = du(strArray[ci++]) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         const window_x = du(strArray[ci++]) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         const window_h = du(strArray[ci++]) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         const window_w = du(strArray[ci++]) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         // TODO use
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         // content
 |  |  |  |         // content
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         let fg = 7 |  |  |  |         let fg = 7 | 
			
		
	
	
		
		
			
				
					|  |  | @ -126,14 +261,14 @@ module.exports = class ScreenParser { | 
			
		
	
		
		
			
				
					
					|  |  |  |           this.screen.screenAttrs = new Array(screenLength).fill(0) |  |  |  |           this.screen.screenAttrs = new Array(screenLength).fill(0) | 
			
		
	
		
		
			
				
					
					|  |  |  |         } |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     const MASK_LINE_ATTR = 0xC8 |  |  |  |         const MASK_LINE_ATTR = ATTR_UNDERLINE | ATTR_OVERLINE | ATTR_STRIKE | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     const MASK_BLINK = 1 << 4 |  |  |  |         const MASK_BLINK = ATTR_BLINK | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         let setCellContent = () => { |  |  |  |         let setCellContent = () => { | 
			
		
	
		
		
			
				
					
					|  |  |  |           // Remove blink attribute if it wouldn't have any effect
 |  |  |  |           // Remove blink attribute if it wouldn't have any effect
 | 
			
		
	
		
		
			
				
					
					|  |  |  |           let myAttrs = attrs |  |  |  |           let myAttrs = attrs | 
			
		
	
		
		
			
				
					
					|  |  |  |       let hasFG = attrs & (1 << 8) |  |  |  |           let hasFG = attrs & ATTR_FG | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |       let hasBG = attrs & (1 << 9) |  |  |  |           let hasBG = attrs & ATTR_BG | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |           if ((myAttrs & MASK_BLINK) !== 0 && |  |  |  |           if ((myAttrs & MASK_BLINK) !== 0 && | 
			
		
	
		
		
			
				
					
					|  |  |  |             ((lastChar === ' ' && ((myAttrs & MASK_LINE_ATTR) === 0)) || // no line styles
 |  |  |  |             ((lastChar === ' ' && ((myAttrs & MASK_LINE_ATTR) === 0)) || // no line styles
 | 
			
		
	
		
		
			
				
					
					|  |  |  |               (fg === bg && hasFG && hasBG) // invisible text
 |  |  |  |               (fg === bg && hasFG && hasBG) // invisible text
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -153,14 +288,14 @@ module.exports = class ScreenParser { | 
			
		
	
		
		
			
				
					
					|  |  |  |           this.screen.screenAttrs[cell] = myAttrs |  |  |  |           this.screen.screenAttrs[cell] = myAttrs | 
			
		
	
		
		
			
				
					
					|  |  |  |         } |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     while (i < strArray.length && cell < screenLength) { |  |  |  |         while (ci < strArray.length && cell < screenLength) { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |       let character = strArray[i++] |  |  |  |           let character = strArray[ci++] | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |           let charCode = character.codePointAt(0) |  |  |  |           let charCode = character.codePointAt(0) | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |           let data |  |  |  |           let data | 
			
		
	
		
		
			
				
					
					|  |  |  |           switch (charCode) { |  |  |  |           switch (charCode) { | 
			
		
	
		
		
			
				
					
					|  |  |  |             case SEQ_REPEAT: |  |  |  |             case SEQ_REPEAT: | 
			
		
	
		
		
			
				
					
					|  |  |  |           let count = strArray[i++].codePointAt(0) - 1 |  |  |  |               let count = strArray[ci++].codePointAt(0) - 1 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |               for (let j = 0; j < count; j++) { |  |  |  |               for (let j = 0; j < count; j++) { | 
			
		
	
		
		
			
				
					
					|  |  |  |                 setCellContent() |  |  |  |                 setCellContent() | 
			
		
	
		
		
			
				
					
					|  |  |  |                 if (++cell > screenLength) break |  |  |  |                 if (++cell > screenLength) break | 
			
		
	
	
		
		
			
				
					|  |  | @ -168,23 +303,23 @@ module.exports = class ScreenParser { | 
			
		
	
		
		
			
				
					
					|  |  |  |               break |  |  |  |               break | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             case SEQ_SET_COLORS: |  |  |  |             case SEQ_SET_COLORS: | 
			
		
	
		
		
			
				
					
					|  |  |  |           data = strArray[i++].codePointAt(0) - 1 |  |  |  |               data = strArray[ci++].codePointAt(0) - 1 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |               fg = data & 0xFF |  |  |  |               fg = data & 0xFF | 
			
		
	
		
		
			
				
					
					|  |  |  |               bg = (data >> 8) & 0xFF |  |  |  |               bg = (data >> 8) & 0xFF | 
			
		
	
		
		
			
				
					
					|  |  |  |               break |  |  |  |               break | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             case SEQ_SET_ATTRS: |  |  |  |             case SEQ_SET_ATTRS: | 
			
		
	
		
		
			
				
					
					|  |  |  |           data = strArray[i++].codePointAt(0) - 1 |  |  |  |               data = strArray[ci++].codePointAt(0) - 1 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |               attrs = data & 0xFFFF |  |  |  |               attrs = data & 0xFFFF | 
			
		
	
		
		
			
				
					
					|  |  |  |               break |  |  |  |               break | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             case SEQ_SET_FG: |  |  |  |             case SEQ_SET_FG: | 
			
		
	
		
		
			
				
					
					|  |  |  |           data = strArray[i++].codePointAt(0) - 1 |  |  |  |               data = strArray[ci++].codePointAt(0) - 1 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |               fg = data & 0xFF |  |  |  |               fg = data & 0xFF | 
			
		
	
		
		
			
				
					
					|  |  |  |               break |  |  |  |               break | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             case SEQ_SET_BG: |  |  |  |             case SEQ_SET_BG: | 
			
		
	
		
		
			
				
					
					|  |  |  |           data = strArray[i++].codePointAt(0) - 1 |  |  |  |               data = strArray[ci++].codePointAt(0) - 1 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |               bg = data & 0xFF |  |  |  |               bg = data & 0xFF | 
			
		
	
		
		
			
				
					
					|  |  |  |               break |  |  |  |               break | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -200,62 +335,24 @@ module.exports = class ScreenParser { | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         this.screen.renderer.scheduleDraw('load', 16) |  |  |  |         this.screen.renderer.scheduleDraw('load', 16) | 
			
		
	
		
		
			
				
					
					|  |  |  |         this.screen.conn.emit('load') |  |  |  |         this.screen.conn.emit('load') | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |       } |  |  |  |       } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   /** |  |  |  |       if ((topics & 0x3B) !== 0) this.hideLoadFailedMsg() | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |    * Parses the content of a `T` message and updates the screen title and button |  |  |  |     } | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |    * labels. |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |    * @param {string} str - the message content |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |    */ |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |   loadLabels (str) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     let pieces = str.split('\x01') |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     let screenTitle = pieces[0] |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     qs('#screen-title').textContent = screenTitle |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     if (screenTitle.length === 0) screenTitle = 'Terminal' |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     qs('title').textContent = `${screenTitle} :: ESPTerm` |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     $('#action-buttons button').forEach((button, i) => { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       let label = pieces[i + 1].trim() |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       // if empty string, use the "dim" effect and put nbsp instead to
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       // stretch the button vertically
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       button.innerHTML = label ? $.htmlEscape(label) : ' ' |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       button.style.opacity = label ? 1 : 0.2 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     }) |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |   } |  |  |  |   } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   /** |  |  |  |   /** | 
			
		
	
		
		
			
				
					
					|  |  |  |    * Loads a message from the server, and optionally a theme. |  |  |  |    * Loads a message from the server, and optionally a theme. | 
			
		
	
		
		
			
				
					
					|  |  |  |    * @param {string} str - the message |  |  |  |    * @param {string} str - the message | 
			
		
	
		
		
			
				
					
					|  |  |  |    * @param {object} [opts] - options |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |    * @param {number} [opts.theme] - theme |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |    * @param {number} [opts.defaultFg] - default foreground |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |    * @param {number} [opts.defaultBg] - default background |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |    */ |  |  |  |    */ | 
			
		
	
		
		
			
				
					
					|  |  |  |   load (str, opts = null) { |  |  |  |   load (str) { | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     console.log(`RX: ${str}`) | 
			
		
	
		
		
			
				
					
					|  |  |  |     const content = str.substr(1) |  |  |  |     const content = str.substr(1) | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     if (opts) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       if (typeof opts.defaultFg !== 'undefined' && typeof opts.defaultBg !== 'undefined') { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         this.screen.renderer.setDefaultColors(opts.defaultFg, opts.defaultBg) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       if (typeof opts.theme !== 'undefined') { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         if (opts.theme >= 0 && opts.theme < themes.length) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |           this.screen.renderer.palette = themes[opts.theme] |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     switch (str[0]) { |  |  |  |     switch (str[0]) { | 
			
		
	
		
		
			
				
					
					|  |  |  |       case 'S': |  |  |  |       case 'U': | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         this.loadContent(content) |  |  |  |         this.loadUpdate(content) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         break |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       case 'T': |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         this.loadLabels(content) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         break |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       case 'B': |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         this.screen.beep() |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |         break |  |  |  |         break | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |       case 'G': |  |  |  |       case 'G': | 
			
		
	
	
		
		
			
				
					|  |  | 
 |