diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 269eb583..83671978 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,16 +1,49 @@ -If you would like to contribute - send pull request to dev branch. -Getting dev version of **Cloud Commander**: - - git clone git://github.com/coderaiser/cloudcmd.git - git checkout dev - -or by [link](https://github.com/coderaiser/cloudcmd/tree/dev "Dev version"). - -It is possible thet dev version Cloud Commander will needed dev version of Minify, -so to get it you should type a couple more commands: - - cd node_modules - rm -rf minify - git clone git://github.com/coderaiser/minify - cd minify +Brunch +--------------- +If you would like to contribute - send pull request to dev branch. +Getting dev version of **Cloud Commander**: + + git clone git://github.com/coderaiser/cloudcmd.git git checkout dev + +or by [link](https://github.com/coderaiser/cloudcmd/tree/dev "Dev version"). + +It is possible thet dev version Cloud Commander will needed dev version of Minify, +so to get it you should type a couple more commands: + + cd node_modules + rm -rf minify + git clone git://github.com/coderaiser/minify + cd minify + git checkout dev + +Commit +--------------- +Format of the commit message: **type(scope): subject** + +**Type**: +- feature +- fix (bug fix) +- docs (documentation) +- style (formatting, missing semi colons, …) +- refactor +- test (when adding missing tests) +- chore (maintain) + +**Scope**: +Scope could be anything specifying place of the commit change. +For example util, console, view, edit, style etc... + +**Subject text**: +- use imperative, present tense: “change” not “changed” nor “changes” +- don't capitalize first letter +- no dot (.) at the end +**Message body**: +- just as in use imperative, present tense: “change” not “changed” nor “changes” +- includes motivation for the change and contrasts with previous behavior + +**Examples**: +- [fix(style) .name{width}: 37% -> 35%](https://github.com/coderaiser/cloudcmd/commit/94b0642e3990c17b3a0ee3efeb75f343e1e7c050) +- [fix(console) dispatch: focus -> mouseup](https://github.com/coderaiser/cloudcmd/commit/f41ec5058d1411e86a881f8e8077e0572e0409ec) + +**Big change should be writed in ChangeLog like [this](https://github.com/coderaiser/cloudcmd/commit/e1893f77be09585decf8a260d45a42efc11c98e5).** \ No newline at end of file diff --git a/ChangeLog b/ChangeLog index 65146bfd..1f8aebfe 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,154 @@ +2012.07.01, v0.3.0 + +* Changed jquery cdn to one with https suport jquery.com -> google cdn. + +* Added Access-Control-Allow-Origin header. + +* Added functions in DOM module: createEvent +(createKeyEvent, createClickEvent, createDblClickEvent), +dispatch +(dispatchKeyEvent, dispatchClickEvent, dispatchDblClickEvent) + +* Changed object name CloudCommander -> CloudCmd + +* Moved loading functions to Loader object in DOM module. + +* Added addtables script' + +* Fixed typo in README. + +* Fixed same background declartion a couple times. + +* Changed the way of work with listeners (DOM.addListener to DOM.Events.add). + +* Added ability to add a couple events in Events.add. + +* Moved jqeuryLoader and socketLoader to CMD object in DOM. + +* Fixed bug with deletting in menu js. + +* Removed function _editFileName from client.js. + +* Removed linuxWatch function from main.js. + +* Added tryCatch to fs.watch in cloudcmd.js. + +* Set F3 to veiw. + +* Renamed KeyBinding -> Key. + +* Renamed: set -> setBinded, unSet -> unsetBinded, get -> isBinded. + +* Functions maked private: ajaxload, changeLinks, createFileTable, +getJSONfromFileTable. + +* Moved CloudCmd.KEY object data to prototype of CloudCmd.Key. + +* Simpified plugins id's. + +* Rewrited _codemirror and view modules with prototypes. + +* Added hide method to view module. + +* Updated socket.io to v0.9.16. + +* Removed init property from view and edit. + +* FilePicker gets key from modules.json. + +* Added ability to put callback to view. + +* Added help module. + +* Added ability to show help on F1. + +* Added ability to set attributes in Loader.anyload. + +* Fixed upload function of filepicker. + +* fix(DOM) this promptNewFile -> Cmd.promptNewFile + +* feature(console) add jq-console + +* fix(style) .name{width}: 37% -> 35% + +* feature(view) show(pData) -> show(pData, pCallBack) + +* doc(license) add + +* doc(contribute) add commit message conventions + +* fix(socket) log level: debug -> info + +* feature(console) jquery-terminal -> jq-console + +* fix(help) remove pre + +* feature(socket) add disconect + +* feature(socket) add minification and gzip + +* feature(socket) if id in use - reconnect + +* chore(console) remove jquery-terminal + +* feature(favicon) add + +* fix(style) .mode width: 25% -> 23% + +* feature(edit) codemirror -> ace + +* feature(edit) add diff + +* chore(dom) jquery: v2.0.0 -> v2.0.3 + +* feature(util) call log with any count of params + +* feature(util) add logArray + +* feature(socket) add chdir on cd + +* feature(dom) add events.add array + +* feauture(client) add unload event + +* feature(update) exec -> exec(cwd) + +* feature(cloudcmd) add bin + +* feature(rest) add put patch + +* feature(edit) save file only if it was changed + +* fix(dom) rm array param from jsload + +* feature(main) add to exports checkCallBackParams + +* feature(win) diskpart -> wmic + +* fix(diff) rm, work bad with win line ending + +* fix(dom) this -> Cmd + +* fix(css) .cmd-button: "outline:0" + +* feature(index) add "~ - console" button + +* chore(css) .cmd-button {width: 10% -> 8%} + +* feature(index) add "f9 - menu" button + +* feature(Events) dispatch: event -> event || eventName + +* feature(css) add media-query for .cmd-button + +* fix(view) open on f3 cmd button click + +* fix(rest) save and create new file + +* chore(minify) v0.2.0 -> v0.2.1 + + 2012.04.22, v0.2.0 * Added alerting about errors. @@ -152,7 +303,7 @@ keyStop: function(e, opt) { * Removed loading spinner by commenting jquery.fancybox.css block #fancybox-loading div { width: 44px; - height: 44px; + height: 44px; background: url('fancybox_loading.gif') center center no-repeat; } diff --git a/ChangeLog.rus.md b/ChangeLog.rus.md index 84ba0b4f..370d48af 100644 --- a/ChangeLog.rus.md +++ b/ChangeLog.rus.md @@ -1,3 +1,78 @@ +2012.07.01, v0.3.0 +=============== +Уже прошла середина лета и, благодаря легкому похолоданию, мы, кажется, начали больше ценить эту волшебную пору года. Через месяц детишки пойдут в школу, в город нахлынут толпы жаждущих новых знаний студентов, и город плавно войдет в привычный ритм. +С момента прошлого релиза прошло уже больше трёх месяцев, а это значит пора выкатывать новый релиз. В нём будет очень много нового и интересного. У командира наконецто появилась новая иконка, терминал и редактор были полностью заменены и привязаны к вьеру. Код значительно упрощен и оптимизирован. Далее подробнее. + +**Добавлена внешняя возможность:** +- Назначено f3 - просмотр. +- FilePicker получает ключ из modules.json. +- Добавлена возможность показывать помощь по F1. +- Jquery-terminal заменён на JQ-Console. +- Добавлена лицензия. +- Добавлено соглашение по именованию коммитов. +- Добавлен favicon. +- CodeMirror заменён на Ace. +- Обновление теперь возможно, при запуске с любого каталога. +- Добавлен исполняемый файл для npm -g. +- Файл сохраняется только если он был изменён в Editor. +- Для определения разделов на Windows, утилита diskpart заменена на wmic. +- Добавлена кнопка "~ - console" для вызова Консоли. +- Добавлена кнопка "f9 - menu" для вызова Меню. + +**Исправленные ошибки:** +- Функция загрузки в Filepicker. +- this.promptNewFile -> Cmd.promptNewFile. +- Стили: .name{width}: 37% -> 35%. +- socket: log level: debug -> info. +- help: удален стиль "pre". +- Стили: .mode width: 25% -> 23%. +- DOM: убрана возможность принимать массив в jsload. +- Стили: .cmd-button: "outline:0". +- Сохранение и создание нового файла. + +**Обновлены:** +- socket.io до v0.9.16. +- jquery до v2.0.3. +- minify до v0.2.1. + +**Внутренние изминения:** +- Изменена jquery cdn в пользу той, что поддерживает https (jquery.com -> google cdn). +- Добавлен заголовок Access-Control-Allow-Origin для под возможности ajax запросов с других адресов. +- Добавлены функции в DOM: createEvent(createKeyEvent, createClickEvent, createDblClickEvent), dispatch(dispatchKeyEvent, dispatchClickEvent, dispatchDblClickEvent). +- Переименован обьект CloudCommander -> CloudCmd. +- Функции загрузки перемещены в обьект Loader модуля DOM. +- Добавлен скрипт addtables.sh, добавляющий правила в фаервол. +- Исправлены повторяющиеся правила, связанные с фоном, в css. +- Переименована функция DOM.addListener - DOM.Events.add. +- Добавлена возможность повесить несколько обработчиков через Events.add. +- jqeuryLoader и socketLoader перемещены в обьект CMD в модуле DOM. +- Исправлена ошибка с удалением файла в Menu. +- Удалена функция _editFileName из Client. +- Удалена функция linuxWatch из Main. +- Добавлен tryCatch в fs.watch в cloudcmd.js. +- Переименовано KeyBinding в Key. +- Переименовано set - setBinded, unSet -> unsetBinded, get -> isBinded. +- Следующие функции теперь приватные: ajaxload, changeLinks, createFileTable, getJSONfromFileTable. +- Данные обйъекта CloudCmd.KEY перемещены в прототип CloudCmd.Key. +- Упрощены id плагинов. +- Переписаны модули _codemirror и View с прототипами. +- Добавлен метод hide в модуль View. +- Удалено свойство init из модулей View и Edit. +- Добавлена возможность передавать колбек во View: show(pData) -> show(pData, pCallBack). +- Добавлен модуль Help. +- Добавлена возможность устанавливать атрибуты в Loader.anyload. +- Добавлен обработчик disconect в Socket. +- Добавлена минификация и gzip в Socket. +- Если id уже используется происходит повторное соединение в Socket. +- Util.log теперь может вызываться с любым количеством параметров. +- Добавлена функция logArray в Util. +- Добавлена возможность смены каталога по cd в Socket. +- Добавлена возможность передавать функции Events.add массив. +- Добавлено событие unload. +- Добавлена в экспорт функция checkCallBackParams. +- Функция dispatch принимает на вход event или его название. +- Добавлены media-query для .cmd-button. + 2012.04.22, v0.2.0 =============== Весна в разгаре, на деревьях появляются почки, наконец-то начинает теплеть. @@ -38,8 +113,8 @@ - Возвращение в папку, из которой был удален файл. **Обновлены:** -- jquery до версии v2.0.0 -- dropbox до версии v0.9.2 +- jquery до версии v2.0.0. +- dropbox до версии v0.9.2. - socket.io до версии v0.9.14. **Внутренние изминения:** @@ -108,7 +183,7 @@ - первый и последующие показы меню, а так же выделение даблкликом в Firefox **Обновлены:** -- jquery до версии v1.9.0 +- jquery до версии v1.9.0. - jquery-terminal до версии v0.4.22. - jQuery-contextMenu до версии v1.6.5. - socket.io до версии 0.9.13. @@ -120,34 +195,34 @@ - Изменен способ получения github id (теперь это делается через config.json, rest api были удалены). - Добавлены функции DOM.getCurrentFileContent(pCallBack [, pCurrentFile]) для получения содержимого файла в ФС, а так же обёртка Util.setTimeout(pFunction [, pCallBack, pTime]). - Добавлена функция в win.js для парсинга вывода команды diskpart (которая используется для опредиления локальных дисков). -- Добавлена функция DOM.getCurrentDir() -- API url на клиенте читается с файла config.json -- Если выбрана загрузка на Gist (GitHub) и у файла в формате json нет расширения — оно добавляется -- Добавлена возможность авторизовыватся на Гитхабе через новое окно. Изминен редирект на /auth и добавлена фнукция rout в cloudcmd.js -- DropBox, GDrive и GitHub модули теперь выглядят одинаково -- Рефакторинг в модуле Viewer -- Улучшена оптимизация файла menu.js с 2539 до 2444 байт -- Добавлена возможность читать GDrive key из конфига -- Добавлена возможность авторизовыватся на дропбоксе через popup +- Добавлена функция DOM.getCurrentDir(). +- API url на клиенте читается с файла config.json. +- Если выбрана загрузка на Gist (GitHub) и у файла в формате json нет расширения — оно добавляется. +- Добавлена возможность авторизовыватся на Гитхабе через новое окно. Изминен редирект на /auth и добавлена фнукция rout в cloudcmd.js. +- DropBox, GDrive и GitHub модули теперь выглядят одинаково. +- Рефакторинг в модуле Viewer. +- Улучшена оптимизация файла menu.js с 2539 до 2444 байт. +- Добавлена возможность читать GDrive key из конфига. +- Добавлена возможность авторизовыватся на дропбоксе через popup. - Добавлена возможность авторизовыватся на vk.com. -- Улучшен формат и парсинг файла modules.json -- Добавлена возможность читать информацию о модулях сохранения из модуля меню -- Добавлена простая система рендеринга шаблонов Util.render -- Добавлены функции DOM.parseJSON и DOM.stringifyJSON, как обёртки над системными функциями -- Добавлен плагин для миграции к новой версии jquery -- Убрано получения данных из кеша Minify -- JSON-файлы перемещены в папки json -- Изминен шрифт с Octicons на Fonteollo +- Улучшен формат и парсинг файла modules.json. +- Добавлена возможность читать информацию о модулях сохранения из модуля меню. +- Добавлена простая система рендеринга шаблонов Util.render. +- Добавлены функции DOM.parseJSON и DOM.stringifyJSON, как обёртки над системными функциями. +- Добавлен плагин для миграции к новой версии jquery. +- Убрано получения данных из кеша Minify. +- JSON-файлы перемещены в папки json. +- Изминен шрифт с Octicons на Fonteollo. - Полностью удален шрифт Octicons. - Удалено свойство allowed из свойства cache в конфиге. -- С этого момента оптимизироватся будут лишь те файлы, дата последнего изминения которых была изменена -- Убрана возможность кешировать файлы в памяти -- Перемещены расширения из main.js в json/ext.json -- Основная функциональность CloudCmd перемещена в commander.js из server.js -- Добавлена возможность удалять приставку к URL /fs когда мы в корневом каталоге -- Убраны перересовки создаваемые js -- Добавлена возможность добавлять флаг ?json только если мы работаем с папкой -- Изминен принцип работы функции clickProcessing в меню, теперь он гораздо проще -- Произведен тотальный рефакторинг в файле commander.js, теперь там только генерация -структуры каталогов в формате json +- С этого момента оптимизироватся будут лишь те файлы, дата последнего изминения которых была изменена. +- Убрана возможность кешировать файлы в памяти. +- Перемещены расширения из main.js в json/ext.json. +- Основная функциональность CloudCmd перемещена в commander.js из server.js. +- Добавлена возможность удалять приставку к URL /fs когда мы в корневом каталоге. +- Убраны перересовки создаваемые js. +- Добавлена возможность добавлять флаг ?json только если мы работаем с папкой. +- Изминен принцип работы функции clickProcessing в меню, теперь он гораздо проще. +- Произведен тотальный рефакторинг в файле commander.js, теперь там только генерация. +структуры каталогов в формате json. - добавлен обьект RESTfull в DOM модуль для упрощения работы с CloudCmd REST API. diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..b9f49cb1 --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +(The MIT License) + +Copyright (c) 2013 Coderaiser + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md index 9131212b..aa364275 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -Cloud Commander v0.2.0 [![NPM version][NPMIMGURL]][NPMURL] [![Dependency Status][DependencyStatusIMGURL]][DependencyStatusURL] [![Build Status][BuildStatusIMGURL]][BuildStatusURL] +Cloud Commander v0.3.0 [![NPM version][NPMIMGURL]][NPMURL] [![Dependency Status][DependencyStatusIMGURL]][DependencyStatusURL] [![Build Status][BuildStatusIMGURL]][BuildStatusURL] =============== [![Flattr][FlattrIMGURL]][FlattrURL] [NPMIMGURL]: https://badge.fury.io/js/cloudcmd.png @@ -19,7 +19,7 @@ DEMO: Google PageSpeed Score : [100](//developers.google.com/speed/pagespeed/insights#url=http_3A_2F_2Fcloudcmd.aws.af.cm_2F&mobile=false "score") (out of 100) (or 96 if js or css minification disabled in config.json). -![Cloud Commander](img/logo/cloudcmd.png "Cloud Commander") +![Cloud Commander](/img/logo/cloudcmd.png "Cloud Commander") Benefits --------------- @@ -47,6 +47,15 @@ Hot keys --------------- In all modern web browsers (but not in IE, becouse he special) hot keys works. There is a short list: +- **F1** - help +- **F2** - rename current file +- **F3** - view +- **F4** - edit +- **F5** - copy +- **F6** - rename/move +- **F7** - new dir +- **F8, Delete** - remove current file +- **F9** = menu - **Ctrl + r** - reload dir content - **Ctrl + d** - clear local cache (wich contains dir contents) - **Alt + q** - disable key bindings @@ -58,23 +67,21 @@ There is a short list: - **Page Down** - down on one page - **Home** - to begin of list - **End** - to end of list -- **F8, Delete** - remove current file - **Shift + Delete** - remove without prompt - **Insert** - select current file -- **F2** - rename current file -- **Shift + F10** - show context menu +- **Shift + F10** - context menu +- **~** - console Viewer's hot keys --------------- -- **Shift + F3** - open viewer window -- **Esc** - close viewer window +- **F3** - open +- **Esc** - close Editor's hot keys --------------- -- **F3** - open CodeMirror editor in read only mode -- **F4** - open CodeMirror editor -- **Ctrl + s** - save file -- **Esc** - close CodeMirror editor +- **F4** - open +- **Ctrl + s** - save +- **Esc** - close Menu --------------- @@ -87,17 +94,24 @@ Right mouse click button show context menu with items: - Download - New (File, Dir, from cloud) -Installing +Install --------------- -**Cloud Commander** installing is very easy. All you need it's just clone -repository from github. Just 2 commands: +**Cloud Commander** install is very easy. +All you need is +- install [node.js](//nodejs.org/ "node.js") +- [download](https://github.com/coderaiser/cloudcmd/archive/master.zip) +and unpack or just clone repository from github: +``` git clone git://github.com/coderaiser/cloudcmd.git cd cloudcmd -or - - npm i cloudcmd - mv node_modules/cloudcmd ./ + node cloudcmd +``` +or install in npm: +``` + npm i cloudcmd -g + cloudcmd +``` Configuration --------------- @@ -117,9 +131,9 @@ All main configuration could be done thrue config.json. "server" : true, /* server mode or testing mode */ "logs" : false, /* logs or console ouput */ "socket" : true /* enable web sockets */ - "port" : 80, /* http port */ - "sslPort" : 443, /* https port */ - "ip" : "127.0.0.1", /* Cloud Commander IP */ + "port" : 80, /* http port or null(default) */ + "sslPort" : 443, /* https port or null(default) */ + "ip" : "127.0.0.1", /* ip or null(default) */ "ssl" : true /* should use https? */ "rest" : true /* enable rest interface */ } @@ -131,12 +145,13 @@ Standard practices say no non-root process gets to talk to the Internet on a port less than 1024. Anyway I suggest you to start Cloud Commander as non-root. How it could be solved? There is a couple easy and fast ways. One of them is port forwarding by iptables. +Just run [shell/addtables.sh](shell/addtables.sh) for default options. ```sh -@:/tmp/cloudcmd (dev) $ su iptables -t nat -L # look rules before -@:/tmp/cloudcmd (dev) $ su iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports 8000 -@:/tmp/cloudcmd (dev) $ su iptables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-ports 4430 -@:/tmp/cloudcmd (dev) $ su iptables -t nat -L # look reles after +@:/tmp/cloudcmd (dev) $ sudo iptables -t nat -L # look rules before +@:/tmp/cloudcmd (dev) $ sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports 8000 +@:/tmp/cloudcmd (dev) $ sudo iptables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-ports 4430 +@:/tmp/cloudcmd (dev) $ sudo iptables -t nat -L # look reles after ``` You should see somethins like this ( **8000** and **4430** should be in config as **port** and **sslPort** ) @@ -148,8 +163,8 @@ If you would want to get things back just clear rules ( **1** and **2** it's rul in your list they could differ). ```sh -@:/tmp/cloudcmd (dev) $ su iptables -t nat -D PREROUTING 1 -@:/tmp/cloudcmd (dev) $ su iptables -t nat -D PREROUTING 2 +@:/tmp/cloudcmd (dev) $ sudo iptables -t nat -D PREROUTING 1 +@:/tmp/cloudcmd (dev) $ sudo iptables -t nat -D PREROUTING 2 ``` To run Cloud Commander as daemon in linux you could set **log** to true in config and @@ -167,7 +182,7 @@ For more information see **config.json** and **shell/seret.bat** *(on win32)* or **shell/secret.sh** *(on nix)*. -Starting +Start --------------- To start **Cloud Commander** only one command neaded: @@ -184,9 +199,9 @@ Then type in browser or http://localhost -Updating +Update --------------- -**Cloud Commander** is very alfa and it's very often updatings. +**Cloud Commander** is very often updates. Update is doing automagically but it could be done also manualy by typing a few commands in cloudcmd directory: @@ -207,37 +222,29 @@ But for minification and optimization tricks optional can be assingned (and installed) modules: [Minify] (https://github.com/coderaiser/minify "Minify") and [socket.io] (https://github.com/LearnBoost/socket.io "Socket.IO"). -Install addtitional modules: +Install addtitional modules (type in **Cloud Commander** directory): npm i - -**Cloud Commander's Client Side** use module jquery for ajaxing. But only for old browsers. -We could not use this module, but this way is fast: -- google cdn -- gzip -- cache - -Perhaps in the future, it will not be used, but so far it has no effect on -start loading of Cloud Commander Client Side and do things fast and stable -it is using now. Extensions --------------- **Cloud Commander** desinged to easily porting extensions. For extend main functionality Cloud Commander use next modules: -- [CodeMirror] [CodeMirrorURL] +- [Ace] [AceURL] - [FancyBox] [FancyBoxURL] - [jQuery-contextMenu] [jQuery-contextMenuURL] -- [jquery.terminal] [jquery.terminalURL] +- [jq-console] [jq-consoleURL] - [github] [githubURL] - [dropbox-js] [dropbox-jsURL] +- [jquery] [jqueryURL] -[CodeMirrorURL]: //github.com/marijnh/CodeMirror "CodeMirror" +[AceURL]: //ace.ajax.org/ "Ace" [FancyBoxURL]: //github.com/fancyapps/fancyBox "FancyBox" [jQuery-contextMenuURL]: //github.com/medialize/jQuery-contextMenu "jQuery-contextMenu" -[jquery.terminalURL]: //github.com/jcubic/jquery.terminal "jquery.terminal" -[githubURL]: //github.com/michael/github -[dropbox-jsURL]: //github.com/dropbox/dropbox-js +[jq-consoleURL]: //github.com/replit/jq-console‎ "jq-console" +[githubURL]: //github.com/michael/github "github" +[dropbox-jsURL]: //github.com/dropbox/dropbox-js "dropbox-js" +[jqueryURL]: //jquery.com Contributing --------------- @@ -257,6 +264,7 @@ so to get it you should type a couple more commands: Version history --------------- +- *2012.07.01*, **[v0.3.0](//github.com/coderaiser/cloudcmd-archive/raw/master/cloudcmd-v0.3.0.zip)** - *2012.04.22*, **[v0.2.0](//github.com/coderaiser/cloudcmd-archive/raw/master/cloudcmd-v0.2.0.zip)** - *2012.03.01*, **[v0.1.9](//github.com/coderaiser/cloudcmd-archive/raw/master/cloudcmd-v0.1.9.zip)** - *2012.12.12*, **[v0.1.8](//github.com/coderaiser/cloudcmd-archive/raw/master/cloudcmd-v0.1.8.zip)** @@ -269,6 +277,11 @@ Version history - *2012.07.11*, **[v0.1.1](//github.com/coderaiser/cloudcmd-archive/raw/master/cloudcmd-v0.1.1.zip)** - *2012.00.00*, **[v0.1.0](//github.com/coderaiser/cloudcmd-archive/raw/master/cloudcmd-v0.1.0.zip)** +License +--------------- +MIT [license](LICENSE "license"). + Special Thanks --------------- -[Elena Zalitok](http://vk.com/politilena "Elena Zalitok") for logo. +[Elena Zalitok](http://vk.com/politilena "Elena Zalitok") for +[logo](img/logo/cloudcmd.png "logo") and [favicon](img/favicon/favicon.png "favicon"). diff --git a/bin/cloudcmd b/bin/cloudcmd new file mode 100755 index 00000000..174f51f0 --- /dev/null +++ b/bin/cloudcmd @@ -0,0 +1,12 @@ +#!/usr/bin/env node + +/* cloudcmd binary + * usage: node cloudcmd + */ +(function(){ + 'use strict'; + + require('../cloudcmd'); + +})(); + diff --git a/cloudcmd.js b/cloudcmd.js index 64716bbf..0f20695d 100644 --- a/cloudcmd.js +++ b/cloudcmd.js @@ -45,7 +45,8 @@ * additional processing of index file */ function indexProcessing(pData){ - var lData = pData.data, + var lPath, lReplace, lKeysPanel, + lData = pData.data, lAdditional = pData.additional; /* @@ -53,10 +54,10 @@ * меняем в index.html обычные css на * минифицированый */ - if(Minify.allowed.css){ - var lPath = '/' + Util.removeStr(Minify.MinFolder, DIR), - lReplace = ''; - lData = Util.removeStr(lData, lReplace) + if (Minify.allowed.css){ + lPath = '/' + Util.removeStr(Minify.MinFolder, DIR); + lReplace = ''; + lData = Util.removeStr(lData, lReplace) .replace('/css/style.css', lPath + 'all.min.css'); } @@ -65,12 +66,12 @@ fm : lAdditional }); - if(!Config.appcache) + if (!Config.appcache) lData = Util.removeStr(lData, ' manifest="/cloudcmd.appcache"'); - if(!Config.show_keys_panel){ - var lKeysPanel = '
' + p.name); pParams.name = main.HTMLDIR + p.name + '.html'; lRet = main.sendFile( pParams ); } - else if( Util.isContainStrAtBegin(p.name, FS) || Util.strCmp( p.name, '/') ){ + else if ( Util.isContainStrAtBegin(p.name, FS) || Util.strCmp( p.name, '/') ){ - if( Util.isContainStrAtBegin(p.name, FS + 'no-js/') ){ + if ( Util.isContainStrAtBegin(p.name, FS + 'no-js/') ){ var lURL = Util.removeStr(pParams.name, 'no-js/'); return main.redirect(pParams, lURL); } - lRet = sendCommanderContent(p); + lRet = sendCommanderContent( pParams ); } /* termporary redirect for old urls */ else @@ -278,20 +286,20 @@ } function sendCommanderContent(pParams){ - var lRet = main.checkParams(pParams); - if(lRet){ - var p = pParams; - p.name = Util.removeStrOneTime(p.name, CloudFunc.FS) || main.SLASH; + var p, lRet = main.checkParams(pParams); + + if (lRet){ + p = pParams; + p.name = Util.removeStrOneTime(p.name, CloudFunc.FS) || main.SLASH; fs.stat(p.name, function(pError, pStat){ - if(!pError) - if( pStat.isDirectory() ) + if (!pError) + if ( pStat.isDirectory() ) processCommanderContent(pParams); else - main.sendFile(p); + main.sendFile( pParams ); else main.sendError(pParams, pError); - }); } @@ -301,12 +309,12 @@ function processCommanderContent(pParams){ var lRet = main.checkParams(pParams); - if(lRet){ + if (lRet){ var p = pParams; main.commander.getDirContent(p.name, function(pError, pJSON){ - if(!pError){ + if (!pError){ var lQuery = main.getQuery(p.request); - if( Util.isContainStr(lQuery, 'json') ){ + if ( Util.isContainStr(lQuery, 'json') ){ p.data = Util.stringifyJSON(pJSON); p.name +='.json'; main.sendResponse(p); @@ -314,7 +322,7 @@ else{ /* get back html*/ p.name = Minify.allowed.html ? Minify.getName(INDEX) : INDEX; fs.readFile(p.name, function(pError, pData){ - if(!pError){ + if (!pError){ var lPanel = CloudFunc.buildFromJSON(pJSON, FileTemplate, PathTemplate), lList = '
    ' + lPanel + '
