├── .gitignore ├── templates ├── content │ └── index.php ├── navigation │ └── index.php ├── settings │ └── index.php └── index.php ├── appinfo ├── screenshot.png ├── routes.php └── info.xml ├── phpunit.xml ├── phpunit.integration.xml ├── composer.json ├── img └── app.svg ├── lib └── Controller │ ├── FakeRequest.php │ ├── OccOutput.php │ └── OccController.php ├── tests ├── bootstrap.php ├── Integration │ └── AppTest.php └── Unit │ └── Controller │ └── PageControllerTest.php ├── README.md ├── js ├── index.js ├── unix_formatting.js └── term.js ├── .travis.yml ├── Makefile ├── css └── style.css └── COPYING /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | build 3 | -------------------------------------------------------------------------------- /templates/content/index.php: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 | -------------------------------------------------------------------------------- /appinfo/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adphi/occweb/HEAD/appinfo/screenshot.png -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ./tests/Unit 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /phpunit.integration.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ./tests/Integration 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /templates/navigation/index.php: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /templates/settings/index.php: -------------------------------------------------------------------------------- 1 |
2 |
3 | 6 |
7 |
8 | 9 |
10 |
11 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "OCC Web", 3 | "description": "OCC Web terminal", 4 | "type": "project", 5 | "license": "AGPL", 6 | "authors": [ 7 | { 8 | "name": "Adphi" 9 | } 10 | ], 11 | "require": {}, 12 | "require-dev": { 13 | "phpunit/phpunit": "^5.4" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /img/app.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /lib/Controller/FakeRequest.php: -------------------------------------------------------------------------------- 1 | ["occ"], 12 | ); 13 | 14 | /** 15 | * FakeRequest constructor. 16 | */ 17 | public function __construct() { 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /templates/index.php: -------------------------------------------------------------------------------- 1 | 7 | 8 |
9 | 10 | inc('navigation/index')); ?> 11 | inc('settings/index')); ?> 12 | 13 | 14 |
15 |
16 |
17 | 18 | -------------------------------------------------------------------------------- /tests/bootstrap.php: -------------------------------------------------------------------------------- 1 | addValidRoot(OC::$SERVERROOT . '/tests'); 11 | 12 | // Fix for "Autoload path not allowed: .../testnextcloudapp/tests/testcase.php" 13 | \OC_App::loadApp('testnextcloudapp'); 14 | 15 | if(!class_exists('PHPUnit_Framework_TestCase')) { 16 | require_once('PHPUnit/Autoload.php'); 17 | } 18 | 19 | OC_Hook::clear(); 20 | -------------------------------------------------------------------------------- /appinfo/routes.php: -------------------------------------------------------------------------------- 1 | OCA\OCCWeb\Controller\PageController->index() 6 | * 7 | * The controller class has to be registered in the application.php file since 8 | * it's instantiated in there 9 | */ 10 | return [ 11 | 'routes' => [ 12 | ['name' => 'occ#index', 'url' => '/', 'verb' => 'GET'], 13 | ['name' => 'occ#cmd', 'url' => '/cmd', 'verb' => 'POST'], 14 | ['name' => 'occ#list', 'url' => '/cmd', 'verb' => 'GET'], 15 | ] 16 | ]; 17 | -------------------------------------------------------------------------------- /tests/Integration/AppTest.php: -------------------------------------------------------------------------------- 1 | container = $app->getContainer(); 22 | } 23 | 24 | public function testAppInstalled() { 25 | $appManager = $this->container->query('OCP\App\IAppManager'); 26 | $this->assertTrue($appManager->isInstalled('testnextcloudapp')); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /tests/Unit/Controller/PageControllerTest.php: -------------------------------------------------------------------------------- 1 | getMockBuilder('OCP\IRequest')->getMock(); 18 | 19 | $this->controller = new OCCController( 20 | 'testnextcloudapp', $request, $this->userId 21 | ); 22 | } 23 | 24 | public function testIndex() { 25 | $result = $this->controller->index(); 26 | 27 | $this->assertEquals('index', $result->getTemplateName()); 28 | $this->assertTrue($result instanceof TemplateResponse); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /lib/Controller/OccOutput.php: -------------------------------------------------------------------------------- 1 | stream === null) { 38 | $this->stream = fopen('php://temp','w'); 39 | } 40 | return new ConsoleSectionOutput($this->stream, $this->consoleSectionOutputs, $this->getVerbosity(), $this->isDecorated(), $this->getFormatter()); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /appinfo/info.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | occweb 5 | OCC Web 6 | OCC Commands in a web terminal 7 | 8 | 0.2.3 9 | agpl 10 | Adphi 11 | OCCWeb 12 | tools 13 | https://github.com/adphi/occweb 14 | https://github.com/adphi/occweb/issues 15 | https://github.com/adphi/occweb 16 | https://github.com/adphi/occweb/raw/main/appinfo/screenshot.png 17 | 18 | 19 | 20 | 21 | 22 | OCCWeb 23 | occweb.occ.index 24 | app.svg 25 | link 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ⚠️ Deprecated ⚠️ OCCWeb terminal 2 | 3 | ### A web terminal for admins to launch Nextcloud's occ commands 4 | 5 | ![occweb](https://github.com/Adphi/OCCWeb/raw/main/appinfo/screenshot.png) 6 | 7 | 8 | ## ⚠️ Deprecated ⚠️ 9 | As nextcloudd has no native support for asynchronous operations, due to the use of php, this aplication is deprecated, and will no longer support the Nextcloud' future versions (19+). I did not find a way to implemement true support for interactive and long running occ tasks in a web terminal whitout introducing addtional dependencies (through websockets, for example), the lack of true asynchronous occ operations can lead to serious alterations of voluminous instances. 10 | [This issue](https://github.com/nextcloud/server/issues/16726) may give some hints on why I decided to not support this application anymore. 11 | 12 | 13 | ## Install 14 | 15 | Place this app in **nextcloud/apps/** 16 | 17 | ## ⚠️ Warnings ⚠️ 18 | 19 | - The application is not a real interactive terminal and does not support long running tasks. 20 | So if your instance is pretty big, commands like `occ files:scan` will time out and fail. 21 | - Do not use `occ maintenance:mode --on`, obvious... 22 | 23 | ## TODOs: 24 | See [open issues](https://github.com/Adphi/occweb/issues) 25 | -------------------------------------------------------------------------------- /js/index.js: -------------------------------------------------------------------------------- 1 | (function (OC, window, $, undefined) { 2 | 'use strict'; 3 | $(function() { 4 | function scrollToBottom(){ 5 | var html = $('html'); 6 | html.scrollTop(html.prop('scrollHeight')); 7 | } 8 | var baseUrl = OC.generateUrl('/apps/occweb'); 9 | $.get(baseUrl + '/cmd', function(response){ 10 | $('#app-content').terminal(function(command, term) { 11 | switch (command) { 12 | case "c": 13 | this.clear(); 14 | break; 15 | case "exit": 16 | this.reset(); 17 | break; 18 | default: 19 | var occCommand = { 20 | command: command 21 | }; 22 | term.pause(); 23 | $.ajax({ 24 | url: baseUrl + '/cmd', 25 | type: 'POST', 26 | contentType: 'application/json', 27 | data: JSON.stringify(occCommand) 28 | }).done(function (response) { 29 | term.echo('\n' + response).resume(); 30 | }).fail(function (response, code) { 31 | term.echo('\n' + response).resume(); 32 | }); 33 | } 34 | }, { 35 | greetings: function (callback) { 36 | callback('[[;green;]' + new Date().toString().slice(0, 24) + "]\n\nPress [[;#ff5e99;]Enter] for more information on [[;#009ae3;]occ] commands.\n") 37 | }, 38 | name: 'occ', 39 | prompt: 'occ $ ', 40 | completion: response, 41 | onResize: function(){ 42 | scrollToBottom() 43 | } 44 | }); 45 | }); 46 | $('html').keypress(function(){ 47 | scrollToBottom() 48 | }) 49 | }); 50 | })(OC, window, jQuery); 51 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | dist: trusty 3 | language: php 4 | php: 5 | - 5.6 6 | - 7 7 | - 7.1 8 | env: 9 | global: 10 | - CORE_BRANCH=stable14 11 | matrix: 12 | - DB=pgsql 13 | 14 | matrix: 15 | allow_failures: 16 | - env: DB=pgsql CORE_BRANCH=master 17 | include: 18 | - php: 5.6 19 | env: DB=sqlite 20 | - php: 5.6 21 | env: DB=mysql 22 | - php: 5.6 23 | env: DB=pgsql CORE_BRANCH=master 24 | fast_finish: true 25 | 26 | 27 | before_install: 28 | # enable a display for running JavaScript tests 29 | - export DISPLAY=:99.0 30 | - sh -e /etc/init.d/xvfb start 31 | - nvm install 8 32 | - npm install -g npm@latest 33 | - make 34 | - make appstore 35 | # install core 36 | - cd ../ 37 | - git clone https://github.com/nextcloud/server.git --recursive --depth 1 -b $CORE_BRANCH nextcloud 38 | - mv "$TRAVIS_BUILD_DIR" nextcloud/apps/testnextcloudapp 39 | 40 | before_script: 41 | - if [[ "$DB" == 'pgsql' ]]; then createuser -U travis -s oc_autotest; fi 42 | - if [[ "$DB" == 'mysql' ]]; then mysql -u root -e 'create database oc_autotest;'; fi 43 | - if [[ "$DB" == 'mysql' ]]; then mysql -u root -e "CREATE USER 'oc_autotest'@'localhost' IDENTIFIED BY '';"; fi 44 | - if [[ "$DB" == 'mysql' ]]; then mysql -u root -e "grant all on oc_autotest.* to 'oc_autotest'@'localhost';"; fi 45 | - cd nextcloud 46 | - mkdir data 47 | - ./occ maintenance:install --database-name oc_autotest --database-user oc_autotest --admin-user admin --admin-pass admin --database $DB --database-pass='' 48 | - ./occ app:enable testnextcloudapp 49 | - php -S localhost:8080 & 50 | - cd apps/testnextcloudapp 51 | 52 | script: 53 | - make test 54 | 55 | after_failure: 56 | - cat ../../data/nextcloud.log 57 | 58 | addons: 59 | firefox: 'latest' 60 | mariadb: '10.1' 61 | 62 | services: 63 | - postgresql 64 | - mariadb 65 | -------------------------------------------------------------------------------- /lib/Controller/OccController.php: -------------------------------------------------------------------------------- 1 | logger = OC::$server->get(LoggerInterface::class); 30 | $this->userId = $userId; 31 | 32 | $this->application = new Application( 33 | OC::$server->get(\OCP\ServerVersion::class), 34 | OC::$server->getConfig(), 35 | OC::$server->get(\OCP\EventDispatcher\IEventDispatcher::class), 36 | new FakeRequest(), 37 | $this->logger, 38 | OC::$server->query(MemoryInfo::class), 39 | OC::$server->get(\OCP\App\IAppManager::class), // Obtain the IAppManager 40 | OC::$server->get(\OCP\Defaults::class) 41 | ); 42 | $this->application->setAutoExit(false); 43 | $this->output = new OccOutput(OutputInterface::VERBOSITY_NORMAL, true); 44 | $this->application->loadCommands(new StringInput(""), $this->output); 45 | $reflectionProperty = new \ReflectionProperty(Application::class, 'application'); 46 | $reflectionProperty->setAccessible(true); 47 | $this->symphonyApplication = $reflectionProperty->getValue($this->application); 48 | } 49 | 50 | /** 51 | * @NoCSRFRequired 52 | */ 53 | public function index() 54 | { 55 | return new TemplateResponse('occweb', 'index'); 56 | } 57 | 58 | /** 59 | * @param $input 60 | * @return string 61 | */ 62 | private function run($input) 63 | { 64 | try { 65 | $this->application->run($input, $this->output); 66 | return $this->output->fetch(); 67 | } catch (Exception $ex) { 68 | $this->logger->error($ex->getMessage(), ['exception' => $ex]); 69 | return "error: " . $ex->getMessage(); 70 | } 71 | } 72 | 73 | /** 74 | * @param string $command 75 | * @return DataResponse 76 | */ 77 | public function cmd($command) 78 | { 79 | $this->logger->debug($command); 80 | $input = new StringInput($command); 81 | $response = $this->run($input); 82 | $this->logger->debug($response); 83 | return new DataResponse($response); 84 | } 85 | 86 | public function list() { 87 | $defs = $this->symphonyApplication->all(); 88 | $cmds = array(); 89 | foreach ($defs as $d) { 90 | array_push($cmds, $d->getName()); 91 | } 92 | return new DataResponse($cmds); 93 | } 94 | } 95 | 96 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # This file is licensed under the Affero General Public License version 3 or 2 | # later. See the COPYING file. 3 | # @author Bernhard Posselt 4 | # @copyright Bernhard Posselt 2016 5 | 6 | # Generic Makefile for building and packaging a Nextcloud app which uses npm and 7 | # Composer. 8 | # 9 | # Dependencies: 10 | # * make 11 | # * which 12 | # * curl: used if phpunit and composer are not installed to fetch them from the web 13 | # * tar: for building the archive 14 | # * npm: for building and testing everything JS 15 | # 16 | # If no composer.json is in the app root directory, the Composer step 17 | # will be skipped. The same goes for the package.json which can be located in 18 | # the app root or the js/ directory. 19 | # 20 | # The npm command by launches the npm build script: 21 | # 22 | # npm run build 23 | # 24 | # The npm test command launches the npm test script: 25 | # 26 | # npm run test 27 | # 28 | # The idea behind this is to be completely testing and build tool agnostic. All 29 | # build tools and additional package managers should be installed locally in 30 | # your project, since this won't pollute people's global namespace. 31 | # 32 | # The following npm scripts in your package.json install and update the bower 33 | # and npm dependencies and use gulp as build system (notice how everything is 34 | # run from the node_modules folder): 35 | # 36 | # "scripts": { 37 | # "test": "node node_modules/gulp-cli/bin/gulp.js karma", 38 | # "prebuild": "npm install && node_modules/bower/bin/bower install && node_modules/bower/bin/bower update", 39 | # "build": "node node_modules/gulp-cli/bin/gulp.js" 40 | # }, 41 | 42 | app_name=$(notdir $(CURDIR)) 43 | build_tools_directory=$(CURDIR)/build/tools 44 | source_build_directory=$(CURDIR)/build/artifacts/source 45 | source_package_name=$(source_build_directory)/$(app_name) 46 | appstore_build_directory=$(CURDIR)/build/artifacts/appstore 47 | appstore_package_name=$(appstore_build_directory)/$(app_name) 48 | npm=$(shell which npm 2> /dev/null) 49 | composer=$(shell which composer 2> /dev/null) 50 | 51 | all: build 52 | 53 | # Fetches the PHP and JS dependencies and compiles the JS. If no composer.json 54 | # is present, the composer step is skipped, if no package.json or js/package.json 55 | # is present, the npm step is skipped 56 | .PHONY: build 57 | build: 58 | ifneq (,$(wildcard $(CURDIR)/composer.json)) 59 | make composer 60 | endif 61 | ifneq (,$(wildcard $(CURDIR)/package.json)) 62 | make npm 63 | endif 64 | ifneq (,$(wildcard $(CURDIR)/js/package.json)) 65 | make npm 66 | endif 67 | 68 | # Installs and updates the composer dependencies. If composer is not installed 69 | # a copy is fetched from the web 70 | .PHONY: composer 71 | composer: 72 | ifeq (, $(composer)) 73 | @echo "No composer command available, downloading a copy from the web" 74 | mkdir -p $(build_tools_directory) 75 | curl -sS https://getcomposer.org/installer | php 76 | mv composer.phar $(build_tools_directory) 77 | php $(build_tools_directory)/composer.phar install --prefer-dist 78 | php $(build_tools_directory)/composer.phar update --prefer-dist 79 | else 80 | composer install --prefer-dist 81 | composer update --prefer-dist 82 | endif 83 | 84 | # Installs npm dependencies 85 | .PHONY: npm 86 | npm: 87 | ifeq (,$(wildcard $(CURDIR)/package.json)) 88 | cd js && $(npm) run build 89 | else 90 | npm run build 91 | endif 92 | 93 | # Removes the appstore build 94 | .PHONY: clean 95 | clean: 96 | rm -rf ./build 97 | 98 | # Same as clean but also removes dependencies installed by composer, bower and 99 | # npm 100 | .PHONY: distclean 101 | distclean: clean 102 | rm -rf vendor 103 | rm -rf node_modules 104 | rm -rf js/vendor 105 | rm -rf js/node_modules 106 | 107 | # Builds the source and appstore package 108 | .PHONY: dist 109 | dist: 110 | make source 111 | make appstore 112 | 113 | # Builds the source package 114 | .PHONY: source 115 | source: 116 | rm -rf $(source_build_directory) 117 | mkdir -p $(source_build_directory) 118 | tar \ 119 | --exclude-vcs \ 120 | --exclude="../$(app_name)/build" \ 121 | --exclude="../$(app_name)/js/node_modules" \ 122 | --exclude="../$(app_name)/node_modules" \ 123 | --exclude="../$(app_name)/*.log" \ 124 | --exclude="../$(app_name)/js/*.log" \ 125 | -cvzf $(source_package_name).tar.gz ../$(app_name) 126 | 127 | # Builds the source package for the app store, ignores php and js tests 128 | .PHONY: appstore 129 | appstore: 130 | rm -rf $(appstore_build_directory) 131 | mkdir -p $(appstore_build_directory) 132 | tar \ 133 | --exclude-vcs \ 134 | --exclude="../$(app_name)/build" \ 135 | --exclude="../$(app_name)/tests" \ 136 | --exclude="../$(app_name)/Makefile" \ 137 | --exclude="../$(app_name)/*.log" \ 138 | --exclude="../$(app_name)/phpunit*xml" \ 139 | --exclude="../$(app_name)/composer.*" \ 140 | --exclude="../$(app_name)/js/node_modules" \ 141 | --exclude="../$(app_name)/js/tests" \ 142 | --exclude="../$(app_name)/js/test" \ 143 | --exclude="../$(app_name)/js/*.log" \ 144 | --exclude="../$(app_name)/js/package.json" \ 145 | --exclude="../$(app_name)/js/bower.json" \ 146 | --exclude="../$(app_name)/js/karma.*" \ 147 | --exclude="../$(app_name)/js/protractor.*" \ 148 | --exclude="../$(app_name)/package.json" \ 149 | --exclude="../$(app_name)/bower.json" \ 150 | --exclude="../$(app_name)/karma.*" \ 151 | --exclude="../$(app_name)/protractor\.*" \ 152 | --exclude="../$(app_name)/.*" \ 153 | --exclude="../$(app_name)/js/.*" \ 154 | -cvzf $(appstore_package_name).tar.gz ../$(app_name) 155 | 156 | .PHONY: test 157 | test: composer 158 | $(CURDIR)/vendor/phpunit/phpunit/phpunit -c phpunit.xml 159 | $(CURDIR)/vendor/phpunit/phpunit/phpunit -c phpunit.integration.xml 160 | 161 | .PHONY: sign 162 | sign: 163 | @openssl dgst -sha512 -sign ~/.nextcloud/certificates/occweb.key build/artifacts/appstore/occweb.tar.gz |openssl base64 164 | 165 | VERSION := $(shell xpath -q -e "//info/version/text()" appinfo/info.xml) 166 | 167 | .PHONY: show-version 168 | show-version: 169 | @echo $(VERSION) 170 | 171 | .PHONY: version 172 | version: 173 | @echo "Creating version v$(VERSION)" 174 | @git tag v$(VERSION) 175 | @git push origin v$(VERSION) 176 | @make dist 177 | @echo "\nRelease Signature: \n" 178 | @make sign 179 | -------------------------------------------------------------------------------- /css/style.css: -------------------------------------------------------------------------------- 1 | ::selection { 2 | background: #FF5E99; 3 | } 4 | .full-width{ 5 | min-width: 100%; 6 | /*min-height: 100%;*/ 7 | margin: 0; 8 | padding: 0; 9 | } 10 | #app-content { 11 | font-size: 11pt; 12 | font-family: Inconsolata, monospace; 13 | color: white; 14 | background-color: black; 15 | min-width: 100%; 16 | min-height: 100%; 17 | overflow-x: hidden; 18 | overflow-y: hidden; 19 | } 20 | /*! 21 | * __ _____ ________ __ 22 | * / // _ /__ __ _____ ___ __ _/__ ___/__ ___ ______ __ __ __ ___ / / 23 | * __ / // // // // // _ // _// // / / // _ // _// // // \/ // _ \/ / 24 | * / / // // // // // ___// / / // / / // ___// / / / / // // /\ // // / /__ 25 | * \___//____ \\___//____//_/ _\_ / /_//____//_/ /_/ /_//_//_/ /_/ \__\_\___/ 26 | * \/ /____/ version 2.0.2 27 | * http://terminal.jcubic.pl 28 | * 29 | * This file is part of jQuery Terminal. 30 | * 31 | * Copyright (c) 2011-2018 Jakub Jankiewicz 32 | * Released under the MIT license 33 | * 34 | * Date: Sat, 22 Dec 2018 15:04:14 +0000 35 | */ 36 | .terminal .terminal-output .format, .cmd .format, 37 | .cmd .prompt, .cmd .prompt div, .terminal .terminal-output div div{ 38 | display: inline-block; 39 | } 40 | .terminal h1, .terminal h2, .terminal h3, .terminal h4, .terminal h5, .terminal h6, .terminal pre, .cmd { 41 | margin: 0; 42 | } 43 | .terminal h1, .terminal h2, .terminal h3, .terminal h4, .terminal h5, .terminal h6 { 44 | line-height: 1.5em; 45 | } 46 | /* 47 | .cmd .mask { 48 | width: 10px; 49 | height: 11px; 50 | background: black; 51 | z-index: 100; 52 | } 53 | */ 54 | .cmd .clipboard { 55 | position: absolute; 56 | left: -16px; 57 | top: 0; 58 | /*width: 16px;*/ 59 | /*height: 16px;*/ 60 | /* this seems to work after all on Android */ 61 | left: -99999px; 62 | clip: rect(1px,1px,1px,1px); 63 | /* on desktop textarea appear when paste */ 64 | /* opacity is needed for Edge and IE 65 | opacity: 0.01; 66 | filter: alpha(opacity = 0.01); 67 | filter: progid:DXImageTransform.Microsoft.Alpha(opacity=0.01);*/ 68 | background-color: transparent; 69 | border: none; 70 | color: transparent; 71 | outline: none; 72 | padding: 0; 73 | resize: none; 74 | z-index: 1000; 75 | overflow: hidden; 76 | white-space: pre; 77 | text-indent: -9999em; /* better cursor hiding for Safari and IE */ 78 | top: calc(var(--cursor-line, 0) * 1em); 79 | /*visibility: hidden;*/ 80 | } 81 | .cmd .noselect, .cmd [role="presentation"]:not(.cursor-line) > span:last-child, 82 | .cmd .cursor-line > span:last-child > span:last-child { 83 | -webkit-touch-callout: none; /* iOS Safari */ 84 | -webkit-user-select: none; /* Safari */ 85 | -khtml-user-select: none; /* Konqueror HTML */ 86 | -moz-user-select: none; /* Firefox */ 87 | -ms-user-select: none; /* Internet Explorer/Edge */ 88 | user-select: none; /* Non-prefixed version, currently supported by Chrome and Opera */ 89 | } 90 | .terminal img, .terminal audio, .terminal object, .terminal canvas { 91 | cursor: default; 92 | } 93 | .terminal { 94 | position: relative; 95 | /*overflow: hidden;*/ 96 | overflow-y: auto; 97 | /* overflow-x: hidden; */ 98 | } 99 | terminal.temp { 100 | visibility: hidden; 101 | } 102 | .terminal { 103 | contain: content; 104 | } 105 | body.terminal { 106 | min-height: 100vh; 107 | height: 100%; 108 | } 109 | html { 110 | height: 100%; 111 | } 112 | body.terminal, body.full-screen-terminal { 113 | margin: 0; 114 | height: 100%; 115 | } 116 | body.full-screen-terminal .terminal { 117 | height: 100%; 118 | } 119 | .terminal > div:not(.font) { 120 | min-height: 100%; 121 | } 122 | .terminal > .resizer, .terminal > .font .resizer { 123 | position: absolute; 124 | top: 0; 125 | right: 0; 126 | bottom: 0; 127 | left: 0; 128 | overflow: hidden; 129 | pointer-events: none; 130 | z-index: -1; 131 | height: 100%; 132 | border: none; 133 | padding: 0; 134 | width: 100% 135 | } 136 | .cmd { 137 | padding: 0; 138 | position: relative; 139 | float: left; 140 | } 141 | .terminal a[tabindex="1000"], 142 | .terminal a[tabindex="1000"]:active, 143 | .terminal a[tabindex="1000"]:focus { 144 | outline: none; 145 | } 146 | .terminal .inverted, .cmd .inverted { 147 | background-color: #fff; 148 | color: #000; 149 | } 150 | .cmd .cursor { 151 | display: inline-block; 152 | position: relative; 153 | height: 14px; 154 | min-width: 1ch; 155 | /* box-sizing: border-box; */ 156 | } 157 | .cmd .cursor span span { 158 | border-bottom: 3px solid transparent; 159 | margin-bottom: -3px; 160 | background-clip: content-box; 161 | border-left: 1px solid transparent; 162 | position: absolute; 163 | top: 0; 164 | /* margin-left: -1px; */ 165 | background-color: inherit; 166 | color: inherit; 167 | bottom: 0; 168 | left: -1px; 169 | } 170 | .cmd .cursor-line > span:empty { 171 | /* display: none; */ 172 | } 173 | .cmd .cursor-line > span:empty + .cursor + span { 174 | /*margin-left: -1px;*/ 175 | } 176 | .cmd .cursor-line > span:not(.cursor):not(:empty) { 177 | /* margin-left: -1px; */ 178 | } 179 | .cmd .cursor-line > span { 180 | display: inline-block; 181 | float: left; 182 | } 183 | .cmd .cursor.blink span span { 184 | -webkit-animation: terminal-blink 1s infinite linear; 185 | -moz-animation: terminal-blink 1s infinite linear; 186 | -ms-animation: terminal-blink 1s infinite linear; 187 | animation: terminal-blink 1s infinite linear; 188 | } 189 | .bar.terminal .inverted, .bar.cmd .inverted { 190 | border-left-color: #fff; 191 | } 192 | .terminal .terminal .terminal-output > div > div, .cmd .prompt { 193 | display: block; 194 | line-height: 16pt; 195 | height: auto; 196 | } 197 | .terminal .terminal-output > div:not(.raw) div { 198 | white-space: nowrap; 199 | } 200 | .cmd .prompt > span { 201 | float: left; 202 | } 203 | .terminal, 204 | .terminal-output > :not(.raw) span:not(.token), 205 | .terminal-output > :not(.raw) a, 206 | .terminal-output > :not(.raw) div, 207 | .cmd, 208 | .cmd span, 209 | .cmd div { 210 | font-family: Inconsolata, monospace; 211 | /*font-family: FreeMono, monospace; this don't work on Android */ 212 | color: white; 213 | background-color: black; 214 | font-size: 12pt; 215 | line-height: 16pt; 216 | } 217 | .terminal, .cmd { 218 | box-sizing: border-box; 219 | cursor: text; 220 | } 221 | .cmd .cursor span:not(.token) { 222 | color: inherit; 223 | background-color: inherit; 224 | } 225 | .cmd .cursor * { 226 | background-color: transparent; 227 | } 228 | .cmd div { 229 | clear: both; 230 | } 231 | .cmd .prompt + div { 232 | clear: right; 233 | } 234 | .terminal-output > div > div, .cmd div { 235 | min-height: 16pt; 236 | } 237 | terminal .terminal-output > div { 238 | margin-top: -1px; 239 | } 240 | .terminal-output > div.raw > div * { 241 | overflow-wrap: break-word; 242 | word-wrap: break-word; 243 | } 244 | .terminal .font { 245 | position: absolute; 246 | float: left; 247 | font-size: inherit; 248 | line-height: inherit; 249 | top: -100%; 250 | left: 0; 251 | margin-bottom: 1px; 252 | } 253 | .terminal .terminal-output div span { 254 | display: inline-block; 255 | } 256 | .cmd > span:not(.prompt) { 257 | float: left; 258 | } 259 | .cmd .prompt span.line { 260 | display: block; 261 | float: none; 262 | } 263 | .terminal table { 264 | border-collapse: collapse; 265 | } 266 | .terminal td { 267 | border: 1px solid #fff; 268 | } 269 | .cmd span[data-text] span { 270 | background-color: inherit; 271 | color: inherit; 272 | } 273 | .cmd [role="presentation"] { 274 | overflow: hidden; 275 | padding-bottom: 3px; 276 | margin-bottom: -3px; 277 | } 278 | /* 279 | * this is set so animation can select original color as backgound for cursor 280 | * so span can have --color for selection 281 | */ 282 | .cmd { 283 | --original-color: var(--color, #fff); 284 | } 285 | @-webkit-keyframes terminal-blink { 286 | 0%, 50% { 287 | background-color: #bbb; 288 | background-color: var(--original-color, #bbb); 289 | color: #000; 290 | color: var(--background, #000); 291 | } 292 | 50.1%, 100% { 293 | background-color: inherit; 294 | color: inherit; 295 | } 296 | } 297 | @-ms-keyframes terminal-blink { 298 | 0%, 50% { 299 | background-color: #bbb; 300 | background-color: var(--original-color, #bbb); 301 | color: #000; 302 | color: var(--background, #000); 303 | } 304 | 50.1%, 100% { 305 | background-color: inherit; 306 | color: inherit; 307 | } 308 | } 309 | @-moz-keyframes terminal-blink { 310 | 0%, 50% { 311 | background-color: #fff; 312 | background-color: var(--original-color, #fff); 313 | color: #000; 314 | color: var(--background, #000); 315 | } 316 | 50.1%, 100% { 317 | background-color: inherit; 318 | color: inherit; 319 | } 320 | } 321 | @keyframes terminal-blink { 322 | 0%, 50% { 323 | background-color: #fff; 324 | background-color: var(--original-color, #fff); 325 | color: #000; 326 | color: var(--background, #000); 327 | } 328 | 50.1%, 100% { 329 | background-color: inherit; 330 | color: inherit; 331 | } 332 | } 333 | @-webkit-keyframes terminal-bar { 334 | 0%, 50% { 335 | border-left-color: #fff; 336 | border-left-color: var(--color, #fff); 337 | } 338 | 50.1%, 100% { 339 | border-left-color: #000; 340 | border-left-color: var(--background, #000); 341 | } 342 | } 343 | @-ms-keyframes terminal-bar { 344 | 0%, 50% { 345 | border-left-color: #fff; 346 | border-left-color: var(--color, #fff); 347 | } 348 | 50.1%, 100% { 349 | border-left-color: #000; 350 | border-left-color: var(--background, #000); 351 | } 352 | } 353 | @-moz-keyframes terminal-bar { 354 | 0%, 50% { 355 | border-left-color: #fff; 356 | border-left-color: var(--color, #fff); 357 | } 358 | 50.1%, 100% { 359 | border-left-color: #000; 360 | border-left-color: var(--background, #000); 361 | } 362 | } 363 | @keyframes terminal-bar { 364 | 0%, 50% { 365 | border-left-color: #fff; 366 | border-left-color: var(--color, #fff); 367 | } 368 | 50.1%, 100% { 369 | border-left-color: #000; 370 | border-left-color: var(--background, #000); 371 | } 372 | } 373 | @-webkit-keyframes terminal-underline { 374 | 0%, 50% { 375 | border-left: none; 376 | border-bottom-color: #fff; 377 | border-bottom-color: var(--color, #fff); 378 | } 379 | 50.1%, 100% { 380 | border-left: none; 381 | border-bottom-color: #000; 382 | border-bottom-color: var(--background, #000); 383 | } 384 | } 385 | @-ms-keyframes terminal-underline { 386 | 0%, 50% { 387 | border-left: none; 388 | border-bottom-color: #fff; 389 | border-bottom-color: var(--color, #fff); 390 | } 391 | 50.1%, 100% { 392 | border-left: none; 393 | border-bottom-color: #000; 394 | border-bottom-color: var(--background, #000); 395 | } 396 | } 397 | @-moz-keyframes terminal-underline { 398 | 0%, 50% { 399 | border-left: none; 400 | border-bottom-color: #fff; 401 | border-bottom-color: var(--color, #fff); 402 | } 403 | 50.1%, 100% { 404 | border-left: none; 405 | border-bottom-color: #000; 406 | border-bottom-color: var(--background, #000); 407 | } 408 | } 409 | @keyframes terminal-underline { 410 | 0%, 50% { 411 | border-bottom-color: #fff; 412 | border-bottom-color: var(--color, #fff); 413 | } 414 | 50.1%, 100% { 415 | border-bottom-color: #000; 416 | border-bottom-color: var(--background, #000); 417 | } 418 | } 419 | .underline-animation .cursor.blink span span { 420 | /* margin-top: 2px; */ 421 | border-left: none; 422 | /* margin-left: 0; */ 423 | margin-right: -1px; 424 | -webkit-animation-name: terminal-underline; 425 | -moz-animation-name: terminal-underline; 426 | -ms-animation-name: terminal-underline; 427 | animation-name: terminal-underline; 428 | right: 1px; 429 | } 430 | .bar-animation .cursor.blink span span { 431 | -webkit-animation-name: terminal-bar; 432 | -moz-animation-name: terminal-bar; 433 | -ms-animation-name: terminal-bar; 434 | animation-name: terminal-bar; 435 | } 436 | /* 437 | Internet Explorer & Edge *, Safari ≤ 6 438 | source: https://w3reign.com/internet-explorer-edge-css-hacks/ 439 | */ 440 | 441 | 442 | @supports (-ms-ime-align:auto) { 443 | .cmd .clipboard { 444 | margin-left: -9999px; 445 | } 446 | @keyframes terminal-blink { 447 | 0%, 50% { 448 | background-color: var(--original-color, #fff); 449 | color: var(--background, #000); 450 | } 451 | 50.1%, 100% { 452 | background-color: var(--background, #000); 453 | color: var(--original-color, #fff); 454 | } 455 | } 456 | @keyframes terminal-bar { 457 | 0%, 50% { 458 | border-left-color: var(--color, #fff); 459 | } 460 | 50.1%, 100% { 461 | border-left-color: var(--background, #000); 462 | } 463 | } 464 | @keyframes terminal-underline { 465 | 0%, 50% { 466 | border-bottom-color: var(--color, #fff); 467 | line-height: 12pt; 468 | line-height: calc(var(--size, 1) * 12pt); 469 | } 470 | 50.1%, 100% { 471 | border-bottom-color: var(--background, #000); 472 | line-height: 12pt; 473 | line-height: calc(var(--size, 1) * 12pt); 474 | } 475 | } 476 | } 477 | /* IE hack Edge one don't work in IE11 */ 478 | @media all and (-ms-high-contrast: none), (-ms-high-contrast: active) { 479 | .cmd .clipboard { 480 | margin-left: -9999px; 481 | } 482 | .underline-animation .cursor.blink span span { 483 | margin-top: 1px; 484 | } 485 | @-ms-keyframes terminal-blink { 486 | 0%, 50% { 487 | background-color: #fff; 488 | color: #000; 489 | } 490 | 50.1%, 100% { 491 | background-color: #000; 492 | color: #fff; 493 | } 494 | } 495 | } 496 | .terminal h1::-moz-selection, 497 | .terminal h2::-moz-selection, 498 | .terminal h3::-moz-selection, 499 | .terminal h4::-moz-selection, 500 | .terminal h5::-moz-selection, 501 | .terminal h6::-moz-selection, 502 | .terminal pre::-moz-selection, 503 | .terminal td::-moz-selection, 504 | .terminal .terminal-output div div::-moz-selection, 505 | .terminal .terminal-output div span::-moz-selection, 506 | .terminal .terminal-output div div a::-moz-selection, 507 | .terminal .terminal-output .raw div::-moz-selection, 508 | .cmd div::-moz-selection, 509 | .cmd > span::-moz-selection, 510 | .cmd > span span::-moz-selection, 511 | .cmd > div::-moz-selection, 512 | .cmd > div span::-moz-selection, 513 | .cmd .prompt span::-moz-selection { 514 | background-color: #fff; 515 | color: #000; 516 | } 517 | /* this don't work in Chrome 518 | .terminal tr td::-moz-selection { 519 | border-color: #000; 520 | } 521 | .terminal tr td::selection { 522 | border-color: #000; 523 | } 524 | */ 525 | .terminal h1::selection, 526 | .terminal h2::selection, 527 | .terminal h3::selection, 528 | .terminal h4::selection, 529 | .terminal h5::selection, 530 | .terminal h6::selection, 531 | .terminal pre::selection, 532 | .terminal td::selection, 533 | .terminal .terminal-output div div::selection, 534 | .terminal .terminal-output div div a::selection, 535 | .terminal .terminal-output div span::selection, 536 | .terminal .terminal-output .raw div::selection, 537 | .cmd div::selection, 538 | .cmd > span::selection, 539 | .cmd > span span::selection, 540 | .cmd > div::selection, 541 | .cmd > div span::selection, 542 | .cmd .prompt span::selection { 543 | /* 544 | * use rgba to fix transparent selection in chrome 545 | * http://stackoverflow.com/questions/7224445/css3-selection-behaves-differently-in-ff-chrome 546 | */ 547 | background-color: #ff5e99; 548 | color: white; 549 | } 550 | 551 | .terminal .terminal-output > :not(.raw) .error, 552 | .terminal .terminal-output > :not(.raw) .error * { 553 | color: red; 554 | color: var(--error-color, red); 555 | } 556 | .tilda { 557 | position: fixed; 558 | top: 0; 559 | left: 0; 560 | width: 100%; 561 | z-index: 1100; 562 | } 563 | .ui-dialog-content .terminal { 564 | width: 100%; 565 | height: 100%; 566 | box-sizing: border-box; 567 | } 568 | .ui-dialog .ui-dialog-content.dterm { 569 | padding: 0; 570 | } 571 | .clear { 572 | clear: both; 573 | } 574 | .terminal .terminal-output > :not(.raw) > div { 575 | padding-bottom: 1px; 576 | } 577 | .terminal .terminal-output > :not(.raw) a[href] { 578 | color: #0F60FF; 579 | color: var(--link-color, #0F60FF); 580 | cursor: pointer; 581 | } 582 | .terminal .terminal-output > :not(.raw) a[href]:hover { 583 | background-color: #0F60FF; 584 | background-color: var(--link-color, #0F60FF); 585 | color: var(--background, #000); 586 | text-decoration: none; 587 | } 588 | .terminal .terminal-fill { 589 | position: absolute; 590 | left: 0; 591 | top: -100%; 592 | width: 100%; 593 | height: 100%; 594 | margin: 6px 0 0; 595 | border: none; 596 | opacity: 0.01; 597 | pointer-events: none; 598 | box-sizing: border-box; 599 | } 600 | .terminal, .terminal .terminal-fill { 601 | padding: 10px; 602 | } 603 | /* padding added as margin to .cmd to fix FireFox bug see: https://stackoverflow.com/q/29986977/387194 */ 604 | .terminal { 605 | padding-bottom: 0; 606 | } 607 | .terminal .cmd { 608 | margin-bottom: 10px; 609 | } 610 | @supports (--css: variables) { 611 | .terminal, 612 | .terminal-output > :not(.raw) span:not(.token), 613 | .terminal-output > :not(.raw) a, 614 | .terminal-output > :not(.raw) div, 615 | .cmd, 616 | .cmd span, 617 | .cmd div { 618 | color: var(--color, #fff); 619 | background-color: var(--background, #000); 620 | } 621 | .terminal span[style*="--length"] { 622 | /* 623 | * default value for char-width taken from Google Chrome for default font 624 | * to silence warning in webpack #371 625 | */ 626 | width: calc(var(--length, 1) * var(--char-width, 7.23438) * 1px); 627 | display: inline-block; 628 | } 629 | .terminal, 630 | .terminal-output > :not(.raw) span:not(.token), 631 | .terminal-output > :not(.raw) a, 632 | .terminal-output > :not(.raw) div, 633 | .cmd, 634 | .cmd span, 635 | .cmd div { 636 | font-size: calc(var(--size, 1) * 12pt); 637 | line-height: calc(var(--size, 1) * 12pt + 3px); 638 | } 639 | .cmd .clipboard { 640 | top: calc(var(--size, 1) * 14 * var(--cursor-line, 0) * 1px); 641 | } 642 | .terminal .terminal-output > div > div, .cmd div{ 643 | min-height: calc(var(--size, 1) * 16pt); 644 | } 645 | .terminal .inverted, .cmd .inverted { 646 | background-color: var(--color, #fff); 647 | color: var(--background, #000); 648 | } 649 | .cmd div { 650 | min-height: calc(var(--size, 1) * 14px); 651 | } 652 | .cmd .cursor.blink { 653 | color: var(--color, #fff); 654 | background-color: var(--background, #000); 655 | } 656 | .cmd .cursor.blink span span { 657 | -webkit-animation: var(--animation, terminal-blink) 1s infinite linear; 658 | -moz-animation: var(--animation, terminal-blink) 1s infinite linear; 659 | -ms-animation: var(--animation, terminal-blink) 1s infinite linear; 660 | animation: var(--animation, terminal-blink) 1s infinite linear; 661 | } 662 | .cmd .cursor { 663 | height: calc(var(--size, 1) * 14px); 664 | min-width: calc(var(--char-width, 7.23438) * 1px); 665 | } 666 | .terminal h1::-moz-selection, 667 | .terminal h2::-moz-selection, 668 | .terminal h3::-moz-selection, 669 | .terminal h4::-moz-selection, 670 | .terminal h5::-moz-selection, 671 | .terminal h6::-moz-selection, 672 | .terminal pre::-moz-selection, 673 | .terminal td::-moz-selection, 674 | .terminal .terminal-output div div::-moz-selection, 675 | .terminal .terminal-output div span::-moz-selection, 676 | .terminal .terminal-output div div a::-moz-selection, 677 | .cmd div::-moz-selection, 678 | .cmd > span::-moz-selection, 679 | .cmd > span span::-moz-selection, 680 | .cmd > div::-moz-selection, 681 | .cmd > div span::-moz-selection, 682 | .cmd .prompt span::-moz-selection { 683 | background-color: var(--color, #ff5e99); 684 | color: var(--background, white); 685 | } 686 | .terminal h1::selection, 687 | .terminal h2::selection, 688 | .terminal h3::selection, 689 | .terminal h4::selection, 690 | .terminal h5::selection, 691 | .terminal h6::selection, 692 | .terminal pre::selection, 693 | .terminal td::selection, 694 | .terminal .terminal-output div div::selection, 695 | .terminal .terminal-output div div a::selection, 696 | .terminal .terminal-output div span::selection, 697 | .cmd div::selection, 698 | .cmd > span::selection, 699 | .cmd > span span::selection, 700 | .cmd > div::selection, 701 | .cmd > div span::selection, 702 | .cmd .prompt span::selection { 703 | background-color: var(--color, #ff5e99); 704 | color: var(--background, #fff) !important; 705 | } 706 | } 707 | /* 708 | * overwrite css variables that don't work with selection in Edge 709 | */ 710 | @supports (-ms-ime-align:auto) { 711 | .terminal h1::selection, 712 | .terminal h2::selection, 713 | .terminal h3::selection, 714 | .terminal h4::selection, 715 | .terminal h5::selection, 716 | .terminal h6::selection, 717 | .terminal pre::selection, 718 | .terminal td::selection, 719 | .terminal .terminal-output div div::selection, 720 | .terminal .terminal-output div div a::selection, 721 | .terminal .terminal-output div span::selection, 722 | .cmd div::selection, 723 | .cmd > span::selection, 724 | .cmd > span span::selection, 725 | .cmd > div::selection, 726 | .cmd > div span::selection, 727 | .cmd .prompt span::selection { 728 | background-color: #ff5e99; 729 | color: #ffffff; 730 | } 731 | } 732 | /* PrismJS style overwrites */ 733 | .terminal .token.operator, 734 | .terminal .token.entity, 735 | .terminal .token.variable, 736 | .terminal .token.url, 737 | .terminal .token.string, 738 | .terminal .style .token.string, 739 | .terminal .token.token, 740 | .cmd .token.operator, 741 | .cmd .token.entity, 742 | .cmd .token.variable, 743 | .cmd .token.url, 744 | .cmd .token.string, 745 | .cmd .style .token.string, 746 | .cmd .token.token { 747 | background-color: inherit; 748 | } 749 | /* FireFox hack 750 | @supports (-moz-animation: foo) { 751 | .terminal, 752 | .terminal .terminal-output > :not(.raw) span, 753 | .terminal .terminal-output > :not(.raw) a, 754 | .terminal .terminal-output > :not(.raw) div, 755 | .cmd, 756 | .cmd span, 757 | .cmd div { 758 | line-height: calc(var(--size, 1) * 13px); 759 | } 760 | } 761 | */ 762 | 763 | ::selection { 764 | background: #ff5e99; 765 | color: white; 766 | } 767 | 768 | .terminal-output div div { 769 | padding: 0 !important; 770 | margin: 0 !important; 771 | border: 0 !important; 772 | } 773 | .prompt span, .cursor-line span span, .command div span{ 774 | color: #009ae3 !important; 775 | } 776 | -------------------------------------------------------------------------------- /js/unix_formatting.js: -------------------------------------------------------------------------------- 1 | /**@license 2 | * __ _____ ________ __ 3 | * / // _ /__ __ _____ ___ __ _/__ ___/__ ___ ______ __ __ __ ___ / / 4 | * __ / // // // // // _ // _// // / / // _ // _// // // \/ // _ \/ / 5 | * / / // // // // // ___// / / // / / // ___// / / / / // // /\ // // / /__ 6 | * \___//____ \\___//____//_/ _\_ / /_//____//_/ /_/ /_//_//_/ /_/ \__\_\___/ 7 | * \/ /____/ 8 | * http://terminal.jcubic.pl 9 | * 10 | * This is example of how to create custom formatter for jQuery Terminal 11 | * 12 | * Copyright (c) 2014-2018 Jakub Jankiewicz 13 | * Released under the MIT license 14 | * 15 | */ 16 | /* global jQuery, define, global, require, module */ 17 | (function(factory) { 18 | var root = typeof window !== 'undefined' ? window : global; 19 | if (typeof define === 'function' && define.amd) { 20 | // AMD. Register as an anonymous module. 21 | // istanbul ignore next 22 | define(['jquery', 'jquery.terminal'], factory); 23 | } else if (typeof module === 'object' && module.exports) { 24 | // Node/CommonJS 25 | module.exports = function(root, jQuery) { 26 | if (jQuery === undefined) { 27 | // require('jQuery') returns a factory that requires window to 28 | // build a jQuery instance, we normalize how we use modules 29 | // that require this pattern but the window provided is a noop 30 | // if it's defined (how jquery works) 31 | if (typeof window !== 'undefined') { 32 | jQuery = require('jquery'); 33 | } else { 34 | jQuery = require('jquery')(root); 35 | } 36 | } 37 | if (!jQuery.fn.terminal) { 38 | if (typeof window !== 'undefined') { 39 | require('jquery.terminal'); 40 | } else { 41 | require('jquery.terminal')(jQuery); 42 | } 43 | } 44 | factory(jQuery); 45 | return jQuery; 46 | }; 47 | } else { 48 | // Browser 49 | // istanbul ignore next 50 | factory(root.jQuery); 51 | } 52 | })(function($) { 53 | $.terminal.defaults.unixFormattingEscapeBrackets = false; 54 | // we match characters and html entities because command line escape brackets 55 | // echo don't, when writing formatter always process html entitites so it work 56 | // for cmd plugin as well for echo 57 | var chr = '[^\\x08]|[\\r\\n]{2}|&[^;]+;'; 58 | var backspace_re = new RegExp('^(' + chr + ')?\\x08'); 59 | var overtyping_re = new RegExp('^(?:(' + chr + ')?\\x08(_|\\1)|' + 60 | '(_)\\x08(' + chr + '))'); 61 | var new_line_re = /^(\r\n|\n\r|\r|\n)/; 62 | var clear_line_re = /[^\r\n]+\r\x1B\[K/g; 63 | // --------------------------------------------------------------------- 64 | function length(string) { 65 | return $.terminal.length(string); 66 | } 67 | // --------------------------------------------------------------------- 68 | // :: Replace overtyping (from man) formatting with terminal formatting 69 | // --------------------------------------------------------------------- 70 | $.terminal.overtyping = function overtyping(string, options) { 71 | string = $.terminal.unescape_brackets(string); 72 | var settings = $.extend({ 73 | unixFormattingEscapeBrackets: false, 74 | position: 0 75 | }, options); 76 | var removed_chars = []; 77 | var new_position; 78 | var char_count = 0; 79 | var backspaces = []; 80 | function replace(string, position) { 81 | var result = ''; 82 | var push = 0; 83 | var start; 84 | char_count = 0; 85 | function correct_position(start, match, rep_string) { 86 | // logic taken from $.terminal.tracking_replace 87 | if (start < position) { 88 | var last_index = start + length(match); 89 | if (last_index < position) { 90 | // It's after the replacement, move it 91 | new_position = Math.max( 92 | 0, 93 | new_position + 94 | length(rep_string) - 95 | length(match) 96 | ); 97 | } else { 98 | // It's *in* the replacement, put it just after 99 | new_position += length(rep_string) - (position - start); 100 | } 101 | } 102 | } 103 | for (var i = 0; i < string.length; ++i) { 104 | var partial = string.substring(i); 105 | var match = partial.match(backspace_re); 106 | var removed_char = removed_chars[0]; 107 | if (match) { 108 | // we remove backspace and character or html entity before it 109 | // but we keep it in removed array so we can put it back 110 | // when we have caritage return or line feed 111 | if (match[1]) { 112 | start = i - match[1].length + push; 113 | removed_chars.push({ 114 | index: start, 115 | string: match[1], 116 | overtyping: partial.match(overtyping_re) 117 | }); 118 | correct_position(start, match[0], '', 1); 119 | } 120 | if (char_count < 0) { 121 | char_count = 0; 122 | } 123 | backspaces = backspaces.map(function(b) { 124 | return b - 1; 125 | }); 126 | backspaces.push(start); 127 | return result + partial.replace(backspace_re, ''); 128 | } else if (partial.match(new_line_re)) { 129 | // if newline we need to add at the end all characters 130 | // removed by backspace but only if there are no more 131 | // other characters than backspaces added between 132 | // backspaces and newline 133 | if (removed_chars.length) { 134 | var chars = removed_chars; 135 | removed_chars = []; 136 | chars.reverse().forEach(function(char) { 137 | if (i > char.index) { 138 | if (--char_count <= 0) { 139 | correct_position(char.index, '', char.string, 2); 140 | result += char.string; 141 | } 142 | } else { 143 | removed_chars.unshift(char); 144 | } 145 | }); 146 | } 147 | var m = partial.match(new_line_re); 148 | result += m[1]; 149 | i += m[1].length - 1; 150 | } else { 151 | if (backspaces.length) { 152 | var backspace = backspaces[0]; 153 | if (i === backspace) { 154 | backspaces.shift(); 155 | } 156 | if (i >= backspace) { 157 | char_count++; 158 | } 159 | } 160 | if (removed_chars.length) { 161 | // if we are in index of removed character we check if the 162 | // character is the same it will be bold or if removed char 163 | // or char at index is underscore then it will 164 | // be terminal formatting with underscore 165 | if (i > removed_char.index && removed_char.overtyping) { 166 | removed_chars.shift(); 167 | correct_position(removed_char.index, '', removed_char.string); 168 | // if we add special character we need to correct 169 | // next push to removed_char array 170 | push++; 171 | // we use special characters instead of terminal 172 | // formatting so it's easier to proccess when removing 173 | // backspaces 174 | if (removed_char.string === string[i]) { 175 | result += string[i] + '\uFFF1'; 176 | continue; 177 | } else if (removed_char.string === '_' || 178 | string[i] === '_') { 179 | var chr; 180 | if (removed_char.string === '_') { 181 | chr = string[i]; 182 | } else { 183 | chr = removed_char.string; 184 | } 185 | result += chr + '\uFFF2'; 186 | continue; 187 | } 188 | } 189 | } 190 | result += string[i]; 191 | } 192 | } 193 | return result; 194 | } 195 | var break_next = false; 196 | // loop until not more backspaces 197 | new_position = settings.position; 198 | // we need to clear line \x1b[K in overtyping because it need to be before 199 | // overtyping and from_ansi need to be called after so it escape stuff 200 | // between Escape Code and cmd will have escaped formatting typed by user 201 | var rep = $.terminal.tracking_replace(string, clear_line_re, '', new_position); 202 | string = rep[0]; 203 | new_position = rep[1]; 204 | while (string.match(/\x08/) || removed_chars.length) { 205 | string = replace(string, new_position); 206 | if (break_next) { 207 | break; 208 | } 209 | if (!string.match(/\x08/)) { 210 | // we break the loop so if removed_chars still chave items 211 | // we don't have infite loop 212 | break_next = true; 213 | } 214 | } 215 | function format(string, chr, style) { 216 | var re = new RegExp('((:?.' + chr + ')+)', 'g'); 217 | return string.replace(re, function(_, string) { 218 | var re = new RegExp(chr, 'g'); 219 | return '[[' + style + ']' + string.replace(re, '') + ']'; 220 | }); 221 | } 222 | // replace special characters with terminal formatting 223 | string = format(string, '\uFFF1', 'b;#fff;'); 224 | string = format(string, '\uFFF2', 'u;;'); 225 | if (settings.unixFormattingEscapeBrackets) { 226 | string = $.terminal.escape_brackets(string); 227 | } 228 | if (options && typeof options.position === 'number') { 229 | return [string, new_position]; 230 | } 231 | return string; 232 | }; 233 | // --------------------------------------------------------------------- 234 | // :: Html colors taken from ANSI formatting in Linux Terminal 235 | // --------------------------------------------------------------------- 236 | $.terminal.ansi_colors = { 237 | normal: { 238 | black: '#000', 239 | red: '#A00', 240 | green: '#008400', 241 | yellow: '#A50', 242 | blue: '#00A', 243 | magenta: '#A0A', 244 | cyan: '#0AA', 245 | white: '#AAA' 246 | }, 247 | faited: { 248 | black: '#000', 249 | red: '#640000', 250 | green: '#006100', 251 | yellow: '#737300', 252 | blue: '#000087', 253 | magenta: '#650065', 254 | cyan: '#008787', 255 | white: '#818181' 256 | }, 257 | bold: { 258 | black: '#000', 259 | red: '#F55', 260 | green: '#44D544', 261 | yellow: '#FF5', 262 | blue: '#55F', 263 | magenta: '#F5F', 264 | cyan: '#5FF', 265 | white: '#FFF' 266 | }, 267 | // XTerm 8-bit pallete 268 | palette: [ 269 | '#000000', '#AA0000', '#00AA00', '#AA5500', '#0000AA', '#AA00AA', 270 | '#00AAAA', '#AAAAAA', '#555555', '#FF5555', '#55FF55', '#FFFF55', 271 | '#5555FF', '#FF55FF', '#55FFFF', '#FFFFFF', '#000000', '#00005F', 272 | '#000087', '#0000AF', '#0000D7', '#0000FF', '#005F00', '#005F5F', 273 | '#005F87', '#005FAF', '#005FD7', '#005FFF', '#008700', '#00875F', 274 | '#008787', '#0087AF', '#0087D7', '#0087FF', '#00AF00', '#00AF5F', 275 | '#00AF87', '#00AFAF', '#00AFD7', '#00AFFF', '#00D700', '#00D75F', 276 | '#00D787', '#00D7AF', '#00D7D7', '#00D7FF', '#00FF00', '#00FF5F', 277 | '#00FF87', '#00FFAF', '#00FFD7', '#00FFFF', '#5F0000', '#5F005F', 278 | '#5F0087', '#5F00AF', '#5F00D7', '#5F00FF', '#5F5F00', '#5F5F5F', 279 | '#5F5F87', '#5F5FAF', '#5F5FD7', '#5F5FFF', '#5F8700', '#5F875F', 280 | '#5F8787', '#5F87AF', '#5F87D7', '#5F87FF', '#5FAF00', '#5FAF5F', 281 | '#5FAF87', '#5FAFAF', '#5FAFD7', '#5FAFFF', '#5FD700', '#5FD75F', 282 | '#5FD787', '#5FD7AF', '#5FD7D7', '#5FD7FF', '#5FFF00', '#5FFF5F', 283 | '#5FFF87', '#5FFFAF', '#5FFFD7', '#5FFFFF', '#870000', '#87005F', 284 | '#870087', '#8700AF', '#8700D7', '#8700FF', '#875F00', '#875F5F', 285 | '#875F87', '#875FAF', '#875FD7', '#875FFF', '#878700', '#87875F', 286 | '#878787', '#8787AF', '#8787D7', '#8787FF', '#87AF00', '#87AF5F', 287 | '#87AF87', '#87AFAF', '#87AFD7', '#87AFFF', '#87D700', '#87D75F', 288 | '#87D787', '#87D7AF', '#87D7D7', '#87D7FF', '#87FF00', '#87FF5F', 289 | '#87FF87', '#87FFAF', '#87FFD7', '#87FFFF', '#AF0000', '#AF005F', 290 | '#AF0087', '#AF00AF', '#AF00D7', '#AF00FF', '#AF5F00', '#AF5F5F', 291 | '#AF5F87', '#AF5FAF', '#AF5FD7', '#AF5FFF', '#AF8700', '#AF875F', 292 | '#AF8787', '#AF87AF', '#AF87D7', '#AF87FF', '#AFAF00', '#AFAF5F', 293 | '#AFAF87', '#AFAFAF', '#AFAFD7', '#AFAFFF', '#AFD700', '#AFD75F', 294 | '#AFD787', '#AFD7AF', '#AFD7D7', '#AFD7FF', '#AFFF00', '#AFFF5F', 295 | '#AFFF87', '#AFFFAF', '#AFFFD7', '#AFFFFF', '#D70000', '#D7005F', 296 | '#D70087', '#D700AF', '#D700D7', '#D700FF', '#D75F00', '#D75F5F', 297 | '#D75F87', '#D75FAF', '#D75FD7', '#D75FFF', '#D78700', '#D7875F', 298 | '#D78787', '#D787AF', '#D787D7', '#D787FF', '#D7AF00', '#D7AF5F', 299 | '#D7AF87', '#D7AFAF', '#D7AFD7', '#D7AFFF', '#D7D700', '#D7D75F', 300 | '#D7D787', '#D7D7AF', '#D7D7D7', '#D7D7FF', '#D7FF00', '#D7FF5F', 301 | '#D7FF87', '#D7FFAF', '#D7FFD7', '#D7FFFF', '#FF0000', '#FF005F', 302 | '#FF0087', '#FF00AF', '#FF00D7', '#FF00FF', '#FF5F00', '#FF5F5F', 303 | '#FF5F87', '#FF5FAF', '#FF5FD7', '#FF5FFF', '#FF8700', '#FF875F', 304 | '#FF8787', '#FF87AF', '#FF87D7', '#FF87FF', '#FFAF00', '#FFAF5F', 305 | '#FFAF87', '#FFAFAF', '#FFAFD7', '#FFAFFF', '#FFD700', '#FFD75F', 306 | '#FFD787', '#FFD7AF', '#FFD7D7', '#FFD7FF', '#FFFF00', '#FFFF5F', 307 | '#FFFF87', '#FFFFAF', '#FFFFD7', '#FFFFFF', '#080808', '#121212', 308 | '#1C1C1C', '#262626', '#303030', '#3A3A3A', '#444444', '#4E4E4E', 309 | '#585858', '#626262', '#6C6C6C', '#767676', '#808080', '#8A8A8A', 310 | '#949494', '#9E9E9E', '#A8A8A8', '#B2B2B2', '#BCBCBC', '#C6C6C6', 311 | '#D0D0D0', '#DADADA', '#E4E4E4', '#EEEEEE' 312 | ] 313 | }; 314 | // --------------------------------------------------------------------- 315 | // :: Replace ANSI formatting with terminal formatting 316 | // --------------------------------------------------------------------- 317 | $.terminal.from_ansi = (function() { 318 | var color_list = { 319 | 30: 'black', 320 | 31: 'red', 321 | 32: 'green', 322 | 33: 'yellow', 323 | 34: 'blue', 324 | 35: 'magenta', 325 | 36: 'cyan', 326 | 37: 'white', 327 | 328 | 39: 'inherit' // default color 329 | }; 330 | var background_list = { 331 | 40: 'black', 332 | 41: 'red', 333 | 42: 'green', 334 | 43: 'yellow', 335 | 44: 'blue', 336 | 45: 'magenta', 337 | 46: 'cyan', 338 | 47: 'white', 339 | 340 | 49: 'transparent' // default background 341 | }; 342 | function format_ansi(code) { 343 | var controls = code.split(';'); 344 | var num; 345 | var faited = false; 346 | var reverse = false; 347 | var bold = false; 348 | var styles = []; 349 | var output_color = ''; 350 | var output_background = ''; 351 | var _process_true_color = -1; 352 | var _ex_color = false; 353 | var _ex_background = false; 354 | var _process_8bit = false; 355 | var palette = $.terminal.ansi_colors.palette; 356 | function set_styles(num) { 357 | switch (num) { 358 | case 1: 359 | styles.push('b'); 360 | bold = true; 361 | faited = false; 362 | break; 363 | case 4: 364 | styles.push('u'); 365 | break; 366 | case 3: 367 | styles.push('i'); 368 | break; 369 | case 5: 370 | if (_ex_color || _ex_background) { 371 | _process_8bit = true; 372 | } 373 | break; 374 | case 38: 375 | _ex_color = true; 376 | break; 377 | case 48: 378 | _ex_background = true; 379 | break; 380 | case 2: 381 | if (_ex_color || _ex_background) { 382 | _process_true_color = 0; 383 | } else { 384 | faited = true; 385 | bold = false; 386 | } 387 | break; 388 | case 7: 389 | reverse = true; 390 | break; 391 | default: 392 | if (controls.indexOf('5') === -1) { 393 | if (color_list[num]) { 394 | output_color = color_list[num]; 395 | } 396 | if (background_list[num]) { 397 | output_background = background_list[num]; 398 | } 399 | } 400 | } 401 | } 402 | // ----------------------------------------------------------------- 403 | function process_true_color() { 404 | if (_ex_color) { 405 | if (!output_color) { 406 | output_color = '#'; 407 | } 408 | if (output_color.length < 7) { 409 | output_color += ('0' + num.toString(16)).slice(-2); 410 | } 411 | } 412 | if (_ex_background) { 413 | if (!output_background) { 414 | output_background = '#'; 415 | } 416 | if (output_background.length < 7) { 417 | output_background += ('0' + num.toString(16)).slice(-2); 418 | } 419 | } 420 | if (_process_true_color === 2) { 421 | _process_true_color = -1; 422 | } else { 423 | _process_true_color++; 424 | } 425 | } 426 | // ----------------------------------------------------------------- 427 | function should__process_8bit() { 428 | return _process_8bit && ((_ex_background && !output_background) || 429 | (_ex_color && !output_color)); 430 | } 431 | // ----------------------------------------------------------------- 432 | function process_8bit() { 433 | if (_ex_color && palette[num] && !output_color) { 434 | output_color = palette[num]; 435 | } 436 | if (_ex_background && palette[num] && !output_background) { 437 | output_background = palette[num]; 438 | } 439 | _process_8bit = false; 440 | } 441 | // ----------------------------------------------------------------- 442 | for (var i in controls) { 443 | if (controls.hasOwnProperty(i)) { 444 | num = parseInt(controls[i], 10); 445 | if (_process_true_color > -1) { 446 | process_true_color(); 447 | } else if (should__process_8bit()) { 448 | process_8bit(); 449 | } else { 450 | set_styles(num); 451 | } 452 | } 453 | } 454 | if (reverse) { 455 | if (output_color || output_background) { 456 | var tmp = output_background; 457 | output_background = output_color; 458 | output_color = tmp; 459 | } else { 460 | output_color = 'black'; 461 | output_background = 'white'; 462 | } 463 | } 464 | var colors, color, background, backgrounds; 465 | if (bold) { 466 | colors = backgrounds = $.terminal.ansi_colors.bold; 467 | } else if (faited) { 468 | colors = backgrounds = $.terminal.ansi_colors.faited; 469 | } else { 470 | colors = backgrounds = $.terminal.ansi_colors.normal; 471 | } 472 | if (_ex_color) { 473 | color = output_color; 474 | } else if (output_color === 'inherit') { 475 | color = output_color; 476 | } else { 477 | color = colors[output_color]; 478 | } 479 | if (_ex_background) { 480 | background = output_background; 481 | } else if (output_background === 'transparent') { 482 | background = output_background; 483 | } else { 484 | background = backgrounds[output_background]; 485 | } 486 | return [styles.join(''), color, background]; 487 | } 488 | return function from_ansi(input, options) { 489 | options = options || {}; 490 | input = $.terminal.unescape_brackets(input); 491 | var settings = $.extend({ 492 | unixFormattingEscapeBrackets: false, 493 | position: 0 494 | }, options); 495 | var new_position = settings.position; 496 | var position = new_position; 497 | var result; 498 | //merge multiple codes 499 | /*input = input.replace(/((?:\x1B\[[0-9;]*[A-Za-z])*)/g, function(group) { 500 | return group.replace(/m\x1B\[/g, ';'); 501 | });*/ 502 | var splitted = input.split(/(\x1B\[[0-9;]*[A-Za-z])/g); 503 | if (splitted.length === 1) { 504 | if (settings.unixFormattingEscapeBrackets) { 505 | result = $.terminal.escape_formatting(input); 506 | } else { 507 | result = input; 508 | } 509 | if (typeof options.position === 'number') { 510 | return [result, new_position]; 511 | } 512 | return result; 513 | } 514 | var output = []; 515 | //skip closing at the begining 516 | if (splitted.length > 3) { 517 | var str = splitted.slice(0, 3).join(''); 518 | if (str.match(/^\[0*m$/)) { 519 | splitted = splitted.slice(3); 520 | } 521 | } 522 | var prev_color, prev_background, code, match; 523 | var inside = false; 524 | for (var i = 0; i < splitted.length; ++i) { 525 | match = splitted[i].match(/^\x1B\[([0-9;]*)([A-Za-z])$/); 526 | if (match) { 527 | var start = match.index; 528 | // logic taken from $.terminal.tracking_replace 529 | if (start < position) { 530 | var last_index = start + $.terminal.length(match[0]); 531 | if (last_index < position) { 532 | // It's after the replacement, move it 533 | new_position = Math.max( 534 | 0, 535 | new_position + 536 | $.terminal.length(match[0]) 537 | ); 538 | } else { 539 | // It's *in* the replacement, put it just after 540 | new_position += position - start; 541 | } 542 | } 543 | switch (match[2]) { 544 | case 'm': 545 | if (+match[1] !== 0) { 546 | code = format_ansi(match[1]); 547 | } 548 | if (inside) { 549 | output.push(']'); 550 | if (+match[1] === 0) { 551 | //just closing 552 | inside = false; 553 | prev_color = prev_background = ''; 554 | } else { 555 | // someone forget to close - move to next 556 | code[1] = code[1] || prev_color; 557 | code[2] = code[2] || prev_background; 558 | output.push('[[' + code.join(';') + ']'); 559 | // store colors to next use 560 | if (code[1]) { 561 | prev_color = code[1]; 562 | } 563 | if (code[2]) { 564 | prev_background = code[2]; 565 | } 566 | } 567 | } else if (+match[1] !== 0) { 568 | inside = true; 569 | code[1] = code[1] || prev_color; 570 | code[2] = code[2] || prev_background; 571 | output.push('[[' + code.join(';') + ']'); 572 | // store colors to next use 573 | if (code[1]) { 574 | prev_color = code[1]; 575 | } 576 | if (code[2]) { 577 | prev_background = code[2]; 578 | } 579 | } 580 | break; 581 | } 582 | } else if (settings.unixFormattingEscapeBrackets) { 583 | output.push($.terminal.escape_formatting(splitted[i])); 584 | } else { 585 | output.push(splitted[i]); 586 | } 587 | } 588 | if (inside) { 589 | output.push(']'); 590 | } 591 | result = output.join(''); 592 | if (options && typeof options.position === 'number') { 593 | return [result, new_position]; 594 | } 595 | return result; 596 | }; 597 | })(); 598 | 599 | $.terminal.defaults.formatters.unshift($.terminal.from_ansi); 600 | $.terminal.defaults.formatters.unshift($.terminal.overtyping); 601 | }); 602 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU AFFERO GENERAL PUBLIC LICENSE 2 | Version 3, 19 November 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU Affero General Public License is a free, copyleft license for 11 | software and other kinds of works, specifically designed to ensure 12 | cooperation with the community in the case of network server software. 13 | 14 | The licenses for most software and other practical works are designed 15 | to take away your freedom to share and change the works. By contrast, 16 | our General Public Licenses are intended to guarantee your freedom to 17 | share and change all versions of a program--to make sure it remains free 18 | software for all its users. 19 | 20 | When we speak of free software, we are referring to freedom, not 21 | price. Our General Public Licenses are designed to make sure that you 22 | have the freedom to distribute copies of free software (and charge for 23 | them if you wish), that you receive source code or can get it if you 24 | want it, that you can change the software or use pieces of it in new 25 | free programs, and that you know you can do these things. 26 | 27 | Developers that use our General Public Licenses protect your rights 28 | with two steps: (1) assert copyright on the software, and (2) offer 29 | you this License which gives you legal permission to copy, distribute 30 | and/or modify the software. 31 | 32 | A secondary benefit of defending all users' freedom is that 33 | improvements made in alternate versions of the program, if they 34 | receive widespread use, become available for other developers to 35 | incorporate. Many developers of free software are heartened and 36 | encouraged by the resulting cooperation. However, in the case of 37 | software used on network servers, this result may fail to come about. 38 | The GNU General Public License permits making a modified version and 39 | letting the public access it on a server without ever releasing its 40 | source code to the public. 41 | 42 | The GNU Affero General Public License is designed specifically to 43 | ensure that, in such cases, the modified source code becomes available 44 | to the community. It requires the operator of a network server to 45 | provide the source code of the modified version running there to the 46 | users of that server. Therefore, public use of a modified version, on 47 | a publicly accessible server, gives the public access to the source 48 | code of the modified version. 49 | 50 | An older license, called the Affero General Public License and 51 | published by Affero, was designed to accomplish similar goals. This is 52 | a different license, not a version of the Affero GPL, but Affero has 53 | released a new version of the Affero GPL which permits relicensing under 54 | this license. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | TERMS AND CONDITIONS 60 | 61 | 0. Definitions. 62 | 63 | "This License" refers to version 3 of the GNU Affero General Public License. 64 | 65 | "Copyright" also means copyright-like laws that apply to other kinds of 66 | works, such as semiconductor masks. 67 | 68 | "The Program" refers to any copyrightable work licensed under this 69 | License. Each licensee is addressed as "you". "Licensees" and 70 | "recipients" may be individuals or organizations. 71 | 72 | To "modify" a work means to copy from or adapt all or part of the work 73 | in a fashion requiring copyright permission, other than the making of an 74 | exact copy. The resulting work is called a "modified version" of the 75 | earlier work or a work "based on" the earlier work. 76 | 77 | A "covered work" means either the unmodified Program or a work based 78 | on the Program. 79 | 80 | To "propagate" a work means to do anything with it that, without 81 | permission, would make you directly or secondarily liable for 82 | infringement under applicable copyright law, except executing it on a 83 | computer or modifying a private copy. Propagation includes copying, 84 | distribution (with or without modification), making available to the 85 | public, and in some countries other activities as well. 86 | 87 | To "convey" a work means any kind of propagation that enables other 88 | parties to make or receive copies. Mere interaction with a user through 89 | a computer network, with no transfer of a copy, is not conveying. 90 | 91 | An interactive user interface displays "Appropriate Legal Notices" 92 | to the extent that it includes a convenient and prominently visible 93 | feature that (1) displays an appropriate copyright notice, and (2) 94 | tells the user that there is no warranty for the work (except to the 95 | extent that warranties are provided), that licensees may convey the 96 | work under this License, and how to view a copy of this License. If 97 | the interface presents a list of user commands or options, such as a 98 | menu, a prominent item in the list meets this criterion. 99 | 100 | 1. Source Code. 101 | 102 | The "source code" for a work means the preferred form of the work 103 | for making modifications to it. "Object code" means any non-source 104 | form of a work. 105 | 106 | A "Standard Interface" means an interface that either is an official 107 | standard defined by a recognized standards body, or, in the case of 108 | interfaces specified for a particular programming language, one that 109 | is widely used among developers working in that language. 110 | 111 | The "System Libraries" of an executable work include anything, other 112 | than the work as a whole, that (a) is included in the normal form of 113 | packaging a Major Component, but which is not part of that Major 114 | Component, and (b) serves only to enable use of the work with that 115 | Major Component, or to implement a Standard Interface for which an 116 | implementation is available to the public in source code form. A 117 | "Major Component", in this context, means a major essential component 118 | (kernel, window system, and so on) of the specific operating system 119 | (if any) on which the executable work runs, or a compiler used to 120 | produce the work, or an object code interpreter used to run it. 121 | 122 | The "Corresponding Source" for a work in object code form means all 123 | the source code needed to generate, install, and (for an executable 124 | work) run the object code and to modify the work, including scripts to 125 | control those activities. However, it does not include the work's 126 | System Libraries, or general-purpose tools or generally available free 127 | programs which are used unmodified in performing those activities but 128 | which are not part of the work. For example, Corresponding Source 129 | includes interface definition files associated with source files for 130 | the work, and the source code for shared libraries and dynamically 131 | linked subprograms that the work is specifically designed to require, 132 | such as by intimate data communication or control flow between those 133 | subprograms and other parts of the work. 134 | 135 | The Corresponding Source need not include anything that users 136 | can regenerate automatically from other parts of the Corresponding 137 | Source. 138 | 139 | The Corresponding Source for a work in source code form is that 140 | same work. 141 | 142 | 2. Basic Permissions. 143 | 144 | All rights granted under this License are granted for the term of 145 | copyright on the Program, and are irrevocable provided the stated 146 | conditions are met. This License explicitly affirms your unlimited 147 | permission to run the unmodified Program. The output from running a 148 | covered work is covered by this License only if the output, given its 149 | content, constitutes a covered work. This License acknowledges your 150 | rights of fair use or other equivalent, as provided by copyright law. 151 | 152 | You may make, run and propagate covered works that you do not 153 | convey, without conditions so long as your license otherwise remains 154 | in force. You may convey covered works to others for the sole purpose 155 | of having them make modifications exclusively for you, or provide you 156 | with facilities for running those works, provided that you comply with 157 | the terms of this License in conveying all material for which you do 158 | not control copyright. Those thus making or running the covered works 159 | for you must do so exclusively on your behalf, under your direction 160 | and control, on terms that prohibit them from making any copies of 161 | your copyrighted material outside their relationship with you. 162 | 163 | Conveying under any other circumstances is permitted solely under 164 | the conditions stated below. Sublicensing is not allowed; section 10 165 | makes it unnecessary. 166 | 167 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 168 | 169 | No covered work shall be deemed part of an effective technological 170 | measure under any applicable law fulfilling obligations under article 171 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 172 | similar laws prohibiting or restricting circumvention of such 173 | measures. 174 | 175 | When you convey a covered work, you waive any legal power to forbid 176 | circumvention of technological measures to the extent such circumvention 177 | is effected by exercising rights under this License with respect to 178 | the covered work, and you disclaim any intention to limit operation or 179 | modification of the work as a means of enforcing, against the work's 180 | users, your or third parties' legal rights to forbid circumvention of 181 | technological measures. 182 | 183 | 4. Conveying Verbatim Copies. 184 | 185 | You may convey verbatim copies of the Program's source code as you 186 | receive it, in any medium, provided that you conspicuously and 187 | appropriately publish on each copy an appropriate copyright notice; 188 | keep intact all notices stating that this License and any 189 | non-permissive terms added in accord with section 7 apply to the code; 190 | keep intact all notices of the absence of any warranty; and give all 191 | recipients a copy of this License along with the Program. 192 | 193 | You may charge any price or no price for each copy that you convey, 194 | and you may offer support or warranty protection for a fee. 195 | 196 | 5. Conveying Modified Source Versions. 197 | 198 | You may convey a work based on the Program, or the modifications to 199 | produce it from the Program, in the form of source code under the 200 | terms of section 4, provided that you also meet all of these conditions: 201 | 202 | a) The work must carry prominent notices stating that you modified 203 | it, and giving a relevant date. 204 | 205 | b) The work must carry prominent notices stating that it is 206 | released under this License and any conditions added under section 207 | 7. This requirement modifies the requirement in section 4 to 208 | "keep intact all notices". 209 | 210 | c) You must license the entire work, as a whole, under this 211 | License to anyone who comes into possession of a copy. This 212 | License will therefore apply, along with any applicable section 7 213 | additional terms, to the whole of the work, and all its parts, 214 | regardless of how they are packaged. This License gives no 215 | permission to license the work in any other way, but it does not 216 | invalidate such permission if you have separately received it. 217 | 218 | d) If the work has interactive user interfaces, each must display 219 | Appropriate Legal Notices; however, if the Program has interactive 220 | interfaces that do not display Appropriate Legal Notices, your 221 | work need not make them do so. 222 | 223 | A compilation of a covered work with other separate and independent 224 | works, which are not by their nature extensions of the covered work, 225 | and which are not combined with it such as to form a larger program, 226 | in or on a volume of a storage or distribution medium, is called an 227 | "aggregate" if the compilation and its resulting copyright are not 228 | used to limit the access or legal rights of the compilation's users 229 | beyond what the individual works permit. Inclusion of a covered work 230 | in an aggregate does not cause this License to apply to the other 231 | parts of the aggregate. 232 | 233 | 6. Conveying Non-Source Forms. 234 | 235 | You may convey a covered work in object code form under the terms 236 | of sections 4 and 5, provided that you also convey the 237 | machine-readable Corresponding Source under the terms of this License, 238 | in one of these ways: 239 | 240 | a) Convey the object code in, or embodied in, a physical product 241 | (including a physical distribution medium), accompanied by the 242 | Corresponding Source fixed on a durable physical medium 243 | customarily used for software interchange. 244 | 245 | b) Convey the object code in, or embodied in, a physical product 246 | (including a physical distribution medium), accompanied by a 247 | written offer, valid for at least three years and valid for as 248 | long as you offer spare parts or customer support for that product 249 | model, to give anyone who possesses the object code either (1) a 250 | copy of the Corresponding Source for all the software in the 251 | product that is covered by this License, on a durable physical 252 | medium customarily used for software interchange, for a price no 253 | more than your reasonable cost of physically performing this 254 | conveying of source, or (2) access to copy the 255 | Corresponding Source from a network server at no charge. 256 | 257 | c) Convey individual copies of the object code with a copy of the 258 | written offer to provide the Corresponding Source. This 259 | alternative is allowed only occasionally and noncommercially, and 260 | only if you received the object code with such an offer, in accord 261 | with subsection 6b. 262 | 263 | d) Convey the object code by offering access from a designated 264 | place (gratis or for a charge), and offer equivalent access to the 265 | Corresponding Source in the same way through the same place at no 266 | further charge. You need not require recipients to copy the 267 | Corresponding Source along with the object code. If the place to 268 | copy the object code is a network server, the Corresponding Source 269 | may be on a different server (operated by you or a third party) 270 | that supports equivalent copying facilities, provided you maintain 271 | clear directions next to the object code saying where to find the 272 | Corresponding Source. Regardless of what server hosts the 273 | Corresponding Source, you remain obligated to ensure that it is 274 | available for as long as needed to satisfy these requirements. 275 | 276 | e) Convey the object code using peer-to-peer transmission, provided 277 | you inform other peers where the object code and Corresponding 278 | Source of the work are being offered to the general public at no 279 | charge under subsection 6d. 280 | 281 | A separable portion of the object code, whose source code is excluded 282 | from the Corresponding Source as a System Library, need not be 283 | included in conveying the object code work. 284 | 285 | A "User Product" is either (1) a "consumer product", which means any 286 | tangible personal property which is normally used for personal, family, 287 | or household purposes, or (2) anything designed or sold for incorporation 288 | into a dwelling. In determining whether a product is a consumer product, 289 | doubtful cases shall be resolved in favor of coverage. For a particular 290 | product received by a particular user, "normally used" refers to a 291 | typical or common use of that class of product, regardless of the status 292 | of the particular user or of the way in which the particular user 293 | actually uses, or expects or is expected to use, the product. A product 294 | is a consumer product regardless of whether the product has substantial 295 | commercial, industrial or non-consumer uses, unless such uses represent 296 | the only significant mode of use of the product. 297 | 298 | "Installation Information" for a User Product means any methods, 299 | procedures, authorization keys, or other information required to install 300 | and execute modified versions of a covered work in that User Product from 301 | a modified version of its Corresponding Source. The information must 302 | suffice to ensure that the continued functioning of the modified object 303 | code is in no case prevented or interfered with solely because 304 | modification has been made. 305 | 306 | If you convey an object code work under this section in, or with, or 307 | specifically for use in, a User Product, and the conveying occurs as 308 | part of a transaction in which the right of possession and use of the 309 | User Product is transferred to the recipient in perpetuity or for a 310 | fixed term (regardless of how the transaction is characterized), the 311 | Corresponding Source conveyed under this section must be accompanied 312 | by the Installation Information. But this requirement does not apply 313 | if neither you nor any third party retains the ability to install 314 | modified object code on the User Product (for example, the work has 315 | been installed in ROM). 316 | 317 | The requirement to provide Installation Information does not include a 318 | requirement to continue to provide support service, warranty, or updates 319 | for a work that has been modified or installed by the recipient, or for 320 | the User Product in which it has been modified or installed. Access to a 321 | network may be denied when the modification itself materially and 322 | adversely affects the operation of the network or violates the rules and 323 | protocols for communication across the network. 324 | 325 | Corresponding Source conveyed, and Installation Information provided, 326 | in accord with this section must be in a format that is publicly 327 | documented (and with an implementation available to the public in 328 | source code form), and must require no special password or key for 329 | unpacking, reading or copying. 330 | 331 | 7. Additional Terms. 332 | 333 | "Additional permissions" are terms that supplement the terms of this 334 | License by making exceptions from one or more of its conditions. 335 | Additional permissions that are applicable to the entire Program shall 336 | be treated as though they were included in this License, to the extent 337 | that they are valid under applicable law. If additional permissions 338 | apply only to part of the Program, that part may be used separately 339 | under those permissions, but the entire Program remains governed by 340 | this License without regard to the additional permissions. 341 | 342 | When you convey a copy of a covered work, you may at your option 343 | remove any additional permissions from that copy, or from any part of 344 | it. (Additional permissions may be written to require their own 345 | removal in certain cases when you modify the work.) You may place 346 | additional permissions on material, added by you to a covered work, 347 | for which you have or can give appropriate copyright permission. 348 | 349 | Notwithstanding any other provision of this License, for material you 350 | add to a covered work, you may (if authorized by the copyright holders of 351 | that material) supplement the terms of this License with terms: 352 | 353 | a) Disclaiming warranty or limiting liability differently from the 354 | terms of sections 15 and 16 of this License; or 355 | 356 | b) Requiring preservation of specified reasonable legal notices or 357 | author attributions in that material or in the Appropriate Legal 358 | Notices displayed by works containing it; or 359 | 360 | c) Prohibiting misrepresentation of the origin of that material, or 361 | requiring that modified versions of such material be marked in 362 | reasonable ways as different from the original version; or 363 | 364 | d) Limiting the use for publicity purposes of names of licensors or 365 | authors of the material; or 366 | 367 | e) Declining to grant rights under trademark law for use of some 368 | trade names, trademarks, or service marks; or 369 | 370 | f) Requiring indemnification of licensors and authors of that 371 | material by anyone who conveys the material (or modified versions of 372 | it) with contractual assumptions of liability to the recipient, for 373 | any liability that these contractual assumptions directly impose on 374 | those licensors and authors. 375 | 376 | All other non-permissive additional terms are considered "further 377 | restrictions" within the meaning of section 10. If the Program as you 378 | received it, or any part of it, contains a notice stating that it is 379 | governed by this License along with a term that is a further 380 | restriction, you may remove that term. If a license document contains 381 | a further restriction but permits relicensing or conveying under this 382 | License, you may add to a covered work material governed by the terms 383 | of that license document, provided that the further restriction does 384 | not survive such relicensing or conveying. 385 | 386 | If you add terms to a covered work in accord with this section, you 387 | must place, in the relevant source files, a statement of the 388 | additional terms that apply to those files, or a notice indicating 389 | where to find the applicable terms. 390 | 391 | Additional terms, permissive or non-permissive, may be stated in the 392 | form of a separately written license, or stated as exceptions; 393 | the above requirements apply either way. 394 | 395 | 8. Termination. 396 | 397 | You may not propagate or modify a covered work except as expressly 398 | provided under this License. Any attempt otherwise to propagate or 399 | modify it is void, and will automatically terminate your rights under 400 | this License (including any patent licenses granted under the third 401 | paragraph of section 11). 402 | 403 | However, if you cease all violation of this License, then your 404 | license from a particular copyright holder is reinstated (a) 405 | provisionally, unless and until the copyright holder explicitly and 406 | finally terminates your license, and (b) permanently, if the copyright 407 | holder fails to notify you of the violation by some reasonable means 408 | prior to 60 days after the cessation. 409 | 410 | Moreover, your license from a particular copyright holder is 411 | reinstated permanently if the copyright holder notifies you of the 412 | violation by some reasonable means, this is the first time you have 413 | received notice of violation of this License (for any work) from that 414 | copyright holder, and you cure the violation prior to 30 days after 415 | your receipt of the notice. 416 | 417 | Termination of your rights under this section does not terminate the 418 | licenses of parties who have received copies or rights from you under 419 | this License. If your rights have been terminated and not permanently 420 | reinstated, you do not qualify to receive new licenses for the same 421 | material under section 10. 422 | 423 | 9. Acceptance Not Required for Having Copies. 424 | 425 | You are not required to accept this License in order to receive or 426 | run a copy of the Program. Ancillary propagation of a covered work 427 | occurring solely as a consequence of using peer-to-peer transmission 428 | to receive a copy likewise does not require acceptance. However, 429 | nothing other than this License grants you permission to propagate or 430 | modify any covered work. These actions infringe copyright if you do 431 | not accept this License. Therefore, by modifying or propagating a 432 | covered work, you indicate your acceptance of this License to do so. 433 | 434 | 10. Automatic Licensing of Downstream Recipients. 435 | 436 | Each time you convey a covered work, the recipient automatically 437 | receives a license from the original licensors, to run, modify and 438 | propagate that work, subject to this License. You are not responsible 439 | for enforcing compliance by third parties with this License. 440 | 441 | An "entity transaction" is a transaction transferring control of an 442 | organization, or substantially all assets of one, or subdividing an 443 | organization, or merging organizations. If propagation of a covered 444 | work results from an entity transaction, each party to that 445 | transaction who receives a copy of the work also receives whatever 446 | licenses to the work the party's predecessor in interest had or could 447 | give under the previous paragraph, plus a right to possession of the 448 | Corresponding Source of the work from the predecessor in interest, if 449 | the predecessor has it or can get it with reasonable efforts. 450 | 451 | You may not impose any further restrictions on the exercise of the 452 | rights granted or affirmed under this License. For example, you may 453 | not impose a license fee, royalty, or other charge for exercise of 454 | rights granted under this License, and you may not initiate litigation 455 | (including a cross-claim or counterclaim in a lawsuit) alleging that 456 | any patent claim is infringed by making, using, selling, offering for 457 | sale, or importing the Program or any portion of it. 458 | 459 | 11. Patents. 460 | 461 | A "contributor" is a copyright holder who authorizes use under this 462 | License of the Program or a work on which the Program is based. The 463 | work thus licensed is called the contributor's "contributor version". 464 | 465 | A contributor's "essential patent claims" are all patent claims 466 | owned or controlled by the contributor, whether already acquired or 467 | hereafter acquired, that would be infringed by some manner, permitted 468 | by this License, of making, using, or selling its contributor version, 469 | but do not include claims that would be infringed only as a 470 | consequence of further modification of the contributor version. For 471 | purposes of this definition, "control" includes the right to grant 472 | patent sublicenses in a manner consistent with the requirements of 473 | this License. 474 | 475 | Each contributor grants you a non-exclusive, worldwide, royalty-free 476 | patent license under the contributor's essential patent claims, to 477 | make, use, sell, offer for sale, import and otherwise run, modify and 478 | propagate the contents of its contributor version. 479 | 480 | In the following three paragraphs, a "patent license" is any express 481 | agreement or commitment, however denominated, not to enforce a patent 482 | (such as an express permission to practice a patent or covenant not to 483 | sue for patent infringement). To "grant" such a patent license to a 484 | party means to make such an agreement or commitment not to enforce a 485 | patent against the party. 486 | 487 | If you convey a covered work, knowingly relying on a patent license, 488 | and the Corresponding Source of the work is not available for anyone 489 | to copy, free of charge and under the terms of this License, through a 490 | publicly available network server or other readily accessible means, 491 | then you must either (1) cause the Corresponding Source to be so 492 | available, or (2) arrange to deprive yourself of the benefit of the 493 | patent license for this particular work, or (3) arrange, in a manner 494 | consistent with the requirements of this License, to extend the patent 495 | license to downstream recipients. "Knowingly relying" means you have 496 | actual knowledge that, but for the patent license, your conveying the 497 | covered work in a country, or your recipient's use of the covered work 498 | in a country, would infringe one or more identifiable patents in that 499 | country that you have reason to believe are valid. 500 | 501 | If, pursuant to or in connection with a single transaction or 502 | arrangement, you convey, or propagate by procuring conveyance of, a 503 | covered work, and grant a patent license to some of the parties 504 | receiving the covered work authorizing them to use, propagate, modify 505 | or convey a specific copy of the covered work, then the patent license 506 | you grant is automatically extended to all recipients of the covered 507 | work and works based on it. 508 | 509 | A patent license is "discriminatory" if it does not include within 510 | the scope of its coverage, prohibits the exercise of, or is 511 | conditioned on the non-exercise of one or more of the rights that are 512 | specifically granted under this License. You may not convey a covered 513 | work if you are a party to an arrangement with a third party that is 514 | in the business of distributing software, under which you make payment 515 | to the third party based on the extent of your activity of conveying 516 | the work, and under which the third party grants, to any of the 517 | parties who would receive the covered work from you, a discriminatory 518 | patent license (a) in connection with copies of the covered work 519 | conveyed by you (or copies made from those copies), or (b) primarily 520 | for and in connection with specific products or compilations that 521 | contain the covered work, unless you entered into that arrangement, 522 | or that patent license was granted, prior to 28 March 2007. 523 | 524 | Nothing in this License shall be construed as excluding or limiting 525 | any implied license or other defenses to infringement that may 526 | otherwise be available to you under applicable patent law. 527 | 528 | 12. No Surrender of Others' Freedom. 529 | 530 | If conditions are imposed on you (whether by court order, agreement or 531 | otherwise) that contradict the conditions of this License, they do not 532 | excuse you from the conditions of this License. If you cannot convey a 533 | covered work so as to satisfy simultaneously your obligations under this 534 | License and any other pertinent obligations, then as a consequence you may 535 | not convey it at all. For example, if you agree to terms that obligate you 536 | to collect a royalty for further conveying from those to whom you convey 537 | the Program, the only way you could satisfy both those terms and this 538 | License would be to refrain entirely from conveying the Program. 539 | 540 | 13. Remote Network Interaction; Use with the GNU General Public License. 541 | 542 | Notwithstanding any other provision of this License, if you modify the 543 | Program, your modified version must prominently offer all users 544 | interacting with it remotely through a computer network (if your version 545 | supports such interaction) an opportunity to receive the Corresponding 546 | Source of your version by providing access to the Corresponding Source 547 | from a network server at no charge, through some standard or customary 548 | means of facilitating copying of software. This Corresponding Source 549 | shall include the Corresponding Source for any work covered by version 3 550 | of the GNU General Public License that is incorporated pursuant to the 551 | following paragraph. 552 | 553 | Notwithstanding any other provision of this License, you have 554 | permission to link or combine any covered work with a work licensed 555 | under version 3 of the GNU General Public License into a single 556 | combined work, and to convey the resulting work. The terms of this 557 | License will continue to apply to the part which is the covered work, 558 | but the work with which it is combined will remain governed by version 559 | 3 of the GNU General Public License. 560 | 561 | 14. Revised Versions of this License. 562 | 563 | The Free Software Foundation may publish revised and/or new versions of 564 | the GNU Affero General Public License from time to time. Such new versions 565 | will be similar in spirit to the present version, but may differ in detail to 566 | address new problems or concerns. 567 | 568 | Each version is given a distinguishing version number. If the 569 | Program specifies that a certain numbered version of the GNU Affero General 570 | Public License "or any later version" applies to it, you have the 571 | option of following the terms and conditions either of that numbered 572 | version or of any later version published by the Free Software 573 | Foundation. If the Program does not specify a version number of the 574 | GNU Affero General Public License, you may choose any version ever published 575 | by the Free Software Foundation. 576 | 577 | If the Program specifies that a proxy can decide which future 578 | versions of the GNU Affero General Public License can be used, that proxy's 579 | public statement of acceptance of a version permanently authorizes you 580 | to choose that version for the Program. 581 | 582 | Later license versions may give you additional or different 583 | permissions. However, no additional obligations are imposed on any 584 | author or copyright holder as a result of your choosing to follow a 585 | later version. 586 | 587 | 15. Disclaimer of Warranty. 588 | 589 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 590 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 591 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 592 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 593 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 594 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 595 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 596 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 597 | 598 | 16. Limitation of Liability. 599 | 600 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 601 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 602 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 603 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 604 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 605 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 606 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 607 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 608 | SUCH DAMAGES. 609 | 610 | 17. Interpretation of Sections 15 and 16. 611 | 612 | If the disclaimer of warranty and limitation of liability provided 613 | above cannot be given local legal effect according to their terms, 614 | reviewing courts shall apply local law that most closely approximates 615 | an absolute waiver of all civil liability in connection with the 616 | Program, unless a warranty or assumption of liability accompanies a 617 | copy of the Program in return for a fee. 618 | 619 | END OF TERMS AND CONDITIONS 620 | 621 | How to Apply These Terms to Your New Programs 622 | 623 | If you develop a new program, and you want it to be of the greatest 624 | possible use to the public, the best way to achieve this is to make it 625 | free software which everyone can redistribute and change under these terms. 626 | 627 | To do so, attach the following notices to the program. It is safest 628 | to attach them to the start of each source file to most effectively 629 | state the exclusion of warranty; and each file should have at least 630 | the "copyright" line and a pointer to where the full notice is found. 631 | 632 | 633 | Copyright (C) 634 | 635 | This program is free software: you can redistribute it and/or modify 636 | it under the terms of the GNU Affero General Public License as published by 637 | the Free Software Foundation, either version 3 of the License, or 638 | (at your option) any later version. 639 | 640 | This program is distributed in the hope that it will be useful, 641 | but WITHOUT ANY WARRANTY; without even the implied warranty of 642 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 643 | GNU Affero General Public License for more details. 644 | 645 | You should have received a copy of the GNU Affero General Public License 646 | along with this program. If not, see . 647 | 648 | Also add information on how to contact you by electronic and paper mail. 649 | 650 | If your software can interact with users remotely through a computer 651 | network, you should also make sure that it provides a way for users to 652 | get its source. For example, if your program is a web application, its 653 | interface could display a "Source" link that leads users to an archive 654 | of the code. There are many ways you could offer source, and different 655 | solutions will be better for different programs; see section 13 for the 656 | specific requirements. 657 | 658 | You should also get your employer (if you work as a programmer) or school, 659 | if any, to sign a "copyright disclaimer" for the program, if necessary. 660 | For more information on this, and how to apply and follow the GNU AGPL, see 661 | . 662 | -------------------------------------------------------------------------------- /js/term.js: -------------------------------------------------------------------------------- 1 | /**@license 2 | * __ _____ ________ __ 3 | * / // _ /__ __ _____ ___ __ _/__ ___/__ ___ ______ __ __ __ ___ / / 4 | * __ / // // // // // _ // _// // / / // _ // _// // // \/ // _ \/ / 5 | * / / // // // // // ___// / / // / / // ___// / / / / // // /\ // // / /__ 6 | * \___//____ \\___//____//_/ _\_ / /_//____//_/ /_/ /_//_//_/ /_/ \__\_\___/ 7 | * \/ /____/ version 2.0.2 8 | * 9 | * This file is part of jQuery Terminal. http://terminal.jcubic.pl 10 | * 11 | * Copyright (c) 2010-2018 Jakub Jankiewicz 12 | * Released under the MIT license 13 | * 14 | * Contains: 15 | * 16 | * Storage plugin Distributed under the MIT License 17 | * modified to work from Data URIs that block storage and cookies in Chrome 18 | * Copyright (c) 2010 Dave Schindler 19 | * 20 | * jQuery Timers licenced with the WTFPL 21 | * 22 | * 23 | * Cross-Browser Split 1.1.1 24 | * Copyright 2007-2012 Steven Levithan 25 | * Available under the MIT License 26 | * 27 | * jQuery Caret 28 | * Copyright (c) 2009, Gideon Sireling 29 | * 3 clause BSD License 30 | * 31 | * sprintf.js 32 | * Copyright (c) 2007-2013 Alexandru Marasteanu 33 | * licensed under 3 clause BSD license 34 | * 35 | * emoji regex v7.0.1 by Mathias Bynens 36 | * MIT license 37 | * 38 | * Date: Sat, 22 Dec 2018 15:04:13 +0000 39 | */ 40 | (function(e){var m=function(){if(!m.cache.hasOwnProperty(arguments[0])){m.cache[arguments[0]]=m.parse(arguments[0])}return m.format.call(null,m.cache[arguments[0]],arguments)};m.format=function(e,t){var n=1,r=e.length,i="",o,a=[],u,s,l,f,c,p;for(u=0;u>>0;break;case"x":o=o.toString(16);break;case"X":o=o.toString(16).toUpperCase();break}o=/[def]/.test(l[8])&&l[3]&&o>=0?" +"+o:o;c=l[4]?l[4]==="0"?"0":l[4].charAt(1):" ";p=l[6]-String(o).length;f=l[6]?d(c,p):"";a.push(l[5]?o+f:f+o)}}return a.join("")};m.cache={};m.parse=function(e){var t=e,n=[],r=[],i=0;while(t){if((n=/^[^\x25]+/.exec(t))!==null){r.push(n[0])}else if((n=/^\x25{2}/.exec(t))!==null){r.push("%")}else if((n=/^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(t))!==null){if(n[2]){i|=1;var o=[],a=n[2],u=[];if((u=/^([a-z_][a-z_\d]*)/i.exec(a))!==null){o.push(u[1]);while((a=a.slice(u[0].length))!==""){if((u=/^\.([a-z_][a-z_\d]*)/i.exec(a))!==null){o.push(u[1])}else if((u=/^\[(\d+)\]/.exec(a))!==null){o.push(u[1])}else{throw"[sprintf] huh?"}}}else{throw"[sprintf] huh?"}n[2]=o}else{i|=2}if(i===3){throw"[sprintf] mixing positional and named placeholders is not (yet) supported"}r.push(n)}else{throw"[sprintf] huh?"}t=t.slice(n[0].length)}return r};var t=function(e,t,n){n=t.slice(0);n.splice(0,0,e);return m.apply(null,n)};function D(e){return Object.prototype.toString.call(e).slice(8,-1).toLowerCase()}function d(e,t){for(var n=[];t>0;n[--t]=e){}return n.join("")}e.sprintf=m;e.vsprintf=t})(typeof global!=="undefined"?global:window);(function(r,i){var e=typeof window!=="undefined"?window:global;if(typeof define==="function"&&define.amd){define(["jquery","wcwidth"],r)}else if(typeof module==="object"&&module.exports){module.exports=function(e,t,n){if(t===i){if(window!==i){t=require("jquery")}else{t=require("jquery")(e)}}if(n===i){n=require("wcwidth")}r(t,n);return t}}else{r(e.jQuery,e.wcwidth)}})(function($,wcwidth,undefined){"use strict";function debug(e){if(false){console.log(e)}}function DelayQueue(){var t=$.Callbacks();var n=false;this.resolve=function(){t.fire();n=true};this.add=function(e){if(n){e()}else{t.add(e)}}}$.omap=function(n,r){var i={};$.each(n,function(e,t){i[e]=r.call(n,e,t)});return i};$.fn.text_length=function(){return this.map(function(){return $(this).text().length}).get().reduce(function(e,t){return e+t},0)};var Clone={clone_object:function(e){var t={};if(typeof e==="object"){if($.isArray(e)){return this.clone_array(e)}else if(e===null){return e}else{for(var n in e){if($.isArray(e[n])){t[n]=this.clone_array(e[n])}else if(typeof e[n]==="object"){t[n]=this.clone_object(e[n])}else{t[n]=e[n]}}}}return t},clone_array:function(e){if(!is_function(Array.prototype.map)){throw new Error("Your browser don't support ES5 array map "+"use es5-shim")}return e.slice(0).map(function(e){if(typeof e==="object"){return this.clone_object(e)}else{return e}}.bind(this))}};var clone=function(e){return Clone.clone_object(e)};var localStorage;(function(){var e=function(){try{var e="test",t=window.localStorage;t.setItem(e,"1");t.removeItem(e);return true}catch(e){return false}};var t=function(){try{document.cookie.split(";");return true}catch(e){return false}};var n=e();function r(e,t){var n;if(typeof e==="string"&&typeof t==="string"){localStorage[e]=t;return true}else if(typeof e==="object"&&typeof t==="undefined"){for(n in e){if(e.hasOwnProperty(n)){localStorage[n]=e[n]}}return true}return false}function i(e,t){var n,r,i;n=new Date;n.setTime(n.getTime()+31536e6);r="; expires="+n.toGMTString();if(typeof e==="string"&&typeof t==="string"){document.cookie=e+"="+t+r+"; path=/";return true}else if(typeof e==="object"&&typeof t==="undefined"){for(i in e){if(e.hasOwnProperty(i)){document.cookie=i+"="+e[i]+r+"; path=/"}}return true}return false}function o(e){return localStorage[e]}function a(e){var t,n,r,i;t=e+"=";n=document.cookie.split(";");for(r=0;ri&&i!==0||r.call(e,a)===false){jQuery.timer.remove(e,n,r)}u.inProgress=false};u.$timerID=r.$timerID;if(!e.$timers[n][r.$timerID]){e.$timers[n][r.$timerID]=window.setInterval(u,t)}if(!this.global[n]){this.global[n]=[]}this.global[n].push(e)},remove:function(e,t,n){var r=e.$timers,i;if(r){if(!t){for(var o in r){if(r.hasOwnProperty(o)){this.remove(e,o,n)}}}else if(r[t]){if(n){if(n.$timerID){window.clearInterval(r[t][n.$timerID]);delete r[t][n.$timerID]}}else{for(var a in r[t]){if(r[t].hasOwnProperty(a)){window.clearInterval(r[t][a]);delete r[t][a]}}}for(i in r[t]){if(r[t].hasOwnProperty(i)){break}}if(!i){i=null;delete r[t]}}for(i in r){if(r.hasOwnProperty(i)){break}}if(!i){e.$timers=null}}}}});if(/(msie) ([\w.]+)/.exec(navigator.userAgent.toLowerCase())){e(window).one("unload",function(){var e=jQuery.timer.global;for(var t in e){if(e.hasOwnProperty(t)){var n=e[t],r=n.length;while(--r){jQuery.timer.remove(n[r],t)}}}})}})(jQuery);(function(f){if(!String.prototype.split.toString().match(/\[native/)){return}var c=String.prototype.split,p=/()??/.exec("")[1]===f,n;n=function(e,t,n){if(Object.prototype.toString.call(t)!=="[object RegExp]"){return c.call(e,t,n)}var r=[],i=(t.ignoreCase?"i":"")+(t.multiline?"m":"")+(t.extended?"x":"")+(t.sticky?"y":""),o=0,a,u,s,l;t=new RegExp(t.source,i+"g");e+="";if(!p){a=new RegExp("^"+t.source+"$(?!\\s)",i)}n=n===f?-1>>>0:n>>>0;while(u=t.exec(e)){s=u.index+u[0].length;if(s>o){r.push(e.slice(o,u.index));if(!p&&u.length>1){u[0].replace(a,function(){for(var e=1;e1&&u.index=n){break}}if(t.lastIndex===u.index){t.lastIndex++}}if(o===e.length){if(l||!t.test("")){r.push("")}}else{r.push(e.slice(o))}return r.length>n?r.slice(0,n):r};String.prototype.split=function(e,t){return n(this,e,t)};return n})();$.fn.caret=function(e){var t=this[0];var n=t.contentEditable==="true";if(arguments.length===0){if(window.getSelection){if(n){t.focus();var r=window.getSelection().getRangeAt(0),i=r.cloneRange();i.selectNodeContents(t);i.setEnd(r.endContainer,r.endOffset);return i.toString().length}return t.selectionStart}if(document.selection){t.focus();if(n){var r=document.selection.createRange(),i=document.body.createTextRange();i.moveToElementText(t);i.setEndPoint("EndToEnd",r);return i.text.length}var e=0,o=t.createTextRange(),i=document.selection.createRange().duplicate(),a=i.getBookmark();o.moveToBookmark(a);while(o.moveStart("character",-1)!==0)e++;return e}return 0}if(e===-1)e=this[n?"text":"val"]().length;if(window.getSelection){if(n){t.focus();window.getSelection().collapse(t.firstChild,e)}else t.setSelectionRange(e,e)}else if(document.body.createTextRange){var o=document.body.createTextRange();o.moveToElementText(t);o.moveStart("character",e);o.collapse(true);o.select()}if(!n&&!this.is(":focus")){t.focus()}return e};$.fn.resizer=function(u){var s=arguments.length===0;var l=arguments[0]==="unbind";if(!s&&!l&&!is_function(u)){throw new Error("Invalid argument, it need to a function or string "+'"unbind" or no arguments.')}if(l){u=is_function(arguments[1])?arguments[1]:null}return this.each(function(){var e=$(this);var t;var n;function r(){n.fire()}if(s||l){n=e.data("callbacks");if(s){n&&n.fire()}else{if(u&&n){n.remove(u);if(!n.has()){n=null}}else{n=null}if(!n){e.removeData("callbacks");if(window.ResizeObserver){var i=e.data("observer");if(i){i.unobserve(this);e.removeData("observer")}}else{t=e.find("> iframe");if(t.length){$(t[0].contentWindow).off("resize").remove();t.remove()}else if(e.is("body")){$(window).off("resize.resizer")}}}}}else if(e.data("callbacks")){$(this).data("callbacks").add(u)}else{n=$.Callbacks();n.add(u);e.data("callbacks",n);var o;var a=true;if(window.ResizeObserver){o=new ResizeObserver(function(){if(!a){r()}a=false});o.observe(this);e.data("observer",o)}else if(e.is("body")){$(window).on("resize.resizer",r)}else{t=$("