├── .gitignore ├── .versions ├── README.md ├── client ├── main.js ├── shell.css ├── shell.html ├── shell.js └── xterm │ ├── addons │ ├── attach │ │ ├── attach.js │ │ └── package.json │ ├── fit │ │ ├── fit.js │ │ └── package.json │ ├── fullscreen │ │ ├── fullscreen.css │ │ ├── fullscreen.js │ │ └── package.json │ ├── linkify │ │ └── linkify.js │ ├── search │ │ ├── search.js │ │ └── search.js.map │ └── terminado │ │ ├── package.json │ │ └── terminado.js │ ├── index.js │ ├── xterm.css │ └── xterm.js ├── package.js └── server ├── main.js └── shell.js /.gitignore: -------------------------------------------------------------------------------- 1 | .npm -------------------------------------------------------------------------------- /.versions: -------------------------------------------------------------------------------- 1 | babel-compiler@6.20.0 2 | babel-runtime@1.0.1 3 | base64@1.0.10 4 | blaze@2.1.8 5 | blaze-tools@1.0.10 6 | boilerplate-generator@1.2.0 7 | caching-compiler@1.1.9 8 | caching-html-compiler@1.0.7 9 | check@1.2.5 10 | deps@1.0.12 11 | diff-sequence@1.0.7 12 | ecmascript@0.8.2 13 | ecmascript-runtime@0.4.1 14 | ecmascript-runtime-client@0.4.3 15 | ecmascript-runtime-server@0.4.1 16 | ejson@1.0.14 17 | html-tools@1.0.11 18 | htmljs@1.0.11 19 | id-map@1.0.9 20 | jquery@1.11.10 21 | logging@1.1.17 22 | meteor@1.7.1 23 | meteorhacks:picker@1.0.3 24 | modules@0.10.0 25 | modules-runtime@0.8.0 26 | mongo-id@1.0.6 27 | observe-sequence@1.0.16 28 | promise@0.9.0 29 | qualia:web-shell@0.0.5 30 | random@1.0.10 31 | reactive-var@1.0.11 32 | routepolicy@1.0.12 33 | spacebars@1.0.12 34 | spacebars-compiler@1.1.0 35 | templating@1.2.14_1 36 | templating-tools@1.1.1 37 | tracker@1.1.3 38 | underscore@1.0.10 39 | webapp@1.3.18 40 | webapp-hashing@1.0.9 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # qualia:web-shell 2 | Open up a Meteor shell in the browser by typing `Ctrl+'`. 3 | 4 | ## Installing 5 | 6 | `meteor add qualia:web-shell` 7 | -------------------------------------------------------------------------------- /client/main.js: -------------------------------------------------------------------------------- 1 | import './shell.html'; 2 | import './shell.js'; 3 | import './shell.css'; 4 | -------------------------------------------------------------------------------- /client/shell.css: -------------------------------------------------------------------------------- 1 | webTerm { 2 | all: initial; 3 | * { 4 | all: unset; 5 | } 6 | } 7 | 8 | webTerm { 9 | position: fixed; 10 | width: 80%; 11 | height: 60%; 12 | bottom: 20px; 13 | right: 0px; 14 | left: 0px; 15 | margin: auto; 16 | z-index: 10000; 17 | box-shadow: 0px 0px 20px 2px #000000; 18 | background-color: black; 19 | will-change: opacity; 20 | padding-left: 8px; 21 | padding-right: 8px; 22 | padding-top: 6px; 23 | padding-bottom: 6px; 24 | 25 | font-size: 12px; 26 | letter-spacing: normal; 27 | } 28 | 29 | webTerm.termVisible { 30 | transition: .2s linear all; 31 | opacity: 0.85; 32 | } 33 | 34 | webTerm.termHidden { 35 | transition: .2s linear all; 36 | bottom: -60%; 37 | opacity: 0; 38 | pointer-events: none 39 | } 40 | 41 | webTerm .xterm { 42 | line-height: 15px; 43 | } 44 | -------------------------------------------------------------------------------- /client/shell.html: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | {{> webTerm }} 7 | 8 | -------------------------------------------------------------------------------- /client/shell.js: -------------------------------------------------------------------------------- 1 | import Terminal from './xterm'; 2 | 3 | Template.webTerm.onCreated(function() { 4 | let tpl = this; 5 | 6 | _.extend(tpl, { 7 | 8 | visible: new ReactiveVar(false), 9 | status: new ReactiveVar('inactive'), 10 | 11 | initialize() { 12 | tpl.bindEvents(); 13 | tpl.startHeartbeat(); 14 | }, 15 | 16 | bindEvents() { 17 | $(document.body).on('keydown.webTerm', async e => { 18 | if (!e.ctrlKey || e.keyCode !== 222) { 19 | return; 20 | } 21 | 22 | if (tpl.status.get() === 'inactive') { 23 | await tpl.connectShell(); 24 | } 25 | 26 | Tracker.afterFlush(tpl.toggleVisibility); 27 | }); 28 | 29 | $(window).on('resize', _.debounce(() => { 30 | if (tpl.status.get() !== 'connected') { 31 | return; 32 | } 33 | 34 | let { cols, rows } = tpl.calcFit(), 35 | url = '/web-shell/terminals/' + tpl.shellPID + '/size?cols=' + cols + '&rows=' + rows; 36 | 37 | tpl.term.resize(cols, rows); 38 | fetch(url, {method: 'POST'}); 39 | }, 500)); 40 | 41 | tpl.autorun(comp => { 42 | if (Meteor.status().connected && tpl.status.get() === 'disconnected') { 43 | tpl.connectShell(); 44 | } 45 | }); 46 | }, 47 | 48 | calcFit() { 49 | let webTerm = tpl.$('webTerm'), 50 | width = webTerm.width(), 51 | height = webTerm.height(), 52 | fontHeight = parseInt(webTerm.css('fontSize')), 53 | fontWidth = 0.6 * fontHeight, 54 | lineHeight = 15 55 | ; 56 | return { 57 | cols: Math.floor(width / fontWidth), 58 | rows: Math.floor(height / lineHeight), 59 | }; 60 | }, 61 | 62 | async connectShell() { 63 | if (tpl.status.get() === 'connecting' || tpl.status.get() === 'connected') { 64 | return; 65 | } 66 | 67 | tpl.status.set('connecting'); 68 | tpl.createTerminal(); 69 | 70 | let { cols, rows } = tpl.calcFit(), 71 | res = await fetch('/web-shell/terminals?cols=' + cols + '&rows=' + rows, {method: 'POST'}), 72 | shellPID = await res.text(), 73 | protocol = (location.protocol === 'https:') ? 'wss://' : 'ws://', 74 | socketURL = protocol + location.hostname + ':8080/web-shell/terminals/' + shellPID 75 | ; 76 | 77 | tpl.shellPID = shellPID; 78 | tpl.socket = new WebSocket(socketURL); 79 | 80 | tpl.socket.onopen = () => { 81 | tpl.term.clear(); 82 | tpl.term.reset() 83 | tpl.term.attach(tpl.socket); 84 | 85 | tpl.status.set('connected'); 86 | }; 87 | tpl.socket.onclose = () => { 88 | tpl.term.detach(tpl.socket); 89 | tpl.printReconnecting(); 90 | 91 | tpl.status.set('disconnected'); 92 | }; 93 | 94 | }, 95 | 96 | createTerminal() { 97 | if (tpl.term) { 98 | return; 99 | } 100 | 101 | let { cols, rows } = tpl.calcFit(); 102 | tpl.term = new Terminal({ 103 | cursorBlink: true, 104 | scrollback: 1000, 105 | tabStopWidth: 4, 106 | cols, 107 | rows, 108 | }); 109 | window.tpl = tpl; 110 | 111 | tpl.term.open(tpl.$('webTerm')[0]); 112 | }, 113 | 114 | startHeartbeat() { 115 | Meteor.setInterval(() => { 116 | if (tpl.status.get() === 'connected') { 117 | tpl.socket.send('---heartbeat---'); 118 | } 119 | }, 10000); 120 | }, 121 | 122 | printReconnecting() { 123 | let message = 'Reconnecting...', 124 | { cols, rows } = tpl.calcFit(), 125 | newlines = _ 126 | .range(Math.floor(rows / 2) - 1) 127 | .map(() => '\n') 128 | .join(''), 129 | spaces = _ 130 | .range(Math.floor(cols/2 - message.length/2) + 1) 131 | .map(() => ' ') 132 | .join('') 133 | ; 134 | 135 | tpl.term.clear(); 136 | tpl.term.reset() 137 | tpl.term.write(newlines + spaces + message) 138 | }, 139 | 140 | toggleVisibility() { 141 | if (tpl.visible.get()) { 142 | tpl.term.blur(); 143 | } 144 | else { 145 | tpl.term.focus(); 146 | } 147 | 148 | tpl.$('webTerm').toggleClass('termVisible'); 149 | tpl.$('webTerm').toggleClass('termHidden'); 150 | 151 | tpl.visible.set(!tpl.visible.get()); 152 | }, 153 | 154 | }).initialize(); 155 | 156 | }); 157 | 158 | 159 | Template.webTerm.onDestroyed(function() { 160 | console.log('destroyed'); 161 | }); 162 | -------------------------------------------------------------------------------- /client/xterm/addons/attach/attach.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Implements the attach method, that attaches the terminal to a WebSocket stream. 3 | * @module xterm/addons/attach/attach 4 | * @license MIT 5 | */ 6 | 7 | (function (attach) { 8 | if (typeof exports === 'object' && typeof module === 'object') { 9 | /* 10 | * CommonJS environment 11 | */ 12 | module.exports = attach(require('../../xterm')); 13 | } else if (typeof define == 'function') { 14 | /* 15 | * Require.js is available 16 | */ 17 | define(['../../xterm'], attach); 18 | } else { 19 | /* 20 | * Plain browser environment 21 | */ 22 | attach(window.Terminal); 23 | } 24 | })(function (Xterm) { 25 | 'use strict'; 26 | 27 | var exports = {}; 28 | 29 | /** 30 | * Attaches the given terminal to the given socket. 31 | * 32 | * @param {Xterm} term - The terminal to be attached to the given socket. 33 | * @param {WebSocket} socket - The socket to attach the current terminal. 34 | * @param {boolean} bidirectional - Whether the terminal should send data 35 | * to the socket as well. 36 | * @param {boolean} buffered - Whether the rendering of incoming data 37 | * should happen instantly or at a maximum 38 | * frequency of 1 rendering per 10ms. 39 | */ 40 | exports.attach = function (term, socket, bidirectional, buffered) { 41 | bidirectional = (typeof bidirectional == 'undefined') ? true : bidirectional; 42 | term.socket = socket; 43 | 44 | term._flushBuffer = function () { 45 | term.write(term._attachSocketBuffer); 46 | term._attachSocketBuffer = null; 47 | clearTimeout(term._attachSocketBufferTimer); 48 | term._attachSocketBufferTimer = null; 49 | }; 50 | 51 | term._pushToBuffer = function (data) { 52 | if (term._attachSocketBuffer) { 53 | term._attachSocketBuffer += data; 54 | } else { 55 | term._attachSocketBuffer = data; 56 | setTimeout(term._flushBuffer, 10); 57 | } 58 | }; 59 | 60 | term._getMessage = function (ev) { 61 | if (buffered) { 62 | term._pushToBuffer(ev.data); 63 | } else { 64 | term.write(ev.data); 65 | } 66 | }; 67 | 68 | term._sendData = function (data) { 69 | socket.send(data); 70 | }; 71 | 72 | socket.addEventListener('message', term._getMessage); 73 | 74 | if (bidirectional) { 75 | term.on('data', term._sendData); 76 | } 77 | 78 | socket.addEventListener('close', term.detach.bind(term, socket)); 79 | socket.addEventListener('error', term.detach.bind(term, socket)); 80 | }; 81 | 82 | /** 83 | * Detaches the given terminal from the given socket 84 | * 85 | * @param {Xterm} term - The terminal to be detached from the given socket. 86 | * @param {WebSocket} socket - The socket from which to detach the current 87 | * terminal. 88 | */ 89 | exports.detach = function (term, socket) { 90 | term.off('data', term._sendData); 91 | 92 | socket = (typeof socket == 'undefined') ? term.socket : socket; 93 | 94 | if (socket) { 95 | socket.removeEventListener('message', term._getMessage); 96 | } 97 | 98 | delete term.socket; 99 | }; 100 | 101 | /** 102 | * Attaches the current terminal to the given socket 103 | * 104 | * @param {WebSocket} socket - The socket to attach the current terminal. 105 | * @param {boolean} bidirectional - Whether the terminal should send data 106 | * to the socket as well. 107 | * @param {boolean} buffered - Whether the rendering of incoming data 108 | * should happen instantly or at a maximum 109 | * frequency of 1 rendering per 10ms. 110 | */ 111 | Xterm.prototype.attach = function (socket, bidirectional, buffered) { 112 | return exports.attach(this, socket, bidirectional, buffered); 113 | }; 114 | 115 | /** 116 | * Detaches the current terminal from the given socket. 117 | * 118 | * @param {WebSocket} socket - The socket from which to detach the current 119 | * terminal. 120 | */ 121 | Xterm.prototype.detach = function (socket) { 122 | return exports.detach(this, socket); 123 | }; 124 | 125 | return exports; 126 | }); 127 | -------------------------------------------------------------------------------- /client/xterm/addons/attach/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "xterm.attach", 3 | "main": "attach.js", 4 | "private": true 5 | } 6 | -------------------------------------------------------------------------------- /client/xterm/addons/fit/fit.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Fit terminal columns and rows to the dimensions of its DOM element. 3 | * 4 | * ## Approach 5 | * - Rows: Truncate the division of the terminal parent element height by the terminal row height. 6 | * 7 | * - Columns: Truncate the division of the terminal parent element width by the terminal character 8 | * width (apply display: inline at the terminal row and truncate its width with the current 9 | * number of columns). 10 | * @module xterm/addons/fit/fit 11 | * @license MIT 12 | */ 13 | 14 | (function (fit) { 15 | if (typeof exports === 'object' && typeof module === 'object') { 16 | /* 17 | * CommonJS environment 18 | */ 19 | module.exports = fit(require('../../xterm')); 20 | } else if (typeof define == 'function') { 21 | /* 22 | * Require.js is available 23 | */ 24 | define(['../../xterm'], fit); 25 | } else { 26 | /* 27 | * Plain browser environment 28 | */ 29 | fit(window.Terminal); 30 | } 31 | })(function (Xterm) { 32 | var exports = {}; 33 | 34 | exports.proposeGeometry = function (term) { 35 | if (!term.element.parentElement) { 36 | return null; 37 | } 38 | var parentElementStyle = window.getComputedStyle(term.element.parentElement), 39 | parentElementHeight = parseInt(parentElementStyle.getPropertyValue('height')), 40 | parentElementWidth = Math.max(0, parseInt(parentElementStyle.getPropertyValue('width')) - 17), 41 | elementStyle = window.getComputedStyle(term.element), 42 | elementPaddingVer = parseInt(elementStyle.getPropertyValue('padding-top')) + parseInt(elementStyle.getPropertyValue('padding-bottom')), 43 | elementPaddingHor = parseInt(elementStyle.getPropertyValue('padding-right')) + parseInt(elementStyle.getPropertyValue('padding-left')), 44 | availableHeight = parentElementHeight - elementPaddingVer, 45 | availableWidth = parentElementWidth - elementPaddingHor, 46 | container = term.rowContainer, 47 | subjectRow = term.rowContainer.firstElementChild, 48 | contentBuffer = subjectRow.innerHTML, 49 | characterHeight, 50 | rows, 51 | characterWidth, 52 | cols, 53 | geometry; 54 | 55 | subjectRow.style.display = 'inline'; 56 | subjectRow.innerHTML = 'W'; // Common character for measuring width, although on monospace 57 | characterWidth = subjectRow.getBoundingClientRect().width; 58 | subjectRow.style.display = ''; // Revert style before calculating height, since they differ. 59 | characterHeight = subjectRow.getBoundingClientRect().height; 60 | subjectRow.innerHTML = contentBuffer; 61 | 62 | rows = parseInt(availableHeight / characterHeight); 63 | cols = parseInt(availableWidth / characterWidth); 64 | 65 | geometry = {cols: cols, rows: rows}; 66 | return geometry; 67 | }; 68 | 69 | exports.fit = function (term) { 70 | var geometry = exports.proposeGeometry(term); 71 | 72 | if (geometry) { 73 | term.resize(geometry.cols, geometry.rows); 74 | } 75 | }; 76 | 77 | Xterm.prototype.proposeGeometry = function () { 78 | return exports.proposeGeometry(this); 79 | }; 80 | 81 | Xterm.prototype.fit = function () { 82 | return exports.fit(this); 83 | }; 84 | 85 | return exports; 86 | }); 87 | -------------------------------------------------------------------------------- /client/xterm/addons/fit/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "xterm.fit", 3 | "main": "fit.js", 4 | "private": true 5 | } 6 | -------------------------------------------------------------------------------- /client/xterm/addons/fullscreen/fullscreen.css: -------------------------------------------------------------------------------- 1 | .xterm.fullscreen { 2 | position: fixed; 3 | top: 0; 4 | bottom: 0; 5 | left: 0; 6 | right: 0; 7 | width: auto; 8 | height: auto; 9 | z-index: 255; 10 | } 11 | -------------------------------------------------------------------------------- /client/xterm/addons/fullscreen/fullscreen.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Fullscreen addon for xterm.js 3 | * @module xterm/addons/fullscreen/fullscreen 4 | * @license MIT 5 | */ 6 | (function (fullscreen) { 7 | if (typeof exports === 'object' && typeof module === 'object') { 8 | /* 9 | * CommonJS environment 10 | */ 11 | module.exports = fullscreen(require('../../xterm')); 12 | } else if (typeof define == 'function') { 13 | /* 14 | * Require.js is available 15 | */ 16 | define(['../../xterm'], fullscreen); 17 | } else { 18 | /* 19 | * Plain browser environment 20 | */ 21 | fullscreen(window.Terminal); 22 | } 23 | })(function (Xterm) { 24 | var exports = {}; 25 | 26 | /** 27 | * Toggle the given terminal's fullscreen mode. 28 | * @param {Xterm} term - The terminal to toggle full screen mode 29 | * @param {boolean} fullscreen - Toggle fullscreen on (true) or off (false) 30 | */ 31 | exports.toggleFullScreen = function (term, fullscreen) { 32 | var fn; 33 | 34 | if (typeof fullscreen == 'undefined') { 35 | fn = (term.element.classList.contains('fullscreen')) ? 'remove' : 'add'; 36 | } else if (!fullscreen) { 37 | fn = 'remove'; 38 | } else { 39 | fn = 'add'; 40 | } 41 | 42 | term.element.classList[fn]('fullscreen'); 43 | }; 44 | 45 | Xterm.prototype.toggleFullscreen = function (fullscreen) { 46 | exports.toggleFullScreen(this, fullscreen); 47 | }; 48 | 49 | return exports; 50 | }); 51 | -------------------------------------------------------------------------------- /client/xterm/addons/fullscreen/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "xterm.fullscreen", 3 | "main": "fullscreen.js", 4 | "private": true 5 | } 6 | -------------------------------------------------------------------------------- /client/xterm/addons/linkify/linkify.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Methods for turning URL subscrings in the terminal's content into links (`a` DOM elements). 3 | * @module xterm/addons/linkify/linkify 4 | * @license MIT 5 | */ 6 | 7 | (function (linkify) { 8 | if (typeof exports === 'object' && typeof module === 'object') { 9 | /* 10 | * CommonJS environment 11 | */ 12 | module.exports = linkify(require('../../xterm')); 13 | } else if (typeof define == 'function') { 14 | /* 15 | * Require.js is available 16 | */ 17 | define(['../../xterm'], linkify); 18 | } else { 19 | /* 20 | * Plain browser environment 21 | */ 22 | linkify(window.Terminal); 23 | } 24 | })(function (Xterm) { 25 | 'use strict'; 26 | 27 | var exports = {}, 28 | protocolClause = '(https?:\\/\\/)', 29 | domainCharacterSet = '[\\da-z\\.-]+', 30 | negatedDomainCharacterSet = '[^\\da-z\\.-]+', 31 | domainBodyClause = '(' + domainCharacterSet + ')', 32 | tldClause = '([a-z\\.]{2,6})', 33 | ipClause = '((\\d{1,3}\\.){3}\\d{1,3})', 34 | portClause = '(:\\d{1,5})', 35 | hostClause = '((' + domainBodyClause + '\\.' + tldClause + ')|' + ipClause + ')' + portClause + '?', 36 | pathClause = '(\\/[\\/\\w\\.-]*)*', 37 | negatedPathCharacterSet = '[^\\/\\w\\.-]+', 38 | bodyClause = hostClause + pathClause, 39 | start = '(?:^|' + negatedDomainCharacterSet + ')(', 40 | end = ')($|' + negatedPathCharacterSet + ')', 41 | lenientUrlClause = start + protocolClause + '?' + bodyClause + end, 42 | strictUrlClause = start + protocolClause + bodyClause + end, 43 | lenientUrlRegex = new RegExp(lenientUrlClause), 44 | strictUrlRegex = new RegExp(strictUrlClause); 45 | 46 | /** 47 | * Converts all valid URLs found in the given terminal line into 48 | * hyperlinks. The terminal line can be either the HTML element itself 49 | * or the index of the termina line in the children of the terminal 50 | * rows container. 51 | * 52 | * @param {Xterm} terminal - The terminal that owns the given line. 53 | * @param {number|HTMLDivElement} line - The terminal line that should get 54 | * "linkified". 55 | * @param {boolean} lenient - The regex type that will be used to identify links. If lenient is 56 | * false, the regex requires a protocol clause. Defaults to true. 57 | * @param {string} target - Sets target="" attribute with value provided to links. 58 | * Default doesn't set target attribute 59 | * @emits linkify 60 | * @emits linkify:line 61 | */ 62 | exports.linkifyTerminalLine = function (terminal, line, lenient, target) { 63 | if (typeof line == 'number') { 64 | line = terminal.rowContainer.children[line]; 65 | } else if (! (line instanceof HTMLDivElement)) { 66 | var message = 'The "line" argument should be either a number'; 67 | message += ' or an HTMLDivElement'; 68 | 69 | throw new TypeError(message); 70 | } 71 | 72 | if (typeof target === 'undefined') { 73 | target = ''; 74 | } else { 75 | target = 'target="' + target + '"'; 76 | } 77 | 78 | var buffer = document.createElement('span'), 79 | nodes = line.childNodes; 80 | 81 | for (var j=0; j' + url + '', 112 | newHTML = nodeHTML.replace(url, link); 113 | 114 | line.innerHTML = line.innerHTML.replace(nodeHTML, newHTML); 115 | } 116 | 117 | /** 118 | * This event gets emitted when conversion of all URL susbtrings 119 | * to HTML anchor elements (links) has finished, for a specific 120 | * line of the current Xterm instance. 121 | * 122 | * @event linkify:line 123 | */ 124 | terminal.emit('linkify:line', line); 125 | }; 126 | 127 | /** 128 | * Finds a link within a block of text. 129 | * 130 | * @param {string} text - The text to search . 131 | * @param {boolean} lenient - Whether to use the lenient search. 132 | * @return {string} A URL. 133 | */ 134 | exports.findLinkMatch = function (text, lenient) { 135 | var match = text.match(lenient ? lenientUrlRegex : strictUrlRegex); 136 | if (!match || match.length === 0) { 137 | return null; 138 | } 139 | return match[1]; 140 | } 141 | 142 | /** 143 | * Converts all valid URLs found in the terminal view into hyperlinks. 144 | * 145 | * @param {Xterm} terminal - The terminal that should get "linkified". 146 | * @param {boolean} lenient - The regex type that will be used to identify links. If lenient is 147 | * false, the regex requires a protocol clause. Defaults to true. 148 | * @param {string} target - Sets target="" attribute with value provided to links. 149 | * Default doesn't set target attribute 150 | * @emits linkify 151 | * @emits linkify:line 152 | */ 153 | exports.linkify = function (terminal, lenient, target) { 154 | var rows = terminal.rowContainer.children; 155 | 156 | lenient = (typeof lenient == "boolean") ? lenient : true; 157 | for (var i=0; i div { 158 | /* Lines containing spans and text nodes ocassionally wrap despite being the same width (#327) */ 159 | white-space: nowrap; 160 | } 161 | 162 | .terminal .xterm-scroll-area { 163 | visibility: hidden; 164 | } 165 | 166 | .terminal .xterm-char-measure-element { 167 | display: inline-block; 168 | visibility: hidden; 169 | position: absolute; 170 | left: -9999em; 171 | } 172 | 173 | .terminal.enable-mouse-events { 174 | /* When mouse events are enabled (eg. tmux), revert to the standard pointer cursor */ 175 | cursor: default; 176 | } 177 | 178 | .terminal .xterm-selection { 179 | position: absolute; 180 | top: 0; 181 | left: 0; 182 | z-index: 1; 183 | opacity: 0.3; 184 | pointer-events: none; 185 | } 186 | 187 | .terminal .xterm-selection div { 188 | position: absolute; 189 | background-color: #fff; 190 | } 191 | 192 | /* 193 | * Determine default colors for xterm.js 194 | */ 195 | .terminal .xterm-bold { 196 | font-weight: bold; 197 | } 198 | 199 | .terminal .xterm-underline { 200 | text-decoration: underline; 201 | } 202 | 203 | .terminal .xterm-blink { 204 | text-decoration: blink; 205 | } 206 | 207 | .terminal .xterm-blink.xterm-underline { 208 | text-decoration: blink underline; 209 | } 210 | 211 | .terminal .xterm-hidden { 212 | visibility: hidden; 213 | } 214 | 215 | .terminal .xterm-color-0 { 216 | color: #2e3436; 217 | } 218 | 219 | .terminal .xterm-bg-color-0 { 220 | background-color: #2e3436; 221 | } 222 | 223 | .terminal .xterm-color-1 { 224 | color: #cc0000; 225 | } 226 | 227 | .terminal .xterm-bg-color-1 { 228 | background-color: #cc0000; 229 | } 230 | 231 | .terminal .xterm-color-2 { 232 | color: #4e9a06; 233 | } 234 | 235 | .terminal .xterm-bg-color-2 { 236 | background-color: #4e9a06; 237 | } 238 | 239 | .terminal .xterm-color-3 { 240 | color: #c4a000; 241 | } 242 | 243 | .terminal .xterm-bg-color-3 { 244 | background-color: #c4a000; 245 | } 246 | 247 | .terminal .xterm-color-4 { 248 | color: #3465a4; 249 | } 250 | 251 | .terminal .xterm-bg-color-4 { 252 | background-color: #3465a4; 253 | } 254 | 255 | .terminal .xterm-color-5 { 256 | color: #75507b; 257 | } 258 | 259 | .terminal .xterm-bg-color-5 { 260 | background-color: #75507b; 261 | } 262 | 263 | .terminal .xterm-color-6 { 264 | color: #06989a; 265 | } 266 | 267 | .terminal .xterm-bg-color-6 { 268 | background-color: #06989a; 269 | } 270 | 271 | .terminal .xterm-color-7 { 272 | color: #d3d7cf; 273 | } 274 | 275 | .terminal .xterm-bg-color-7 { 276 | background-color: #d3d7cf; 277 | } 278 | 279 | .terminal .xterm-color-8 { 280 | color: #555753; 281 | } 282 | 283 | .terminal .xterm-bg-color-8 { 284 | background-color: #555753; 285 | } 286 | 287 | .terminal .xterm-color-9 { 288 | color: #ef2929; 289 | } 290 | 291 | .terminal .xterm-bg-color-9 { 292 | background-color: #ef2929; 293 | } 294 | 295 | .terminal .xterm-color-10 { 296 | color: #8ae234; 297 | } 298 | 299 | .terminal .xterm-bg-color-10 { 300 | background-color: #8ae234; 301 | } 302 | 303 | .terminal .xterm-color-11 { 304 | color: #fce94f; 305 | } 306 | 307 | .terminal .xterm-bg-color-11 { 308 | background-color: #fce94f; 309 | } 310 | 311 | .terminal .xterm-color-12 { 312 | color: #729fcf; 313 | } 314 | 315 | .terminal .xterm-bg-color-12 { 316 | background-color: #729fcf; 317 | } 318 | 319 | .terminal .xterm-color-13 { 320 | color: #ad7fa8; 321 | } 322 | 323 | .terminal .xterm-bg-color-13 { 324 | background-color: #ad7fa8; 325 | } 326 | 327 | .terminal .xterm-color-14 { 328 | color: #34e2e2; 329 | } 330 | 331 | .terminal .xterm-bg-color-14 { 332 | background-color: #34e2e2; 333 | } 334 | 335 | .terminal .xterm-color-15 { 336 | color: #eeeeec; 337 | } 338 | 339 | .terminal .xterm-bg-color-15 { 340 | background-color: #eeeeec; 341 | } 342 | 343 | .terminal .xterm-color-16 { 344 | color: #000000; 345 | } 346 | 347 | .terminal .xterm-bg-color-16 { 348 | background-color: #000000; 349 | } 350 | 351 | .terminal .xterm-color-17 { 352 | color: #00005f; 353 | } 354 | 355 | .terminal .xterm-bg-color-17 { 356 | background-color: #00005f; 357 | } 358 | 359 | .terminal .xterm-color-18 { 360 | color: #000087; 361 | } 362 | 363 | .terminal .xterm-bg-color-18 { 364 | background-color: #000087; 365 | } 366 | 367 | .terminal .xterm-color-19 { 368 | color: #0000af; 369 | } 370 | 371 | .terminal .xterm-bg-color-19 { 372 | background-color: #0000af; 373 | } 374 | 375 | .terminal .xterm-color-20 { 376 | color: #0000d7; 377 | } 378 | 379 | .terminal .xterm-bg-color-20 { 380 | background-color: #0000d7; 381 | } 382 | 383 | .terminal .xterm-color-21 { 384 | color: #0000ff; 385 | } 386 | 387 | .terminal .xterm-bg-color-21 { 388 | background-color: #0000ff; 389 | } 390 | 391 | .terminal .xterm-color-22 { 392 | color: #005f00; 393 | } 394 | 395 | .terminal .xterm-bg-color-22 { 396 | background-color: #005f00; 397 | } 398 | 399 | .terminal .xterm-color-23 { 400 | color: #005f5f; 401 | } 402 | 403 | .terminal .xterm-bg-color-23 { 404 | background-color: #005f5f; 405 | } 406 | 407 | .terminal .xterm-color-24 { 408 | color: #005f87; 409 | } 410 | 411 | .terminal .xterm-bg-color-24 { 412 | background-color: #005f87; 413 | } 414 | 415 | .terminal .xterm-color-25 { 416 | color: #005faf; 417 | } 418 | 419 | .terminal .xterm-bg-color-25 { 420 | background-color: #005faf; 421 | } 422 | 423 | .terminal .xterm-color-26 { 424 | color: #005fd7; 425 | } 426 | 427 | .terminal .xterm-bg-color-26 { 428 | background-color: #005fd7; 429 | } 430 | 431 | .terminal .xterm-color-27 { 432 | color: #005fff; 433 | } 434 | 435 | .terminal .xterm-bg-color-27 { 436 | background-color: #005fff; 437 | } 438 | 439 | .terminal .xterm-color-28 { 440 | color: #008700; 441 | } 442 | 443 | .terminal .xterm-bg-color-28 { 444 | background-color: #008700; 445 | } 446 | 447 | .terminal .xterm-color-29 { 448 | color: #00875f; 449 | } 450 | 451 | .terminal .xterm-bg-color-29 { 452 | background-color: #00875f; 453 | } 454 | 455 | .terminal .xterm-color-30 { 456 | color: #008787; 457 | } 458 | 459 | .terminal .xterm-bg-color-30 { 460 | background-color: #008787; 461 | } 462 | 463 | .terminal .xterm-color-31 { 464 | color: #0087af; 465 | } 466 | 467 | .terminal .xterm-bg-color-31 { 468 | background-color: #0087af; 469 | } 470 | 471 | .terminal .xterm-color-32 { 472 | color: #0087d7; 473 | } 474 | 475 | .terminal .xterm-bg-color-32 { 476 | background-color: #0087d7; 477 | } 478 | 479 | .terminal .xterm-color-33 { 480 | color: #0087ff; 481 | } 482 | 483 | .terminal .xterm-bg-color-33 { 484 | background-color: #0087ff; 485 | } 486 | 487 | .terminal .xterm-color-34 { 488 | color: #00af00; 489 | } 490 | 491 | .terminal .xterm-bg-color-34 { 492 | background-color: #00af00; 493 | } 494 | 495 | .terminal .xterm-color-35 { 496 | color: #00af5f; 497 | } 498 | 499 | .terminal .xterm-bg-color-35 { 500 | background-color: #00af5f; 501 | } 502 | 503 | .terminal .xterm-color-36 { 504 | color: #00af87; 505 | } 506 | 507 | .terminal .xterm-bg-color-36 { 508 | background-color: #00af87; 509 | } 510 | 511 | .terminal .xterm-color-37 { 512 | color: #00afaf; 513 | } 514 | 515 | .terminal .xterm-bg-color-37 { 516 | background-color: #00afaf; 517 | } 518 | 519 | .terminal .xterm-color-38 { 520 | color: #00afd7; 521 | } 522 | 523 | .terminal .xterm-bg-color-38 { 524 | background-color: #00afd7; 525 | } 526 | 527 | .terminal .xterm-color-39 { 528 | color: #00afff; 529 | } 530 | 531 | .terminal .xterm-bg-color-39 { 532 | background-color: #00afff; 533 | } 534 | 535 | .terminal .xterm-color-40 { 536 | color: #00d700; 537 | } 538 | 539 | .terminal .xterm-bg-color-40 { 540 | background-color: #00d700; 541 | } 542 | 543 | .terminal .xterm-color-41 { 544 | color: #00d75f; 545 | } 546 | 547 | .terminal .xterm-bg-color-41 { 548 | background-color: #00d75f; 549 | } 550 | 551 | .terminal .xterm-color-42 { 552 | color: #00d787; 553 | } 554 | 555 | .terminal .xterm-bg-color-42 { 556 | background-color: #00d787; 557 | } 558 | 559 | .terminal .xterm-color-43 { 560 | color: #00d7af; 561 | } 562 | 563 | .terminal .xterm-bg-color-43 { 564 | background-color: #00d7af; 565 | } 566 | 567 | .terminal .xterm-color-44 { 568 | color: #00d7d7; 569 | } 570 | 571 | .terminal .xterm-bg-color-44 { 572 | background-color: #00d7d7; 573 | } 574 | 575 | .terminal .xterm-color-45 { 576 | color: #00d7ff; 577 | } 578 | 579 | .terminal .xterm-bg-color-45 { 580 | background-color: #00d7ff; 581 | } 582 | 583 | .terminal .xterm-color-46 { 584 | color: #00ff00; 585 | } 586 | 587 | .terminal .xterm-bg-color-46 { 588 | background-color: #00ff00; 589 | } 590 | 591 | .terminal .xterm-color-47 { 592 | color: #00ff5f; 593 | } 594 | 595 | .terminal .xterm-bg-color-47 { 596 | background-color: #00ff5f; 597 | } 598 | 599 | .terminal .xterm-color-48 { 600 | color: #00ff87; 601 | } 602 | 603 | .terminal .xterm-bg-color-48 { 604 | background-color: #00ff87; 605 | } 606 | 607 | .terminal .xterm-color-49 { 608 | color: #00ffaf; 609 | } 610 | 611 | .terminal .xterm-bg-color-49 { 612 | background-color: #00ffaf; 613 | } 614 | 615 | .terminal .xterm-color-50 { 616 | color: #00ffd7; 617 | } 618 | 619 | .terminal .xterm-bg-color-50 { 620 | background-color: #00ffd7; 621 | } 622 | 623 | .terminal .xterm-color-51 { 624 | color: #00ffff; 625 | } 626 | 627 | .terminal .xterm-bg-color-51 { 628 | background-color: #00ffff; 629 | } 630 | 631 | .terminal .xterm-color-52 { 632 | color: #5f0000; 633 | } 634 | 635 | .terminal .xterm-bg-color-52 { 636 | background-color: #5f0000; 637 | } 638 | 639 | .terminal .xterm-color-53 { 640 | color: #5f005f; 641 | } 642 | 643 | .terminal .xterm-bg-color-53 { 644 | background-color: #5f005f; 645 | } 646 | 647 | .terminal .xterm-color-54 { 648 | color: #5f0087; 649 | } 650 | 651 | .terminal .xterm-bg-color-54 { 652 | background-color: #5f0087; 653 | } 654 | 655 | .terminal .xterm-color-55 { 656 | color: #5f00af; 657 | } 658 | 659 | .terminal .xterm-bg-color-55 { 660 | background-color: #5f00af; 661 | } 662 | 663 | .terminal .xterm-color-56 { 664 | color: #5f00d7; 665 | } 666 | 667 | .terminal .xterm-bg-color-56 { 668 | background-color: #5f00d7; 669 | } 670 | 671 | .terminal .xterm-color-57 { 672 | color: #5f00ff; 673 | } 674 | 675 | .terminal .xterm-bg-color-57 { 676 | background-color: #5f00ff; 677 | } 678 | 679 | .terminal .xterm-color-58 { 680 | color: #5f5f00; 681 | } 682 | 683 | .terminal .xterm-bg-color-58 { 684 | background-color: #5f5f00; 685 | } 686 | 687 | .terminal .xterm-color-59 { 688 | color: #5f5f5f; 689 | } 690 | 691 | .terminal .xterm-bg-color-59 { 692 | background-color: #5f5f5f; 693 | } 694 | 695 | .terminal .xterm-color-60 { 696 | color: #5f5f87; 697 | } 698 | 699 | .terminal .xterm-bg-color-60 { 700 | background-color: #5f5f87; 701 | } 702 | 703 | .terminal .xterm-color-61 { 704 | color: #5f5faf; 705 | } 706 | 707 | .terminal .xterm-bg-color-61 { 708 | background-color: #5f5faf; 709 | } 710 | 711 | .terminal .xterm-color-62 { 712 | color: #5f5fd7; 713 | } 714 | 715 | .terminal .xterm-bg-color-62 { 716 | background-color: #5f5fd7; 717 | } 718 | 719 | .terminal .xterm-color-63 { 720 | color: #5f5fff; 721 | } 722 | 723 | .terminal .xterm-bg-color-63 { 724 | background-color: #5f5fff; 725 | } 726 | 727 | .terminal .xterm-color-64 { 728 | color: #5f8700; 729 | } 730 | 731 | .terminal .xterm-bg-color-64 { 732 | background-color: #5f8700; 733 | } 734 | 735 | .terminal .xterm-color-65 { 736 | color: #5f875f; 737 | } 738 | 739 | .terminal .xterm-bg-color-65 { 740 | background-color: #5f875f; 741 | } 742 | 743 | .terminal .xterm-color-66 { 744 | color: #5f8787; 745 | } 746 | 747 | .terminal .xterm-bg-color-66 { 748 | background-color: #5f8787; 749 | } 750 | 751 | .terminal .xterm-color-67 { 752 | color: #5f87af; 753 | } 754 | 755 | .terminal .xterm-bg-color-67 { 756 | background-color: #5f87af; 757 | } 758 | 759 | .terminal .xterm-color-68 { 760 | color: #5f87d7; 761 | } 762 | 763 | .terminal .xterm-bg-color-68 { 764 | background-color: #5f87d7; 765 | } 766 | 767 | .terminal .xterm-color-69 { 768 | color: #5f87ff; 769 | } 770 | 771 | .terminal .xterm-bg-color-69 { 772 | background-color: #5f87ff; 773 | } 774 | 775 | .terminal .xterm-color-70 { 776 | color: #5faf00; 777 | } 778 | 779 | .terminal .xterm-bg-color-70 { 780 | background-color: #5faf00; 781 | } 782 | 783 | .terminal .xterm-color-71 { 784 | color: #5faf5f; 785 | } 786 | 787 | .terminal .xterm-bg-color-71 { 788 | background-color: #5faf5f; 789 | } 790 | 791 | .terminal .xterm-color-72 { 792 | color: #5faf87; 793 | } 794 | 795 | .terminal .xterm-bg-color-72 { 796 | background-color: #5faf87; 797 | } 798 | 799 | .terminal .xterm-color-73 { 800 | color: #5fafaf; 801 | } 802 | 803 | .terminal .xterm-bg-color-73 { 804 | background-color: #5fafaf; 805 | } 806 | 807 | .terminal .xterm-color-74 { 808 | color: #5fafd7; 809 | } 810 | 811 | .terminal .xterm-bg-color-74 { 812 | background-color: #5fafd7; 813 | } 814 | 815 | .terminal .xterm-color-75 { 816 | color: #5fafff; 817 | } 818 | 819 | .terminal .xterm-bg-color-75 { 820 | background-color: #5fafff; 821 | } 822 | 823 | .terminal .xterm-color-76 { 824 | color: #5fd700; 825 | } 826 | 827 | .terminal .xterm-bg-color-76 { 828 | background-color: #5fd700; 829 | } 830 | 831 | .terminal .xterm-color-77 { 832 | color: #5fd75f; 833 | } 834 | 835 | .terminal .xterm-bg-color-77 { 836 | background-color: #5fd75f; 837 | } 838 | 839 | .terminal .xterm-color-78 { 840 | color: #5fd787; 841 | } 842 | 843 | .terminal .xterm-bg-color-78 { 844 | background-color: #5fd787; 845 | } 846 | 847 | .terminal .xterm-color-79 { 848 | color: #5fd7af; 849 | } 850 | 851 | .terminal .xterm-bg-color-79 { 852 | background-color: #5fd7af; 853 | } 854 | 855 | .terminal .xterm-color-80 { 856 | color: #5fd7d7; 857 | } 858 | 859 | .terminal .xterm-bg-color-80 { 860 | background-color: #5fd7d7; 861 | } 862 | 863 | .terminal .xterm-color-81 { 864 | color: #5fd7ff; 865 | } 866 | 867 | .terminal .xterm-bg-color-81 { 868 | background-color: #5fd7ff; 869 | } 870 | 871 | .terminal .xterm-color-82 { 872 | color: #5fff00; 873 | } 874 | 875 | .terminal .xterm-bg-color-82 { 876 | background-color: #5fff00; 877 | } 878 | 879 | .terminal .xterm-color-83 { 880 | color: #5fff5f; 881 | } 882 | 883 | .terminal .xterm-bg-color-83 { 884 | background-color: #5fff5f; 885 | } 886 | 887 | .terminal .xterm-color-84 { 888 | color: #5fff87; 889 | } 890 | 891 | .terminal .xterm-bg-color-84 { 892 | background-color: #5fff87; 893 | } 894 | 895 | .terminal .xterm-color-85 { 896 | color: #5fffaf; 897 | } 898 | 899 | .terminal .xterm-bg-color-85 { 900 | background-color: #5fffaf; 901 | } 902 | 903 | .terminal .xterm-color-86 { 904 | color: #5fffd7; 905 | } 906 | 907 | .terminal .xterm-bg-color-86 { 908 | background-color: #5fffd7; 909 | } 910 | 911 | .terminal .xterm-color-87 { 912 | color: #5fffff; 913 | } 914 | 915 | .terminal .xterm-bg-color-87 { 916 | background-color: #5fffff; 917 | } 918 | 919 | .terminal .xterm-color-88 { 920 | color: #870000; 921 | } 922 | 923 | .terminal .xterm-bg-color-88 { 924 | background-color: #870000; 925 | } 926 | 927 | .terminal .xterm-color-89 { 928 | color: #87005f; 929 | } 930 | 931 | .terminal .xterm-bg-color-89 { 932 | background-color: #87005f; 933 | } 934 | 935 | .terminal .xterm-color-90 { 936 | color: #870087; 937 | } 938 | 939 | .terminal .xterm-bg-color-90 { 940 | background-color: #870087; 941 | } 942 | 943 | .terminal .xterm-color-91 { 944 | color: #8700af; 945 | } 946 | 947 | .terminal .xterm-bg-color-91 { 948 | background-color: #8700af; 949 | } 950 | 951 | .terminal .xterm-color-92 { 952 | color: #8700d7; 953 | } 954 | 955 | .terminal .xterm-bg-color-92 { 956 | background-color: #8700d7; 957 | } 958 | 959 | .terminal .xterm-color-93 { 960 | color: #8700ff; 961 | } 962 | 963 | .terminal .xterm-bg-color-93 { 964 | background-color: #8700ff; 965 | } 966 | 967 | .terminal .xterm-color-94 { 968 | color: #875f00; 969 | } 970 | 971 | .terminal .xterm-bg-color-94 { 972 | background-color: #875f00; 973 | } 974 | 975 | .terminal .xterm-color-95 { 976 | color: #875f5f; 977 | } 978 | 979 | .terminal .xterm-bg-color-95 { 980 | background-color: #875f5f; 981 | } 982 | 983 | .terminal .xterm-color-96 { 984 | color: #875f87; 985 | } 986 | 987 | .terminal .xterm-bg-color-96 { 988 | background-color: #875f87; 989 | } 990 | 991 | .terminal .xterm-color-97 { 992 | color: #875faf; 993 | } 994 | 995 | .terminal .xterm-bg-color-97 { 996 | background-color: #875faf; 997 | } 998 | 999 | .terminal .xterm-color-98 { 1000 | color: #875fd7; 1001 | } 1002 | 1003 | .terminal .xterm-bg-color-98 { 1004 | background-color: #875fd7; 1005 | } 1006 | 1007 | .terminal .xterm-color-99 { 1008 | color: #875fff; 1009 | } 1010 | 1011 | .terminal .xterm-bg-color-99 { 1012 | background-color: #875fff; 1013 | } 1014 | 1015 | .terminal .xterm-color-100 { 1016 | color: #878700; 1017 | } 1018 | 1019 | .terminal .xterm-bg-color-100 { 1020 | background-color: #878700; 1021 | } 1022 | 1023 | .terminal .xterm-color-101 { 1024 | color: #87875f; 1025 | } 1026 | 1027 | .terminal .xterm-bg-color-101 { 1028 | background-color: #87875f; 1029 | } 1030 | 1031 | .terminal .xterm-color-102 { 1032 | color: #878787; 1033 | } 1034 | 1035 | .terminal .xterm-bg-color-102 { 1036 | background-color: #878787; 1037 | } 1038 | 1039 | .terminal .xterm-color-103 { 1040 | color: #8787af; 1041 | } 1042 | 1043 | .terminal .xterm-bg-color-103 { 1044 | background-color: #8787af; 1045 | } 1046 | 1047 | .terminal .xterm-color-104 { 1048 | color: #8787d7; 1049 | } 1050 | 1051 | .terminal .xterm-bg-color-104 { 1052 | background-color: #8787d7; 1053 | } 1054 | 1055 | .terminal .xterm-color-105 { 1056 | color: #8787ff; 1057 | } 1058 | 1059 | .terminal .xterm-bg-color-105 { 1060 | background-color: #8787ff; 1061 | } 1062 | 1063 | .terminal .xterm-color-106 { 1064 | color: #87af00; 1065 | } 1066 | 1067 | .terminal .xterm-bg-color-106 { 1068 | background-color: #87af00; 1069 | } 1070 | 1071 | .terminal .xterm-color-107 { 1072 | color: #87af5f; 1073 | } 1074 | 1075 | .terminal .xterm-bg-color-107 { 1076 | background-color: #87af5f; 1077 | } 1078 | 1079 | .terminal .xterm-color-108 { 1080 | color: #87af87; 1081 | } 1082 | 1083 | .terminal .xterm-bg-color-108 { 1084 | background-color: #87af87; 1085 | } 1086 | 1087 | .terminal .xterm-color-109 { 1088 | color: #87afaf; 1089 | } 1090 | 1091 | .terminal .xterm-bg-color-109 { 1092 | background-color: #87afaf; 1093 | } 1094 | 1095 | .terminal .xterm-color-110 { 1096 | color: #87afd7; 1097 | } 1098 | 1099 | .terminal .xterm-bg-color-110 { 1100 | background-color: #87afd7; 1101 | } 1102 | 1103 | .terminal .xterm-color-111 { 1104 | color: #87afff; 1105 | } 1106 | 1107 | .terminal .xterm-bg-color-111 { 1108 | background-color: #87afff; 1109 | } 1110 | 1111 | .terminal .xterm-color-112 { 1112 | color: #87d700; 1113 | } 1114 | 1115 | .terminal .xterm-bg-color-112 { 1116 | background-color: #87d700; 1117 | } 1118 | 1119 | .terminal .xterm-color-113 { 1120 | color: #87d75f; 1121 | } 1122 | 1123 | .terminal .xterm-bg-color-113 { 1124 | background-color: #87d75f; 1125 | } 1126 | 1127 | .terminal .xterm-color-114 { 1128 | color: #87d787; 1129 | } 1130 | 1131 | .terminal .xterm-bg-color-114 { 1132 | background-color: #87d787; 1133 | } 1134 | 1135 | .terminal .xterm-color-115 { 1136 | color: #87d7af; 1137 | } 1138 | 1139 | .terminal .xterm-bg-color-115 { 1140 | background-color: #87d7af; 1141 | } 1142 | 1143 | .terminal .xterm-color-116 { 1144 | color: #87d7d7; 1145 | } 1146 | 1147 | .terminal .xterm-bg-color-116 { 1148 | background-color: #87d7d7; 1149 | } 1150 | 1151 | .terminal .xterm-color-117 { 1152 | color: #87d7ff; 1153 | } 1154 | 1155 | .terminal .xterm-bg-color-117 { 1156 | background-color: #87d7ff; 1157 | } 1158 | 1159 | .terminal .xterm-color-118 { 1160 | color: #87ff00; 1161 | } 1162 | 1163 | .terminal .xterm-bg-color-118 { 1164 | background-color: #87ff00; 1165 | } 1166 | 1167 | .terminal .xterm-color-119 { 1168 | color: #87ff5f; 1169 | } 1170 | 1171 | .terminal .xterm-bg-color-119 { 1172 | background-color: #87ff5f; 1173 | } 1174 | 1175 | .terminal .xterm-color-120 { 1176 | color: #87ff87; 1177 | } 1178 | 1179 | .terminal .xterm-bg-color-120 { 1180 | background-color: #87ff87; 1181 | } 1182 | 1183 | .terminal .xterm-color-121 { 1184 | color: #87ffaf; 1185 | } 1186 | 1187 | .terminal .xterm-bg-color-121 { 1188 | background-color: #87ffaf; 1189 | } 1190 | 1191 | .terminal .xterm-color-122 { 1192 | color: #87ffd7; 1193 | } 1194 | 1195 | .terminal .xterm-bg-color-122 { 1196 | background-color: #87ffd7; 1197 | } 1198 | 1199 | .terminal .xterm-color-123 { 1200 | color: #87ffff; 1201 | } 1202 | 1203 | .terminal .xterm-bg-color-123 { 1204 | background-color: #87ffff; 1205 | } 1206 | 1207 | .terminal .xterm-color-124 { 1208 | color: #af0000; 1209 | } 1210 | 1211 | .terminal .xterm-bg-color-124 { 1212 | background-color: #af0000; 1213 | } 1214 | 1215 | .terminal .xterm-color-125 { 1216 | color: #af005f; 1217 | } 1218 | 1219 | .terminal .xterm-bg-color-125 { 1220 | background-color: #af005f; 1221 | } 1222 | 1223 | .terminal .xterm-color-126 { 1224 | color: #af0087; 1225 | } 1226 | 1227 | .terminal .xterm-bg-color-126 { 1228 | background-color: #af0087; 1229 | } 1230 | 1231 | .terminal .xterm-color-127 { 1232 | color: #af00af; 1233 | } 1234 | 1235 | .terminal .xterm-bg-color-127 { 1236 | background-color: #af00af; 1237 | } 1238 | 1239 | .terminal .xterm-color-128 { 1240 | color: #af00d7; 1241 | } 1242 | 1243 | .terminal .xterm-bg-color-128 { 1244 | background-color: #af00d7; 1245 | } 1246 | 1247 | .terminal .xterm-color-129 { 1248 | color: #af00ff; 1249 | } 1250 | 1251 | .terminal .xterm-bg-color-129 { 1252 | background-color: #af00ff; 1253 | } 1254 | 1255 | .terminal .xterm-color-130 { 1256 | color: #af5f00; 1257 | } 1258 | 1259 | .terminal .xterm-bg-color-130 { 1260 | background-color: #af5f00; 1261 | } 1262 | 1263 | .terminal .xterm-color-131 { 1264 | color: #af5f5f; 1265 | } 1266 | 1267 | .terminal .xterm-bg-color-131 { 1268 | background-color: #af5f5f; 1269 | } 1270 | 1271 | .terminal .xterm-color-132 { 1272 | color: #af5f87; 1273 | } 1274 | 1275 | .terminal .xterm-bg-color-132 { 1276 | background-color: #af5f87; 1277 | } 1278 | 1279 | .terminal .xterm-color-133 { 1280 | color: #af5faf; 1281 | } 1282 | 1283 | .terminal .xterm-bg-color-133 { 1284 | background-color: #af5faf; 1285 | } 1286 | 1287 | .terminal .xterm-color-134 { 1288 | color: #af5fd7; 1289 | } 1290 | 1291 | .terminal .xterm-bg-color-134 { 1292 | background-color: #af5fd7; 1293 | } 1294 | 1295 | .terminal .xterm-color-135 { 1296 | color: #af5fff; 1297 | } 1298 | 1299 | .terminal .xterm-bg-color-135 { 1300 | background-color: #af5fff; 1301 | } 1302 | 1303 | .terminal .xterm-color-136 { 1304 | color: #af8700; 1305 | } 1306 | 1307 | .terminal .xterm-bg-color-136 { 1308 | background-color: #af8700; 1309 | } 1310 | 1311 | .terminal .xterm-color-137 { 1312 | color: #af875f; 1313 | } 1314 | 1315 | .terminal .xterm-bg-color-137 { 1316 | background-color: #af875f; 1317 | } 1318 | 1319 | .terminal .xterm-color-138 { 1320 | color: #af8787; 1321 | } 1322 | 1323 | .terminal .xterm-bg-color-138 { 1324 | background-color: #af8787; 1325 | } 1326 | 1327 | .terminal .xterm-color-139 { 1328 | color: #af87af; 1329 | } 1330 | 1331 | .terminal .xterm-bg-color-139 { 1332 | background-color: #af87af; 1333 | } 1334 | 1335 | .terminal .xterm-color-140 { 1336 | color: #af87d7; 1337 | } 1338 | 1339 | .terminal .xterm-bg-color-140 { 1340 | background-color: #af87d7; 1341 | } 1342 | 1343 | .terminal .xterm-color-141 { 1344 | color: #af87ff; 1345 | } 1346 | 1347 | .terminal .xterm-bg-color-141 { 1348 | background-color: #af87ff; 1349 | } 1350 | 1351 | .terminal .xterm-color-142 { 1352 | color: #afaf00; 1353 | } 1354 | 1355 | .terminal .xterm-bg-color-142 { 1356 | background-color: #afaf00; 1357 | } 1358 | 1359 | .terminal .xterm-color-143 { 1360 | color: #afaf5f; 1361 | } 1362 | 1363 | .terminal .xterm-bg-color-143 { 1364 | background-color: #afaf5f; 1365 | } 1366 | 1367 | .terminal .xterm-color-144 { 1368 | color: #afaf87; 1369 | } 1370 | 1371 | .terminal .xterm-bg-color-144 { 1372 | background-color: #afaf87; 1373 | } 1374 | 1375 | .terminal .xterm-color-145 { 1376 | color: #afafaf; 1377 | } 1378 | 1379 | .terminal .xterm-bg-color-145 { 1380 | background-color: #afafaf; 1381 | } 1382 | 1383 | .terminal .xterm-color-146 { 1384 | color: #afafd7; 1385 | } 1386 | 1387 | .terminal .xterm-bg-color-146 { 1388 | background-color: #afafd7; 1389 | } 1390 | 1391 | .terminal .xterm-color-147 { 1392 | color: #afafff; 1393 | } 1394 | 1395 | .terminal .xterm-bg-color-147 { 1396 | background-color: #afafff; 1397 | } 1398 | 1399 | .terminal .xterm-color-148 { 1400 | color: #afd700; 1401 | } 1402 | 1403 | .terminal .xterm-bg-color-148 { 1404 | background-color: #afd700; 1405 | } 1406 | 1407 | .terminal .xterm-color-149 { 1408 | color: #afd75f; 1409 | } 1410 | 1411 | .terminal .xterm-bg-color-149 { 1412 | background-color: #afd75f; 1413 | } 1414 | 1415 | .terminal .xterm-color-150 { 1416 | color: #afd787; 1417 | } 1418 | 1419 | .terminal .xterm-bg-color-150 { 1420 | background-color: #afd787; 1421 | } 1422 | 1423 | .terminal .xterm-color-151 { 1424 | color: #afd7af; 1425 | } 1426 | 1427 | .terminal .xterm-bg-color-151 { 1428 | background-color: #afd7af; 1429 | } 1430 | 1431 | .terminal .xterm-color-152 { 1432 | color: #afd7d7; 1433 | } 1434 | 1435 | .terminal .xterm-bg-color-152 { 1436 | background-color: #afd7d7; 1437 | } 1438 | 1439 | .terminal .xterm-color-153 { 1440 | color: #afd7ff; 1441 | } 1442 | 1443 | .terminal .xterm-bg-color-153 { 1444 | background-color: #afd7ff; 1445 | } 1446 | 1447 | .terminal .xterm-color-154 { 1448 | color: #afff00; 1449 | } 1450 | 1451 | .terminal .xterm-bg-color-154 { 1452 | background-color: #afff00; 1453 | } 1454 | 1455 | .terminal .xterm-color-155 { 1456 | color: #afff5f; 1457 | } 1458 | 1459 | .terminal .xterm-bg-color-155 { 1460 | background-color: #afff5f; 1461 | } 1462 | 1463 | .terminal .xterm-color-156 { 1464 | color: #afff87; 1465 | } 1466 | 1467 | .terminal .xterm-bg-color-156 { 1468 | background-color: #afff87; 1469 | } 1470 | 1471 | .terminal .xterm-color-157 { 1472 | color: #afffaf; 1473 | } 1474 | 1475 | .terminal .xterm-bg-color-157 { 1476 | background-color: #afffaf; 1477 | } 1478 | 1479 | .terminal .xterm-color-158 { 1480 | color: #afffd7; 1481 | } 1482 | 1483 | .terminal .xterm-bg-color-158 { 1484 | background-color: #afffd7; 1485 | } 1486 | 1487 | .terminal .xterm-color-159 { 1488 | color: #afffff; 1489 | } 1490 | 1491 | .terminal .xterm-bg-color-159 { 1492 | background-color: #afffff; 1493 | } 1494 | 1495 | .terminal .xterm-color-160 { 1496 | color: #d70000; 1497 | } 1498 | 1499 | .terminal .xterm-bg-color-160 { 1500 | background-color: #d70000; 1501 | } 1502 | 1503 | .terminal .xterm-color-161 { 1504 | color: #d7005f; 1505 | } 1506 | 1507 | .terminal .xterm-bg-color-161 { 1508 | background-color: #d7005f; 1509 | } 1510 | 1511 | .terminal .xterm-color-162 { 1512 | color: #d70087; 1513 | } 1514 | 1515 | .terminal .xterm-bg-color-162 { 1516 | background-color: #d70087; 1517 | } 1518 | 1519 | .terminal .xterm-color-163 { 1520 | color: #d700af; 1521 | } 1522 | 1523 | .terminal .xterm-bg-color-163 { 1524 | background-color: #d700af; 1525 | } 1526 | 1527 | .terminal .xterm-color-164 { 1528 | color: #d700d7; 1529 | } 1530 | 1531 | .terminal .xterm-bg-color-164 { 1532 | background-color: #d700d7; 1533 | } 1534 | 1535 | .terminal .xterm-color-165 { 1536 | color: #d700ff; 1537 | } 1538 | 1539 | .terminal .xterm-bg-color-165 { 1540 | background-color: #d700ff; 1541 | } 1542 | 1543 | .terminal .xterm-color-166 { 1544 | color: #d75f00; 1545 | } 1546 | 1547 | .terminal .xterm-bg-color-166 { 1548 | background-color: #d75f00; 1549 | } 1550 | 1551 | .terminal .xterm-color-167 { 1552 | color: #d75f5f; 1553 | } 1554 | 1555 | .terminal .xterm-bg-color-167 { 1556 | background-color: #d75f5f; 1557 | } 1558 | 1559 | .terminal .xterm-color-168 { 1560 | color: #d75f87; 1561 | } 1562 | 1563 | .terminal .xterm-bg-color-168 { 1564 | background-color: #d75f87; 1565 | } 1566 | 1567 | .terminal .xterm-color-169 { 1568 | color: #d75faf; 1569 | } 1570 | 1571 | .terminal .xterm-bg-color-169 { 1572 | background-color: #d75faf; 1573 | } 1574 | 1575 | .terminal .xterm-color-170 { 1576 | color: #d75fd7; 1577 | } 1578 | 1579 | .terminal .xterm-bg-color-170 { 1580 | background-color: #d75fd7; 1581 | } 1582 | 1583 | .terminal .xterm-color-171 { 1584 | color: #d75fff; 1585 | } 1586 | 1587 | .terminal .xterm-bg-color-171 { 1588 | background-color: #d75fff; 1589 | } 1590 | 1591 | .terminal .xterm-color-172 { 1592 | color: #d78700; 1593 | } 1594 | 1595 | .terminal .xterm-bg-color-172 { 1596 | background-color: #d78700; 1597 | } 1598 | 1599 | .terminal .xterm-color-173 { 1600 | color: #d7875f; 1601 | } 1602 | 1603 | .terminal .xterm-bg-color-173 { 1604 | background-color: #d7875f; 1605 | } 1606 | 1607 | .terminal .xterm-color-174 { 1608 | color: #d78787; 1609 | } 1610 | 1611 | .terminal .xterm-bg-color-174 { 1612 | background-color: #d78787; 1613 | } 1614 | 1615 | .terminal .xterm-color-175 { 1616 | color: #d787af; 1617 | } 1618 | 1619 | .terminal .xterm-bg-color-175 { 1620 | background-color: #d787af; 1621 | } 1622 | 1623 | .terminal .xterm-color-176 { 1624 | color: #d787d7; 1625 | } 1626 | 1627 | .terminal .xterm-bg-color-176 { 1628 | background-color: #d787d7; 1629 | } 1630 | 1631 | .terminal .xterm-color-177 { 1632 | color: #d787ff; 1633 | } 1634 | 1635 | .terminal .xterm-bg-color-177 { 1636 | background-color: #d787ff; 1637 | } 1638 | 1639 | .terminal .xterm-color-178 { 1640 | color: #d7af00; 1641 | } 1642 | 1643 | .terminal .xterm-bg-color-178 { 1644 | background-color: #d7af00; 1645 | } 1646 | 1647 | .terminal .xterm-color-179 { 1648 | color: #d7af5f; 1649 | } 1650 | 1651 | .terminal .xterm-bg-color-179 { 1652 | background-color: #d7af5f; 1653 | } 1654 | 1655 | .terminal .xterm-color-180 { 1656 | color: #d7af87; 1657 | } 1658 | 1659 | .terminal .xterm-bg-color-180 { 1660 | background-color: #d7af87; 1661 | } 1662 | 1663 | .terminal .xterm-color-181 { 1664 | color: #d7afaf; 1665 | } 1666 | 1667 | .terminal .xterm-bg-color-181 { 1668 | background-color: #d7afaf; 1669 | } 1670 | 1671 | .terminal .xterm-color-182 { 1672 | color: #d7afd7; 1673 | } 1674 | 1675 | .terminal .xterm-bg-color-182 { 1676 | background-color: #d7afd7; 1677 | } 1678 | 1679 | .terminal .xterm-color-183 { 1680 | color: #d7afff; 1681 | } 1682 | 1683 | .terminal .xterm-bg-color-183 { 1684 | background-color: #d7afff; 1685 | } 1686 | 1687 | .terminal .xterm-color-184 { 1688 | color: #d7d700; 1689 | } 1690 | 1691 | .terminal .xterm-bg-color-184 { 1692 | background-color: #d7d700; 1693 | } 1694 | 1695 | .terminal .xterm-color-185 { 1696 | color: #d7d75f; 1697 | } 1698 | 1699 | .terminal .xterm-bg-color-185 { 1700 | background-color: #d7d75f; 1701 | } 1702 | 1703 | .terminal .xterm-color-186 { 1704 | color: #d7d787; 1705 | } 1706 | 1707 | .terminal .xterm-bg-color-186 { 1708 | background-color: #d7d787; 1709 | } 1710 | 1711 | .terminal .xterm-color-187 { 1712 | color: #d7d7af; 1713 | } 1714 | 1715 | .terminal .xterm-bg-color-187 { 1716 | background-color: #d7d7af; 1717 | } 1718 | 1719 | .terminal .xterm-color-188 { 1720 | color: #d7d7d7; 1721 | } 1722 | 1723 | .terminal .xterm-bg-color-188 { 1724 | background-color: #d7d7d7; 1725 | } 1726 | 1727 | .terminal .xterm-color-189 { 1728 | color: #d7d7ff; 1729 | } 1730 | 1731 | .terminal .xterm-bg-color-189 { 1732 | background-color: #d7d7ff; 1733 | } 1734 | 1735 | .terminal .xterm-color-190 { 1736 | color: #d7ff00; 1737 | } 1738 | 1739 | .terminal .xterm-bg-color-190 { 1740 | background-color: #d7ff00; 1741 | } 1742 | 1743 | .terminal .xterm-color-191 { 1744 | color: #d7ff5f; 1745 | } 1746 | 1747 | .terminal .xterm-bg-color-191 { 1748 | background-color: #d7ff5f; 1749 | } 1750 | 1751 | .terminal .xterm-color-192 { 1752 | color: #d7ff87; 1753 | } 1754 | 1755 | .terminal .xterm-bg-color-192 { 1756 | background-color: #d7ff87; 1757 | } 1758 | 1759 | .terminal .xterm-color-193 { 1760 | color: #d7ffaf; 1761 | } 1762 | 1763 | .terminal .xterm-bg-color-193 { 1764 | background-color: #d7ffaf; 1765 | } 1766 | 1767 | .terminal .xterm-color-194 { 1768 | color: #d7ffd7; 1769 | } 1770 | 1771 | .terminal .xterm-bg-color-194 { 1772 | background-color: #d7ffd7; 1773 | } 1774 | 1775 | .terminal .xterm-color-195 { 1776 | color: #d7ffff; 1777 | } 1778 | 1779 | .terminal .xterm-bg-color-195 { 1780 | background-color: #d7ffff; 1781 | } 1782 | 1783 | .terminal .xterm-color-196 { 1784 | color: #ff0000; 1785 | } 1786 | 1787 | .terminal .xterm-bg-color-196 { 1788 | background-color: #ff0000; 1789 | } 1790 | 1791 | .terminal .xterm-color-197 { 1792 | color: #ff005f; 1793 | } 1794 | 1795 | .terminal .xterm-bg-color-197 { 1796 | background-color: #ff005f; 1797 | } 1798 | 1799 | .terminal .xterm-color-198 { 1800 | color: #ff0087; 1801 | } 1802 | 1803 | .terminal .xterm-bg-color-198 { 1804 | background-color: #ff0087; 1805 | } 1806 | 1807 | .terminal .xterm-color-199 { 1808 | color: #ff00af; 1809 | } 1810 | 1811 | .terminal .xterm-bg-color-199 { 1812 | background-color: #ff00af; 1813 | } 1814 | 1815 | .terminal .xterm-color-200 { 1816 | color: #ff00d7; 1817 | } 1818 | 1819 | .terminal .xterm-bg-color-200 { 1820 | background-color: #ff00d7; 1821 | } 1822 | 1823 | .terminal .xterm-color-201 { 1824 | color: #ff00ff; 1825 | } 1826 | 1827 | .terminal .xterm-bg-color-201 { 1828 | background-color: #ff00ff; 1829 | } 1830 | 1831 | .terminal .xterm-color-202 { 1832 | color: #ff5f00; 1833 | } 1834 | 1835 | .terminal .xterm-bg-color-202 { 1836 | background-color: #ff5f00; 1837 | } 1838 | 1839 | .terminal .xterm-color-203 { 1840 | color: #ff5f5f; 1841 | } 1842 | 1843 | .terminal .xterm-bg-color-203 { 1844 | background-color: #ff5f5f; 1845 | } 1846 | 1847 | .terminal .xterm-color-204 { 1848 | color: #ff5f87; 1849 | } 1850 | 1851 | .terminal .xterm-bg-color-204 { 1852 | background-color: #ff5f87; 1853 | } 1854 | 1855 | .terminal .xterm-color-205 { 1856 | color: #ff5faf; 1857 | } 1858 | 1859 | .terminal .xterm-bg-color-205 { 1860 | background-color: #ff5faf; 1861 | } 1862 | 1863 | .terminal .xterm-color-206 { 1864 | color: #ff5fd7; 1865 | } 1866 | 1867 | .terminal .xterm-bg-color-206 { 1868 | background-color: #ff5fd7; 1869 | } 1870 | 1871 | .terminal .xterm-color-207 { 1872 | color: #ff5fff; 1873 | } 1874 | 1875 | .terminal .xterm-bg-color-207 { 1876 | background-color: #ff5fff; 1877 | } 1878 | 1879 | .terminal .xterm-color-208 { 1880 | color: #ff8700; 1881 | } 1882 | 1883 | .terminal .xterm-bg-color-208 { 1884 | background-color: #ff8700; 1885 | } 1886 | 1887 | .terminal .xterm-color-209 { 1888 | color: #ff875f; 1889 | } 1890 | 1891 | .terminal .xterm-bg-color-209 { 1892 | background-color: #ff875f; 1893 | } 1894 | 1895 | .terminal .xterm-color-210 { 1896 | color: #ff8787; 1897 | } 1898 | 1899 | .terminal .xterm-bg-color-210 { 1900 | background-color: #ff8787; 1901 | } 1902 | 1903 | .terminal .xterm-color-211 { 1904 | color: #ff87af; 1905 | } 1906 | 1907 | .terminal .xterm-bg-color-211 { 1908 | background-color: #ff87af; 1909 | } 1910 | 1911 | .terminal .xterm-color-212 { 1912 | color: #ff87d7; 1913 | } 1914 | 1915 | .terminal .xterm-bg-color-212 { 1916 | background-color: #ff87d7; 1917 | } 1918 | 1919 | .terminal .xterm-color-213 { 1920 | color: #ff87ff; 1921 | } 1922 | 1923 | .terminal .xterm-bg-color-213 { 1924 | background-color: #ff87ff; 1925 | } 1926 | 1927 | .terminal .xterm-color-214 { 1928 | color: #ffaf00; 1929 | } 1930 | 1931 | .terminal .xterm-bg-color-214 { 1932 | background-color: #ffaf00; 1933 | } 1934 | 1935 | .terminal .xterm-color-215 { 1936 | color: #ffaf5f; 1937 | } 1938 | 1939 | .terminal .xterm-bg-color-215 { 1940 | background-color: #ffaf5f; 1941 | } 1942 | 1943 | .terminal .xterm-color-216 { 1944 | color: #ffaf87; 1945 | } 1946 | 1947 | .terminal .xterm-bg-color-216 { 1948 | background-color: #ffaf87; 1949 | } 1950 | 1951 | .terminal .xterm-color-217 { 1952 | color: #ffafaf; 1953 | } 1954 | 1955 | .terminal .xterm-bg-color-217 { 1956 | background-color: #ffafaf; 1957 | } 1958 | 1959 | .terminal .xterm-color-218 { 1960 | color: #ffafd7; 1961 | } 1962 | 1963 | .terminal .xterm-bg-color-218 { 1964 | background-color: #ffafd7; 1965 | } 1966 | 1967 | .terminal .xterm-color-219 { 1968 | color: #ffafff; 1969 | } 1970 | 1971 | .terminal .xterm-bg-color-219 { 1972 | background-color: #ffafff; 1973 | } 1974 | 1975 | .terminal .xterm-color-220 { 1976 | color: #ffd700; 1977 | } 1978 | 1979 | .terminal .xterm-bg-color-220 { 1980 | background-color: #ffd700; 1981 | } 1982 | 1983 | .terminal .xterm-color-221 { 1984 | color: #ffd75f; 1985 | } 1986 | 1987 | .terminal .xterm-bg-color-221 { 1988 | background-color: #ffd75f; 1989 | } 1990 | 1991 | .terminal .xterm-color-222 { 1992 | color: #ffd787; 1993 | } 1994 | 1995 | .terminal .xterm-bg-color-222 { 1996 | background-color: #ffd787; 1997 | } 1998 | 1999 | .terminal .xterm-color-223 { 2000 | color: #ffd7af; 2001 | } 2002 | 2003 | .terminal .xterm-bg-color-223 { 2004 | background-color: #ffd7af; 2005 | } 2006 | 2007 | .terminal .xterm-color-224 { 2008 | color: #ffd7d7; 2009 | } 2010 | 2011 | .terminal .xterm-bg-color-224 { 2012 | background-color: #ffd7d7; 2013 | } 2014 | 2015 | .terminal .xterm-color-225 { 2016 | color: #ffd7ff; 2017 | } 2018 | 2019 | .terminal .xterm-bg-color-225 { 2020 | background-color: #ffd7ff; 2021 | } 2022 | 2023 | .terminal .xterm-color-226 { 2024 | color: #ffff00; 2025 | } 2026 | 2027 | .terminal .xterm-bg-color-226 { 2028 | background-color: #ffff00; 2029 | } 2030 | 2031 | .terminal .xterm-color-227 { 2032 | color: #ffff5f; 2033 | } 2034 | 2035 | .terminal .xterm-bg-color-227 { 2036 | background-color: #ffff5f; 2037 | } 2038 | 2039 | .terminal .xterm-color-228 { 2040 | color: #ffff87; 2041 | } 2042 | 2043 | .terminal .xterm-bg-color-228 { 2044 | background-color: #ffff87; 2045 | } 2046 | 2047 | .terminal .xterm-color-229 { 2048 | color: #ffffaf; 2049 | } 2050 | 2051 | .terminal .xterm-bg-color-229 { 2052 | background-color: #ffffaf; 2053 | } 2054 | 2055 | .terminal .xterm-color-230 { 2056 | color: #ffffd7; 2057 | } 2058 | 2059 | .terminal .xterm-bg-color-230 { 2060 | background-color: #ffffd7; 2061 | } 2062 | 2063 | .terminal .xterm-color-231 { 2064 | color: #ffffff; 2065 | } 2066 | 2067 | .terminal .xterm-bg-color-231 { 2068 | background-color: #ffffff; 2069 | } 2070 | 2071 | .terminal .xterm-color-232 { 2072 | color: #080808; 2073 | } 2074 | 2075 | .terminal .xterm-bg-color-232 { 2076 | background-color: #080808; 2077 | } 2078 | 2079 | .terminal .xterm-color-233 { 2080 | color: #121212; 2081 | } 2082 | 2083 | .terminal .xterm-bg-color-233 { 2084 | background-color: #121212; 2085 | } 2086 | 2087 | .terminal .xterm-color-234 { 2088 | color: #1c1c1c; 2089 | } 2090 | 2091 | .terminal .xterm-bg-color-234 { 2092 | background-color: #1c1c1c; 2093 | } 2094 | 2095 | .terminal .xterm-color-235 { 2096 | color: #262626; 2097 | } 2098 | 2099 | .terminal .xterm-bg-color-235 { 2100 | background-color: #262626; 2101 | } 2102 | 2103 | .terminal .xterm-color-236 { 2104 | color: #303030; 2105 | } 2106 | 2107 | .terminal .xterm-bg-color-236 { 2108 | background-color: #303030; 2109 | } 2110 | 2111 | .terminal .xterm-color-237 { 2112 | color: #3a3a3a; 2113 | } 2114 | 2115 | .terminal .xterm-bg-color-237 { 2116 | background-color: #3a3a3a; 2117 | } 2118 | 2119 | .terminal .xterm-color-238 { 2120 | color: #444444; 2121 | } 2122 | 2123 | .terminal .xterm-bg-color-238 { 2124 | background-color: #444444; 2125 | } 2126 | 2127 | .terminal .xterm-color-239 { 2128 | color: #4e4e4e; 2129 | } 2130 | 2131 | .terminal .xterm-bg-color-239 { 2132 | background-color: #4e4e4e; 2133 | } 2134 | 2135 | .terminal .xterm-color-240 { 2136 | color: #585858; 2137 | } 2138 | 2139 | .terminal .xterm-bg-color-240 { 2140 | background-color: #585858; 2141 | } 2142 | 2143 | .terminal .xterm-color-241 { 2144 | color: #626262; 2145 | } 2146 | 2147 | .terminal .xterm-bg-color-241 { 2148 | background-color: #626262; 2149 | } 2150 | 2151 | .terminal .xterm-color-242 { 2152 | color: #6c6c6c; 2153 | } 2154 | 2155 | .terminal .xterm-bg-color-242 { 2156 | background-color: #6c6c6c; 2157 | } 2158 | 2159 | .terminal .xterm-color-243 { 2160 | color: #767676; 2161 | } 2162 | 2163 | .terminal .xterm-bg-color-243 { 2164 | background-color: #767676; 2165 | } 2166 | 2167 | .terminal .xterm-color-244 { 2168 | color: #808080; 2169 | } 2170 | 2171 | .terminal .xterm-bg-color-244 { 2172 | background-color: #808080; 2173 | } 2174 | 2175 | .terminal .xterm-color-245 { 2176 | color: #8a8a8a; 2177 | } 2178 | 2179 | .terminal .xterm-bg-color-245 { 2180 | background-color: #8a8a8a; 2181 | } 2182 | 2183 | .terminal .xterm-color-246 { 2184 | color: #949494; 2185 | } 2186 | 2187 | .terminal .xterm-bg-color-246 { 2188 | background-color: #949494; 2189 | } 2190 | 2191 | .terminal .xterm-color-247 { 2192 | color: #9e9e9e; 2193 | } 2194 | 2195 | .terminal .xterm-bg-color-247 { 2196 | background-color: #9e9e9e; 2197 | } 2198 | 2199 | .terminal .xterm-color-248 { 2200 | color: #a8a8a8; 2201 | } 2202 | 2203 | .terminal .xterm-bg-color-248 { 2204 | background-color: #a8a8a8; 2205 | } 2206 | 2207 | .terminal .xterm-color-249 { 2208 | color: #b2b2b2; 2209 | } 2210 | 2211 | .terminal .xterm-bg-color-249 { 2212 | background-color: #b2b2b2; 2213 | } 2214 | 2215 | .terminal .xterm-color-250 { 2216 | color: #bcbcbc; 2217 | } 2218 | 2219 | .terminal .xterm-bg-color-250 { 2220 | background-color: #bcbcbc; 2221 | } 2222 | 2223 | .terminal .xterm-color-251 { 2224 | color: #c6c6c6; 2225 | } 2226 | 2227 | .terminal .xterm-bg-color-251 { 2228 | background-color: #c6c6c6; 2229 | } 2230 | 2231 | .terminal .xterm-color-252 { 2232 | color: #d0d0d0; 2233 | } 2234 | 2235 | .terminal .xterm-bg-color-252 { 2236 | background-color: #d0d0d0; 2237 | } 2238 | 2239 | .terminal .xterm-color-253 { 2240 | color: #dadada; 2241 | } 2242 | 2243 | .terminal .xterm-bg-color-253 { 2244 | background-color: #dadada; 2245 | } 2246 | 2247 | .terminal .xterm-color-254 { 2248 | color: #e4e4e4; 2249 | } 2250 | 2251 | .terminal .xterm-bg-color-254 { 2252 | background-color: #e4e4e4; 2253 | } 2254 | 2255 | .terminal .xterm-color-255 { 2256 | color: #eeeeee; 2257 | } 2258 | 2259 | .terminal .xterm-bg-color-255 { 2260 | background-color: #eeeeee; 2261 | } 2262 | -------------------------------------------------------------------------------- /package.js: -------------------------------------------------------------------------------- 1 | Package.describe({ 2 | name: 'qualia:web-shell', 3 | version: '0.0.6', 4 | summary: 'Meteor shell access in the browser', 5 | git: 'https://github.com/qualialabs/web-shell', 6 | documentation: 'README.md', 7 | debugOnly: true, 8 | }); 9 | 10 | Npm.depends({ 11 | 'node-pty': '0.7.0', 12 | 'ws': '3.1.0', 13 | }); 14 | 15 | Package.onUse(function(api) { 16 | api.versionsFrom('METEOR@1.4'); 17 | 18 | api.use([ 19 | 'ecmascript', 20 | 'underscore', 21 | 'spacebars-compiler', 22 | 'templating', 23 | 'blaze', 24 | 'reactive-var', 25 | 'meteorhacks:picker@1.0.3', 26 | ], ['client', 'server']); 27 | 28 | api.mainModule('client/main.js', 'client'); 29 | api.mainModule('server/main.js', 'server'); 30 | }); 31 | -------------------------------------------------------------------------------- /server/main.js: -------------------------------------------------------------------------------- 1 | import './shell.js'; 2 | -------------------------------------------------------------------------------- /server/shell.js: -------------------------------------------------------------------------------- 1 | import os from 'os'; 2 | import pty from 'node-pty'; 3 | import { Picker } from 'meteor/meteorhacks:picker'; 4 | import WebSocket from 'ws'; 5 | 6 | // Right now only one terminal can run at a time 7 | // but in the future, web-shell may support running 8 | // multiple simultaneously. 9 | var wss = new WebSocket.Server({ port: 8080 }), 10 | terminals = {}, 11 | logs = {} 12 | ; 13 | 14 | Picker.route('/web-shell/terminals', (params, req, res) => { 15 | let cols = parseInt(params.query.cols), 16 | rows = parseInt(params.query.rows) 17 | ; 18 | 19 | if (_.size(terminals) === 0) { 20 | let term = pty.spawn('meteor', ['shell'], { 21 | name: 'xterm-color', 22 | cols: cols, 23 | rows: rows, 24 | cwd: process.env.PWD, 25 | env: process.env 26 | }); 27 | 28 | terminals[term.pid] = term; 29 | logs[term.pid] = ''; 30 | 31 | term.on('data', stripPreamble(data => { 32 | logs[term.pid] += data; 33 | })); 34 | } 35 | 36 | let term = Object.values(terminals)[0]; 37 | term.resize(cols, rows); 38 | res.end(term.pid.toString()); 39 | }); 40 | 41 | Picker.route('/web-shell/terminals/:pid/size', (params, req, res) => { 42 | var pid = parseInt(params.pid), 43 | cols = parseInt(params.query.cols), 44 | rows = parseInt(params.query.rows), 45 | term = terminals[pid] 46 | ; 47 | 48 | console.log(cols, rows); 49 | term.resize(cols, rows); 50 | res.end(); 51 | }); 52 | 53 | wss.on('connection', (ws, req) => { 54 | let url = req 55 | ? req.url 56 | : ws.upgradeReq.url 57 | ; 58 | 59 | var term = terminals[parseInt(url.split('/').pop())]; 60 | ws.send(logs[term.pid]); 61 | 62 | term.on('data', stripPreamble(data => { 63 | try { 64 | ws.send(data); 65 | } catch (ex) { 66 | // The WebSocket is not open, ignore 67 | } 68 | })); 69 | 70 | ws.on('message', msg => { 71 | if (msg !== '---heartbeat---') { 72 | term.write(msg); 73 | } 74 | }); 75 | 76 | }); 77 | 78 | // This needs work 79 | let stripped = false; 80 | let stripPreamble = function(handler) { 81 | return data => { 82 | if (stripped) { 83 | return handler(data); 84 | } 85 | 86 | if (data.includes('>') && !data.includes('<')) { 87 | stripped = true; 88 | return handler('> '); 89 | } 90 | }; 91 | }; 92 | --------------------------------------------------------------------------------