' + ''; diff --git a/css/reset.css b/css/reset.css index 17497957..f6003d74 100644 --- a/css/reset.css +++ b/css/reset.css @@ -8,11 +8,7 @@ */ html{ - font-family: sans-serif; - font-size: 100%; color: #222; - -webkit-text-size-adjust: 100%; - -ms-text-size-adjust: 100%; } body { margin: 0; font-size: 1em; line-height: 1.4; } @@ -22,15 +18,8 @@ body { margin: 0; font-size: 1em; line-height: 1.4; } * Also: hot pink! (or customize the background color to match your design) */ /* -::-moz-selection { background: #fe57a1; color: #fff; text-shadow: none; } ::selection { background: #fe57a1; color: #fff; text-shadow: none; } */ -::-moz-selection{ text-shadow: none; opacity: 0;} -::selection { - text-shadow: none; - opacity: 0; - background-color:white; /* opera */ -} /* ============================================================================= @@ -86,4 +75,4 @@ a:hover, a:active { outline: 0; } a[href]:after { content: " (" attr(href) ")"; } .ir a:after, a[href^="javascript:"]:after, a[href^="#"]:after { content: ""; } /* Don't show links for images, or javascript/internal links */ @page { margin: 0.5cm; } -} \ No newline at end of file +} diff --git a/css/style.css b/css/style.css index b68f19c2..840ba253 100644 --- a/css/style.css +++ b/css/style.css @@ -26,12 +26,24 @@ src: local('Droid Sans Mono'), local('DroidSansMono'), url('//themes.googleusercontent.com/static/fonts/droidsansmono/v4/ns-m2xQYezAtqh7ai59hJUYuTAAIFFn5GTWtryCmBQ4.woff') format('woff'); } -body{ +body { font:16px "Droid Sans Mono"; background-color:white; } -.path-icon{ +#fm::-moz-selection, #left>li::-moz-selection, #right>li::-moz-selection, .path::-moz-selection, .fm-header::-moz-selection, +.mini-icon::-moz-selection, .name::-moz-selection, .size::-moz-selection, .owner::-moz-selection, .mode::-moz-selection { + text-shadow: none; opacity: 0; +} + +#fm::selection, #left>li::selection, #right>li::selection, .path::selection, .fm-header::selection, +.mini-icon::selection, .name::selection, .size::selection, .owner::selection, .mode::selection { + text-shadow: none; + opacity: 0; + background-color:white; /* opera */ +} + +.path-icon { position: relative; top: 3px; left: -4px; @@ -44,15 +56,15 @@ body{ color: #46A4C3;/*#55BF3F; green*/ text-shadow:black 0 2px 1px; } -.path-icon:hover{ +.path-icon:hover { cursor:pointer; } -.path-icon:active{ +.path-icon:active { position: relative; top: 4px; text-shadow:black 0 0 1px; } -.icon{ +.icon { display:inline-block; width:16px; height:16px; @@ -60,60 +72,63 @@ body{ /* font-family: 'GeneralFoundicons'; */ font-family: 'Fontello'; } -.error::before{ +.error::before { position: relative; font-size: 14px; color: rgb(222, 41, 41); cursor :default; content: '\2757'; } -.loading{ +.loading { position:relative; top:1px; background:url(/img/spinner.gif); } -.error:hover{ + +.error:hover { color:rgb(222, 41, 41); color:rgba(222, 41, 41, 0.81); } -.refresh-icon{ + +.refresh-icon { background:url(/img/panel_refresh.png) no-repeat; } -.refresh-icon:active{ - /*background-position-y: -15px;*/ - background:url(/img/panel_refresh.png) 0 -15px no-repeat; + +.refresh-icon:active { + background-position: 0 -15px; } -.cmd-button{ - width: 10%; - margin: 20px 2px 0 2px; - overflow: hidden; - color: rgb(49,123,249); - text-overflow: ellipsis; - white-space: nowrap; +.cmd-button { background-color: white; border: 1.5px solid rgba(49,123,249,.40); + color: rgb(49,123,249); + margin: 20px 2px 0 2px; + text-overflow: ellipsis; + overflow: hidden; + outline: 0; + white-space: nowrap; + width: 8%; } -.cmd-button:hover{ +.cmd-button:hover { border: 1.5px solid rgb(0,0,0); } -.cmd-button:active{ +.cmd-button:active { color: white; background-color: rgb(49,123,249); } -.clear-cache{ +.clear-cache { margin-right: 6px; margin-left: 7px; background:url(/img/console_clear.png) -4px -4px no-repeat; } -.clear-cache:active{ +.clear-cache:active { top:5px; } -.links{ +.links { color:red; } @@ -135,17 +150,17 @@ body{ * именем файла во время * установления курсора */ -.current-file > .mini-icon{ +.current-file > .mini-icon { left: -6px; } /* freeupex */ -.directory{ +.directory { /*list-style-image*/ background-image:url('/img/dir.png'); background-position: 0 0; background-repeat: no-repeat; } -.text-file{ +.text-file { /*list-style-image*/ background-image:url('/img/txt.png'); background-position: 0 0; @@ -155,7 +170,7 @@ body{ height: 90%; margin: 26px 26px 0 26px; } -.fm-header{ +.fm-header { font-weight: bold; } #path{ @@ -166,7 +181,7 @@ body{ } /* фон файла, на котором курсор*/ -.current-file{ +.current-file { border: 1.5px solid rgba(49, 123, 249, .40); } @@ -187,9 +202,9 @@ body{ } /* информация о файлах и папках*/ -.name{ +.name { float: left; - width: 37%; + width: 35%; /* если длина имени файла больше 16 символов * отрезаем лишнее, оставляя лишь 16, * и добавляем две точки и тайтл @@ -198,7 +213,7 @@ body{ text-overflow: ellipsis; white-space: nowrap; } -.size{ +.size { float:left; width:16%; /* Ставим отступ, что бы @@ -212,9 +227,9 @@ body{ */ text-align: right; } -.mode{ +.mode { float: right; - width: 25%; + width: 23%; } /* changin ul to panel for high speed parsing*/ @@ -250,7 +265,7 @@ a:hover, a:active { display:none; } /* текущий файл под курсором */ - .current-file{ + .current-file { background-color: rgb(49, 123, 249); background-color: rgba(49, 123, 249, .40); color:white; @@ -259,11 +274,11 @@ a:hover, a:active { .current-file > .mini-icon{ color:white; } - .current-file > .text-file::before{ + .current-file > .text-file::before { color:white; } - .fm-header{ + .fm-header { display:none; } @@ -279,23 +294,23 @@ a:hover, a:active { position: relative; top: 10px } - .directory::before{ + .directory::before { content: '\1f4c1'; } - .text-file::before{ + .text-file::before { color: rgb(26, 224, 124); color: rgba(26, 224, 124, 0.56); content: '\1f4c4'; } - .text-file{ + .text-file { background-image:none; } /* убираем заголовок*/ - .fm_header{ + .fm_header { display:none; } - .mode,.size,.owner{ + .mode,.size,.owner { /* располагаем элементы * один под другим */ @@ -306,32 +321,36 @@ a:hover, a:active { text-align: left; } /* выводим заголовки рядом с полями */ - .name::before{ + .name::before { content: 'name:'; font-weight: bold; font-size: 13px; } - .mode::before{ + .mode::before { content: 'mode:'; font-weight: bold; font-size: 13px; } - .size::before{ + .size::before { content: 'size:'; font-weight: bold; font-size: 13px; } - .owner::before{ + .owner::before { content: 'owner:'; font-weight: bold; font-size: 13px; } - .name{ + .name { float: none; width:100%; font-size: 18px; } + + .cmd-button { + width: 20%; + } } @media only screen and (min-width: 601px) and (max-width: 785px){ .panel{ @@ -340,6 +359,10 @@ a:hover, a:active { #right{ display:none; } + + .cmd-button { + width: 15%; + } } @media only screen and (min-width:786px) and (max-width: 1155px){ @@ -350,4 +373,8 @@ a:hover, a:active { #right{ display:none; } + + .cmd-button { + width: 10%; + } } \ No newline at end of file diff --git a/favicon.ico b/favicon.ico deleted file mode 100644 index e69de29b..00000000 diff --git a/html/index.html b/html/index.html index b8da6c04..d40145bd 100644 --- a/html/index.html +++ b/html/index.html @@ -1,37 +1,39 @@ - - - - - - - - - {title} - - - - - - -
{fm}
-
- - - - - - - - -
- - - - - + + + + + + + + + + {title} + + + + + + +
{fm}
+
+ + + + + + + + + + +
+ + + + + \ No newline at end of file diff --git a/img/favicon/favicon-big.png b/img/favicon/favicon-big.png new file mode 100644 index 00000000..d8a00b9b Binary files /dev/null and b/img/favicon/favicon-big.png differ diff --git a/img/favicon/favicon.ai b/img/favicon/favicon.ai new file mode 100644 index 00000000..0df4f382 --- /dev/null +++ b/img/favicon/favicon.ai @@ -0,0 +1,737 @@ +%PDF-1.5 +4 0 obj +<< +/Type /Page +/Parent 2 0 R +/Contents 5 0 R +/PieceInfo << + /Illustrator 6 0 R>> +/MediaBox [-0.0000 -0.0000 595.2756 841.8898] +/TrimBox [0.0000 0.0000 595.2756 841.8898] +/CropBox [-0.0000 -0.0000 595.2756 841.8898] +/Resources << +/ProcSet [/PDF] +>> +>> +endobj +6 0 obj +<< + /Private 7 0 R>> +endobj +7 0 obj +<< + /AIPrivateData1 8 0 R /CreatorVersion 11 + /ContainerVersion 9 + /RoundtripVersion 11 + /NumBlock 1 >> +endobj +8 0 obj +<< +/Filter [/ASCIIHexDecode /FlateDecode ] +/Length 53205 +>> +stream +78daecdd5bafe3f6b91fe0fb01fc1dd48b00098aa8e299f49dd6a9cd6eb2bb11a7d8298a8d6062af +6d4f3b9ef19e1927713f7d499112252d9d2851c7f5c8805f89e2234aef9fa224fed690bffa4ffff2 +cd6fc7df7dfcebf36fa3e1e8ab37bffad5fda7e7b75f3e7efa7a3271f0bbf7ef7ffefce5533565f0 +eb3ffde1378320188e2697c1e33f7efaf8e9cbf377837ffff4f1c7c1fdc74fcfef1ffe38fed7f221 +fef4eecbfbe7affffdeddfde7dfbf1c3f0edbbd9c3befbf8e1e1ed97e7af07dfbcfd32f8a79fdf0f +46e92048bf0ee3afa368108e82e84d39e7ddc79f3f7cf7eec3f7771ffff175180cc2ac1824593048 +a3bc7a9c878fdffefce3f3872ffff2e9e3b7cf9f3fdf7f7cfff1d3e7af07f7bfbcfd30f8c3dbefcb +7bde0efed7f3fbf71fff3eb87bfff6dbff3b6fbef9f9a79fdebf7bfeee8fcf9f3ffefca9e45f0f7e +2a1fe6f3f397c1e4d5fee5fdf3df9edf877f19ff2e1904c37030e9c77f5e9ae7cb2f3f7dfcfed3db +9f7ef8a5996f340856cd377966bffbb17c4ae57ce5cb1c06ab1f6faec39b17fcede71fca171596cb +cb57ddfdf987b755d7cac7c8274faa7a8cf1efa2fa79fccfcfe5f328bb545d6fa6ffe9f9c79fde97 +83316973910de2aad7756de6685bfdfcb777cf7fff7af0cf1f3f3c4fee4bfe32fef4e59b77ffaf7c +c8a44806791c0e9ae9fffcf38fbf7ffbcb733524a366d2d3bbf7cf4f1f3ffd580e7938ac27667ff9 +d30f3ffff8d70f6fdfbdff7a108479f908f58bba7bfefe5db58abcfd7a1045a378f0df9eff31b8fb +e5cbf3e7f2cee029b80bb23029d79387300fe3300cefc22c4cc3a7f03e1c4741f8183e94ff7f2aff +1f57b5fc7f188da2b4fc7ff58aca2b5114c4e3388b936414dfc7e3344a47c953364aefd3221b6769 +16e7591ee5a3bbe46e347eaa2ff5ba5ef2d101171cc771fc4278395b12961f01c9d34314961f150f +a3fbd1e8e9210b26d7a3eafae87e723daeaea7774158b1a78720aaae4d96524ece669327d7ca29f1 +6cca787a2d0deafb82c7ba268fd567597367f959564fbcaf6b184def498a664ad2cc9137b7b38697 +93d26652336bd2cc1a8e9bdb5173bb79f024689e7c39a97932cdab9cbcfaa87911e153735fde76a0 +992f6a7814d7b344cdd31f258b0d9adcd7bcee691dcdb72e98b56ebab4661c26bd0fee9a67f2d0dc +174d5b38dfba66a6245eeac2b42b4dc392e9cb2a6bb3f4592fa7bd6d1a16c66b6e378b2a79182d0d +58f3ea9287a5db4d836703fc345bfae869f24ab3c9f5e649070f4daff3c9ffd3c9ab2e16c6289af2 +6c7233995c6f9e60309d352abfb84c066e743fb9954f1e289d8d7bbdbcb96751f6bb79887a44c6a3 +c7b9fbc6ed50574b6fda16b46b79f5c8c5e8a999369e80a643a3746eedcb264b0faa0728eab16e57 +9b6696a479d364c1fc8ad52e7d32535cce54d5876af6d94cd3f5bc1aa6a89ce3a99eb35eb58270d6 +f9c94384cd0c7741307d1f04e1dc0304cd2086ed034cf974b50c9bd91a5c4d8b9fe657d9fa7af6b0 +c0b3c769db76b9d63ec4842f3ee2fcf5e6d6fdcb5b7567a64bbf5b6cd6ec76d3e16cbc382659d18e +7b339259d66e1826b7d335b7672b5916cd3656a3e62965d3b16fde30d974109b06a64d0d46b39536 +6d66ad5f5dbb419eae89e5ede9db289dcdd1aef3c1ece9a4d3b74bc3d3b07df7355bdda7f9b7ed74 +73b17ee39cb61badf9adefdca63219cd3658b3118e1f5e6ef3e27cb6e14c17deef71bb45bd6b37c8 +d1ec29c7731f5a51d65e2f799cce81d1dcb2eaad4d3af712e2e9a673ba65aa066edc6e69d2c95282 +f174b358fd587bfcf05df553adb97afff1c7eac7e2e7d9cfb8f217fafb8fdf57377ff7e1dbf73f7f +f73cfdd9bdcbafee2d64dd8ff02d6cdd6ff22d6ced4ff42d6ee9177bd9a4b62793167df3fce5e79f +be7af3a20dffe5dd87775fdebd7d5ffec21e7c5f3edcf33f9ebf9dce563fe8a639969eee5ffef6f6 +d3e735af646537373df652073b3c8d35f34edad2f461b2bb60d298c93e84afde0c82e6bf51f9df6f +8341140cc274104683dffff5ab37bf9ecc34087e33f8fd87afde04833ffff1ab37a3c1ff28af4ef6 +500d16cb9fdf56f756b3d4b7174b33d37fafe6a997568a5faa5bff54fdefff7cf5260c874598a483 +3f548f1f075934f8fb576ffef7bf8d06df7df526caa2e12828ef4c926258147132f8f1ab37c9281e +e6699c0ecaadce30ce8b7890e4f9b0188dc2419c25c3a4884783244d8759912783a88886591a2583 +b22349120fd328cb07519c0fb378940c92201a8693fd3379f5506517a2341e164134aaf68e0dcbaf +ad131806e930c9a3a29c980d8ba8c80761308cc262348892701895d76613e27219595aa4356ba615 +a5cae362503ea93849a341f915791897730d822829975f2e242e9f661206d9e0beec429857b32583 +34c886691e4783b0bab76cd2201be5c32848a2c1cbc694f0afed60f5321ca361d9c6627e3846e1b0 +6c593048e2aacf795c0dc7f2c46cf0fb557396133f1f6f4529bf580ccba12bd780b45c5e968caa67 +f672621814c3720cb3b2df65db826a4a79573c2ae74946e9b0daf25703577eb31e26d1282bd78f72 +78cb2fb3e53847c320c8a3419ca7c33429df28d58a52ae8479f9e0a372654a836a04bef9eacd7f94 +3c2e1f2a2ac7bb5aabc2b45c3baa3645e13018956b64b56215515eae85a37278e3b85af9ca579694 +2b74752518257179251b961f7ba3ea31c3f2d1c26a0d0e8bb8ec5150ae7ce55a10a6934728d78b72 +0d1904d55d79513eabf2ae7454ae7ed57a54ad35e56a3399983563504d2c3f9dd37262318c92f285 +4f27a6513e9998951f8b9345c4650b06713c1ae6619ecf4d2957f9f2232f9a3cb7f9894196a5cd6c +693c9912475587ab2969334f56bef229cccae75576af7aa549b9c4ea3d9624558783eacd514e09cb +2753948f1917c1302d92a2ee46d9abbcec76f9f13fccb3aa696950bdccbc9c52be39f2f2ed15e651 +7565349d32e9c6d2c462d28d6a6251beefda89615e0e6bf9c5a6991256539261548ce27a4a9a27f5 +a395ab4d3c8a9a89e5baf8fb6662568e543db15cfbab774250aee0e5332e2726c351b9791894dfe3 +87e56babdef4e5f6208cb341b5c284615c76a35c7a946561b588f2dbca30884741b9512b57c2222a +674babf77a5ef536abdefde5946c54c2209e0cd3288be209ac2616e51b378eca472b7fec94b395bd +4ac2f2f1c36aeb54aee4d5f6238baa872ab780415caf30e59287595e3dc3727b1a86d5d6b36a5af9 +9226eb7f91976b7254aebdc1641b1a66d53a934c619004e5bd41b53d2b9f7ff5f879b54a47e5c63a +a87665979d2b1b1b54bbc293f27d9c15f56b2c1f7f54d42b7c3a8aab05a5c3f29b7452bf17aa57f1 +f2dd54c21f06ff3af830b71bfcebf9cfb83fbefdfca5fa90fbf56faa6dc87f2d37126543aaadf6f2 +86a79c980d9ab7c96c6d29fe6d90e5a341512eb1d43f74d7d5966bfa08d35ab6bed9a68d96f6c697 +6fc6acfc6cf8eacd9f7f67ff128ee3388ee3388ef7c2efb37dea84df17cda4ceb55dfa5e0fd16de9 +e3e5da2e7dbc4fad973edeef21ac75388ee3388ee3388ee3388ee3388ee3387e91fc3edd54eb7420 +dd65d655b5cd26f67a887ae97b453a55ed2515da959c3715eab0f4ad918eb70c8ee3388ee3388ee3 +388ee3388ee3388e4f2ef751d7daee9f5f374bbca9d6e9c09a59a6075d5d5f674bdf3eebaa5a1f58 +e969df87b8b0a51f3315ea90491d2f15f286c5711cc7711cc7711cc7711cc7711cc72f90df075d6a +bd87bc9974f5d984a55fcad2cf940a653617388ee3388ee3388ee3388ee3388ee378077ef7b8b94a +072cfdb52ffd90e3d7ad4f856cac701cc7711cc7711cc7711cc7711cc76f86db3f6fe9967ea14bef +1aedd8d6e1388ee3388ee3388ee3388ee3388e9f86db436ee9072e3d5aa8131eadbc6b457d5caeb3 +a5bfbc6b975a2ffdd1b81fb0f4cde74eb2a5c5711cc7711cc7711cc7711cc7711c970edcd4d2e370 +b6f438dca74e78dc9c5ba77b6d97bed743745afacbbca6cd659ef6a9dd52a1f54bb7ceefb5f4fba8 +9e34ad36d4388ee3388ee3388ee3388ee3388e5f03974d5cf0d2e3a4a9f1a65a6713f12eb3aeaa6d +32b2d743d44bdf2bd2e92d15da959c3515eab0f46d918e77dc5e4b6ff31b1f13388ee3388ee3388e +e3388ee3388ef7cfeda73dd7d2e3ac6b6df7cfaf9b25d954adf3c7e77da4421d32a9e3a542deef9d +96ee2d83e3388ee3388ee3388ee3388ee3af9ddb537aeca5c7f93ed54a8b1f939f38155aaab6363b +2ddd4a8be3388ee3388ee3388ee3388ee3d7c32523bdff8b95bbcdd55a87e3fb1fbf6e7d2a2405de +e59fe058eb701cc7711cc7711cc7711cc771fcd8dcbecac3ceb1f260adc3f18be65da31ddbba9d66 +b5d6e1388ee3388ee3388ee3388ee3f8fcc5bf58d96be97781b50ec7f1177cdd39946c69372edd5a +87e3388ee3388ee3388ee3388edf10f757dcebebf87155b5dae0387e421e67f58d699580eff24f6f +ac75388ee3388ee3388ee3388ee3f879b9fd75a3d1f87e5a674b6f27596d701cbf11dee637f2f7d1 +ae474db3dae0388ee3388ee3388ee3388ee31df96b3ebecdf86e73b5dae0388eafbcdc6557b29d3f +e1d2ad36388ee3388ee3388ee3388ee3787b794d7bccc67953c7abea844f27596d701cc78fcdef92 +1bfb94d963e9561b1cc7711cc7711cc7711cc7f19be3b77f24b16c5adb2389659babd506c771fc0a +f85dbc589dddc66a83e3388ee3388ee3388ee3387e29fc96ff96789cec5aad36388ee3af8c2f4737 +6d8473259f71ce6e83e3388ee3388ee3388ee3387ed9fce68ef1328ee76b7d24b178d55d6db5dae0 +388ee33b5eeec2f93ae1d349377f761bab0d8ee3388ee3388ee3388ee378077e337fcd3b0ebbd43a +9709ad36388ee3f8a9f85db0ba3abb8dd506c7711cc7711cc7711cc7f19be3577f9495e2456dcff0 +126cae561b1cc771fc2af878fa8706739f71b77e761be38ee3388ee3388ee3388ee3f895f3abdd6f +533c76adb3a5174fc61dc7711cbf6d3e7edc5c6ff1ec36c61dc7711cc7711cc7711cc7f18be1577b +9c93e27ebe4ef8e2a4edd56a83e3388ee32f2e8b394d7dacce8dd1cd159fddc6b8e3388ee3388ee3 +388ee3387e747e757b4e8abb5d6a9dcbac99c5b8e3388ee3781f7c7cbf5bbdfab3db18771cc7711c +c7711cc7711cc73bf3eb3ad24851b447122bf6a9c61dc7711cc7cfcec777cbb53dbbcdddc9bf5d1c +e7bb8d71c7711cc7711cc7711cc7717c740547802ff26db5cd65b6cc6adc711cc771fcfaf878bc5b +bddab3db18771cc7711cc7711cc7711cbf497e357f535a244b35dd56db5c2635ee388ee338fe5af8 +38df54ebb3dbe497f0dde680a51b771cc7711cc7711cc7711cbf1e7ed9c7fa28a2f95a9fe1255a75 +d78a9c2631ee388ee3388eafbd8cb319afafced5a508e7eace9db7db21d1ac36388ee3388ee3388e +e3387e347ef17b0f8a70975ae7326b6631ee388ee3388ef7cb5fe4354bf5e27399cd398d71c7711c +c7711cc7711cc7f1def865fe5567d13ef962b44fad7319e38ee3388ee3f859f93899d6f6ec36c962 +bdcc5c66c3d28d3b8ee3388ee3388ee3388e77e1977914f4fc459d2d3d7fdaad1a771cc7711cc7af +898fe3ddeac5e532dd0f8566dc711cc7711cc7711cc7f1d7c42febf77bfeb06b6d739935b318771c +c7711cc76f918fc355b53ebb4d7849dfeb76cf698c3b8ee3388ee3388ee3387eb3fce28e7791dfd7 +93ba57e38ee3388ee3385e5ec6c18cd757d7d7cb3c3eed8aa51b771cc7711cc7711cc771fc5af965 +1c873c2f96ea78b6f4faeaeed5b8e3388ee3388eefca8ba7ddeac5e532bb1f02cdb8e3388ee3388e +e3388ee3e7e197f50b3acfb6d462b6f417914d61dc711cc7711cc78fcb8bc7a5da7eaf7b19d99cf3 +5be56e874233ee388ee3388ee3388ee3f891f9651c71224fdb33bca41d6b365bfa34aa31ee388ee3 +388ee317c05f44366beac51d1d77bf43a019771cc7711cc7711cc7717cd3e5bc4702cfe3e5dae632 +71b76adc711cc7711cc7af8317f7bbd40bca65ba1d02cdb8e3388ee3388ee3388ee3f397f3fe86cd +a36db5cd65b6cc6adc711cc7711cc76f8b1777f375c21727b5f5bcdf69b7e735c61dc7711cc7711c +c771fcf5f2f3fe6d611e74ad6d2eb3749771c7711cc7711c7fb5bc2836d7cbc865562cddb8e3388e +e3388ee3388edf363fefb1b8f3f6c9e7a3f949bb57e38ee3388ee3388e6fe745bead5e482ed3fd10 +68c61dc7711cc7711cc771fc92f9697f452ed76c659df06ce32c6d35ee388ee3388ee3787fbc48a7 +75c6db495dbe169ffa2f9d8c3b8ee3388ee3388ee3f865f2f3fe8acc1e77a9752eb36616e38ee338 +8ee3388e9f9417c99aba31af39d7bf409f5bba71c7711cc7711cc7711c3f033fef5117b287a63e76 +a90bb98c71c7711cc7711cc72f92afcd6b923ebf51f7f87ddec0e1388ee3388ee3388e1f8b9fe72c +a5d9fdb4b6b9cc74d2c36ed5b8e3388ee3388ee3d7ca8b68be4ef8e2a473e732bbe734c61dc7711c +c7711cc7717cf3e53cbfe3b2bb75b5cd65a693ee5757e38ee3388ee3388ebf025e849beb79becfaf +cf690c1c8ee3388ee3388ee3f8e2e53c7f5f978d77ad6d2e339d7467e0701cc7711cc771bcb9145b +ea79729915bf260c1c8ee3388ee3388ee3af9c9ff6b807bbe730cbd5c0e1388ee3388ee3f8ee33e7 +4fcb75c6f3b3e632fb9da2c6b8e3388ee3388ee3387eb5fc84e709cd8af95ae732c5aabbb6570387 +e3388ee3388ee33df1fc61733d6d2eb35b4e63e0701cc7711cc7711cbf0e7e9e5f5259beaad6b94c +be6996b61a771cc7711cc7711c3f11cfef37d7d3fe9a589dd318381cc7711cc7711cc72f9b9ff62f +dcb26c975ae7326b663170388ee3388ee3387e213c1fafaa133e9d74c25c66c56f190387e3388ee3 +388ee3f8d9f9698f089da5fbd43a97490d1c8ee3388ee3388e5f15cfdbe312e7cd718697a39bd3e6 +32dd4f5163dc711cc7711cc7711cef899fe04c9d6db8d2472e63e0701cc7711cc771fcfaf92c9f59 +534f9bcb6ccf690c1c8ee3388ee3388ee3fb5c4efb5b264b966b9bcb24bb550387e3388ee3388ee3 +af82e7d9e67adadf322f731a0387e3388ee3388ee37897cb69fec62c8b9a1aafab6d2eb366160387 +e3388ee3388ee3f8dc254fa775c6a7934e98cbacf82565e0701cc7711cc7711c9fbb9cf698cc59b8 +54a375b5cd65220387e3388ee3388ee3f83e3c8f57d7d3e632dd4e5163e0701cc7711cc771fc46f9 +69ce95f92287d9b91a381cc7711cc7711cc77be679b4ba9e3697d99cd318381cc7711cc7711cbf31 +7ec45f13b37f1413cc965e5fdd5097f2180387e3388ee3388ee3f8c9781eacaaa7ce6556a442060e +c7711cc7711cc7af979fe0d7447376cda55ae732a34db3b4f98c81c3711cc7711cc771fcec3c6f79 +be30e9d4b9cc7ea7a631ee388ee3388ee3387e367e9a7f7d9f6eac13be6e160387e3388ee3388ee3 +f835f0ec69753ded993a9ffc92c2711cc7711cc7f1cbe4c73d2a72fad8a5d6b9cca381c3711cc771 +1cc771fc7678f6b8ba9e2697d99ed318381cc7711cc7711c3f2aeff1fbfc865ca65b1eb390cb1838 +1cc7711cc7711cc76f99bfcc694e99cbbccc690c1c8ee3388ee3388e1f851ff1fb7cfa30ad6d2ef3 +b05b3570388ee3388ee3388ebf723e97cbacff2735bdff8e5bf1f775060ec7711cc7711cc7fbe047 +fc3babf47eb9b6b9ccfde66ae0701cc7711cc7711cc79779f6b0ba9e2697e97e6a1a0387e3388ee3 +388ebf7a7edce312a777db6a9bcb2cdd65e0701cc7711cc7711cc7bbf2ec7e753d4d2eb35b4e63e0 +701cc7711cc7f157c98f7bbec874bc6b6d7399b181c3711cc7711cc7711cef976777abeaa97299d5 +f98c81c3711cc7711cc75f15efe11bf5865c66f73c665a0d1c8ee3388ee3388ee3f8c978369ef16c +3c3fe9a8b9cc8a5f91060ec7711cc7711cbf757e846fd4693e5b7a5a349376ac060ec7711cc7711c +c771fc3278f77ce618475d3070388ee3388ee3f8b5f323fea5539acdd73a97c99b495baa81c3711c +c7711cc7711cbf6c9e158bf534b9cceef98c81c3711cc7711cc72f8b1ff1c8c069baaad6b9cc4254 +d3560387e3388ee3388ee3387e9d3ccb57d7e3e632db731a0387e3388ee3388e5f063fe2191b57e7 +318bb9ccd25d060ec7711cc7711cc771fcb678964deb8c4f271d31977999cf18381cc7711cc771fc +8cfc80efb41b729934e9521772190387e3388ee3388ee338fe6a78962ed623e6322b7ec31a381cc7 +711cc771fc74fc38df69d3b85b3570388ee3388ee3388ee3787bd92da739d6311f0c1c8ee3388ee3 +38de3f3fc277da346a739968b76ae0701cc7711cc7711cc7f1f597e57c6631a739f6b1b80d1c8ee3 +388ee338be3f3fe2bf014fc3696d739970733570388ee3388ee3388ee378779e25f3f5d8b9cce69c +c6c0e1388ee3388ee3abf811ce99b83e74d99acb18381cc7711cc7711cc771bc579e3507c89ed623 +e6328bf98c81c3711cc7711cc7e7f97e7f30b4319749836db5cd65020387e3388ee3388ee3388e9f +9067d1623d622eb3e217b481c3711cc7711c7f9dbcdf6f95b33c66b46b3570388ee3388ee3388ee3 +f865f02c5cacc7cd65bae733060ec7711cc771fc9af971be55261dab81c3711cc7711cc7711cc72f +8dafcf678e79c489ed398d81c3711cc7711cbf467e9cbff6491eeb49bb560387e3388ee3388ee338 +8e5f0bcf82693d452eb33e9f3170388ee3388ee3d7c48f7074dc3a64d929973170388ee3388ee338 +8ee3f80df16ceb8fed55b5532ef3329fd1791cc7711cc7f16be047386b61f2305feb5ce661d55d06 +0ec7711cc7711cc7711cbf699e3e2dd623e4322b7ebfeb3c8ee3388ee3f805f23dbed7adcd61ee37 +d53a9759bacbc0e1388ee3388ee3388ee3af90a78f8bf538b9ccf653d118381cc7711cc7f193f11e +bed7cdf298bb5d6a9dcbdce93c8ee3388ee3388ee3388e3797d5f94cdfb9ccf653d218381cc7711c +c7f1a3f11ebfd725e32ed5c0e1388ee3388ee3388ee3f8e64bfa708cdfefddf2190387e3388ee338 +7e38eff7ef6d9262a96ec9650c1c8ee3388ee3388ee3388e77e4697346d6693d422eb33a9f317038 +8ee3388ee3fbf31e8f4f9be46d2e932fd5a59c46e7711cc7711cc7711cc771bc679edeeffa3bbe73 +2eb362ef81cee3388ee3388e77e21bbe5975ce63b2696d73996ca9e63a8fe3388ee3388ee3388ee3 +27e1e9dd623d4e2eb3dba9680c1c8ee3388ee3af9e77f866b5358f49976b9bcb2cdda5f3388ee338 +8ee3388ee3387e269e8e977fd7f799cbec764a1a0387e3388ee3f8abe33d7cb39ae531c9badae632 +89cee3388ee3388ee3388ee3f845f1693e938e8f99cb6ccf670c1c8ee3388ee337cd7bfc66b53e8f +99569dc7711cc7711cc7711cc7f12be269d1fbde83edf98ccee3388ee3387e93bcc7bf7849e2ddaa +cee3388ee3388ee3388ee3f855f2343f78efc1eef98ccee3388ee3387e3bbcdf23c426d16e55e771 +1cc7711cc7711cc771fc26789a2dd61e73991567b7d1791cc7711cc7af96f77be6be24ac276dab3a +8fe3388ee3388ee3388ee337cdd374edde831e7299eda7a23170388ee3388e5f18dfe1bbcdae3509 +664bafafaeaf3a8fe3388ee3388ee3388ee3af8a2fe6337de732ddf2190387e3388ee3f819f96973 +199dc7711cc7711cc7711cc7f157cdd364c6ebabbde632bbe534060ec7711cc7f133f01ebedbccf2 +98d17cad7399d1e25d3a8fe3388ee3388ee3388ee3f86a9ec6dd7644ecb1ef42e7711cc7711c3f1b +eff1bb4dbcb24e78fca4f3388ee3388ee3388ee3388e77e169d4fbbe8bd5f98ccee3388ee3387e02 +dee3df9cc48f9baacee3388ee3388ee3388ee3387e004fc3a6467befbbd85c751ec7711cc7f123f2 +1e8fd11a3f6cae3a8fe3388ee3388ee3388ee378ef7c9ad3f49bcb3c39d6078ee3388ee3bdf2fdbe +98acfc6eb35b1ea3f3388ee3388ee3388ee3388e1f91b7f94c9fb9cce653d1e83c8ee3388ee31b2f +3b7cbbe890cbc4f79babcee3388ee3388ee3388ee3387e729e06c7cc65b6e733060ec7711cc7f1d9 +a5875c26be6b7399bbd555e7711cc7711cc7711cc7711cbf249e8ebaecfee8b4e744e7711cc7711c +5f7139e0dbc58b5c66dce632e3c5aaf3388ee3388ee3388ee3388e5f324ffacf655ee6333a8fe338 +8ee3af98f7f8ed222ea6b5cd650a9dc7711cc7711cc7711cc771fcfa78f2d8fb9e93369fd1791cc7 +711c7f85bcc7bffa88f3a6ca65701cc7711cc7711cc7711cbf2dbe3a9fe9ebccbcdb4f4563e0701c +c771fc56780fb94c9c2dd5693e93eb3c8ee3388ee3388ee3388ee337c98f93cb74cb670c1c8ee338 +8e5f13efe1ec7571baa6663a8fe3388ee3388ee3388ee3f86be1c97d979d2d3be532bbe533060ec7 +711cc7af8177fb8ab032978993cd55e7711cc7711cc7711cc7711c7f7d3cb9ebbaf3656b2eb3399f +d1791cc7711cbf64bedf3fa9ed94cbe83c8ee3388ee3388ee3388ee37832de75e74be7fd363a8fe3 +388ee317cef7f87cdf90cbc4f1eaaaf3388ee3388ee3388ee3388ee3cb97edf9ccdefb6d741ec771 +1cc72f94f793cbc4513d69b9ea3c8ee3388ee3388ee3388ee3f8b64b52acdbf9d2c77e1b9dc7711c +c7f14be03d7cbec7e16ce9f5d59755e7711cc7711cc7711cc7711cc7bb5efacd65369f8246e7711c +c771fcb8bcc7bfbb8883d9d2ebab6dd5791cc7711cc7711cc7711cc7f14379921de3bcc03a8fe338 +8ee35796cb2c86300bb98ccee3388ee3388ee3388ee3388e1f8127695d7bc86576cf69741ec7711c +c7f7e73d9c3f2e1eadaa3a8fe3388ee3388ee3388ee3387e2ade2d9fd92997599fcfe83c8ee3388e +77e7db3f79b7e632d19aaaf3388ee3388ee3388ee3388ee3e7e14952d71e739997f98ccee3388ee3 +f8ee7cf74fdcedb9cce3eaaaf3388ee3388ee3388ee3388ee3e7e59bf399bd7299369fd1791cc771 +1cdf9df790cb440fababcee3388ee3388ee3388ee3388e5f164f9a03cff798cbcced35d2791cc771 +1c5fcb0ff884ed96c7e83c8ee3388ee3388ee3388ee3f8a5f124aa6bbfb9ccfa53d0e83c8ee338fe +6a798f9fb0d1fd62d5791cc7711cc7711cc7711cc7f1abe53dee35ea96cf18381cc771dc27ece64f +d8e86eb1ea3c8ee3388ee3388ee3388ee3b8a3ac6c3a058dcee3388ee3af8bf7f02f52a3719bcb8c +17abcee3388ee3388ee3388ee3388e3b2bf1f659751ec7711cbf75dee319dca2a2cd650a9dc7711c +c7711cc7711cc7711c7f25bcc75c66753ea3f3388ee3f8edf01e729969083397cbe83c8ee3388ee3 +388ee3388ee3f8abe33de6328bf98ccee3388ee3d7cf577fd675ca65a27cb9ea3c8ee3388ee3388e +e3388ee338de632e33b7cf4ae7711cc7f1abe67de432d962d5791cc7711cc7711cc7711cc771bcbd +f49bcb6c3e058dcee3388ee317ca3b7cc6adcd63d2c5aaf3388ee3388ee3388ee3388ee3f8fa4bbf +b94cf77cc6c0e1388ee367e0077cc6cdf2986475d5791cc7711cc7711cc7711cc7717c27de632eb3 +7b3ea3f3388ee3f819f81172199dc7711cc7711cc7711cc7711cc7f7e23de632dbf3199dc7711cc7 +afeb332e8a17abcee3388ee3388ee3388ee3388ee3bd70b90c8ee3382e9769f39868b1ea3c8ee338 +8ee3388ee3388ee3387e14de432eb33e9fd1791cc771fc04bc87637546e162d5791cc7711cc7711c +c7711cc771fca8bc875ce6653ea3f3388ee3f8b1f8d3531fb94c14d493a655e7711cc7711cc7711c +c7711cc7f193f21e7299369fd1791cc771fc58bca75ca67934b90c8ee3388ee3388ee3388ee3387e +56de432e33b7c74ce7711cc7f19ef88a4f99ae1f5061fb19173ee93c8ee3388ee3388ee3388ee338 +7e013cce66bc875ce6e949e7711cc7f15e781fb9cca3cee3388ee3388ee3388ee3388ee317cbe3b4 +bed1432ed32d9f3170388ee3f8ecd2e153666d1ef3305f751ec7711cc7711cc7711cc7711cbf681e +2775ed2197d92d9fd1791cc7717c7639209759cc63741ec7711cc7711cc7711cc7711cbf2abe7b3e +b3f31e339dc7711cc7d75c7af89409ef751ec7711cc7711cc7711cc7711cbf7a1ec775ed618fd9ea +7c46e7711cc7f1433e65c2bbc5aaf3388ee3388ee3388ee3388ee3f80df038aaab5c06c7711cef8f +f7f0af32c3b1cee3388ee3388ee3388ee3388ee337cb7bc86516f3199dc7711c7fc5fc805c262c16 +abcee3388ee3388ee3388ee3388ee337cc7bc865eaaaf3388ee3af90effe51b13597d1791cc7711c +c7711cc7711cc771fc15f17e7299d58738d3791cc7f15be507e43261be58751ec7711cc7711cc771 +1cc7711c7f453c1ef599cb74cf670c1c8ee3f835f1ee1f152f73994ce7711cc7711cc7711cc7711c +c7717c348afacb6576cf67741ec771fc9af801b94c98ea3c8ee3388ee3388ee3388ee3388ebfe4d1 +635de532388ee3f896ed7c975c26d1791cc7711cc7711cc7711cc7711c5fcfa387ba1e90cb6ccf67 +741ec771fc1af8beb94c98e83c8ee3388ee3388ee3388ee3388e77e23de432ebf3199dc7711cbf58 +bec776fe452e13eb3c8ee3388ee3388ee3388ee3388eefc57bc8655ee6333a8fe3387eb1fc80ed7c +18e93c8ee3388ee3388ee3388ee3388e1fc4a3bbbaf690cbb4f98ccee3388e5f1cef613b1f863a8f +e3388ee3388ee3388ee3388ee3bdf0685c57b90c8ee3f86df203729930d0791cc7711cc7711cc771 +1cc7711c3f0a8f8a19df3797797ad2791cc7f18be13d1caf522e83e3388ee3388ee3388ee3388ee3 +c7e73de4322f4f3da3f3388ee3a7e507e432a1cee3388ee3388ee3388ee3388ee3f8c9790fb94cb7 +7c46e7711cc70fe79b37d63be532c193cee3388ee3388ee3388ee3388ee3f8a97994d5552e83e338 +7e45fc805c2678d4791cc7711cc7711cc7711cc7711c3f378fd2ba1e90cbec96cfe83c8ee3f8e1fc +905ce641e7711cc7711cc7711cc7711cc771fc52780fb9cce67c46e7711cc7f7e7bbfde3c68db98c +cee3388ee3388ee3388ee3388ee3f8e571b90c8ee3f805f2037299e05ee7711cc7711cc7711cc771 +1cc771fc527994d4f5805c66753ea3f3388ee3ddf9ee27019bf117b9cc9dcee3388ee3388ee3388e +e3388ee3f8a5f328aeeb01b9cc623ea3f3388ee3ddf901b94c30d6791cc7711cc7711cc7711cc771 +1cbf36de432e33b7b750e7711cc73bf143729942e7711cc7711cc7711cc7711cc771fc5ab95c06c7 +71fc84fc802dede6937de93c8ee3388ee3388ee3388ee3388e5f038f027b0b711cc74fc60fd8d206 +b9cee3388ee3388ee3388ee3388ee3f80df11e7299eef98ccee3387efbdcbf4cc4711cc7711cc771 +1cc7711cc7717c2d97cbe0388ef7ca0fc8658254e7711cc7711cc7711cc7711cc771fcb67978782e +b37b3ea3f3388edf3e3f249749741ec7711cc7711cc7711cc7711cc75f070f1feb7a402eb33d9fd1 +791cc76f97b7dbc2bd73199dc7711cc7711cc7711cc7711cc7f1d7c6e532388ee3a7ce658258e771 +1cc7711cc7711cc7711cc771fc75f2f0a1ae07e432ebf3199dc771fc76f901b98ccee3388ee3388e +e3388ee3388ee3f86be7e17d5d0fc8655eee70d4791cc76f8fbfdcf6c965701cc7711cc7711cc771 +1cc7711cdf93cb65701cc73b6c263be53241a0f3388ee3388ee3388ee3388ee3388ecf5fc2715d0f +c865da7c46e7711cbf3d7e402ea3f3388ee3388ee3388ee3388ee3388eafbec865701cc7376c1ee5 +32388ee3388ee3388ee3388ee3388e1f87ef9bcbccedabd4791cc7af9eefb0ad5b9bc73cea3c8ee3 +388ee3388ee3388ee3388ee33bf230af6f1c90cb6cfe5b719dc771fcc673199dc7711cc7711cc771 +1cc7711cc771bc2b97cbe038fe9ab95c06c7711cc7711cc7711cc7711cc7f153f230adeb01b94cb7 +7c46e7711cbf047ebfadb6fc7e9f6d9ecee3388ee3388ee3388ee3388ee338be81cb65701c7f55fc +6e5b6df9f25d3a8fe3388ee3388ee3388ee3388ee3785ffc805cc6df90e3387e3d7cbcadb67cf92e +9dc7711cc7711cc7711cc7711cc771bc2f1ec67595cbe0387ed3bcd8565bbe7c97cee3388ee3388e +e3388ee3388ee338de373f2097d99ccfe83c8ee3e7e4c5aef5652ea3f3388ee3388ee3388ee3388e +e3388e1f8b87615d0fc86556e7333a8fe3f83979be6b6d79ae75388ee3388ee3388ee3388ee3388e +9f88cb65701cbf299eed5a5b9e691d8ee3388ee3388ee3388ee3388ee327e607e4328bf98ccee338 +7e0e9e76ad5a87e3388ee3388ee3388ee3388ee3f8f9b85c06c7f1abe649d7aa75388ee3388ee338 +8ee3388ee3388e9f9f1f90cbd455e7711c3f0797cbe0388ee3388ee3388ee3388ee3387e853c90cb +e0387e8d3cee5ab50ec7711cc7711cc7711cc7711cc7f18be207e4328b8736d3791cc78fc6a3e656 +d7aa75388ee3388ee3388ee3388ee3388e5f160f1eea2a97c171fc7279d8dcea5ab50ec7711cc771 +1cc7711cc7711cc7f1cbe407e432ddf3199dc771bc130f9a5b5dabd6e1388ee3388ee3388ee3388e +e3387e993cb8afab5c06c7711cc7711cc7711cc7711cc7711cc771fc34fc805c66f77c46e7711cc7 +711cc7711cc7711cc7711cc7711cc747c1b8ae72191cc7711cc7711cc7711cc7711cc7711cc7f1d3 +f0037299edf98ccee3388ee3388ee3388ee3388ee3388ee3388ecf2e415157b90c8ee3388ee3388e +e3388ee3388ee3388ee3f869f801b9ccfa7c46e7711cc7711cc7711cc7711cc7711cc7711cc75f5c +f6c865826cb1ea3c8ee3388ee3388ee3388ee3388ee3388ee37887cb865c264837579dc7711cc771 +1cc7711cc7711cc7711cc7711cef700992f93ae18b93b6579dc7711cc7711cc7711cc7711cc7711c +c7711cef7091cbe0388ee3388ee3388ee3388ee3388ee3388e9f8607f18cd757bb579dc7711cc771 +1cc7711cc7711cc7711cc7711cefc683a8bed1b56a1d8ee3388ee3388ee3388ee3388ee3388ee378 +371e84f58dee55e7711cc7711cc7711cc7711cc7711cc7711cc7f7e141d0b56a1d8ee3388ee3388e +e3388ee3388ee3388ee3f83e5c2e83e3388ee3388ee3388ee3388ee3388ee3387e1a1e74ae331ee8 +3c8ee3388ee3388ee3388ee3388ee3388ee3f81efc69d7daf227adc3711cc7711cc7711cc7711cc7 +711cc7711cefce1f77ad2d5fbe4be7711cc7711cc7711cc7711cc7711cc7711cc73bf0876db5e5cb +77e93c8ee3388ee3388ee3388ee3388ee3388ee378072e97c1711cc7711cc7711cc7711cc7711cc7 +711c3f2dbf5f575bbe6e169dc7711cc7711cc7711cc7711cc7711cc7711cefc0efd6d596af9b45e7 +711cc7711cc7711cc7711cc7711cc7711cc73bf0f1badaf2f196aaf3388ee3388ee3388ee3388ee3 +388ee3388ee31de62e966bcb8b2d55e7711cc7711cc7711cc7711cc7711cc7711cc73bcc2d97c171 +1cc7711cc7711cc7711cc7711cc7711c3f0dcf976bcbf32db5d0791cc7711cc7711cc7711cc7711c +c7711cc7f1ee976c5a5b9e6da9b9d6e1388ee3388ee3388ee3388ee3388ee3388e77bfa4d3daf274 +4bcdb40ec7711cc7711cc7711cc7711cc7711cc7717cff4bd2f2644b5dce69741ec7711cc7711cc7 +711cc7711cc7711cc771bcc3a5432eb35c751ec7711cc7711cc7711cc7711cc7711cc771bcc3256e +79bca5ca65701cc7711cc7711cc7711cc7711cc7711cc7fbe1d196ba32afd13a1cc7711cc7711cc7 +711cc7711cc7711cc7f1ce3cdc5257e6355a87e3388ee3388ee3388ee3388ee3388ee338de99075b +eacabc46eb701cc7711cc7711cc7711cc7711cc7711cc77be72bf39a9a075a87e3388ee3388ee338 +8ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388e +e3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3 +388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee338 +8ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388e +e3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3 +388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee338 +8ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388e +e3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3 +388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee338 +8ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388e +e3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3 +388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee338 +8ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388e +e3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3 +388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee338 +8ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388e +e3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3 +388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee338 +8ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388e +e3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3 +388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee338 +8ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388e +e3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3 +388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee338 +8ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388e +e3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3 +388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee338 +8ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388e +e3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3 +388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee338 +8ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388e +e3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3 +388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee338 +8ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388e +e3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3 +388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee338 +8ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388e +e3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3 +388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee338 +8ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388e +e3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3 +388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee338 +8ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388e +e3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3 +388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee338 +8ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388e +e3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3 +388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee338 +8ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388e +e3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3 +388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee338 +8ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388e +e3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3 +388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee338 +8ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388e +e3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3 +388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee338 +8ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388e +e3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3 +388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee338 +8ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388e +e3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3 +388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee338 +8ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388e +e3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3 +388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee338 +8ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388e +e3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3 +388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee338 +8ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388e +e3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3 +388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee338 +8ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388e +e3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3 +388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee338 +8ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388e +e3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3 +388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee338 +8ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388e +e3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3 +388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee338 +8ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388e +e3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3 +388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee338 +8ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388e +e3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3 +388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee338 +8ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388e +e3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3 +388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee338 +8ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388e +e3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3 +388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee338 +8ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388e +e3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3 +388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee338 +8ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388e +e3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3 +388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee338 +8ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388e +e3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3 +388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee338 +8ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388e +e3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3 +388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee338 +8ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388e +e3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3 +388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee338 +8ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388e +e3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3 +388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee338 +8ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388e +e3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3 +388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee338 +8ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388e +e3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3 +388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee338 +8ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388e +e3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3 +388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee338 +8ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388e +e3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3 +388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee338 +8ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388e +e3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3 +388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee338 +8ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388e +e3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3 +388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee338 +8ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388e +e3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3388ee3 +388ee3388ee3388ee3388ee3388ee3388ee3388ee3ffbfbdbb696de38ac200bc17e83f68d3652814 +da7dfa116208fda28beecc341994806219494deb7fdf51a16ddc48a31979a4b967cee38d88adc727 +e89e49162fe71e1cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc771 +1cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711c +c7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7 +711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc771 +1cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711c +c7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7 +711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc771 +1cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711c +c7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7 +711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc771 +1cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711c +c7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7 +711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc771 +1cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711c +c7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7 +711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc771 +1cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711c +c7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7 +711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc771 +1cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711c +c7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7 +711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc771 +1cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711c +c7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7 +711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc771 +1cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711c +c7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7 +711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc771 +1cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711c +c7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7 +711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc771 +1cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711c +c7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7 +711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc771 +1cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711c +c7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7 +711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc771 +1cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711c +c7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7 +711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc771 +1cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711c +c7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7 +711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc771 +1cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711c +c7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7 +711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc771 +1cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711c +c7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7 +711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc771 +1cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711c +c7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7 +711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc771 +1cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711c +c7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7 +711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc771 +1cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711c +c7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7 +711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc771 +1cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711c +c7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7 +711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc771 +1cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711c +c7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7 +711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc771 +1cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711c +c7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7 +711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc771 +1cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711c +c7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7 +711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc771 +1cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711c +c7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7 +711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc771 +1cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711c +c7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7 +711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc771 +1cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711c +c7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7 +711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc771 +1cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711c +c7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7 +711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc771 +1cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711c +c7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7 +711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc771 +1cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711c +c7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7 +711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc771 +1cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711c +c7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7 +711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc771 +1cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711c +c7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7 +711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc771 +1cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711c +c7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7 +711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc771 +1cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711c +c7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7 +711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc771 +1cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711c +c7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7 +711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc771 +1cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711c +c7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7 +711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc771 +1cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711c +c7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7 +711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc771 +1cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711c +c7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7 +711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc771 +1cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711c +c7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7 +711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc771 +1cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711c +c7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7 +711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc771 +1cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711c +c7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7 +711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc771 +1cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711c +c7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7 +711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc771 +1cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711c +c7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7 +711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc771 +1cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711c +c7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7 +711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc771 +1cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711c +c7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7 +711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc771 +1cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711c +c7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7 +711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc771 +1cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711c +c7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7 +711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc771 +1cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711c +c7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7 +711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc771 +1cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711c +c7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7 +711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc771 +1cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711c +c7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7 +711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc771 +1cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711c +c7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7 +711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc771 +1cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711c +c7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7 +711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc771 +1cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711c +c7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7 +711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc771 +1cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711c +c7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7 +711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7711cc7f150fcc58bc7af +3e3a1cc7711cc7711cc7711cc7711cc7711cc7f1cbf0ffe732c75e7d74388ee3388ee3388ee3388e +e3388ee3388ee34fe35d7399c7af7ff37e23363e791cc7711cc7711cc7711cc7711cc7711cc793f3 +0172997ea3363e791cc7711cc7711cc7711cc7711cc7711cc793f22be4329fbefae4711cc7711cc7 +711cc7711cc7711cc7711c4fc8c7cd65ba8fd838381cc7711cc7711cc7711cc7711cc7711cc7a3f3 +327399f6bcc6c1e1388ee3388ee3388ee3388ee3388ee3383e055e762ed3a1ba73c7711cc7711cc7 +711cc7711cc7711cc7713c380f93cb9cce6b9c3b8ee3388ee3388ee3388ee3388ee3388ee351798c +5ca6a5ba73c7711cc7711cc7711cc7711cc7711cc7713c380f93cbf4bb12cdb9e3388ee3388ee338 +8ee3388ee3388ee3381e8687c9653a5477ee388ee3388ee3388ee3388ee3388ee3388e07e5e17299 +7ea336ce1dc7711cc7711cc7711cc7711cc7711cc7f1303c4c2e733caf71ee388ee3388ee3388ee3 +388ee3388ee3388e47e73172990ed59d3b8ee3388ee3388ee3388ee3388ee3388ee34179b85ca63d +af71ee388ee3388ee3388ee3388ee3388ee3388e47e4b1729996eace1dc7711cc7711cc7711cc771 +1cc7711cc7f1e03c4c2ed36dd4c6b9e3388ee3388ee3388ee3388ee3388ee3381e91c7ca655aaa3b +771cc7711cc7711cc7711cc7711cc7711cc783f270b94cf7511be78ee3388ee3388ee3388ee3388e +e3388ee378281e2e9769a9eedc711cc7711cc7711cc7711cc7711cc7711c0fcac3e532fd466d9c3b +8ee3388ee3388ee3388ee3388ee3388ee36178b85ca6a5ba73c7711cc7711cc7711cc7711cc7711c +c7713c280f97cbf41fb571ee388ee3388ee3388ee3388ee3388ee3388e17cdc3e6322dd59d3b8ee3 +388ee3388ee3388ee3388ee3388ee34179b85ce6bc511be78ee3388ee3388ee3388ee3388ee3388e +e378b13c6c2e63bb0d8ee3388ee3388ee3388ee3388ee3388ee3d3e3617399fea336ce1dc7711cc7 +711cc7711cc7711cc7711cc7f12279d85cc6761b1cc7711cc7711cc7711cc7711cc7711cc7a7c7c3 +e632b6dbe0388ee3388ee3388ee3388ee3388ee3383e111e3e97399ed738771cc7711cc7711cc771 +1cc7711cc7711cc7a3f198b98ced36388ee3388ee3388ee3388ee3388ee3388e4f8fdb6ea36d701c +c7711cc7711cc7711cc7711cc7711c1f974f2197396fd446dbe0388ee3388ee3388ee3388ee3388e +e3385e1cb7dd46dbe0388ee3388ee3388ee3388ee3388ee3383e2e0f9fcbd86e83e3388ee3388ee3 +388ee3388ee3388ee3f87478f85cc6761b1cc7711cc7711cc7711cc7711cc7711cc727c2a7bcdde6 +f4c88db6c1711cc7711cc7711cc7711cc7711cc771bc283ed9ed361f5577ee388ee3388ee3388ee3 +388ee3388ee3388e97cc336cb7691fb9d136388ee3388ee3388ee3388ee3388ee3388e17c3336cb7 +397d5b9ab6c1711cc7711cc7711cc7711cc7711cc7717c7c9e61bbcdf1dc46dbe0388ee3388ee338 +8ee3388ee3388ee3385e14cfb0dde6bc911b6d83e3388ee3388ee3388ee3388ee3388ee3f8d5f9e4 +b7db1cce6db40d8ee3388ee3388ee3388ee3388ee3388ee3c5f04cdb6dfa8fdc681b1cc7711cc771 +1cc7711cc7711cc7711cc7afc7336db7f934b7d136388ee3388ee3388ee3388ee3388ee3388e17c5 +336db7e93772a36d701cc7711cc7711cc7711cc7711cc7711cbf3a4fb3dde6716ea36d701cc7711c +c7711cc7711cc7711cc7711c2f8e67da6ed37de446dbe0388ee3388ee3388ee3388ee3388ee3383e +0a4fb3dde640756d83e3388ee3388ee3388ee3388ee3388ee378493cd3769b6ea337da06c7711cc7 +711cc7711cc7711cc7711cc7f1d1789aed3607aa6b1b1cc7711cc7711cc7711cc7711cc7711cc74b +e419b6db9c1ebdd136388ee3388ee3388ee3388ee3388ee3388e17c1336db7e9766b9ab6c1711cc7 +711cc7711cc7711cc7711cc7717c1c9e69bbcde1dc46dbe0388ee3388ee3388ee3388ee3388ee338 +5e0ccfb4dde6f4ad69da06c7711cc7711cc7711cc7711cc7711cc7f1f178c6ed3607aa6b1b1cc771 +1cc7711cc7711cc7711cc7711cc74be299b6db741bbdd136388ee3388ee3388ee3388ee3388ee338 +8e8fc6d36cb769a9ae6d701cc7711cc7711cc7711cc7711cc7711c2f8167dc6e737cf446dbe0388e +e3388ee3388ee3388ee3388ee3385e04cfb4dda6dfed69da06c7711cc7711cc7711cc7711cc7711c +c7f1ebf28cdb6d5aaa6b1b1cc7711cc7711cc7711cc7711cc7711cc74be099b6db741fbdd136388e +e3388ee3388ee3388ee3388ee3388e8fc2d36db7e9505ddbe0388ee3388ee3388ee3388ee3388ee3 +383e26cfb8ddc62d6a388ee3388ee3388ee3388ee3388ee3388e17ca33e6326e51c3711cc7711cc7 +711cc7711cc7711cc771bc649e3197718b1a8ee3388ee3388ee3388ee3388ee3388ee385f2ccb98c +5bd4701cc7711cc7711cc7711cc7711cc7711c2f9467ce65dca286e3388ee3388ee3388ee3388ee3 +388ee378893c732ee316351cc7711cc7711cc7711cc7711cc7711cc70be56e51738b1a8ee3388ee3 +388ee3388ee3388ee3388ee3c571b7a8b9450dc7711cc7711cc7711cc7711cc7711cc7f1b2b85bd4 +dca286e3388ee3388ee3388ee3388ee3388ee378315c2e7356755d87e3388ee3388ee3388ee3388e +e3388ee3f825b95ce69cdbd4741d8ee3388ee3388ee3388ee3388ee3388ee397e77299b3aaeb3a1c +c7711cc7711cc7711cc7711cc7711cc72fc9e5326755d775388ee3388ee3388ee3388ee3388ee338 +8e5f92cb659e545dd7e1388ee3388ee3388ee3388ee3388ee3383e3897cb0c555dd7e1388ee3388e +e3388ee3388ee3388ee3383e1897cb0c5a5dd7e1388ee3388ee3388ee3388ee3388ee3383e2497cb +0c525dd7e1388ee3388ee3388ee3388ee3388ee3383e1897cb0c5d5dd7e1388ee3388ee3388ee338 +8ee3388ee3383e1897cb5caabaaec3711cc7711cc7711cc7711cc7711cc771fc6c2e97b974755d87 +e3388ee3388ee3388ee3388ee3388ee3f8d95c2e73d1eaba0ec7711cc7711cc7711cc7711cc7711c +c7f1a770b9cc55aaeb3a1cc7711cc7711cc7711cc7711cc7711cc77b7fc965ae555dd7e1388ee338 +8ee3388ee3388ee3388ee338de9bcb65ae5d5dd7e1388ee3388ee3388ee3388ee3388ee338de99cb +65ae5d5dd7e1388ee3388ee3388ee3388ee3388ee338de99cb65c6aaae69711cc7711cc7711cc771 +1cc7711cc7711c3fc9e5326357d7b4388ee3388ee3388ee3388ee3388ee3388e1ffe92cb98d6c171 +1cc7711cc7711cc7711cc7711cc771bc782e9731ad83e3388ee3388ee3388ee3388ee3388ee378b1 +5c2e635a07c7711cc7711cc7711cc7711cc7711cc7f1e2b95cc6b40e8ee3388ee3388ee3388ee338 +8ee3388ee3c573b98c691d1cc7711cc7711cc7711cc7711cc7711cc78be77299c0d5f53c8ee3388e +e3388ee3388ee3388ee3388e67e192910954d7f3388ee3388ee3388ee3388ee3388ee3383e752e19 +9960753d8fe3388ee3388ee3388ee3388ee3388ee353e3929104d5f53c8ee3388ee3388ee3388ee3 +388ee3388e4f854b467256f7c8e0388ee3388ee3388ee3388ee3388ee378482e19c95ddd2383e338 +8ee3388ee3388ee3388ee3388ee3a1b86444f543af1e191cc7711cc7711cc7711cc7711cc7711c2f +924b4654ef59dd1387e3388ee3388ee3388ee3388ee3388ee3e373c988ea4facee89c3711cc7711c +c7711cc7711cc7711cc7f1eb73c988ea36fbe0388ee3388ee3388ee3388ee3388ee378442e9b507d +fcea1e581cc7711cc7711cc7711cc7711cc7711cefc96513aa87aaee79c7711cc7711cc7711cc771 +1cc7711cc7f18fbf6413aa4fbdbae71dc7711cc7711cc7711cc7711cc7711ccfc1a503aaabdefeea +9f0b1cc7f144fcb3efeede7c5bedaaf9ecd797cd1f9fdf7c79db7ce7e76abbab37f3d9f7f3d94ff3 +d9abaffffbc9abeaa1de3c7bb6973f56cbfa974df56eb57fe7725b7da817d5dddd7a57edeafbe647 +8be5a6deeed69b7ab17dbbfe63ff9d3dfa173c7fb3feadbebd59ad7edfee3655f3bedba6c2e2f3a6 +ecfb7777cdaf582cebdda2feb37efdcf5bbf59afd69b9bf7cdef69def955db3b770ff7ebe5a6ba7f +fb70ea77bedeffd5dadeb0aa3fd4ab2f8eff9ae6f3fba1f9cf7a3efb0b7c5a3962> +endstream +endobj +5 0 obj +<< +/Filter [/ASCII85Decode /FlateDecode ] +/Length 34 +>> +stream +GhOt'1B7FZ"#S^CKb'rAF*Y:rk'%+Q~> +endstream +endobj +2 0 obj +<< +/Type /Pages +/Kids [4 0 R] +/Count 1 +>> +endobj +1 0 obj +<< +/Type /Catalog +/Pages 2 0 R +/OCProperties<< /D<< /Order[]/ON[]/OFF[]/RBGroups[]>>/OCGs[]>> +>> +endobj +3 0 obj +<< +/CreationDate +/ModDate +/Producer +/Creator +/Title +>> +endobj +xref +0 9 +0000000000 65535 f +0000053966 00000 n +0000053902 00000 n +0000054085 00000 n +0000000010 00000 n +0000053772 00000 n +0000000291 00000 n +0000000331 00000 n +0000000467 00000 n +trailer +<< +/Size 9 +/Root 1 0 R +/Info 3 0 R +/ID [<9d32286e24df501f4a2e9b23eeae29ff><9d32286e24df501f4a2e9b23eeae29ff>] +>> +startxref +54555 +%%EOF \ No newline at end of file diff --git a/img/favicon/favicon.cdr b/img/favicon/favicon.cdr new file mode 100644 index 00000000..c8327d3b Binary files /dev/null and b/img/favicon/favicon.cdr differ diff --git a/img/favicon/favicon.eps b/img/favicon/favicon.eps new file mode 100644 index 00000000..98264072 Binary files /dev/null and b/img/favicon/favicon.eps differ diff --git a/img/favicon/favicon.png b/img/favicon/favicon.png new file mode 100644 index 00000000..cbfaddc3 Binary files /dev/null and b/img/favicon/favicon.png differ diff --git a/json/config.json b/json/config.json index 5f9fc6cf..b012c13a 100644 --- a/json/config.json +++ b/json/config.json @@ -12,9 +12,9 @@ "show_keys_panel" : true, "server" : true, "socket" : true, - "port" : 80, - "sslPort" : 443, + "port" : 8000, + "sslPort" : 4430, "ip" : null, "ssl" : false, "rest" : true -} \ No newline at end of file +} diff --git a/json/modules.json b/json/modules.json index 28b5e6db..64732a08 100644 --- a/json/modules.json +++ b/json/modules.json @@ -1,8 +1,9 @@ [ - "editor/_codemirror", + "edit", "menu", - "viewer", - "terminal", { + "view", + "help", + "console", { "name": "storage", "data": [{ "name": "DropBox", diff --git a/lib/README.md b/lib/README.md deleted file mode 100644 index a741f80c..00000000 --- a/lib/README.md +++ /dev/null @@ -1,5 +0,0 @@ -Cloud Commander Libraries -=============== -**Cloud Commander Libraries** - dir thet contains scripts, thet uses -on client and server side, and modules, wich is not necessary -for CloudCommander work, but they adds some sugor. \ No newline at end of file diff --git a/lib/client.js b/lib/client.js index 02d244c3..ab3e4568 100644 --- a/lib/client.js +++ b/lib/client.js @@ -1,53 +1,21 @@ -/* Функция которая возвратит обьект CloudCommander +/* Функция которая возвратит обьект CloudCmd * @CloudFunc - обьект содержащий общий функционал * клиентский и серверный */ -var Util, DOM, CloudFunc, $, KeyBinding, CloudCommander; +var Util, DOM, CloudFunc, CloudCmd; (function(Util, DOM){ 'use strict'; - var Config, Modules, FileTemplate, PathTemplate; + var Key, Config, Modules, FileTemplate, PathTemplate, + Events = DOM.Events, + Cache = DOM.Cache; - /* Клиентский обьект, содержащий функциональную часть*/ - var CloudCmd = { - /* Конструктор CloudClient, который выполняет - * весь функционал по инициализации - */ - init : null, /* start initialization */ - - KeyBinding : null, /* обьект обработки нажатий клавишь */ - KeysPanel : null, /* panel with key buttons f1-f8 */ - Editor : null, /* function loads and shows editor */ - Storage : null, /* function loads storage */ - Viewer : null, /* function loads and shows viewer */ - Terminal : null, /* function loads and shows terminal*/ - Menu : null, /* function loads and shows menu */ - GoogleAnalytics : null, - - loadDir : null, /* Функция привязываеться ко всем ссылкам и - * загружает содержимое каталогов */ - - /* ОБЬЕКТЫ */ - - /* ПРИВАТНЫЕ ФУНКЦИИ */ - /* функция загружает json-данные о файловой системе */ - _ajaxLoad : null, - - /* Функция генерирует JSON из html-таблицы файлов */ - _getJSONfromFileTable : null, - - /* функция меняет ссыки на ajax-овые */ - _changeLinks : null, - - /* КОНСТАНТЫ*/ + CloudCmd = { LIBDIR : '/lib/', LIBDIRCLIENT : '/lib/client/', JSONDIR : '/json/', HTMLDIR : '/html/', - /* height of Cloud Commander - * seting up in init() - */ HEIGHT : 0, MIN_ONE_PANEL_WIDTH : 1155, OLD_BROWSER : false, @@ -59,7 +27,7 @@ var Util, DOM, CloudFunc, $, KeyBinding, CloudCommander; }; CloudCmd.GoogleAnalytics = function(){ - DOM.addOneTimeListener('mousemove', function(){ + Events.addOneTime('mousemove', function(){ var lUrl = CloudCmd.LIBDIRCLIENT + 'google_analytics.js'; setTimeout(function(){ @@ -90,7 +58,7 @@ var Util, DOM, CloudFunc, $, KeyBinding, CloudCommander; DOM.Images.showLoad(pNeedRefresh ? {top:true} : null); /* загружаем содержимое каталога */ - CloudCmd._ajaxLoad(lLink, { refresh: pNeedRefresh }); + ajaxLoad(lLink, { refresh: pNeedRefresh }); } DOM.preventDefault(pEvent); @@ -99,38 +67,12 @@ var Util, DOM, CloudFunc, $, KeyBinding, CloudCommander; /** - * Function edits file name - * - * @param pParent - parent element - * @param pEvent - */ - CloudCmd._editFileName = function(pParent){ - var lA = DOM.getCurrentLink(pParent), - lName = DOM.getCurrentName(); - - if ( lName !== '..' ){ - - lA.contentEditable = true; - KeyBinding && KeyBinding.unSet(); - - /* setting event handler onclick - * if user clicks somewhere keyBinded - * backs - */ - DOM.addOneTimeListener('click', function(){ - //lA.contentEditable = false; - //KeyBinding && KeyBinding.set(); - }); - } - }; - - - /** функция устанавливает курсор на каталог + * функция устанавливает курсор на каталог * с которого мы пришли, если мы поднялись * в верх по файловой структуре * @param pDirName - имя каталога с которого мы пришли */ - CloudCmd._currentToParent = function(pDirName){ + function currentToParent(pDirName){ /* убираем слэш с имени каталога */ pDirName = Util.removeStr(pDirName, '/'); @@ -145,7 +87,7 @@ var Util, DOM, CloudFunc, $, KeyBinding, CloudCommander; DOM.setCurrentFile(lRootDir); DOM.scrollIntoViewIfNeeded(lRootDir, true); } - }; + } /** * function load modules @@ -186,6 +128,7 @@ var Util, DOM, CloudFunc, $, KeyBinding, CloudCommander; }; } } + /** Конструктор CloudClient, который * выполняет весь функционал по * инициализации @@ -200,44 +143,54 @@ var Util, DOM, CloudFunc, $, KeyBinding, CloudCommander; }, lFunc = function(pCallBack){ CloudCmd.OLD_BROWSER = true; - var lSrc = CloudCmd.LIBDIRCLIENT + 'ie.js'; + var lSrc = CloudCmd.LIBDIRCLIENT + 'polyfill.js'; DOM.jqueryLoad( DOM.retJSLoad(lSrc, pCallBack) ); }; - - //Util.socketLoad(); Util.ifExec(document.body.scrollIntoViewIfNeeded, lCallBack, lFunc); + + DOM.Events.add(['unload', 'beforeunload'], function (pEvent) { + var lRet, lIsBind = Key.isBind(); + + if(!lIsBind) { + DOM.preventDefault(pEvent); + lRet = 'Please make sure that you saved all work.'; + } + + return lRet; + }); }; function initModules(pCallBack){ loadModule({ /* привязываем клавиши к функциям */ - path : 'keyBinding.js', + path : 'key.js', func : function(){ - KeyBinding = CloudCmd.KeyBinding; - KeyBinding.init(); + Key = CloudCmd.Key; + Key.bind(); } }); - CloudCmd.getModules(function(pModules){ + CloudCmd.getModules(function(pModules) { pModules = pModules || []; - DOM.addContextMenuListener(function(pEvent){ + Events.addContextMenu(function(pEvent){ CloudCmd.Menu.ENABLED || DOM.preventDefault(pEvent); }, document); - var lStorage = 'storage', - lShowLoadFunc = Util.retFunc( DOM.Images.showLoad ), + var i, n, lStorage = 'storage', + lShowLoadFunc = Util.retFunc( DOM.Images.showLoad, {top:true} ), lDoBefore = { - 'editor/_codemirror' : lShowLoadFunc, - 'viewer' : lShowLoadFunc + 'edit' : lShowLoadFunc, + 'view' : lShowLoadFunc, + 'menu' : lShowLoadFunc }, - lLoad = function(pName, pPath, pDoBefore){ + lLoad = function(pName, pPath, pDoBefore) { loadModule({ path : pPath, name : pName, @@ -245,7 +198,7 @@ var Util, DOM, CloudFunc, $, KeyBinding, CloudCommander; }); }; - for(var i = 0, n = pModules.length; i < n ; i++){ + for (i = 0, n = pModules.length; i < n ; i++) { var lModule = pModules[i]; if( Util.isString(lModule) ) @@ -255,7 +208,7 @@ var Util, DOM, CloudFunc, $, KeyBinding, CloudCommander; var lStorageObj = Util.findObjByNameInArr( pModules, lStorage ), lMod = Util.getNamesFromObjArray( lStorageObj ); - for(i = 0, n = lMod.length; i < n; i++){ + for (i = 0, n = lMod.length; i < n; i++){ var lName = lMod[i], lPath = lStorage + '/_' + lName.toLowerCase(); @@ -269,30 +222,38 @@ var Util, DOM, CloudFunc, $, KeyBinding, CloudCommander; } function initKeysPanel(pCallBack){ - var lKeysPanel = {}, + var i, lButton, lEl, + lKeysPanel = {}, lFuncs =[ null, - null, /* f1 */ + CloudCmd.Help, /* f1 */ DOM.renameCurrent, /* f2 */ - CloudCmd.Viewer, /* f3 */ - CloudCmd.Editor, /* f4 */ + CloudCmd.View, /* f3 */ + CloudCmd.Edit, /* f4 */ DOM.copyCurrent, /* f5 */ DOM.moveCurrent, /* f6 */ DOM.promptNewDir, /* f7 */ DOM.promptDeleteSelected, /* f8 */ + CloudCmd.Menu, /* f9 */ ]; - for(var i = 1; i <= 8; i++){ - var lButton = 'f' + i, - lEl = DOM.getById('f' + i); - if( i === 3 || i === 4) - DOM.addOneTimeListener('click', lFuncs[i], lEl); - else - DOM.addClickListener(lFuncs[i], lEl); + for (i = 1; i <= 9; i++) { + lButton = 'f' + i, + lEl = DOM.getById('f' + i); lKeysPanel[lButton] = lEl; + + if (i === 1 || i === 3 || i === 4 || i === 9) + Events.addOneTime('click', lFuncs[i], lEl); + else + Events.addClick(lFuncs[i], lEl); } + lButton = '~', + lEl = DOM.getById('~'); + lKeysPanel[lButton] = lEl; + Events.addOneTime('click', CloudCmd.Console, lEl); + CloudCmd.KeysPanel = lKeysPanel; Util.exec(pCallBack); } @@ -311,25 +272,24 @@ var Util, DOM, CloudFunc, $, KeyBinding, CloudCommander; /* загружаем общие функции для клиента и сервера */ DOM.jsload(CloudCmd.LIBDIR + 'cloudfunc.js', function(){ - DOM.addListener("popstate", function(pEvent) { + Events.add("popstate", function(pEvent) { var lPath = pEvent.state + '?json'; if(lPath) - CloudCmd._ajaxLoad(lPath, {nohistory: true}); + ajaxLoad(lPath, {nohistory: true}); return true; }); - /* меняем ссылки на ajax'овые */ - CloudCmd._changeLinks(CloudFunc.LEFTPANEL); - CloudCmd._changeLinks(CloudFunc.RIGHTPANEL); + changeLinks(CloudFunc.LEFTPANEL); + changeLinks(CloudFunc.RIGHTPANEL); /* устанавливаем переменную доступности кэша */ - DOM.Cache.setAllowed(true); + Cache.setAllowed(true); /* Устанавливаем кэш корневого каталога */ var lDirPath = DOM.getCurrentDirPath(); - if( !DOM.Cache.get(lDirPath) ) - DOM.Cache.set(lDirPath, CloudCmd._getJSONfromFileTable()); + if( !Cache.get(lDirPath) ) + Cache.set(lDirPath, getJSONfromFileTable()); }); /* выделяем строку с первым файлом */ @@ -367,7 +327,7 @@ var Util, DOM, CloudFunc, $, KeyBinding, CloudCommander; }); Util.exec(pCallBack); - CloudCmd.KeyBinding(); + CloudCmd.Key(); } @@ -410,11 +370,14 @@ var Util, DOM, CloudFunc, $, KeyBinding, CloudCommander; }; - /* функция меняет ссыки на ajax-овые */ - CloudCmd._changeLinks = function(pPanelID){ + /** + * функция меняет ссыки на ajax-овые + * @param pPanelID + */ + function changeLinks(pPanelID){ /* назначаем кнопку очистить кэш и показываем её */ var lClearcache = DOM.getById('clear-cache'); - DOM.addClickListener(DOM.Cache.clear, lClearcache); + Events.addClick(Cache.clear, lClearcache); /* меняем ссылки на ajax-запросы */ var lPanel = DOM.getById(pPanelID), @@ -424,7 +387,7 @@ var Util, DOM, CloudFunc, $, KeyBinding, CloudCommander; lOnContextMenu_f = function(pEvent){ var lReturn_b = true; - KeyBinding && KeyBinding.unSet(); + Key && Key.unsetBind(); /* getting html element * currentTarget - DOM event @@ -495,7 +458,7 @@ var Util, DOM, CloudFunc, $, KeyBinding, CloudCommander; }; /* ставим загрузку гифа на клик*/ - DOM.addClickListener( CloudCmd.refresh, a[0].parentElement ); + Events.addClick( CloudCmd.refresh, a[0].parentElement ); /* start from 1 cous 0 is a path and it's setted up */ for(var i = 1, n = a.length; i < n ; i++){ @@ -509,27 +472,29 @@ var Util, DOM, CloudFunc, $, KeyBinding, CloudCommander; /* if we in path - set click event */ if (lLi.className === 'path') - DOM.addClickListener( lLoadDir, ai ); + Events.addClick( lLoadDir, ai ); else { - DOM.addClickListener( DOM.preventDefault, lLi); - DOM.addListener('mousedown', lSetCurrentFile_f, lLi); - DOM.addListener('dragstart', lOnDragStart_f, ai); - /* if right button clicked menu will - * loads and shows - */ - DOM.addListener('contextmenu', lOnContextMenu_f, lLi); + Events.add({ + 'click' : DOM.preventDefault, + 'mousedown' : lSetCurrentFile_f, + 'contextmenu' : lOnContextMenu_f + }, lLi); + + Events.add('dragstart', lOnDragStart_f, ai); /* если ссылка на папку, а не файл */ if(ai.target !== '_blank'){ - DOM.addListener('dblclick', lLoadDirOnce, lLi); - DOM.addListener('touchend', lLoadDirOnce, lLi); + Events.add({ + 'dblclick' : lLoadDirOnce, + 'touchend' : lLoadDirOnce + }, lLi); } lLi.id = (ai.title ? ai.title : ai.textContent) + '(' + pPanelID + ')'; } } - }; + } /** * Функция загружает json-данные о Файловой Системе @@ -538,7 +503,7 @@ var Util, DOM, CloudFunc, $, KeyBinding, CloudCommander; * @param pOptions * { refresh, nohistory } - необходимость обновить данные о каталоге */ - CloudCmd._ajaxLoad = function(pPath, pOptions){ + function ajaxLoad(pPath, pOptions){ if(!pOptions) pOptions = {}; @@ -570,12 +535,11 @@ var Util, DOM, CloudFunc, $, KeyBinding, CloudCommander; */ var lRet = pOptions.refresh; if(!lRet){ - var lJSON = DOM.Cache.get(lCleanPath); + var lJSON = Cache.get(lCleanPath); if (lJSON){ - /* переводим из текста в JSON */ lJSON = Util.parseJSON(lJSON); - CloudCmd._createFileTable(lPanel, lJSON); + createFileTable(lPanel, lJSON); } else lRet = true; @@ -590,7 +554,7 @@ var Util, DOM, CloudFunc, $, KeyBinding, CloudCommander; }, success : function(pData){ - CloudCmd._createFileTable(lPanel, pData); + createFileTable(lPanel, pData); /* переводим таблицу файлов в строку, для * * сохранения в localStorage */ @@ -600,27 +564,25 @@ var Util, DOM, CloudFunc, $, KeyBinding, CloudCommander; /* если размер данных не очень бошьой * * сохраняем их в кэше */ if(lJSON_s.length < 50000 ) - DOM.Cache.set(lCleanPath, lJSON_s); + Cache.set(lCleanPath, lJSON_s); } }); - }; + } /** * Функция строит файловую таблицу * @param pEleme - родительский элемент * @param pJSON - данные о файлах */ - CloudCmd._createFileTable = function(pElem, pJSON){ + function createFileTable(pElem, pJSON){ var lElem = DOM.getById(pElem), /* getting current element if was refresh */ lPath = DOM.getByClass('path', lElem), lCurrent = DOM.getCurrentFile(), - lCurrentLink = DOM.getCurrentLink(lCurrent), - lParent = lCurrentLink.textContent, lDir = DOM.getCurrentDirName(), - lName = DOM.getCurrentName(lName), + lName = DOM.getCurrentName(lCurrent), lWasRefresh_b = lPath[0].textContent === pJSON[0].path; CloudCmd.getFileTemplate(function(pTemplate){ @@ -655,19 +617,19 @@ var Util, DOM, CloudFunc, $, KeyBinding, CloudCommander; DOM.setCurrentFile(lCurrent); - CloudCmd._changeLinks(pElem); + changeLinks(pElem); - if(lParent === '..' && lDir !== '/') - CloudCmd._currentToParent(lDir); + if(lName === '..' && lDir !== '/') + currentToParent(lDir); }); }); - }; + } /** * Функция генерирует JSON из html-таблицы файлов и * используеться при первом заходе в корень */ - CloudCmd._getJSONfromFileTable = function(){ + function getJSONfromFileTable(){ var lLeft = DOM.getById('left'), lPath = DOM.getByClass('path')[0].textContent, @@ -676,7 +638,7 @@ var Util, DOM, CloudFunc, $, KeyBinding, CloudCommander; size : 'dir' }], - lLI = lLeft.getElementsByTagName('li'), + lLI = DOM.getByTag('li', lLeft), i, n, j = 1; /* счётчик реальных файлов */ /* счётчик элементов файлов в DOM @@ -690,9 +652,7 @@ var Util, DOM, CloudFunc, $, KeyBinding, CloudCommander; var lCurrent = lLI[i], lName = DOM.getCurrentName(lCurrent), lSize = DOM.getCurrentSize(lCurrent), - /* переводим права доступа в цыфровой вид - * для хранения в localStorage - */ + lMode = DOM.getCurrentMode(lCurrent); lMode = CloudFunc.getNumericPermissions(lMode); @@ -704,11 +664,9 @@ var Util, DOM, CloudFunc, $, KeyBinding, CloudCommander; }; } return Util.stringifyJSON(lFileTable); - }; + } - CloudCommander = CloudCmd; - - DOM.addOneTimeListener('load', function(){ + Events.addOneTime('load', function(){ /* базовая инициализация*/ CloudCmd.init(); diff --git a/lib/client/config.js b/lib/client/config.js deleted file mode 100644 index e86b5596..00000000 --- a/lib/client/config.js +++ /dev/null @@ -1,28 +0,0 @@ -/* gui module for config.json editing */ -var CloudCommander; - -(function(){ - "use strict"; - - var cloudcmd = CloudCommander; - - var Config = {}; - - Config.Show = (function(){ - console.log('config showed'); - - var lFancyBox = cloudcmd.Viewer.FancyBox; - lFancyBox.loadData({hreef: 'htlm/config.html'}, - lFancyBox.onDataLoaded); - }); - - Config.Keys = function(){ - console.log('config.js loaded'); - cloudcmd.Viewer(function(){ - Config.Show(); - }); - }; - - cloudcmd.Config = Config; - -})(); \ No newline at end of file diff --git a/lib/client/console.js b/lib/client/console.js new file mode 100644 index 00000000..32d6a744 --- /dev/null +++ b/lib/client/console.js @@ -0,0 +1,164 @@ +var CloudCmd, Util, DOM, $; +(function(CloudCmd, Util, DOM){ + 'use strict'; + + CloudCmd.Console = new ConsoleProto(CloudCmd, Util, DOM); + + function ConsoleProto(CloudCmd, Util, DOM){ + var Name = 'Console', + jqconsole, + Element, + MouseBinded, + Key = CloudCmd.Key, + Images = DOM.Images, + Console = this; + + this.init = function(pCallBack) { + var lFunc, lIsFunc = Util.isFunction(CloudCmd.View); + + if (lIsFunc) + lFunc = CloudCmd.View; + else + lFunc = Util.exec; + + Util.loadOnLoad([ + Console.show, + load, + lFunc, + DOM.jqueryLoad, + DOM.socketLoad + ]); + + DOM.Events.addKey(listener); + DOM.setButtonKey('~', Console.show); + + delete Console.init; + }; + + this.show = function() { + Images.showLoad({top:true}); + + if (!Element) { + Element = DOM.anyload({ + name : 'div', + className : 'console' + }); + + jqconsole = $(Element).jqconsole('', '> '); + // Abort prompt on Ctrl+Z. + jqconsole.RegisterShortcut('Z', function() { + jqconsole.AbortPrompt(); + handler(); + }); + + // Handle a command. + var handler = function(command) { + var lSocket = CloudCmd.Socket; + if (command) { + Images.showLoad({ top:true }); + + if(lSocket) + lSocket.send(command); + } + + jqconsole.Prompt(true, handler); + }; + + // Initiate the first prompt. + handler(); + } + + CloudCmd.View.show(Element, function(){ + var l$Console = jqconsole.$console, + l$Input = jqconsole.$input_source, + lFocus = function(){ + var x = window.scrollX, + y = window.scrollY; + + l$Input.focus(); + window.scrollTo(x,y); + }; + + lFocus(); + + if (!MouseBinded) { + MouseBinded = true; + + $(l$Console).unbind('mouseup'); + $(l$Console).mouseup(function() { + if( !window.getSelection().toString() ) { + var lTop = l$Console.scrollTop(); + + lFocus(); + l$Console.scrollTop(lTop); + } + }); + } + }); + }; + + this.hide = function(){ + CloudCmd.View.hide(); + }; + + this.log = function(pText){ + if (jqconsole) + jqconsole.Write( addNewLine(pText), 'log-msg'); + }; + + this.error = function(pText){ + if (jqconsole) + jqconsole.Write( addNewLine(pText), 'error-msg'); + }; + + function addNewLine(pText){ + var lNewLine = '', + n = pText && pText.length; + + if(n && pText[n-1] !== '\n') + lNewLine = '\n'; + + return pText + lNewLine; + } + + + function load(pCallBack){ + Util.time(Name + ' load'); + + var lDir = CloudCmd.LIBDIRCLIENT + 'console/', + lFiles = [ + lDir + 'jqconsole.js', + lDir + 'jqconsole.css', + lDir + 'ansi.css', + lDir + 'jquery-migrate-1.2.1.js' + ]; + + DOM.anyLoadInParallel(lFiles, function(){ + console.timeEnd(Name + ' load'); + + Util.exec(pCallBack); + }); + } + + function listener(pEvent){ + var lTRA = Key.TRA, + lESC = Key.ESC, + lIsBind = Key.isBind(), + lKey = pEvent.keyCode; + + switch(lKey){ + case lTRA: + if (lIsBind){ + Console.show(); + DOM.preventDefault(pEvent); + } + break; + case lESC: + Console.hide(); + break; + } + + } + } + +})(CloudCmd, Util, DOM); diff --git a/lib/client/console/Cakefile b/lib/client/console/Cakefile new file mode 100644 index 00000000..af53e80d --- /dev/null +++ b/lib/client/console/Cakefile @@ -0,0 +1,16 @@ +{spawn, exec} = require 'child_process' + +task 'watch', 'Build and watch the CoffeeScript source files', -> + coffee = spawn 'coffee', ['-cw', '-o', 'lib', 'src'] + test = spawn 'coffee', ['-cw', 'test'] + log = (d)-> console.log d.toString() + coffee.stdout.on 'data', log + test.stdout.on 'data', log + +task 'build', 'Build minified file with uglify', -> + console.log 'building...' + exec 'uglifyjs -o jqconsole.min.js lib/jqconsole.js', (err, res)-> + if err + console.error 'failed with', err + else + console.log 'build complete' diff --git a/lib/client/console/ChangeLog b/lib/client/console/ChangeLog new file mode 100644 index 00000000..85ae8052 --- /dev/null +++ b/lib/client/console/ChangeLog @@ -0,0 +1,68 @@ +2011.08.28, Version 2.4.2 + +* Fix for issue #13 . +* Add optional parameter "escape" to the Write method, see README for more +info. + +20011.10.9, Version 2.5 + +* Added mobile support. +* Follow the cursor's position when the window is scrolled away. +* Add async_multiline option in prompt, see README for more info. +* Add Dump method that would dump the console's text content. +* Add GetState method that gets the current state of the console. +* Publicize MoveToStart and MoveToEnd methods. + +2011.11.1, Version 2.5.1 + +* Added Disable/Enable functionality and methods. +* Added IsDisabled method. + +2011.11.3, Version 2.5.2 + +* Added multibyte character input support, issue #19. + +2011.11.4, Version 2.6 + +* Fix safari paste. Issue #15. +* Created constants and minifier friendliness. Issue #14. + +2011.11.19, Version 2.6.1 + +* Fix issues #20, #21 +* Implement feature #22 +* Add built-in css for ease of use. + +2011.12.6, Version 2.6.2 +* Fix issue #23. + +2011.12.16 Version 2.6.3 +* Fix issue #24. + +2011.12.28 Version 2.7 +* Implement ANSI graphics, Issue #12 +* Fix issue #25 + +2012.3.7 Version 2.7.1 +* Fix issue #26 +* Complete issue #12 by adding stacking graphics support. + +2012.10.28 Version 2.7.2 +* Add set / get History methods. +* Add Append method. + +2012.11.10 Version 2.7.3 +* Allow empty string in prompt. + +2012.12.13 Version 2.7.4 +* Fix issue #36 +* Fix issue #35 + +2013.1.21 Version 2.7.5 +* Add SetPromptLabel method. + +2013.1.22 Version 2.7.6 +* Continue label argument in SetPromptLabel method. + +2013.1.26 Version 2.7.7 +* Support for middle click paste on linux. #47. diff --git a/lib/client/console/README.md b/lib/client/console/README.md new file mode 100644 index 00000000..7eada46b --- /dev/null +++ b/lib/client/console/README.md @@ -0,0 +1,723 @@ +#jq-console + +A jQuery terminal plugin written in CoffeeScript. + +This project was spawned because of our need for a simple web terminal plugin +for the repl.it project. It tries to simulate a low level terminal by providing (almost) +raw input/output streams as well as input and output states. + +Version 2.0 adds baked-in support for rich multi-line prompting and operation +queueing. + + +##Tested Browsers + +The plugin has been tested on the following browsers: + +* IE 9+ +* Chrome 10+ +* Firefox 4+ +* Opera 11+ +* iOS 4+ + + +##Getting Started + +###Echo example + +```css + /* The console container element */ + #console { + position: absolute; + width: 400px; + height: 500px; + background-color:black; + } + /* The inner console element. */ + .jqconsole { + padding: 10px; + } + /* The cursor. */ + .jqconsole-cursor { + background-color: gray; + } + /* The cursor color when the console looses focus. */ + .jqconsole-blurred .jqconsole-cursor { + background-color: #666; + } + /* The current prompt text color */ + .jqconsole-prompt { + color: #0d0; + } + /* The command history */ + .jqconsole-old-prompt { + color: #0b0; + font-weight: normal; + } + /* The text color when in input mode. */ + .jqconsole-input { + color: #dd0; + } + /* Previously entered input. */ + .jqconsole-old-input { + color: #bb0; + font-weight: normal; + } + /* The text color of the output. */ + .jqconsole-output { + color: white; + } +``` + +```html +
+ + + +``` + + +###Instantiating + +```javascript + $(div).jqconsole(welcomeString, promptLabel, continueLabel); +``` + +* `div` is the div element or selector. Note that this element must be + explicity sized and positioned `absolute` or `relative`. +* `welcomeString` is the string to be shown when the terminal is first rendered. +* `promptLabel` is the label to be shown before the input when using Prompt(). +* `continueLabel` is the label to be shown before the continued lines of the + input when using Prompt(). + +##Configuration + +There isn't much initial configuration needed, because the user must supply +options and callbacks with each state change. There are a few config methods +provided to create custom shortcuts and change indentation width: + +###jqconsole.RegisterShortcut +Registers a callback for a keyboard shortcut. +Takes two arguments: + + * __(int|string)__ *keyCode*: The code of the key pressing which (when Ctrl is + held) will trigger this shortcut. If a string is provided, the ASCII code + of the first character is taken. + + * __function__ *callback*: A function called when the shortcut is pressed; + "this" will point to the JQConsole object. + + + Example: + + // Ctrl+R: resets the console. + jqconsole.RegisterShortcut('R', function() { + this.Reset(); + }); + +###jqconsole.SetIndentWidth +Sets the number of spaces inserted when indenting and removed when unindenting. +Takes one argument: + + * __int__ *width*: The code of the key pressing which (when Ctrl is held) will + trigger this shortcut. + + + Example: + + // Sets the indent width to 4 spaces. + jqconsole.SetIndentWidth(4); + +###jqconsole.RegisterMatching +Registers an opening and closing characters to match and wraps each of the +opening and closing characters with a span with the specified class. +Takes one parameters: + + * __char__ *open*: The opening character of a "block". + * __char__ *close*: The closing character of a "block". + * __string__ *class*: The css class that is applied to the matched characters. + + + Example: + + jqconsole.RegisterMatching('{', '}', 'brackets'); + +##Usage + +Unlike most terminal plugins, jq-console gives you complete low-level control +over the execution; you have to call the appropriate methods to start input +or output: + +###jqconsole.Input: +Asks user for input. If another input or prompt operation is currently underway, +the new input operation is enqueued and will be called when the current +operation and all previously enqueued operations finish. Takes one argument: + + * __function__ *input_callback*: A function called with the user's input when + the user presses Enter and the input operation is complete. + + + Example: + + // Echo the input. + jqconsole.Input(function(input) { + jqconsole.Write(input); + }); + + +###jqconsole.Prompt +Asks user for input. If another input or prompt operation is currently underway +the new prompt operation is enqueued and will be called when the current +peration and all previously enqueued operations finish. Takes three arguments: + + * __bool__ *history_enabled*: Whether this input should use history. If true, + the user can select the input from history, and their input will also be + added as a new history item. + + * __function__ *result_callback*: A function called with the user's input when + the user presses Enter and the prompt operation is complete. + + * __function__ *multiline_callback*: If specified, this function is called when + the user presses Enter to check whether the input should continue to the + next line. The function must return one of the following values: + + * `false`: the input operation is completed. + + * `0`: the input continues to the next line with the current indent. + + * `N` (int): the input continues to the next line, and the current + indent is adjusted by `N`, e.g. `-2` to unindent two levels. + + + * __bool__ *async_multiline*: Whether the multiline callback function should + be treated as an asynchronous operation and be passed a continuation + function that should be called with one of the return values mentioned + above: `false`/`0`/`N`. + + + Example: + + jqconsole.Prompt(true, function(input) { + // Alert the user with the command. + alert(input); + }, function (input) { + // Continue if the last character is a backslash. + return /\\$/.test(input); + }); + +###jqconsole.AbortPrompt +Aborts the current prompt operation and returns to output mode or the next +queued input/prompt operation. Takes no arguments. + + Example: + + jqconsole.Prompt(true, function(input) { + alert(input); + }); + // Give the user 2 seconds to enter the command. + setTimeout(function() { + jqconsole.AbortPrompt(); + }, 2000); + +###jqconsole.Write +Writes the given text to the console in a ``, with an +optional class. If a prompt is currently being shown, the text is inserted +before it. Takes two arguments: + + * __string__ *text*: The text to write. + + * __string__ *cls*: The class to give the span containing the text. Optional. + + * __bool__ *escape*: Whether the text to write should be html escaped. + Optional, defaults to true. + + + Examples: + + jqconsole.Write(output, 'my-output-class') + jqconsole.Write(err.message, 'my-error-class') + +###jqconsole.Append +Append the given node to the DOM. If a prompt is currently being shown, the +text is inserted before it. Takes a single argument: + + * __(string|Element)__ *node*: The DOM Element or html string to append to + the console just before the prompt. + + Example: + + // Add a div with the text 'hello' on a red background using jquery + jqconsole.Append($('
hello
').css('background-color', 'red')); + + // We can also use document.createElement + node = document.createElement("div"); + content = document.createTextNode("hello"); + node.appendChild(content); + jqconsole.Append(node); + + +###jqconsole.SetPromptText +Sets the text currently in the input prompt. Takes one parameter: + + * __string__ *text*: The text to put in the prompt. + + Examples: + + jqconsole.SetPromptText('ls') + jqconsole.SetPromptText('print [i ** 2 for i in range(10)]') + + +###jqconsole.SetPromptLabel +Replaces the main prompt label. Takes two parameters: + + * __string__ *main_label*: String to replace the main prompt label. + * __string__ *continuation_label*: String to replace the continuation prompt label. Optional. + + Examples: + + jqconsole.SetPromptLabel('$') + jqconsole.SetPromptLabel(' $','..') + + +###jqconsole.ClearPromptText +Clears all the text currently in the input prompt. Takes one parameter: + + * __bool__ *clear_label*: If specified and true, also clears the main prompt + label (e.g. ">>>"). + + + Example: + + jqconsole.ClearPromptText() + + +###jqconsole.GetPromptText +Returns the contents of the prompt. Takes one parameter: + + * __bool__ *full*: If specified and true, also includes the prompt labels + (e.g. ">>>"). + + + Examples: + + var currentCommand = jqconsole.GetPromptText() + var logEntry = jqconsole.GetPromptText(true) + + +###jqconsole.Reset +Resets the console to its initial state, cancelling all current and pending +operations. Takes no parameters. + + Example: + + jqconsole.Reset() + + +###jqconsole.GetColumn +Returns the 0-based number of the column on which the cursor currently is. +Takes no parameters. + + Example: + + // Show the current line and column in a status area. + $('#status').text(jqconsole.GetLine() + ', ' + jqconsole.GetColumn()) + + +###jqconsole.GetLine +Returns the 0-based number of the line on which the cursor currently is. +Takes no parameters. + + Example: + + // Show the current line and column in a status area. + $('#status').text(jqconsole.GetLine() + ', ' + jqconsole.GetColumn()) + +###jqconsole.Focus +Forces the focus onto the console so events can be captured. +Takes no parameters. + + Example: + + // Redirect focus to the console whenever the user clicks anywhere. + $(window).click(function() { + jqconsole.Focus(); + }) + + +###jqconsole.GetIndentWidth +Returns the number of spaces inserted when indenting. Takes no parameters. + + Example: + + jqconsole.SetIndentWidth(4); + console.assert(jqconsole.GetIndentWidth() == 4); + + +###jqconsole.UnRegisterMatching +Deletes a certain matching settings set by `jqconsole.RegisterMatching`. +Takes two paramaters: + + * __char__ *open*: The opening character of a "block". + * __char__ *close*: The closing character of a "block". + + + Example: + + jqconsole.UnRegisterMatching('{', '}'); + + +###jqconsole.Dump +Returns the text content of the console. + +###jqconsole.GetState +Returns the current state of the console. Could be one of the following: + + * Input: `"input"` + * Output: `"output"` + * Prompt: `"prompt"` + + + Example: + + jqconsole.GetState(); //output + + +###jqconsole.MoveToStart +Moves the cursor to the start of the current line. +Takes one parameter: + + * __bool__ *all_lines*: If true moves the cursor to the beginning of the first + line in the current prompt. Defaults to false. + + + Example: + + // Move to line start Ctrl+A. + jqconsole.RegisterShortcut('A', function() { + jqconsole.MoveToStart(); + handler(); + }); + + +###jqconsole.MoveToEnd +Moves the cursor to the end of the current line. +Takes one parameter: + + * __bool__ *all_lines*: If true moves the cursor to the end of the first + line in the current prompt. Defaults to false. + + Example: + + // Move to line end Ctrl+E. + jqconsole.RegisterShortcut('E', function() { + jqconsole.MoveToEnd(); + handler(); + }); + +###jqconsole.Disable +Disables input and focus on the console. + + +###jqconsole.Enable +Enables input and focus on the console. + + +###jqconsole.IsDisabled +Returns true if the console is disabled. + + +###jqconsole.GetHistory +Returns the contents of the history buffer. + + +###jqconsole.SetHistory +Set the history buffer to the given array. + +Takes one parameter: + + * __array__ *history*: The history buffer to use. + + Example: + + jqconsole.SetHistory(['a = 3', 'a + 3']); + + +###jqconsole.ResetHistory +Resets the console history. + + +###jqconsole.ResetMatchings +Resets the character matching configuration. + + +###jqconsole.ResetShortcuts +Resets the shortcut configuration. + + +##Default Key Config + +The console responds to the followind keys and key combinations by default: + +* `Delete`: Delete the following character. +* `Ctrl+Delete`: Delete the following word. +* `Backspace`: Delete the preceding character. +* `Ctrl+Backspace`: Delete the preceding word. +* `Ctrl+Left`: Move one word to the left. +* `Ctrl+Right`: Move one word to the right. +* `Home`: Move to the beginning of the current line. +* `Ctrl+Home`: Move to the beginnig of the first line. +* `End`: Move to the end of the current line. +* `Ctrl+End`: Move to the end of the last line. +* `Shift+Up`, `Ctrl+Up`: Move cursor to the line above the current one. +* `Shift+Down`, `Ctrl+Down`: Move cursor to the line below the current one. +* `Tab`: Indent. +* `Shift+Tab`: Unindent. +* `Up`: Previous history item. +* `Down`: Next history item. +* `Enter`: Finish input/prompt operation. See Input() and Prompt() for details. +* `Shift+Enter`: New line. +* `Page Up`: Scroll console one page up. +* `Page Down`: Scroll console one page down. + +##ANSI escape code SGR support + +jq-console implements a large subset of the ANSI escape code graphics. +Using the `.Write` method you could add style to the console using +the following syntax: + +`ASCII 27 (decimal) or 0x1b (hex)` `[` `SGR code` `m` + +Example: + + jqconsole.Write('\033[31mRed Text'); + +Note that the third parameter `escape` must be true which defaults to it. + +You'll need to include the `ansi.css` file for default effects or create your +own using the css classes from the table below. + +###SGR +[Reference](http://en.wikipedia.org/wiki/ANSI_escape_code#graphics). + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CodeEffectClass
0Reset / Normal
1Bold`jqconsole-ansi-bold`
2Faint`jqconsole-ansi-lighter`
3Italic`jqconsole-ansi-italic`
4Line below text`jqconsole-ansi-underline`
5Blink: 1s delay`jqconsole-ansi-blink`
6Blink: 0.5s delay`jqconsole-ansi-blink-rapid`
8Hide text`jqconsole-ansi-hidden`
9Line through text`jqconsole-ansi-line-through`
10Remove all fonts
11-19Add custom font`jqconsole-ansi-fonts-{N}` where N is code - 10
20Add Fraktur font (not implemented in ansi.css)`jqconsole-ansi-fraktur`
21Remove Bold and Faint effects
22Same as 21
23Remove italic and fraktur effects
24Remove underline effect
25Remove blinking effect(s).
28Reveal text
29Remove line-through effect
30-37Set foreground color to color from the color table belowjqconsole-ansi-color-{COLOR} where {COLOR} is the color name
39Restore default foreground color
40-47Set background color to color from the color table below`jqconsole-ansi-background-color-{COLOR}` where {COLOR} is the color name
49Restore default background color
51Adds a frame around the text`jqconsole-ansi-framed`
53Line above textjqconsole-ansi-overline
54Remove frame effect
55Remove over-line effect
+ +###Colors +[Reference](http://en.wikipedia.org/wiki/ANSI_escape_code#Colors). + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Code offsetColor
0Black
1Red
2Green
3Yellow
4Blue
5Magenta
6Cyan
7White
+ +##CSS Classes + +Several CSS classes are provided to help stylize the console: + +* `jqconsole`: The main console container. +* `jqconsole, jqconsole-blurred`: The main console container, when not in focus. +* `jqconsole-cursor`: The cursor. +* `jqconsole-header`: The welcome message at the top of the console. +* `jqconsole-input`: The prompt area during input. May have multiple lines. +* `jqconsole-old-input`: Previously-entered inputs. +* `jqconsole-prompt`: The prompt area during prompting. May have multiple lines. +* `jqconsole-old-prompt`: Previously-entered prompts. +* `jqconsole-composition`: The div encapsulating the composition of multi-byte + characters. + + +Of course, custom classes may be specified when using `jqconsole.Write()` for +further customization. + + +##Contributors + +[Max Shawabkeh](http://max99x.com/) +[Amjad Masad](http://twitter.com/amjad_masad) diff --git a/lib/client/console/ansi.css b/lib/client/console/ansi.css new file mode 100644 index 00000000..e84d4794 --- /dev/null +++ b/lib/client/console/ansi.css @@ -0,0 +1,173 @@ + +.jqconsole-ansi-bold { + /* font-weight: bold; */ +} + +.jqconsole-ansi-lighter { + font-weight: lighter; +} + +.jqconsole-ansi-italic { + font-style: italic; +} + +.jqconsole-ansi-underline { + text-decoration: underline; +} + +@-webkit-keyframes blinker { + from { opacity: 1.0; } + to { opacity: 0.0; } +} + +@-moz-keyframes blinker { + from { opacity: 1.0; } + to { opacity: 0.0; } +} + +@-ms-keyframes blinker { + from { opacity: 1.0; } + to { opacity: 0.0; } +} + +@-o-keyframes blinker { + from { opacity: 1.0; } + to { opacity: 0.0; } +} + +.jqconsole-ansi-blink { + -webkit-animation-name: blinker; + -moz-animation-name: blinker; + -ms-animation-name: blinker; + -o-animation-name: blinker; + -webkit-animation-iteration-count: infinite; + -moz-animation-iteration-count: infinite; + -ms-animation-iteration-count: infinite; + -o-animation-iteration-count: infinite; + -webkit-animation-timing-function: cubic-bezier(1.0,0,0,1.0); + -ms-animation-timing-function: cubic-bezier(1.0,0,0,1.0); + -o-animation-timing-function: cubic-bezier(1.0,0,0,1.0); + -moz-animation-timing-function: cubic-bezier(1.0,0,0,1.0); + -webkit-animation-duration: 1s; + -moz-animation-duration: 1s; + -o-animation-duration: 1s; + -ms-animation-duration: 1s; +} + +.jqconsole-ansi-blink-rapid { + -webkit-animation-name: blinker; + -moz-animation-name: blinker; + -ms-animation-name: blinker; + -o-animation-name: blinker; + -webkit-animation-iteration-count: infinite; + -moz-animation-iteration-count: infinite; + -ms-animation-iteration-count: infinite; + -o-animation-iteration-count: infinite; + -webkit-animation-timing-function: cubic-bezier(1.0,0,0,1.0); + -ms-animation-timing-function: cubic-bezier(1.0,0,0,1.0); + -o-animation-timing-function: cubic-bezier(1.0,0,0,1.0); + -moz-animation-timing-function: cubic-bezier(1.0,0,0,1.0); + -webkit-animation-duration: 0.5s; + -moz-animation-duration: 0.5s; + -o-animation-duration: 0.5s; + -ms-animation-duration: 0.5s; +} + + +.jqconsole-ansi-hidden { + visibility:hidden; +} + +.jqconsole-ansi-line-through { + text-decoration: line-through; +} + +.jqconsole-ansi-fonts-1 { + +} +.jqconsole-ansi-fonts-2 { + +} +.jqconsole-ansi-fonts-3 { + +} +.jqconsole-ansi-fonts-4 { + +} +.jqconsole-ansi-fonts-5 { + +} +.jqconsole-ansi-fonts-6 { + +} +.jqconsole-ansi-fonts-7 { + +} +.jqconsole-ansi-fonts-8 { + +} +.jqconsole-ansi-fonts-9 { + +} + +.jqconsole-ansi-fraktur { + +} + +.jqconsole-ansi-color-black { + color: black; +} +.jqconsole-ansi-color-red { + color: red; +} +.jqconsole-ansi-color-green { + color: #65b04b; +} +.jqconsole-ansi-color-yellow { + color: #fed563; +} +.jqconsole-ansi-color-blue { + color: rgb(49,123,249); +} +.jqconsole-ansi-color-magenta { + color: magenta; +} +.jqconsole-ansi-color-cyan { + color: cyan; +} +.jqconsole-ansi-color-white { + color: white; +} + +.jqconsole-ansi-background-color-black { + background-color: black; +} +.jqconsole-ansi-background-color-red { + background-color: red; +} +.jqconsole-ansi-background-color-green { + background-color: #65b04b; +} +.jqconsole-ansi-background-color-yellow { + background-color: #fed563; +} +.jqconsole-ansi-background-color-blue { + background-color: blue; +} +.jqconsole-ansi-background-color-magenta { + background-color: magenta; +} +.jqconsole-ansi-background-color-cyan { + background-color: cyan; +} +.jqconsole-ansi-background-color-white { + background-color: white; +} + +.jqconsole-ansi-framed { + border: 1px solid; +} +.jqconsole-ansi-overline { + text-decoration: overline; +} + diff --git a/lib/client/console/jqconsole.coffee b/lib/client/console/jqconsole.coffee new file mode 100644 index 00000000..0230629c --- /dev/null +++ b/lib/client/console/jqconsole.coffee @@ -0,0 +1,1310 @@ +### +Copyrights 2011, the repl.it project. +Licensed under the MIT license +### + +# Shorthand for jQuery. +$ = jQuery + +# The states in which the console can be. +STATE_INPUT = 0 +STATE_OUTPUT = 1 +STATE_PROMPT = 2 + +# Key code values. +KEY_ENTER = 13 +KEY_TAB = 9 +KEY_DELETE = 46 +KEY_BACKSPACE = 8 +KEY_LEFT = 37 +KEY_RIGHT = 39 +KEY_UP = 38 +KEY_DOWN = 40 +KEY_HOME = 36 +KEY_END = 35 +KEY_PAGE_UP = 33 +KEY_PAGE_DOWN = 34 + +# CSS classes +CLASS_PREFIX = 'jqconsole-' +CLASS_CURSOR = "#{CLASS_PREFIX}cursor" +CLASS_HEADER = "#{CLASS_PREFIX}header" +CLASS_PROMPT = "#{CLASS_PREFIX}prompt" +CLASS_OLD_PROMPT = "#{CLASS_PREFIX}old-prompt" +CLASS_INPUT = "#{CLASS_PREFIX}input" +CLASS_BLURRED = "#{CLASS_PREFIX}blurred" + +# Frequently used string literals +E_KEYPRESS = 'keypress' +EMPTY_SPAN = '' +EMPTY_DIV = '
' +EMPTY_SELECTOR = ':empty' +NEWLINE = '\n' + +# Default prompt text for main and continuation prompts. +DEFAULT_PROMPT_LABEL = '>>> ' +DEFAULT_PROMPT_CONINUE_LABEL = '... ' + +# The default number of spaces inserted when indenting. +DEFAULT_INDENT_WIDTH = 2 + +CLASS_ANSI = "#{CLASS_PREFIX}ansi-" +ESCAPE_CHAR = '\x1B' +ESCAPE_SYNTAX = /\[(\d*)(?:;(\d*))*m/ + +class Ansi + COLORS: ['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white'] + + constructor: -> + @klasses = []; + + _append: (klass) => + klass = "#{CLASS_ANSI}#{klass}" + if @klasses.indexOf(klass) is -1 + @klasses.push klass + + _remove: (klasses...) => + for klass in klasses + if klass in ['fonts', 'color', 'background-color'] + @klasses = (cls for cls in @klasses when cls.indexOf(klass) isnt CLASS_ANSI.length) + else + klass = "#{CLASS_ANSI}#{klass}" + @klasses = (cls for cls in @klasses when cls isnt klass) + + _color: (i) => @COLORS[i] + + _style: (code) => + code = 0 if code == '' + code = parseInt code + + return if isNaN code + + switch code + when 0 then @klasses = [] + when 1 then @_append 'bold' + when 2 then @_append 'lighter' + when 3 then @_append 'italic' + when 4 then @_append 'underline' + when 5 then @_append 'blink' + when 6 then @_append 'blink-rapid' + when 8 then @_append 'hidden' + when 9 then @_append 'line-through' + when 10 then @_remove 'fonts' + when 11,12,13,14,15,16,17,18,19 + @_remove 'fonts' + @_append "fonts-#{code - 10}" + when 20 then @_append 'fraktur' + when 21 then @_remove 'bold', 'lighter' + when 22 then @_remove 'bold', 'lighter' + when 23 then @_remove 'italic', 'fraktur' + when 24 then @_remove 'underline' + when 25 then @_remove 'blink', 'blink-rapid' + when 28 then @_remove 'hidden' + when 29 then @_remove 'line-through' + when 30,31,32,33,34,35,36,37 + @_remove 'color' + @_append 'color-' + @_color code - 30 + when 39 then @_remove 'color' + when 40,41,42,43,44,45,46,47 + @_remove 'background-color' + @_append 'background-color-' + @_color code - 40 + when 49 then @_remove 'background-color' + when 51 then @_append 'framed' + when 53 then @_append 'overline' + when 54 then @_remove 'framed' + when 55 then @_remove 'overline' + + getClasses: => @klasses.join ' ' + + _openSpan: (text) => "#{text}" + _closeSpan: (text) => "#{text}" + + stylize: (text) => + text = @_openSpan text + + i = 0 + while (i = text.indexOf(ESCAPE_CHAR ,i)) and i isnt -1 + if d = text[i...].match ESCAPE_SYNTAX + @_style code for code in d[1...] + text = @_closeSpan(text[0...i]) + @_openSpan text[i + 1 + d[0].length...] + else i++ + + return @_closeSpan text + +# Helper functions +spanHtml = (klass, content) -> "#{content or ''}" + +class JQConsole + # Creates a console. + # @arg container: The DOM element into which the console is inserted. + # @arg header: Text to print at the top of the console on reset. Optional. + # Defaults to an empty string. + # @arg prompt_label: The label to show before the command prompt. Optional. + # Defaults to DEFAULT_PROMPT_LABEL. + # @arg prompt_continue: The label to show before continuation lines of the + # command prompt. Optional. Defaults to DEFAULT_PROMPT_CONINUE_LABEL. + constructor: (@container, header, prompt_label, prompt_continue_label) -> + # Mobile devices supported sniff. + @isMobile = !!navigator.userAgent.match /iPhone|iPad|iPod|Android/i + @isIos = !!navigator.userAgent.match /iPhone|iPad|iPod/i + @isAndroid = !!navigator.userAgent.match /Android/i + + @$window = $(window) + + # The header written when the console is reset. + @header = header or '' + + # The prompt label used by Prompt(). + @prompt_label_main = if typeof prompt_label == 'string' + prompt_label + else + DEFAULT_PROMPT_LABEL + @prompt_label_continue = (prompt_continue_label or + DEFAULT_PROMPT_CONINUE_LABEL) + + # How many spaces are inserted when a tab character is pressed. + @indent_width = DEFAULT_INDENT_WIDTH + + # By default, the console is in the output state. + @state = STATE_OUTPUT + + # A queue of input/prompt operations waiting to be called. The items are + # bound functions ready to be called. + @input_queue = [] + + # The function to call when input is accepted. Valid only in + # input/prompt mode. + @input_callback = null + # The function to call to determine whether the input should continue to the + # next line. + @multiline_callback = null + + # A table of all "recorded" inputs given so far. + @history = [] + # The index of the currently selected history item. If this is past the end + # of @history, then the user has not selected a history item. + @history_index = 0 + # The command which the user was typing before browsing history. Keeping + # track of this allows us to restore the user's command if they browse the + # history then decide to go back to what they were typing. + @history_new = '' + # Whether the current input operation is using history. + @history_active = false + + # A table of custom shortcuts, mapping character codes to callbacks. + @shortcuts = {} + + # The main console area. Everything else happens inside this. + @$console = $('
').appendTo @container
+    @$console.css 
+      position: 'absolute'
+      top: 0
+      bottom: 0
+      right: 0
+      left: 0
+      margin: 0
+      overflow: 'auto'
+
+    # Whether the console currently has focus.
+    @$console_focused = true
+    
+    # On screen somehow invisible textbox for input.
+    # Copied from codemirror2, this works for both mobile and desktop browsers.
+    @$input_container = $(EMPTY_DIV).appendTo @container
+    @$input_container.css
+      position: 'relative'
+      width: 1
+      height: 0
+      overflow: 'hidden'
+    @$input_source = $('