From 422f9d8d6a5146999b248320640df130d52937c9 Mon Sep 17 00:00:00 2001 From: HFO4 <912394456@qq.com> Date: Sun, 3 Mar 2019 20:26:25 +0800 Subject: [PATCH 01/22] Feat:initial test --- application/config.php | 2 +- application/index/controller/File.php | 2 +- application/index/view/home/home.html | 127 +- application/index/view/home/home1.html | 100 + composer.lock | 981 ++ static/js/uploader/i18n/zh_CN.js | 2 + static/js/uploader/main.js | 274 + static/js/uploader/moxie.js | 11509 ++++++++++++++++ static/js/uploader/plupload.dev.js | 2476 ++++ static/js/uploader/qiniu.js | 1831 +++ static/js/uploader/ui.js | 278 + thinkphp/.gitignore | 4 + thinkphp/CONTRIBUTING.md | 4 +- thinkphp/LICENSE.txt | 2 +- thinkphp/README.md | 114 + thinkphp/base.php | 6 +- thinkphp/convention.php | 15 +- thinkphp/helper.php | 4 +- thinkphp/lang/zh-cn.php | 172 +- thinkphp/library/think/App.php | 451 +- thinkphp/library/think/Build.php | 167 +- thinkphp/library/think/Cache.php | 111 +- thinkphp/library/think/Collection.php | 330 +- thinkphp/library/think/Config.php | 160 +- thinkphp/library/think/Console.php | 388 +- thinkphp/library/think/Controller.php | 105 +- thinkphp/library/think/Cookie.php | 164 +- thinkphp/library/think/Db.php | 81 +- thinkphp/library/think/Debug.php | 128 +- thinkphp/library/think/Env.php | 13 +- thinkphp/library/think/Error.php | 75 +- thinkphp/library/think/Exception.php | 21 +- thinkphp/library/think/File.php | 246 +- thinkphp/library/think/Hook.php | 62 +- thinkphp/library/think/Lang.php | 127 +- thinkphp/library/think/Loader.php | 501 +- thinkphp/library/think/Log.php | 180 +- thinkphp/library/think/Model.php | 353 +- thinkphp/library/think/Paginator.php | 58 +- thinkphp/library/think/Request.php | 242 +- thinkphp/library/think/Response.php | 11 +- thinkphp/library/think/Route.php | 342 +- thinkphp/library/think/Session.php | 7 +- thinkphp/library/think/Template.php | 60 +- thinkphp/library/think/Url.php | 27 +- thinkphp/library/think/Validate.php | 300 +- thinkphp/library/think/View.php | 23 +- thinkphp/library/think/cache/Driver.php | 42 +- thinkphp/library/think/cache/driver/File.php | 64 +- thinkphp/library/think/cache/driver/Lite.php | 22 +- .../library/think/cache/driver/Memcache.php | 13 +- .../library/think/cache/driver/Memcached.php | 11 +- thinkphp/library/think/cache/driver/Redis.php | 50 +- .../library/think/cache/driver/Sqlite.php | 16 +- .../library/think/cache/driver/Wincache.php | 11 +- .../library/think/cache/driver/Xcache.php | 11 +- thinkphp/library/think/config/driver/Ini.php | 2 +- thinkphp/library/think/config/driver/Json.php | 2 +- thinkphp/library/think/config/driver/Xml.php | 2 +- .../library/think/console/command/Clear.php | 13 +- .../think/console/command/optimize/Config.php | 2 +- .../think/console/command/optimize/Route.php | 5 + .../think/console/command/optimize/Schema.php | 6 +- .../think/console/output/Descriptor.php | 10 +- thinkphp/library/think/controller/Rest.php | 6 +- thinkphp/library/think/db/Builder.php | 177 +- thinkphp/library/think/db/Connection.php | 113 +- thinkphp/library/think/db/Expression.php | 48 + thinkphp/library/think/db/Query.php | 580 +- thinkphp/library/think/db/builder/Mysql.php | 81 +- thinkphp/library/think/db/builder/Pgsql.php | 14 +- thinkphp/library/think/db/builder/Sqlite.php | 13 +- thinkphp/library/think/db/builder/Sqlsrv.php | 50 +- thinkphp/library/think/db/connector/Mysql.php | 15 +- thinkphp/library/think/db/connector/Pgsql.php | 2 +- .../library/think/db/connector/Sqlite.php | 2 +- .../library/think/db/connector/Sqlsrv.php | 5 +- .../think/db/exception/BindParamException.php | 2 +- .../db/exception/DataNotFoundException.php | 2 +- .../db/exception/ModelNotFoundException.php | 2 +- thinkphp/library/think/debug/Console.php | 2 +- thinkphp/library/think/debug/Html.php | 2 +- .../library/think/exception/DbException.php | 3 +- .../think/exception/ErrorException.php | 2 +- thinkphp/library/think/exception/Handle.php | 18 +- .../library/think/exception/PDOException.php | 2 +- .../exception/RouteNotFoundException.php | 2 +- thinkphp/library/think/log/driver/File.php | 243 +- thinkphp/library/think/log/driver/Socket.php | 2 +- thinkphp/library/think/model/Collection.php | 18 +- thinkphp/library/think/model/Merge.php | 2 +- thinkphp/library/think/model/Pivot.php | 8 +- thinkphp/library/think/model/Relation.php | 35 +- .../think/model/relation/BelongsTo.php | 54 +- .../think/model/relation/BelongsToMany.php | 104 +- .../library/think/model/relation/HasMany.php | 77 +- .../think/model/relation/HasManyThrough.php | 25 +- .../library/think/model/relation/HasOne.php | 78 +- .../think/model/relation/MorphMany.php | 47 +- .../library/think/model/relation/MorphOne.php | 44 +- .../library/think/model/relation/MorphTo.php | 42 +- .../library/think/model/relation/OneToOne.php | 42 +- .../think/paginator/driver/Bootstrap.php | 2 +- thinkphp/library/think/response/Json.php | 2 +- thinkphp/library/think/response/Jsonp.php | 2 +- thinkphp/library/think/response/Redirect.php | 8 +- thinkphp/library/think/response/View.php | 2 +- thinkphp/library/think/response/Xml.php | 9 +- .../library/think/session/driver/Memcache.php | 2 +- .../think/session/driver/Memcached.php | 2 +- .../library/think/session/driver/Redis.php | 2 +- thinkphp/library/think/template/TagLib.php | 6 +- .../library/think/template/driver/File.php | 7 +- thinkphp/library/think/template/taglib/Cx.php | 2 +- thinkphp/library/think/view/driver/Php.php | 32 +- thinkphp/library/think/view/driver/Think.php | 6 +- thinkphp/library/traits/controller/Jump.php | 110 +- thinkphp/library/traits/model/SoftDelete.php | 101 +- thinkphp/library/traits/think/Instance.php | 35 +- thinkphp/start.php | 7 +- thinkphp/tests/.gitignore | 4 - thinkphp/tests/README.md | 132 - thinkphp/tests/application/config.php | 33 - thinkphp/tests/application/database.php | 44 - .../application/index/controller/Index.php | 10 - thinkphp/tests/application/route.php | 22 - thinkphp/tests/conf/apcu.ini | 3 - thinkphp/tests/conf/apcu_bc.ini | 4 - thinkphp/tests/conf/memcached.ini | 1 - thinkphp/tests/conf/redis.ini | 1 - thinkphp/tests/conf/timezone.ini | 1 - thinkphp/tests/extensions/5.4/apcu.so | Bin 404136 -> 0 bytes thinkphp/tests/extensions/5.5/apcu.so | Bin 402984 -> 0 bytes thinkphp/tests/extensions/5.6/apcu.so | Bin 404405 -> 0 bytes thinkphp/tests/extensions/7.0/apc.so | Bin 43511 -> 0 bytes thinkphp/tests/extensions/7.0/apcu.so | Bin 320965 -> 0 bytes thinkphp/tests/extensions/7.0/memcached.so | Bin 323764 -> 0 bytes thinkphp/tests/extensions/7.0/redis.so | Bin 1541380 -> 0 bytes thinkphp/tests/mock.php | 20 - thinkphp/tests/script/install.sh | 18 - thinkphp/tests/thinkphp/baseTest.php | 39 - .../tests/thinkphp/library/think/appTest.php | 90 - .../thinkphp/library/think/behavior/One.php | 15 - .../thinkphp/library/think/behavior/Three.php | 9 - .../thinkphp/library/think/behavior/Two.php | 9 - .../thinkphp/library/think/buildTest.php | 73 - .../think/cache/driver/cacheTestCase.php | 207 - .../library/think/cache/driver/fileTest.php | 46 - .../library/think/cache/driver/liteTest.php | 69 - .../think/cache/driver/memcacheTest.php | 49 - .../think/cache/driver/memcachedTest.php | 72 - .../library/think/cache/driver/redisTest.php | 66 - .../think/config/driver/fixtures/config.ini | 1 - .../think/config/driver/fixtures/config.json | 1 - .../think/config/driver/fixtures/config.xml | 6 - .../library/think/config/driver/iniTest.php | 33 - .../library/think/config/driver/jsonTest.php | 33 - .../library/think/config/driver/xmlTest.php | 33 - .../thinkphp/library/think/configTest.php | 169 - .../library/think/controller/.gitignore | 2 - .../thinkphp/library/think/controllerTest.php | 194 - .../thinkphp/library/think/cookieTest.php | 150 - .../library/think/db/driver/.gitignore | 2 - .../tests/thinkphp/library/think/dbTest.php | 352 - .../thinkphp/library/think/debugTest.php | 179 - .../tests/thinkphp/library/think/display.html | 1 - .../thinkphp/library/think/exceptionTest.php | 52 - .../tests/thinkphp/library/think/extend.html | 2 - .../tests/thinkphp/library/think/extend2.html | 17 - .../tests/thinkphp/library/think/hookTest.php | 67 - .../tests/thinkphp/library/think/include.html | 2 - .../thinkphp/library/think/include2.html | 1 - .../thinkphp/library/think/lang/lang.php | 4 - .../tests/thinkphp/library/think/langTest.php | 76 - .../tests/thinkphp/library/think/layout.html | 2 - .../tests/thinkphp/library/think/layout2.html | 2 - .../library/think/loader/test/Hello.php | 7 - .../thinkphp/library/think/loaderTest.php | 71 - .../library/think/log/driver/fileTest.php | 34 - .../tests/thinkphp/library/think/logTest.php | 39 - .../thinkphp/library/think/model/.gitignore | 2 - .../thinkphp/library/think/paginateTest.php | 40 - .../thinkphp/library/think/requestTest.php | 187 - .../thinkphp/library/think/responseTest.php | 95 - .../thinkphp/library/think/routeTest.php | 287 - .../thinkphp/library/think/session/.gitignore | 2 - .../thinkphp/library/think/sessionTest.php | 319 - .../library/think/template/driver/.gitignore | 2 - .../library/think/template/taglib/cxTest.php | 575 - .../thinkphp/library/think/templateTest.php | 414 - .../tests/thinkphp/library/think/urlTest.php | 127 - .../thinkphp/library/think/validateTest.php | 200 - .../library/think/view/driver/.gitignore | 2 - .../think/view/theme/index/template.html | 14 - .../tests/thinkphp/library/think/viewTest.php | 76 - .../library/traits/controller/.gitignore | 2 - .../thinkphp/library/traits/model/.gitignore | 2 - thinkphp/tpl/dispatch_jump.tpl | 1 + thinkphp/tpl/think_exception.tpl | 10 +- 199 files changed, 22557 insertions(+), 7588 deletions(-) create mode 100644 application/index/view/home/home1.html create mode 100644 composer.lock create mode 100644 static/js/uploader/i18n/zh_CN.js create mode 100644 static/js/uploader/main.js create mode 100644 static/js/uploader/moxie.js create mode 100644 static/js/uploader/plupload.dev.js create mode 100644 static/js/uploader/qiniu.js create mode 100644 static/js/uploader/ui.js create mode 100644 thinkphp/.gitignore create mode 100644 thinkphp/README.md create mode 100644 thinkphp/library/think/db/Expression.php delete mode 100644 thinkphp/tests/.gitignore delete mode 100644 thinkphp/tests/README.md delete mode 100644 thinkphp/tests/application/config.php delete mode 100644 thinkphp/tests/application/database.php delete mode 100644 thinkphp/tests/application/index/controller/Index.php delete mode 100644 thinkphp/tests/application/route.php delete mode 100644 thinkphp/tests/conf/apcu.ini delete mode 100644 thinkphp/tests/conf/apcu_bc.ini delete mode 100644 thinkphp/tests/conf/memcached.ini delete mode 100644 thinkphp/tests/conf/redis.ini delete mode 100644 thinkphp/tests/conf/timezone.ini delete mode 100644 thinkphp/tests/extensions/5.4/apcu.so delete mode 100644 thinkphp/tests/extensions/5.5/apcu.so delete mode 100644 thinkphp/tests/extensions/5.6/apcu.so delete mode 100644 thinkphp/tests/extensions/7.0/apc.so delete mode 100644 thinkphp/tests/extensions/7.0/apcu.so delete mode 100644 thinkphp/tests/extensions/7.0/memcached.so delete mode 100644 thinkphp/tests/extensions/7.0/redis.so delete mode 100644 thinkphp/tests/mock.php delete mode 100644 thinkphp/tests/script/install.sh delete mode 100644 thinkphp/tests/thinkphp/baseTest.php delete mode 100644 thinkphp/tests/thinkphp/library/think/appTest.php delete mode 100644 thinkphp/tests/thinkphp/library/think/behavior/One.php delete mode 100644 thinkphp/tests/thinkphp/library/think/behavior/Three.php delete mode 100644 thinkphp/tests/thinkphp/library/think/behavior/Two.php delete mode 100644 thinkphp/tests/thinkphp/library/think/buildTest.php delete mode 100644 thinkphp/tests/thinkphp/library/think/cache/driver/cacheTestCase.php delete mode 100644 thinkphp/tests/thinkphp/library/think/cache/driver/fileTest.php delete mode 100644 thinkphp/tests/thinkphp/library/think/cache/driver/liteTest.php delete mode 100644 thinkphp/tests/thinkphp/library/think/cache/driver/memcacheTest.php delete mode 100644 thinkphp/tests/thinkphp/library/think/cache/driver/memcachedTest.php delete mode 100644 thinkphp/tests/thinkphp/library/think/cache/driver/redisTest.php delete mode 100644 thinkphp/tests/thinkphp/library/think/config/driver/fixtures/config.ini delete mode 100644 thinkphp/tests/thinkphp/library/think/config/driver/fixtures/config.json delete mode 100644 thinkphp/tests/thinkphp/library/think/config/driver/fixtures/config.xml delete mode 100644 thinkphp/tests/thinkphp/library/think/config/driver/iniTest.php delete mode 100644 thinkphp/tests/thinkphp/library/think/config/driver/jsonTest.php delete mode 100644 thinkphp/tests/thinkphp/library/think/config/driver/xmlTest.php delete mode 100644 thinkphp/tests/thinkphp/library/think/configTest.php delete mode 100644 thinkphp/tests/thinkphp/library/think/controller/.gitignore delete mode 100644 thinkphp/tests/thinkphp/library/think/controllerTest.php delete mode 100644 thinkphp/tests/thinkphp/library/think/cookieTest.php delete mode 100644 thinkphp/tests/thinkphp/library/think/db/driver/.gitignore delete mode 100644 thinkphp/tests/thinkphp/library/think/dbTest.php delete mode 100644 thinkphp/tests/thinkphp/library/think/debugTest.php delete mode 100644 thinkphp/tests/thinkphp/library/think/display.html delete mode 100644 thinkphp/tests/thinkphp/library/think/exceptionTest.php delete mode 100644 thinkphp/tests/thinkphp/library/think/extend.html delete mode 100644 thinkphp/tests/thinkphp/library/think/extend2.html delete mode 100644 thinkphp/tests/thinkphp/library/think/hookTest.php delete mode 100644 thinkphp/tests/thinkphp/library/think/include.html delete mode 100644 thinkphp/tests/thinkphp/library/think/include2.html delete mode 100644 thinkphp/tests/thinkphp/library/think/lang/lang.php delete mode 100644 thinkphp/tests/thinkphp/library/think/langTest.php delete mode 100644 thinkphp/tests/thinkphp/library/think/layout.html delete mode 100644 thinkphp/tests/thinkphp/library/think/layout2.html delete mode 100644 thinkphp/tests/thinkphp/library/think/loader/test/Hello.php delete mode 100644 thinkphp/tests/thinkphp/library/think/loaderTest.php delete mode 100644 thinkphp/tests/thinkphp/library/think/log/driver/fileTest.php delete mode 100644 thinkphp/tests/thinkphp/library/think/logTest.php delete mode 100644 thinkphp/tests/thinkphp/library/think/model/.gitignore delete mode 100644 thinkphp/tests/thinkphp/library/think/paginateTest.php delete mode 100644 thinkphp/tests/thinkphp/library/think/requestTest.php delete mode 100644 thinkphp/tests/thinkphp/library/think/responseTest.php delete mode 100644 thinkphp/tests/thinkphp/library/think/routeTest.php delete mode 100644 thinkphp/tests/thinkphp/library/think/session/.gitignore delete mode 100644 thinkphp/tests/thinkphp/library/think/sessionTest.php delete mode 100644 thinkphp/tests/thinkphp/library/think/template/driver/.gitignore delete mode 100644 thinkphp/tests/thinkphp/library/think/template/taglib/cxTest.php delete mode 100644 thinkphp/tests/thinkphp/library/think/templateTest.php delete mode 100644 thinkphp/tests/thinkphp/library/think/urlTest.php delete mode 100644 thinkphp/tests/thinkphp/library/think/validateTest.php delete mode 100644 thinkphp/tests/thinkphp/library/think/view/driver/.gitignore delete mode 100644 thinkphp/tests/thinkphp/library/think/view/theme/index/template.html delete mode 100644 thinkphp/tests/thinkphp/library/think/viewTest.php delete mode 100644 thinkphp/tests/thinkphp/library/traits/controller/.gitignore delete mode 100644 thinkphp/tests/thinkphp/library/traits/model/.gitignore diff --git a/application/config.php b/application/config.php index 38405e4a..fd8a9488 100644 --- a/application/config.php +++ b/application/config.php @@ -18,7 +18,7 @@ return [ // 应用命名空间 'app_namespace' => 'app', // 应用调试模式 - 'app_debug' => false, + 'app_debug' => true, // 应用Trace 'app_trace' => false, // 应用模式状态 diff --git a/application/index/controller/File.php b/application/index/controller/File.php index eb729005..fd744e59 100644 --- a/application/index/controller/File.php +++ b/application/index/controller/File.php @@ -44,7 +44,7 @@ class File extends Controller{ */ public function ListFile(){ $reqPath = stripslashes(json_decode(file_get_contents("php://input"),true)['path']); - return FileManage::ListFile($reqPath,$this->userObj->uid); + return json(FileManage::ListFile($reqPath,$this->userObj->uid)); } public function Delete(){ diff --git a/application/index/view/home/home.html b/application/index/view/home/home.html index 76332275..fa7b77ed 100644 --- a/application/index/view/home/home.html +++ b/application/index/view/home/home.html @@ -1,25 +1,26 @@ - - - - - - - 我的文件 - {$options.siteName} - - - - - - - - - - - - - - - - - -
- {include file="navbar_home" /} - - -
- -
-
- - - + + + + + +
+ + + diff --git a/application/index/view/home/home1.html b/application/index/view/home/home1.html new file mode 100644 index 00000000..76332275 --- /dev/null +++ b/application/index/view/home/home1.html @@ -0,0 +1,100 @@ + + + + + + + 我的文件 - {$options.siteName} + + + + + + + + + + + + + + + + + +
+ {include file="navbar_home" /} + + +
+ +
+
+ + + + + +{$options.js_code} + diff --git a/composer.lock b/composer.lock new file mode 100644 index 00000000..99877299 --- /dev/null +++ b/composer.lock @@ -0,0 +1,981 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "This file is @generated automatically" + ], + "content-hash": "1d88e4f4d3f5fc270f16d563f3fb7c5e", + "packages": [ + { + "name": "aliyuncs/oss-sdk-php", + "version": "v2.3.0", + "source": { + "type": "git", + "url": "https://github.com/aliyun/aliyun-oss-php-sdk.git", + "reference": "e69f57916678458642ac9d2fd341ae78a56996c8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/aliyun/aliyun-oss-php-sdk/zipball/e69f57916678458642ac9d2fd341ae78a56996c8", + "reference": "e69f57916678458642ac9d2fd341ae78a56996c8", + "shasum": "" + }, + "require": { + "php": ">=5.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.0", + "satooshi/php-coveralls": "~1.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "OSS\\": "src/OSS" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Aliyuncs", + "homepage": "http://www.aliyun.com" + } + ], + "description": "Aliyun OSS SDK for PHP", + "homepage": "http://www.aliyun.com/product/oss/", + "time": "2018-01-08T06:59:35+00:00" + }, + { + "name": "guzzlehttp/guzzle", + "version": "6.3.3", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/407b0cb880ace85c9b63c5f9551db498cb2d50ba", + "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba", + "shasum": "" + }, + "require": { + "guzzlehttp/promises": "^1.0", + "guzzlehttp/psr7": "^1.4", + "php": ">=5.5" + }, + "require-dev": { + "ext-curl": "*", + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0", + "psr/log": "^1.0" + }, + "suggest": { + "psr/log": "Required for using the Log middleware" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.3-dev" + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "rest", + "web service" + ], + "time": "2018-04-22T15:46:56+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "v1.3.1", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/a59da6cf61d80060647ff4d3eb2c03a2bc694646", + "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646", + "shasum": "" + }, + "require": { + "php": ">=5.5.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "time": "2016-12-20T10:07:11+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "1.5.2", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "9f83dded91781a01c63574e387eaa769be769115" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/9f83dded91781a01c63574e387eaa769be769115", + "reference": "9f83dded91781a01c63574e387eaa769be769115", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "psr/http-message": "~1.0", + "ralouphie/getallheaders": "^2.0.5" + }, + "provide": { + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.5-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Schultze", + "homepage": "https://github.com/Tobion" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "time": "2018-12-04T20:46:45+00:00" + }, + { + "name": "psr/http-message", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "time": "2016-08-06T14:39:51+00:00" + }, + { + "name": "psr/log", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd", + "reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "time": "2018-11-20T15:27:04+00:00" + }, + { + "name": "ralouphie/getallheaders", + "version": "2.0.5", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "5601c8a83fbba7ef674a7369456d12f1e0d0eafa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/5601c8a83fbba7ef674a7369456d12f1e0d0eafa", + "reference": "5601c8a83fbba7ef674a7369456d12f1e0d0eafa", + "shasum": "" + }, + "require": { + "php": ">=5.3" + }, + "require-dev": { + "phpunit/phpunit": "~3.7.0", + "satooshi/php-coveralls": ">=1.0" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "time": "2016-02-11T07:05:27+00:00" + }, + { + "name": "sabre/dav", + "version": "3.2.3", + "source": { + "type": "git", + "url": "https://github.com/sabre-io/dav.git", + "reference": "a9780ce4f35560ecbd0af524ad32d9d2c8954b80" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sabre-io/dav/zipball/a9780ce4f35560ecbd0af524ad32d9d2c8954b80", + "reference": "a9780ce4f35560ecbd0af524ad32d9d2c8954b80", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-date": "*", + "ext-dom": "*", + "ext-iconv": "*", + "ext-mbstring": "*", + "ext-pcre": "*", + "ext-simplexml": "*", + "ext-spl": "*", + "lib-libxml": ">=2.7.0", + "php": ">=5.5.0", + "psr/log": "^1.0", + "sabre/event": ">=2.0.0, <4.0.0", + "sabre/http": "^4.2.1", + "sabre/uri": "^1.0.1", + "sabre/vobject": "^4.1.0", + "sabre/xml": "^1.4.0" + }, + "require-dev": { + "evert/phpdoc-md": "~0.1.0", + "monolog/monolog": "^1.18", + "phpunit/phpunit": "> 4.8, <6.0.0", + "sabre/cs": "^1.0.0" + }, + "suggest": { + "ext-curl": "*", + "ext-pdo": "*" + }, + "bin": [ + "bin/sabredav", + "bin/naturalselection" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1.0-dev" + } + }, + "autoload": { + "psr-4": { + "Sabre\\DAV\\": "lib/DAV/", + "Sabre\\DAVACL\\": "lib/DAVACL/", + "Sabre\\CalDAV\\": "lib/CalDAV/", + "Sabre\\CardDAV\\": "lib/CardDAV/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Evert Pot", + "email": "me@evertpot.com", + "homepage": "http://evertpot.com/", + "role": "Developer" + } + ], + "description": "WebDAV Framework for PHP", + "homepage": "http://sabre.io/", + "keywords": [ + "CalDAV", + "CardDAV", + "WebDAV", + "framework", + "iCalendar" + ], + "time": "2018-10-19T09:58:27+00:00" + }, + { + "name": "sabre/event", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/sabre-io/event.git", + "reference": "831d586f5a442dceacdcf5e9c4c36a4db99a3534" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sabre-io/event/zipball/831d586f5a442dceacdcf5e9c4c36a4db99a3534", + "reference": "831d586f5a442dceacdcf5e9c4c36a4db99a3534", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "phpunit/phpunit": "*", + "sabre/cs": "~0.0.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "Sabre\\Event\\": "lib/" + }, + "files": [ + "lib/coroutine.php", + "lib/Loop/functions.php", + "lib/Promise/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Evert Pot", + "email": "me@evertpot.com", + "homepage": "http://evertpot.com/", + "role": "Developer" + } + ], + "description": "sabre/event is a library for lightweight event-based programming", + "homepage": "http://sabre.io/event/", + "keywords": [ + "EventEmitter", + "async", + "events", + "hooks", + "plugin", + "promise", + "signal" + ], + "time": "2015-11-05T20:14:39+00:00" + }, + { + "name": "sabre/http", + "version": "v4.2.4", + "source": { + "type": "git", + "url": "https://github.com/sabre-io/http.git", + "reference": "acccec4ba863959b2d10c1fa0fb902736c5c8956" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sabre-io/http/zipball/acccec4ba863959b2d10c1fa0fb902736c5c8956", + "reference": "acccec4ba863959b2d10c1fa0fb902736c5c8956", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-mbstring": "*", + "php": ">=5.4", + "sabre/event": ">=1.0.0,<4.0.0", + "sabre/uri": "~1.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.3", + "sabre/cs": "~0.0.1" + }, + "suggest": { + "ext-curl": " to make http requests with the Client class" + }, + "type": "library", + "autoload": { + "files": [ + "lib/functions.php" + ], + "psr-4": { + "Sabre\\HTTP\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Evert Pot", + "email": "me@evertpot.com", + "homepage": "http://evertpot.com/", + "role": "Developer" + } + ], + "description": "The sabre/http library provides utilities for dealing with http requests and responses. ", + "homepage": "https://github.com/fruux/sabre-http", + "keywords": [ + "http" + ], + "time": "2018-02-23T11:10:29+00:00" + }, + { + "name": "sabre/uri", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/sabre-io/uri.git", + "reference": "ada354d83579565949d80b2e15593c2371225e61" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sabre-io/uri/zipball/ada354d83579565949d80b2e15593c2371225e61", + "reference": "ada354d83579565949d80b2e15593c2371225e61", + "shasum": "" + }, + "require": { + "php": ">=5.4.7" + }, + "require-dev": { + "phpunit/phpunit": ">=4.0,<6.0", + "sabre/cs": "~1.0.0" + }, + "type": "library", + "autoload": { + "files": [ + "lib/functions.php" + ], + "psr-4": { + "Sabre\\Uri\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Evert Pot", + "email": "me@evertpot.com", + "homepage": "http://evertpot.com/", + "role": "Developer" + } + ], + "description": "Functions for making sense out of URIs.", + "homepage": "http://sabre.io/uri/", + "keywords": [ + "rfc3986", + "uri", + "url" + ], + "time": "2017-02-20T19:59:28+00:00" + }, + { + "name": "sabre/vobject", + "version": "4.2.0", + "source": { + "type": "git", + "url": "https://github.com/sabre-io/vobject.git", + "reference": "bd500019764e434ff65872d426f523e7882a0739" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sabre-io/vobject/zipball/bd500019764e434ff65872d426f523e7882a0739", + "reference": "bd500019764e434ff65872d426f523e7882a0739", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": ">=5.5", + "sabre/xml": ">=1.5 <3.0" + }, + "require-dev": { + "phpunit/phpunit": "> 4.8.35, <6.0.0" + }, + "suggest": { + "hoa/bench": "If you would like to run the benchmark scripts" + }, + "bin": [ + "bin/vobject", + "bin/generate_vcards" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Sabre\\VObject\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Evert Pot", + "email": "me@evertpot.com", + "homepage": "http://evertpot.com/", + "role": "Developer" + }, + { + "name": "Dominik Tobschall", + "email": "dominik@fruux.com", + "homepage": "http://tobschall.de/", + "role": "Developer" + }, + { + "name": "Ivan Enderlin", + "email": "ivan.enderlin@hoa-project.net", + "homepage": "http://mnt.io/", + "role": "Developer" + } + ], + "description": "The VObject library for PHP allows you to easily parse and manipulate iCalendar and vCard objects", + "homepage": "http://sabre.io/vobject/", + "keywords": [ + "availability", + "freebusy", + "iCalendar", + "ical", + "ics", + "jCal", + "jCard", + "recurrence", + "rfc2425", + "rfc2426", + "rfc2739", + "rfc4770", + "rfc5545", + "rfc5546", + "rfc6321", + "rfc6350", + "rfc6351", + "rfc6474", + "rfc6638", + "rfc6715", + "rfc6868", + "vCalendar", + "vCard", + "vcf", + "xCal", + "xCard" + ], + "time": "2019-02-19T13:05:37+00:00" + }, + { + "name": "sabre/xml", + "version": "1.5.1", + "source": { + "type": "git", + "url": "https://github.com/sabre-io/xml.git", + "reference": "a367665f1df614c3b8fefc30a54de7cd295e444e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sabre-io/xml/zipball/a367665f1df614c3b8fefc30a54de7cd295e444e", + "reference": "a367665f1df614c3b8fefc30a54de7cd295e444e", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-xmlreader": "*", + "ext-xmlwriter": "*", + "lib-libxml": ">=2.6.20", + "php": ">=5.5.5", + "sabre/uri": ">=1.0,<3.0.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.8|~5.7", + "sabre/cs": "~1.0.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Sabre\\Xml\\": "lib/" + }, + "files": [ + "lib/Deserializer/functions.php", + "lib/Serializer/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Evert Pot", + "email": "me@evertpot.com", + "homepage": "http://evertpot.com/", + "role": "Developer" + }, + { + "name": "Markus Staab", + "email": "markus.staab@redaxo.de", + "role": "Developer" + } + ], + "description": "sabre/xml is an XML library that you may not hate.", + "homepage": "https://sabre.io/xml/", + "keywords": [ + "XMLReader", + "XMLWriter", + "dom", + "xml" + ], + "time": "2019-01-09T13:51:57+00:00" + }, + { + "name": "topthink/framework", + "version": "v5.0.24", + "source": { + "type": "git", + "url": "https://github.com/top-think/framework.git", + "reference": "c255c22b2f5fa30f320ecf6c1d29f7740eb3e8be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/framework/zipball/c255c22b2f5fa30f320ecf6c1d29f7740eb3e8be", + "reference": "c255c22b2f5fa30f320ecf6c1d29f7740eb3e8be", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "topthink/think-installer": "~1.0" + }, + "require-dev": { + "johnkary/phpunit-speedtrap": "^1.0", + "mikey179/vfsstream": "~1.6", + "phpdocumentor/reflection-docblock": "^2.0", + "phploc/phploc": "2.*", + "phpunit/phpunit": "4.8.*", + "sebastian/phpcpd": "2.*" + }, + "type": "think-framework", + "autoload": { + "psr-4": { + "think\\": "library/think" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "liu21st", + "email": "liu21st@gmail.com" + } + ], + "description": "the new thinkphp framework", + "homepage": "http://thinkphp.cn/", + "keywords": [ + "framework", + "orm", + "thinkphp" + ], + "time": "2019-01-11T08:04:58+00:00" + }, + { + "name": "topthink/think-captcha", + "version": "v1.0.8", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-captcha.git", + "reference": "1d64363c814c92f6086c4fa5e3223fe7e23db09d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-captcha/zipball/1d64363c814c92f6086c4fa5e3223fe7e23db09d", + "reference": "1d64363c814c92f6086c4fa5e3223fe7e23db09d", + "shasum": "" + }, + "require": { + "topthink/framework": "~5.0.0", + "topthink/think-installer": ">=1.0.10" + }, + "type": "library", + "autoload": { + "psr-4": { + "think\\captcha\\": "src/" + }, + "files": [ + "src/helper.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "yunwuxin", + "email": "448901948@qq.com" + } + ], + "description": "captcha package for thinkphp5", + "time": "2019-01-28T04:48:36+00:00" + }, + { + "name": "topthink/think-installer", + "version": "v1.0.12", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-installer.git", + "reference": "1be326e68f63de4e95977ed50f46ae75f017556d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-installer/zipball/1be326e68f63de4e95977ed50f46ae75f017556d", + "reference": "1be326e68f63de4e95977ed50f46ae75f017556d", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.0" + }, + "require-dev": { + "composer/composer": "1.0.*@dev" + }, + "type": "composer-plugin", + "extra": { + "class": "think\\composer\\Plugin" + }, + "autoload": { + "psr-4": { + "think\\composer\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "yunwuxin", + "email": "448901948@qq.com" + } + ], + "time": "2017-05-27T06:58:09+00:00" + }, + { + "name": "upyun/sdk", + "version": "3.3.0", + "source": { + "type": "git", + "url": "https://github.com/upyun/php-sdk.git", + "reference": "1a2dd5ae31047956c733aef0f764f3a527d30628" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/upyun/php-sdk/zipball/1a2dd5ae31047956c733aef0f764f3a527d30628", + "reference": "1a2dd5ae31047956c733aef0f764f3a527d30628", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "guzzlehttp/guzzle": "~6.0", + "php": ">=5.5.0" + }, + "require-dev": { + "consolidation/robo": "^1.0", + "phpdocumentor/phpdocumentor": "^2.9", + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Upyun\\": "src/Upyun/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "totoleo", + "email": "totoleo@163.com" + }, + { + "name": "lfeng", + "email": "bonevv@gmail.com" + }, + { + "name": "lvtongda", + "email": "riyao.lyu@gmail.com" + }, + { + "name": "sabakugaara", + "email": "senellise@gmail.com" + } + ], + "description": "UPYUN sdk for php", + "homepage": "https://github.com/upyun/php-sdk/", + "keywords": [ + "sdk", + "upyun" + ], + "time": "2017-11-12T09:17:42+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "ext-curl": "*", + "ext-fileinfo": "*", + "ext-gd": "*" + }, + "platform-dev": [] +} diff --git a/static/js/uploader/i18n/zh_CN.js b/static/js/uploader/i18n/zh_CN.js new file mode 100644 index 00000000..f48e0c43 --- /dev/null +++ b/static/js/uploader/i18n/zh_CN.js @@ -0,0 +1,2 @@ +// Chinese (China) (zh_CN) +plupload.addI18n({"Stop Upload":"停止上传","Upload URL might be wrong or doesn't exist.":"上传的URL可能是错误的或不存在。","tb":"tb","Size":"大小","Close":"关闭","Init error.":"初始化错误。","Add files to the upload queue and click the start button.":"将文件添加到上传队列,然后点击”开始上传“按钮。","Filename":"文件名","Image format either wrong or not supported.":"图片格式错误或者不支持。","Status":"状态","HTTP Error.":"HTTP 错误。","Start Upload":"开始上传","mb":"mb","kb":"kb","Duplicate file error.":"重复文件错误。","File size error.":"文件大小错误。","N/A":"N/A","gb":"gb","Error: Invalid file extension:":"错误:无效的文件扩展名:","Select files":"选择文件","%s already present in the queue.":"%s 已经在当前队列里。","File: %s":"文件: %s","b":"b","Uploaded %d/%d files":"已上传 %d/%d 个文件","Upload element accepts only %d file(s) at a time. Extra files were stripped.":"每次只接受同时上传 %d 个文件,多余的文件将会被删除。","%d files queued":"%d 个文件加入到队列","File: %s, size: %d, max file size: %d":"文件: %s, 大小: %d, 最大文件大小: %d","Drag files here.":"把文件拖到这里。","Runtime ran out of available memory.":"运行时已消耗所有可用内存。","File count error.":"文件数量错误。","File extension error.":"文件扩展名错误。","Error: File too large:":"错误: 文件太大:","Add Files":"增加文件"}); \ No newline at end of file diff --git a/static/js/uploader/main.js b/static/js/uploader/main.js new file mode 100644 index 00000000..e0fa990b --- /dev/null +++ b/static/js/uploader/main.js @@ -0,0 +1,274 @@ +// /*global Qiniu */ +// /*global plupload */ +// /*global FileProgress */ +// /*global hljs */ +// function getCookieByString(cookieName){ +// var start = document.cookie.indexOf(cookieName+'='); +// if (start == -1) return false; +// start = start+cookieName.length+1; +// var end = document.cookie.indexOf(';', start); +// if (end == -1) end=document.cookie.length; +// return document.cookie.substring(start, end); +// } + +// if(uploadConfig.saveType == "oss" || uploadConfig.saveType == "upyun" || uploadConfig.saveType == "s3"){ +// ChunkSize = "0"; +// }else{ +// ChunkSize = "4mb"; +// } + +// uploader = Qiniu.uploader({ +// runtimes: 'html5,flash,html4', +// browse_button: 'pickfiles', +// container: 'container', +// drop_element: 'container', +// max_file_size: uploadConfig.maxSize, +// flash_swf_url: '/bower_components/plupload/js/Moxie.swf', +// dragdrop: true, +// chunk_size: ChunkSize, +// filters: { +// mime_types :uploadConfig.allowedType, +// }, +// multi_selection: !(moxie.core.utils.Env.OS.toLowerCase() === "ios"), +// uptoken_url: "/Upload/Token", +// // uptoken_func: function(){ +// // var ajax = new XMLHttpRequest(); +// // ajax.open('GET', $('#uptoken_url').val(), false); +// // ajax.setRequestHeader("If-Modified-Since", "0"); +// // ajax.send(); +// // if (ajax.status === 200) { +// // var res = JSON.parse(ajax.responseText); +// // console.log('custom uptoken_func:' + res.uptoken); +// // return res.uptoken; +// // } else { +// // console.log('custom uptoken_func err'); +// // return ''; +// // } +// // }, +// domain: $('#domain').val(), +// get_new_uptoken: true, +// // downtoken_url: '/downtoken', +// // unique_names: true, +// // save_key: true, +// // x_vars: { +// // 'id': '1234', +// // 'time': function(up, file) { +// // var time = (new Date()).getTime(); +// // // do something with 'time' +// // return time; +// // }, +// // }, +// auto_start: true, +// log_level: 5, +// init: { +// 'FilesAdded': function(up, files) { +// $('table').show(); +// $('#upload_box').show(); +// $('#success').hide(); +// $('#info_box').hide(); + +// $.cookie('path', decodeURI(getCookieByString("path_tmp"))); +// plupload.each(files, function(file) { +// var progress = new FileProgress(file, 'fsUploadProgress'); +// progress.setStatus("等待..."); +// progress.bindUploadCancel(up); +// }); + +// }, +// 'BeforeUpload': function(up, file) { +// var progress = new FileProgress(file, 'fsUploadProgress'); +// var chunk_size = plupload.parseSize(this.getOption('chunk_size')); +// if (up.runtime === 'html5' && chunk_size) { +// progress.setChunkProgess(chunk_size); +// } +// }, +// 'UploadProgress': function(up, file) { +// var progress = new FileProgress(file, 'fsUploadProgress'); +// var chunk_size = plupload.parseSize(this.getOption('chunk_size')); +// progress.setProgress(file.percent + "%", file.speed, chunk_size); +// }, +// 'UploadComplete': function(up, file) { +// $('#success').show(); +// toastr["success"]("队列全部文件处理完毕"); +// getMemory(); +// }, +// 'FileUploaded': function(up, file, info) { +// var progress = new FileProgress(file, 'fsUploadProgress'); +// progress.setComplete(up, info); +// }, +// 'Error': function(up, err, errTip) { +// $('#upload_box').show(); +// $('table').show(); +// $('#info_box').hide(); +// var progress = new FileProgress(err.file, 'fsUploadProgress'); +// progress.setError(); +// progress.setStatus(errTip); +// toastr["error"]("上传时遇到错误"); +// } +// // , +// // 'Key': function(up, file) { +// // var key = ""; +// // // do something with key +// // return key +// // } +// } +// }); + +// uploader.bind('FileUploaded', function(up,file) { +// console.log('a file is uploaded'); +// }); +// $('#container').on( +// 'dragenter', +// function(e) { +// e.preventDefault(); +// $('#container').addClass('draging'); +// e.stopPropagation(); +// } +// ).on('drop', function(e) { +// e.preventDefault(); +// $('#container').removeClass('draging'); +// e.stopPropagation(); +// }).on('dragleave', function(e) { +// e.preventDefault(); +// $('#container').removeClass('draging'); +// e.stopPropagation(); +// }).on('dragover', function(e) { +// e.preventDefault(); +// $('#container').addClass('draging'); +// e.stopPropagation(); +// }); + + + +// $('#show_code').on('click', function() { +// $('#myModal-code').modal(); +// $('pre code').each(function(i, e) { +// hljs.highlightBlock(e); +// }); +// }); + + +// $('body').on('click', 'table button.btn', function() { +// $(this).parents('tr').next().toggle(); +// }); + + +// var getRotate = function(url) { +// if (!url) { +// return 0; +// } +// var arr = url.split('/'); +// for (var i = 0, len = arr.length; i < len; i++) { +// if (arr[i] === 'rotate') { +// return parseInt(arr[i + 1], 10); +// } +// } +// return 0; +// }; + +// $('#myModal-img .modal-body-footer').find('a').on('click', function() { +// var img = $('#myModal-img').find('.modal-body img'); +// var key = img.data('key'); +// var oldUrl = img.attr('src'); +// var originHeight = parseInt(img.data('h'), 10); +// var fopArr = []; +// var rotate = getRotate(oldUrl); +// if (!$(this).hasClass('no-disable-click')) { +// $(this).addClass('disabled').siblings().removeClass('disabled'); +// if ($(this).data('imagemogr') !== 'no-rotate') { +// fopArr.push({ +// 'fop': 'imageMogr2', +// 'auto-orient': true, +// 'strip': true, +// 'rotate': rotate, +// 'format': 'png' +// }); +// } +// } else { +// $(this).siblings().removeClass('disabled'); +// var imageMogr = $(this).data('imagemogr'); +// if (imageMogr === 'left') { +// rotate = rotate - 90 < 0 ? rotate + 270 : rotate - 90; +// } else if (imageMogr === 'right') { +// rotate = rotate + 90 > 360 ? rotate - 270 : rotate + 90; +// } +// fopArr.push({ +// 'fop': 'imageMogr2', +// 'auto-orient': true, +// 'strip': true, +// 'rotate': rotate, +// 'format': 'png' +// }); +// } + +// $('#myModal-img .modal-body-footer').find('a.disabled').each(function() { + +// var watermark = $(this).data('watermark'); +// var imageView = $(this).data('imageview'); +// var imageMogr = $(this).data('imagemogr'); + +// if (watermark) { +// fopArr.push({ +// fop: 'watermark', +// mode: 1, +// image: 'http://www.b1.qiniudn.com/images/logo-2.png', +// dissolve: 100, +// gravity: watermark, +// dx: 100, +// dy: 100 +// }); +// } + +// if (imageView) { +// var height; +// switch (imageView) { +// case 'large': +// height = originHeight; +// break; +// case 'middle': +// height = originHeight * 0.5; +// break; +// case 'small': +// height = originHeight * 0.1; +// break; +// default: +// height = originHeight; +// break; +// } +// fopArr.push({ +// fop: 'imageView2', +// mode: 3, +// h: parseInt(height, 10), +// q: 100, +// format: 'png' +// }); +// } + +// if (imageMogr === 'no-rotate') { +// fopArr.push({ +// 'fop': 'imageMogr2', +// 'auto-orient': true, +// 'strip': true, +// 'rotate': 0, +// 'format': 'png' +// }); +// } +// }); + + + +// var newUrl = Qiniu.pipeline(fopArr, key); + +// var newImg = new Image(); +// img.attr('src', 'images/loading.gif'); +// newImg.onload = function() { +// img.attr('src', newUrl); +// img.parent('a').attr('href', newUrl); +// }; +// newImg.src = newUrl; +// return false; +// }); + +// function t(){ +// uploader.getNewUpToken(); +// } \ No newline at end of file diff --git a/static/js/uploader/moxie.js b/static/js/uploader/moxie.js new file mode 100644 index 00000000..d41397cd --- /dev/null +++ b/static/js/uploader/moxie.js @@ -0,0 +1,11509 @@ +;var MXI_DEBUG = true; +/** + * mOxie - multi-runtime File API & XMLHttpRequest L2 Polyfill + * v1.5.3 + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + * + * Date: 2017-02-02 + */ +;(function (global, factory) { + var extract = function() { + var ctx = {}; + factory.apply(ctx, arguments); + return ctx.moxie; + }; + + if (typeof define === "function" && define.amd) { + define("moxie", [], extract); + } else if (typeof module === "object" && module.exports) { + module.exports = extract(); + } else { + global.moxie = extract(); + } +}(this || window, function() { +/** + * Compiled inline version. (Library mode) + */ + +/*jshint smarttabs:true, undef:true, latedef:true, curly:true, bitwise:true, camelcase:true */ +/*globals $code */ + +(function(exports, undefined) { + "use strict"; + + var modules = {}; + + function require(ids, callback) { + var module, defs = []; + + for (var i = 0; i < ids.length; ++i) { + module = modules[ids[i]] || resolve(ids[i]); + if (!module) { + throw 'module definition dependecy not found: ' + ids[i]; + } + + defs.push(module); + } + + callback.apply(null, defs); + } + + function define(id, dependencies, definition) { + if (typeof id !== 'string') { + throw 'invalid module definition, module id must be defined and be a string'; + } + + if (dependencies === undefined) { + throw 'invalid module definition, dependencies must be specified'; + } + + if (definition === undefined) { + throw 'invalid module definition, definition function must be specified'; + } + + require(dependencies, function() { + modules[id] = definition.apply(null, arguments); + }); + } + + function defined(id) { + return !!modules[id]; + } + + function resolve(id) { + var target = exports; + var fragments = id.split(/[.\/]/); + + for (var fi = 0; fi < fragments.length; ++fi) { + if (!target[fragments[fi]]) { + return; + } + + target = target[fragments[fi]]; + } + + return target; + } + + function expose(ids) { + for (var i = 0; i < ids.length; i++) { + var target = exports; + var id = ids[i]; + var fragments = id.split(/[.\/]/); + + for (var fi = 0; fi < fragments.length - 1; ++fi) { + if (target[fragments[fi]] === undefined) { + target[fragments[fi]] = {}; + } + + target = target[fragments[fi]]; + } + + target[fragments[fragments.length - 1]] = modules[id]; + } + } + +// Included from: src/javascript/core/utils/Basic.js + +/** + * Basic.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/core/utils/Basic +@public +@static +*/ +define('moxie/core/utils/Basic', [], function() { + /** + Gets the true type of the built-in object (better version of typeof). + @author Angus Croll (http://javascriptweblog.wordpress.com/) + + @method typeOf + @for Utils + @static + @param {Object} o Object to check. + @return {String} Object [[Class]] + */ + function typeOf(o) { + var undef; + + if (o === undef) { + return 'undefined'; + } else if (o === null) { + return 'null'; + } else if (o.nodeType) { + return 'node'; + } + + // the snippet below is awesome, however it fails to detect null, undefined and arguments types in IE lte 8 + return ({}).toString.call(o).match(/\s([a-z|A-Z]+)/)[1].toLowerCase(); + } + + /** + Extends the specified object with another object(s). + + @method extend + @static + @param {Object} target Object to extend. + @param {Object} [obj]* Multiple objects to extend with. + @return {Object} Same as target, the extended object. + */ + function extend() { + return merge(false, false, arguments); + } + + + /** + Extends the specified object with another object(s), but only if the property exists in the target. + + @method extendIf + @static + @param {Object} target Object to extend. + @param {Object} [obj]* Multiple objects to extend with. + @return {Object} Same as target, the extended object. + */ + function extendIf() { + return merge(true, false, arguments); + } + + + function extendImmutable() { + return merge(false, true, arguments); + } + + + function extendImmutableIf() { + return merge(true, true, arguments); + } + + + function shallowCopy(obj) { + switch (typeOf(obj)) { + case 'array': + return Array.prototype.slice.call(obj); + + case 'object': + return extend({}, obj); + } + return obj; + } + + + function merge(strict, immutable, args) { + var undef; + var target = args[0]; + + each(args, function(arg, i) { + if (i > 0) { + each(arg, function(value, key) { + var isComplex = inArray(typeOf(value), ['array', 'object']) !== -1; + + if (value === undef || strict && target[key] === undef) { + return true; + } + + if (isComplex && immutable) { + value = shallowCopy(value); + } + + if (typeOf(target[key]) === typeOf(value) && isComplex) { + merge(strict, immutable, [target[key], value]); + } else { + target[key] = value; + } + }); + } + }); + + return target; + } + + + /** + A way to inherit one `class` from another in a consisstent way (more or less) + + @method inherit + @static + @since >1.4.1 + @param {Function} child + @param {Function} parent + @return {Function} Prepared constructor + */ + function inherit(child, parent) { + // copy over all parent properties + for (var key in parent) { + if ({}.hasOwnProperty.call(parent, key)) { + child[key] = parent[key]; + } + } + + // give child `class` a place to define its own methods + function ctor() { + this.constructor = child; + } + ctor.prototype = parent.prototype; + child.prototype = new ctor(); + + // keep a way to reference parent methods + child.__parent__ = parent.prototype; + return child; + } + + + /** + Executes the callback function for each item in array/object. If you return false in the + callback it will break the loop. + + @method each + @static + @param {Object} obj Object to iterate. + @param {function} callback Callback function to execute for each item. + */ + function each(obj, callback) { + var length, key, i, undef; + + if (obj) { + try { + length = obj.length; + } catch(ex) { + length = undef; + } + + if (length === undef || typeof(length) !== 'number') { + // Loop object items + for (key in obj) { + if (obj.hasOwnProperty(key)) { + if (callback(obj[key], key) === false) { + return; + } + } + } + } else { + // Loop array items + for (i = 0; i < length; i++) { + if (callback(obj[i], i) === false) { + return; + } + } + } + } + } + + /** + Checks if object is empty. + + @method isEmptyObj + @static + @param {Object} o Object to check. + @return {Boolean} + */ + function isEmptyObj(obj) { + var prop; + + if (!obj || typeOf(obj) !== 'object') { + return true; + } + + for (prop in obj) { + return false; + } + + return true; + } + + /** + Recieve an array of functions (usually async) to call in sequence, each function + receives a callback as first argument that it should call, when it completes. Finally, + after everything is complete, main callback is called. Passing truthy value to the + callback as a first argument will interrupt the sequence and invoke main callback + immediately. + + @method inSeries + @static + @param {Array} queue Array of functions to call in sequence + @param {Function} cb Main callback that is called in the end, or in case of error + */ + function inSeries(queue, cb) { + var i = 0, length = queue.length; + + if (typeOf(cb) !== 'function') { + cb = function() {}; + } + + if (!queue || !queue.length) { + cb(); + } + + function callNext(i) { + if (typeOf(queue[i]) === 'function') { + queue[i](function(error) { + /*jshint expr:true */ + ++i < length && !error ? callNext(i) : cb(error); + }); + } + } + callNext(i); + } + + + /** + Recieve an array of functions (usually async) to call in parallel, each function + receives a callback as first argument that it should call, when it completes. After + everything is complete, main callback is called. Passing truthy value to the + callback as a first argument will interrupt the process and invoke main callback + immediately. + + @method inParallel + @static + @param {Array} queue Array of functions to call in sequence + @param {Function} cb Main callback that is called in the end, or in case of erro + */ + function inParallel(queue, cb) { + var count = 0, num = queue.length, cbArgs = new Array(num); + + each(queue, function(fn, i) { + fn(function(error) { + if (error) { + return cb(error); + } + + var args = [].slice.call(arguments); + args.shift(); // strip error - undefined or not + + cbArgs[i] = args; + count++; + + if (count === num) { + cbArgs.unshift(null); + cb.apply(this, cbArgs); + } + }); + }); + } + + + /** + Find an element in array and return it's index if present, otherwise return -1. + + @method inArray + @static + @param {Mixed} needle Element to find + @param {Array} array + @return {Int} Index of the element, or -1 if not found + */ + function inArray(needle, array) { + if (array) { + if (Array.prototype.indexOf) { + return Array.prototype.indexOf.call(array, needle); + } + + for (var i = 0, length = array.length; i < length; i++) { + if (array[i] === needle) { + return i; + } + } + } + return -1; + } + + + /** + Returns elements of first array if they are not present in second. And false - otherwise. + + @private + @method arrayDiff + @param {Array} needles + @param {Array} array + @return {Array|Boolean} + */ + function arrayDiff(needles, array) { + var diff = []; + + if (typeOf(needles) !== 'array') { + needles = [needles]; + } + + if (typeOf(array) !== 'array') { + array = [array]; + } + + for (var i in needles) { + if (inArray(needles[i], array) === -1) { + diff.push(needles[i]); + } + } + return diff.length ? diff : false; + } + + + /** + Find intersection of two arrays. + + @private + @method arrayIntersect + @param {Array} array1 + @param {Array} array2 + @return {Array} Intersection of two arrays or null if there is none + */ + function arrayIntersect(array1, array2) { + var result = []; + each(array1, function(item) { + if (inArray(item, array2) !== -1) { + result.push(item); + } + }); + return result.length ? result : null; + } + + + /** + Forces anything into an array. + + @method toArray + @static + @param {Object} obj Object with length field. + @return {Array} Array object containing all items. + */ + function toArray(obj) { + var i, arr = []; + + for (i = 0; i < obj.length; i++) { + arr[i] = obj[i]; + } + + return arr; + } + + + /** + Generates an unique ID. The only way a user would be able to get the same ID is if the two persons + at the same exact millisecond manage to get the same 5 random numbers between 0-65535; it also uses + a counter so each ID is guaranteed to be unique for the given page. It is more probable for the earth + to be hit with an asteroid. + + @method guid + @static + @param {String} prefix to prepend (by default 'o' will be prepended). + @method guid + @return {String} Virtually unique id. + */ + var guid = (function() { + var counter = 0; + + return function(prefix) { + var guid = new Date().getTime().toString(32), i; + + for (i = 0; i < 5; i++) { + guid += Math.floor(Math.random() * 65535).toString(32); + } + + return (prefix || 'o_') + guid + (counter++).toString(32); + }; + }()); + + + /** + Trims white spaces around the string + + @method trim + @static + @param {String} str + @return {String} + */ + function trim(str) { + if (!str) { + return str; + } + return String.prototype.trim ? String.prototype.trim.call(str) : str.toString().replace(/^\s*/, '').replace(/\s*$/, ''); + } + + + /** + Parses the specified size string into a byte value. For example 10kb becomes 10240. + + @method parseSizeStr + @static + @param {String/Number} size String to parse or number to just pass through. + @return {Number} Size in bytes. + */ + function parseSizeStr(size) { + if (typeof(size) !== 'string') { + return size; + } + + var muls = { + t: 1099511627776, + g: 1073741824, + m: 1048576, + k: 1024 + }, + mul; + + size = /^([0-9\.]+)([tmgk]?)$/.exec(size.toLowerCase().replace(/[^0-9\.tmkg]/g, '')); + mul = size[2]; + size = +size[1]; + + if (muls.hasOwnProperty(mul)) { + size *= muls[mul]; + } + return Math.floor(size); + } + + + /** + * Pseudo sprintf implementation - simple way to replace tokens with specified values. + * + * @param {String} str String with tokens + * @return {String} String with replaced tokens + */ + function sprintf(str) { + var args = [].slice.call(arguments, 1); + + return str.replace(/%[a-z]/g, function() { + var value = args.shift(); + return typeOf(value) !== 'undefined' ? value : ''; + }); + } + + + + function delay(cb, timeout) { + var self = this; + setTimeout(function() { + cb.call(self); + }, timeout || 1); + } + + + return { + guid: guid, + typeOf: typeOf, + extend: extend, + extendIf: extendIf, + extendImmutable: extendImmutable, + extendImmutableIf: extendImmutableIf, + inherit: inherit, + each: each, + isEmptyObj: isEmptyObj, + inSeries: inSeries, + inParallel: inParallel, + inArray: inArray, + arrayDiff: arrayDiff, + arrayIntersect: arrayIntersect, + toArray: toArray, + trim: trim, + sprintf: sprintf, + parseSizeStr: parseSizeStr, + delay: delay + }; +}); + +// Included from: src/javascript/core/utils/Encode.js + +/** + * Encode.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +define('moxie/core/utils/Encode', [], function() { + + /** + @class moxie/core/utils/Encode + */ + + /** + Encode string with UTF-8 + + @method utf8_encode + @for Utils + @static + @param {String} str String to encode + @return {String} UTF-8 encoded string + */ + var utf8_encode = function(str) { + return unescape(encodeURIComponent(str)); + }; + + /** + Decode UTF-8 encoded string + + @method utf8_decode + @static + @param {String} str String to decode + @return {String} Decoded string + */ + var utf8_decode = function(str_data) { + return decodeURIComponent(escape(str_data)); + }; + + /** + Decode Base64 encoded string (uses browser's default method if available), + from: https://raw.github.com/kvz/phpjs/master/functions/url/base64_decode.js + + @method atob + @static + @param {String} data String to decode + @return {String} Decoded string + */ + var atob = function(data, utf8) { + if (typeof(window.atob) === 'function') { + return utf8 ? utf8_decode(window.atob(data)) : window.atob(data); + } + + // http://kevin.vanzonneveld.net + // + original by: Tyler Akins (http://rumkin.com) + // + improved by: Thunder.m + // + input by: Aman Gupta + // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + bugfixed by: Onno Marsman + // + bugfixed by: Pellentesque Malesuada + // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + input by: Brett Zamir (http://brett-zamir.me) + // + bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // * example 1: base64_decode('S2V2aW4gdmFuIFpvbm5ldmVsZA=='); + // * returns 1: 'Kevin van Zonneveld' + // mozilla has this native + // - but breaks in 2.0.0.12! + //if (typeof this.window.atob == 'function') { + // return atob(data); + //} + var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + var o1, o2, o3, h1, h2, h3, h4, bits, i = 0, + ac = 0, + dec = "", + tmp_arr = []; + + if (!data) { + return data; + } + + data += ''; + + do { // unpack four hexets into three octets using index points in b64 + h1 = b64.indexOf(data.charAt(i++)); + h2 = b64.indexOf(data.charAt(i++)); + h3 = b64.indexOf(data.charAt(i++)); + h4 = b64.indexOf(data.charAt(i++)); + + bits = h1 << 18 | h2 << 12 | h3 << 6 | h4; + + o1 = bits >> 16 & 0xff; + o2 = bits >> 8 & 0xff; + o3 = bits & 0xff; + + if (h3 == 64) { + tmp_arr[ac++] = String.fromCharCode(o1); + } else if (h4 == 64) { + tmp_arr[ac++] = String.fromCharCode(o1, o2); + } else { + tmp_arr[ac++] = String.fromCharCode(o1, o2, o3); + } + } while (i < data.length); + + dec = tmp_arr.join(''); + + return utf8 ? utf8_decode(dec) : dec; + }; + + /** + Base64 encode string (uses browser's default method if available), + from: https://raw.github.com/kvz/phpjs/master/functions/url/base64_encode.js + + @method btoa + @static + @param {String} data String to encode + @return {String} Base64 encoded string + */ + var btoa = function(data, utf8) { + if (utf8) { + data = utf8_encode(data); + } + + if (typeof(window.btoa) === 'function') { + return window.btoa(data); + } + + // http://kevin.vanzonneveld.net + // + original by: Tyler Akins (http://rumkin.com) + // + improved by: Bayron Guevara + // + improved by: Thunder.m + // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + bugfixed by: Pellentesque Malesuada + // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + improved by: Rafał Kukawski (http://kukawski.pl) + // * example 1: base64_encode('Kevin van Zonneveld'); + // * returns 1: 'S2V2aW4gdmFuIFpvbm5ldmVsZA==' + // mozilla has this native + // - but breaks in 2.0.0.12! + var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + var o1, o2, o3, h1, h2, h3, h4, bits, i = 0, + ac = 0, + enc = "", + tmp_arr = []; + + if (!data) { + return data; + } + + do { // pack three octets into four hexets + o1 = data.charCodeAt(i++); + o2 = data.charCodeAt(i++); + o3 = data.charCodeAt(i++); + + bits = o1 << 16 | o2 << 8 | o3; + + h1 = bits >> 18 & 0x3f; + h2 = bits >> 12 & 0x3f; + h3 = bits >> 6 & 0x3f; + h4 = bits & 0x3f; + + // use hexets to index into b64, and append result to encoded string + tmp_arr[ac++] = b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4); + } while (i < data.length); + + enc = tmp_arr.join(''); + + var r = data.length % 3; + + return (r ? enc.slice(0, r - 3) : enc) + '==='.slice(r || 3); + }; + + + return { + utf8_encode: utf8_encode, + utf8_decode: utf8_decode, + atob: atob, + btoa: btoa + }; +}); + +// Included from: src/javascript/core/utils/Env.js + +/** + * Env.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +define("moxie/core/utils/Env", [ + "moxie/core/utils/Basic" +], function(Basic) { + + /** + * UAParser.js v0.7.7 + * Lightweight JavaScript-based User-Agent string parser + * https://github.com/faisalman/ua-parser-js + * + * Copyright © 2012-2015 Faisal Salman + * Dual licensed under GPLv2 & MIT + */ + var UAParser = (function (undefined) { + + ////////////// + // Constants + ///////////// + + + var EMPTY = '', + UNKNOWN = '?', + FUNC_TYPE = 'function', + UNDEF_TYPE = 'undefined', + OBJ_TYPE = 'object', + MAJOR = 'major', + MODEL = 'model', + NAME = 'name', + TYPE = 'type', + VENDOR = 'vendor', + VERSION = 'version', + ARCHITECTURE= 'architecture', + CONSOLE = 'console', + MOBILE = 'mobile', + TABLET = 'tablet'; + + + /////////// + // Helper + ////////// + + + var util = { + has : function (str1, str2) { + return str2.toLowerCase().indexOf(str1.toLowerCase()) !== -1; + }, + lowerize : function (str) { + return str.toLowerCase(); + } + }; + + + /////////////// + // Map helper + ////////////// + + + var mapper = { + + rgx : function () { + + // loop through all regexes maps + for (var result, i = 0, j, k, p, q, matches, match, args = arguments; i < args.length; i += 2) { + + var regex = args[i], // even sequence (0,2,4,..) + props = args[i + 1]; // odd sequence (1,3,5,..) + + // construct object barebones + if (typeof(result) === UNDEF_TYPE) { + result = {}; + for (p in props) { + q = props[p]; + if (typeof(q) === OBJ_TYPE) { + result[q[0]] = undefined; + } else { + result[q] = undefined; + } + } + } + + // try matching uastring with regexes + for (j = k = 0; j < regex.length; j++) { + matches = regex[j].exec(this.getUA()); + if (!!matches) { + for (p = 0; p < props.length; p++) { + match = matches[++k]; + q = props[p]; + // check if given property is actually array + if (typeof(q) === OBJ_TYPE && q.length > 0) { + if (q.length == 2) { + if (typeof(q[1]) == FUNC_TYPE) { + // assign modified match + result[q[0]] = q[1].call(this, match); + } else { + // assign given value, ignore regex match + result[q[0]] = q[1]; + } + } else if (q.length == 3) { + // check whether function or regex + if (typeof(q[1]) === FUNC_TYPE && !(q[1].exec && q[1].test)) { + // call function (usually string mapper) + result[q[0]] = match ? q[1].call(this, match, q[2]) : undefined; + } else { + // sanitize match using given regex + result[q[0]] = match ? match.replace(q[1], q[2]) : undefined; + } + } else if (q.length == 4) { + result[q[0]] = match ? q[3].call(this, match.replace(q[1], q[2])) : undefined; + } + } else { + result[q] = match ? match : undefined; + } + } + break; + } + } + + if(!!matches) break; // break the loop immediately if match found + } + return result; + }, + + str : function (str, map) { + + for (var i in map) { + // check if array + if (typeof(map[i]) === OBJ_TYPE && map[i].length > 0) { + for (var j = 0; j < map[i].length; j++) { + if (util.has(map[i][j], str)) { + return (i === UNKNOWN) ? undefined : i; + } + } + } else if (util.has(map[i], str)) { + return (i === UNKNOWN) ? undefined : i; + } + } + return str; + } + }; + + + /////////////// + // String map + ////////////// + + + var maps = { + + browser : { + oldsafari : { + major : { + '1' : ['/8', '/1', '/3'], + '2' : '/4', + '?' : '/' + }, + version : { + '1.0' : '/8', + '1.2' : '/1', + '1.3' : '/3', + '2.0' : '/412', + '2.0.2' : '/416', + '2.0.3' : '/417', + '2.0.4' : '/419', + '?' : '/' + } + } + }, + + device : { + sprint : { + model : { + 'Evo Shift 4G' : '7373KT' + }, + vendor : { + 'HTC' : 'APA', + 'Sprint' : 'Sprint' + } + } + }, + + os : { + windows : { + version : { + 'ME' : '4.90', + 'NT 3.11' : 'NT3.51', + 'NT 4.0' : 'NT4.0', + '2000' : 'NT 5.0', + 'XP' : ['NT 5.1', 'NT 5.2'], + 'Vista' : 'NT 6.0', + '7' : 'NT 6.1', + '8' : 'NT 6.2', + '8.1' : 'NT 6.3', + 'RT' : 'ARM' + } + } + } + }; + + + ////////////// + // Regex map + ///////////// + + + var regexes = { + + browser : [[ + + // Presto based + /(opera\smini)\/([\w\.-]+)/i, // Opera Mini + /(opera\s[mobiletab]+).+version\/([\w\.-]+)/i, // Opera Mobi/Tablet + /(opera).+version\/([\w\.]+)/i, // Opera > 9.80 + /(opera)[\/\s]+([\w\.]+)/i // Opera < 9.80 + + ], [NAME, VERSION], [ + + /\s(opr)\/([\w\.]+)/i // Opera Webkit + ], [[NAME, 'Opera'], VERSION], [ + + // Mixed + /(kindle)\/([\w\.]+)/i, // Kindle + /(lunascape|maxthon|netfront|jasmine|blazer)[\/\s]?([\w\.]+)*/i, + // Lunascape/Maxthon/Netfront/Jasmine/Blazer + + // Trident based + /(avant\s|iemobile|slim|baidu)(?:browser)?[\/\s]?([\w\.]*)/i, + // Avant/IEMobile/SlimBrowser/Baidu + /(?:ms|\()(ie)\s([\w\.]+)/i, // Internet Explorer + + // Webkit/KHTML based + /(rekonq)\/([\w\.]+)*/i, // Rekonq + /(chromium|flock|rockmelt|midori|epiphany|silk|skyfire|ovibrowser|bolt|iron|vivaldi)\/([\w\.-]+)/i + // Chromium/Flock/RockMelt/Midori/Epiphany/Silk/Skyfire/Bolt/Iron + ], [NAME, VERSION], [ + + /(trident).+rv[:\s]([\w\.]+).+like\sgecko/i // IE11 + ], [[NAME, 'IE'], VERSION], [ + + /(edge)\/((\d+)?[\w\.]+)/i // Microsoft Edge + ], [NAME, VERSION], [ + + /(yabrowser)\/([\w\.]+)/i // Yandex + ], [[NAME, 'Yandex'], VERSION], [ + + /(comodo_dragon)\/([\w\.]+)/i // Comodo Dragon + ], [[NAME, /_/g, ' '], VERSION], [ + + /(chrome|omniweb|arora|[tizenoka]{5}\s?browser)\/v?([\w\.]+)/i, + // Chrome/OmniWeb/Arora/Tizen/Nokia + /(uc\s?browser|qqbrowser)[\/\s]?([\w\.]+)/i + // UCBrowser/QQBrowser + ], [NAME, VERSION], [ + + /(dolfin)\/([\w\.]+)/i // Dolphin + ], [[NAME, 'Dolphin'], VERSION], [ + + /((?:android.+)crmo|crios)\/([\w\.]+)/i // Chrome for Android/iOS + ], [[NAME, 'Chrome'], VERSION], [ + + /XiaoMi\/MiuiBrowser\/([\w\.]+)/i // MIUI Browser + ], [VERSION, [NAME, 'MIUI Browser']], [ + + /android.+version\/([\w\.]+)\s+(?:mobile\s?safari|safari)/i // Android Browser + ], [VERSION, [NAME, 'Android Browser']], [ + + /FBAV\/([\w\.]+);/i // Facebook App for iOS + ], [VERSION, [NAME, 'Facebook']], [ + + /version\/([\w\.]+).+?mobile\/\w+\s(safari)/i // Mobile Safari + ], [VERSION, [NAME, 'Mobile Safari']], [ + + /version\/([\w\.]+).+?(mobile\s?safari|safari)/i // Safari & Safari Mobile + ], [VERSION, NAME], [ + + /webkit.+?(mobile\s?safari|safari)(\/[\w\.]+)/i // Safari < 3.0 + ], [NAME, [VERSION, mapper.str, maps.browser.oldsafari.version]], [ + + /(konqueror)\/([\w\.]+)/i, // Konqueror + /(webkit|khtml)\/([\w\.]+)/i + ], [NAME, VERSION], [ + + // Gecko based + /(navigator|netscape)\/([\w\.-]+)/i // Netscape + ], [[NAME, 'Netscape'], VERSION], [ + /(swiftfox)/i, // Swiftfox + /(icedragon|iceweasel|camino|chimera|fennec|maemo\sbrowser|minimo|conkeror)[\/\s]?([\w\.\+]+)/i, + // IceDragon/Iceweasel/Camino/Chimera/Fennec/Maemo/Minimo/Conkeror + /(firefox|seamonkey|k-meleon|icecat|iceape|firebird|phoenix)\/([\w\.-]+)/i, + // Firefox/SeaMonkey/K-Meleon/IceCat/IceApe/Firebird/Phoenix + /(mozilla)\/([\w\.]+).+rv\:.+gecko\/\d+/i, // Mozilla + + // Other + /(polaris|lynx|dillo|icab|doris|amaya|w3m|netsurf)[\/\s]?([\w\.]+)/i, + // Polaris/Lynx/Dillo/iCab/Doris/Amaya/w3m/NetSurf + /(links)\s\(([\w\.]+)/i, // Links + /(gobrowser)\/?([\w\.]+)*/i, // GoBrowser + /(ice\s?browser)\/v?([\w\._]+)/i, // ICE Browser + /(mosaic)[\/\s]([\w\.]+)/i // Mosaic + ], [NAME, VERSION] + ], + + engine : [[ + + /windows.+\sedge\/([\w\.]+)/i // EdgeHTML + ], [VERSION, [NAME, 'EdgeHTML']], [ + + /(presto)\/([\w\.]+)/i, // Presto + /(webkit|trident|netfront|netsurf|amaya|lynx|w3m)\/([\w\.]+)/i, // WebKit/Trident/NetFront/NetSurf/Amaya/Lynx/w3m + /(khtml|tasman|links)[\/\s]\(?([\w\.]+)/i, // KHTML/Tasman/Links + /(icab)[\/\s]([23]\.[\d\.]+)/i // iCab + ], [NAME, VERSION], [ + + /rv\:([\w\.]+).*(gecko)/i // Gecko + ], [VERSION, NAME] + ], + + os : [[ + + // Windows based + /microsoft\s(windows)\s(vista|xp)/i // Windows (iTunes) + ], [NAME, VERSION], [ + /(windows)\snt\s6\.2;\s(arm)/i, // Windows RT + /(windows\sphone(?:\sos)*|windows\smobile|windows)[\s\/]?([ntce\d\.\s]+\w)/i + ], [NAME, [VERSION, mapper.str, maps.os.windows.version]], [ + /(win(?=3|9|n)|win\s9x\s)([nt\d\.]+)/i + ], [[NAME, 'Windows'], [VERSION, mapper.str, maps.os.windows.version]], [ + + // Mobile/Embedded OS + /\((bb)(10);/i // BlackBerry 10 + ], [[NAME, 'BlackBerry'], VERSION], [ + /(blackberry)\w*\/?([\w\.]+)*/i, // Blackberry + /(tizen)[\/\s]([\w\.]+)/i, // Tizen + /(android|webos|palm\os|qnx|bada|rim\stablet\sos|meego|contiki)[\/\s-]?([\w\.]+)*/i, + // Android/WebOS/Palm/QNX/Bada/RIM/MeeGo/Contiki + /linux;.+(sailfish);/i // Sailfish OS + ], [NAME, VERSION], [ + /(symbian\s?os|symbos|s60(?=;))[\/\s-]?([\w\.]+)*/i // Symbian + ], [[NAME, 'Symbian'], VERSION], [ + /\((series40);/i // Series 40 + ], [NAME], [ + /mozilla.+\(mobile;.+gecko.+firefox/i // Firefox OS + ], [[NAME, 'Firefox OS'], VERSION], [ + + // Console + /(nintendo|playstation)\s([wids3portablevu]+)/i, // Nintendo/Playstation + + // GNU/Linux based + /(mint)[\/\s\(]?(\w+)*/i, // Mint + /(mageia|vectorlinux)[;\s]/i, // Mageia/VectorLinux + /(joli|[kxln]?ubuntu|debian|[open]*suse|gentoo|arch|slackware|fedora|mandriva|centos|pclinuxos|redhat|zenwalk|linpus)[\/\s-]?([\w\.-]+)*/i, + // Joli/Ubuntu/Debian/SUSE/Gentoo/Arch/Slackware + // Fedora/Mandriva/CentOS/PCLinuxOS/RedHat/Zenwalk/Linpus + /(hurd|linux)\s?([\w\.]+)*/i, // Hurd/Linux + /(gnu)\s?([\w\.]+)*/i // GNU + ], [NAME, VERSION], [ + + /(cros)\s[\w]+\s([\w\.]+\w)/i // Chromium OS + ], [[NAME, 'Chromium OS'], VERSION],[ + + // Solaris + /(sunos)\s?([\w\.]+\d)*/i // Solaris + ], [[NAME, 'Solaris'], VERSION], [ + + // BSD based + /\s([frentopc-]{0,4}bsd|dragonfly)\s?([\w\.]+)*/i // FreeBSD/NetBSD/OpenBSD/PC-BSD/DragonFly + ], [NAME, VERSION],[ + + /(ip[honead]+)(?:.*os\s*([\w]+)*\slike\smac|;\sopera)/i // iOS + ], [[NAME, 'iOS'], [VERSION, /_/g, '.']], [ + + /(mac\sos\sx)\s?([\w\s\.]+\w)*/i, + /(macintosh|mac(?=_powerpc)\s)/i // Mac OS + ], [[NAME, 'Mac OS'], [VERSION, /_/g, '.']], [ + + // Other + /((?:open)?solaris)[\/\s-]?([\w\.]+)*/i, // Solaris + /(haiku)\s(\w+)/i, // Haiku + /(aix)\s((\d)(?=\.|\)|\s)[\w\.]*)*/i, // AIX + /(plan\s9|minix|beos|os\/2|amigaos|morphos|risc\sos|openvms)/i, + // Plan9/Minix/BeOS/OS2/AmigaOS/MorphOS/RISCOS/OpenVMS + /(unix)\s?([\w\.]+)*/i // UNIX + ], [NAME, VERSION] + ] + }; + + + ///////////////// + // Constructor + //////////////// + + + var UAParser = function (uastring) { + + var ua = uastring || ((window && window.navigator && window.navigator.userAgent) ? window.navigator.userAgent : EMPTY); + + this.getBrowser = function () { + return mapper.rgx.apply(this, regexes.browser); + }; + this.getEngine = function () { + return mapper.rgx.apply(this, regexes.engine); + }; + this.getOS = function () { + return mapper.rgx.apply(this, regexes.os); + }; + this.getResult = function() { + return { + ua : this.getUA(), + browser : this.getBrowser(), + engine : this.getEngine(), + os : this.getOS() + }; + }; + this.getUA = function () { + return ua; + }; + this.setUA = function (uastring) { + ua = uastring; + return this; + }; + this.setUA(ua); + }; + + return UAParser; + })(); + + + function version_compare(v1, v2, operator) { + // From: http://phpjs.org/functions + // + original by: Philippe Jausions (http://pear.php.net/user/jausions) + // + original by: Aidan Lister (http://aidanlister.com/) + // + reimplemented by: Kankrelune (http://www.webfaktory.info/) + // + improved by: Brett Zamir (http://brett-zamir.me) + // + improved by: Scott Baker + // + improved by: Theriault + // * example 1: version_compare('8.2.5rc', '8.2.5a'); + // * returns 1: 1 + // * example 2: version_compare('8.2.50', '8.2.52', '<'); + // * returns 2: true + // * example 3: version_compare('5.3.0-dev', '5.3.0'); + // * returns 3: -1 + // * example 4: version_compare('4.1.0.52','4.01.0.51'); + // * returns 4: 1 + + // Important: compare must be initialized at 0. + var i = 0, + x = 0, + compare = 0, + // vm maps textual PHP versions to negatives so they're less than 0. + // PHP currently defines these as CASE-SENSITIVE. It is important to + // leave these as negatives so that they can come before numerical versions + // and as if no letters were there to begin with. + // (1alpha is < 1 and < 1.1 but > 1dev1) + // If a non-numerical value can't be mapped to this table, it receives + // -7 as its value. + vm = { + 'dev': -6, + 'alpha': -5, + 'a': -5, + 'beta': -4, + 'b': -4, + 'RC': -3, + 'rc': -3, + '#': -2, + 'p': 1, + 'pl': 1 + }, + // This function will be called to prepare each version argument. + // It replaces every _, -, and + with a dot. + // It surrounds any nonsequence of numbers/dots with dots. + // It replaces sequences of dots with a single dot. + // version_compare('4..0', '4.0') == 0 + // Important: A string of 0 length needs to be converted into a value + // even less than an unexisting value in vm (-7), hence [-8]. + // It's also important to not strip spaces because of this. + // version_compare('', ' ') == 1 + prepVersion = function (v) { + v = ('' + v).replace(/[_\-+]/g, '.'); + v = v.replace(/([^.\d]+)/g, '.$1.').replace(/\.{2,}/g, '.'); + return (!v.length ? [-8] : v.split('.')); + }, + // This converts a version component to a number. + // Empty component becomes 0. + // Non-numerical component becomes a negative number. + // Numerical component becomes itself as an integer. + numVersion = function (v) { + return !v ? 0 : (isNaN(v) ? vm[v] || -7 : parseInt(v, 10)); + }; + + v1 = prepVersion(v1); + v2 = prepVersion(v2); + x = Math.max(v1.length, v2.length); + for (i = 0; i < x; i++) { + if (v1[i] == v2[i]) { + continue; + } + v1[i] = numVersion(v1[i]); + v2[i] = numVersion(v2[i]); + if (v1[i] < v2[i]) { + compare = -1; + break; + } else if (v1[i] > v2[i]) { + compare = 1; + break; + } + } + if (!operator) { + return compare; + } + + // Important: operator is CASE-SENSITIVE. + // "No operator" seems to be treated as "<." + // Any other values seem to make the function return null. + switch (operator) { + case '>': + case 'gt': + return (compare > 0); + case '>=': + case 'ge': + return (compare >= 0); + case '<=': + case 'le': + return (compare <= 0); + case '==': + case '=': + case 'eq': + return (compare === 0); + case '<>': + case '!=': + case 'ne': + return (compare !== 0); + case '': + case '<': + case 'lt': + return (compare < 0); + default: + return null; + } + } + + + var can = (function() { + var caps = { + define_property: (function() { + /* // currently too much extra code required, not exactly worth it + try { // as of IE8, getters/setters are supported only on DOM elements + var obj = {}; + if (Object.defineProperty) { + Object.defineProperty(obj, 'prop', { + enumerable: true, + configurable: true + }); + return true; + } + } catch(ex) {} + + if (Object.prototype.__defineGetter__ && Object.prototype.__defineSetter__) { + return true; + }*/ + return false; + }()), + + create_canvas: (function() { + // On the S60 and BB Storm, getContext exists, but always returns undefined + // so we actually have to call getContext() to verify + // github.com/Modernizr/Modernizr/issues/issue/97/ + var el = document.createElement('canvas'); + return !!(el.getContext && el.getContext('2d')); + }()), + + return_response_type: function(responseType) { + try { + if (Basic.inArray(responseType, ['', 'text', 'document']) !== -1) { + return true; + } else if (window.XMLHttpRequest) { + var xhr = new XMLHttpRequest(); + xhr.open('get', '/'); // otherwise Gecko throws an exception + if ('responseType' in xhr) { + xhr.responseType = responseType; + // as of 23.0.1271.64, Chrome switched from throwing exception to merely logging it to the console (why? o why?) + if (xhr.responseType !== responseType) { + return false; + } + return true; + } + } + } catch (ex) {} + return false; + }, + + // ideas for this heavily come from Modernizr (http://modernizr.com/) + use_data_uri: (function() { + var du = new Image(); + + du.onload = function() { + caps.use_data_uri = (du.width === 1 && du.height === 1); + }; + + setTimeout(function() { + du.src = "data:image/gif;base64,R0lGODlhAQABAIAAAP8AAAAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw=="; + }, 1); + return false; + }()), + + use_data_uri_over32kb: function() { // IE8 + return caps.use_data_uri && (Env.browser !== 'IE' || Env.version >= 9); + }, + + use_data_uri_of: function(bytes) { + return (caps.use_data_uri && bytes < 33000 || caps.use_data_uri_over32kb()); + }, + + use_fileinput: function() { + if (navigator.userAgent.match(/(Android (1.0|1.1|1.5|1.6|2.0|2.1))|(Windows Phone (OS 7|8.0))|(XBLWP)|(ZuneWP)|(w(eb)?OSBrowser)|(webOS)|(Kindle\/(1.0|2.0|2.5|3.0))/)) { + return false; + } + + var el = document.createElement('input'); + el.setAttribute('type', 'file'); + return !el.disabled; + } + }; + + return function(cap) { + var args = [].slice.call(arguments); + args.shift(); // shift of cap + return Basic.typeOf(caps[cap]) === 'function' ? caps[cap].apply(this, args) : !!caps[cap]; + }; + }()); + + + var uaResult = new UAParser().getResult(); + + + var Env = { + can: can, + + uaParser: UAParser, + + browser: uaResult.browser.name, + version: uaResult.browser.version, + os: uaResult.os.name, // everybody intuitively types it in a lowercase for some reason + osVersion: uaResult.os.version, + + verComp: version_compare, + + swf_url: "../flash/Moxie.swf", + xap_url: "../silverlight/Moxie.xap", + global_event_dispatcher: "moxie.core.EventTarget.instance.dispatchEvent" + }; + + // for backward compatibility + // @deprecated Use `Env.os` instead + Env.OS = Env.os; + + if (MXI_DEBUG) { + Env.debug = { + runtime: true, + events: false + }; + + Env.log = function() { + + function logObj(data) { + // TODO: this should recursively print out the object in a pretty way + console.appendChild(document.createTextNode(data + "\n")); + } + + var data = arguments[0]; + + if (Basic.typeOf(data) === 'string') { + data = Basic.sprintf.apply(this, arguments); + } + + if (window && window.console && window.console.log) { + window.console.log(data); + } else if (document) { + var console = document.getElementById('moxie-console'); + if (!console) { + console = document.createElement('pre'); + console.id = 'moxie-console'; + //console.style.display = 'none'; + document.body.appendChild(console); + } + + if (Basic.inArray(Basic.typeOf(data), ['object', 'array']) !== -1) { + logObj(data); + } else { + console.appendChild(document.createTextNode(data + "\n")); + } + } + }; + } + + return Env; +}); + +// Included from: src/javascript/core/Exceptions.js + +/** + * Exceptions.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +define('moxie/core/Exceptions', [ + 'moxie/core/utils/Basic' +], function(Basic) { + + function _findKey(obj, value) { + var key; + for (key in obj) { + if (obj[key] === value) { + return key; + } + } + return null; + } + + /** + @class moxie/core/Exception + */ + return { + RuntimeError: (function() { + var namecodes = { + NOT_INIT_ERR: 1, + EXCEPTION_ERR: 3, + NOT_SUPPORTED_ERR: 9, + JS_ERR: 4 + }; + + function RuntimeError(code, message) { + this.code = code; + this.name = _findKey(namecodes, code); + this.message = this.name + (message || ": RuntimeError " + this.code); + } + + Basic.extend(RuntimeError, namecodes); + RuntimeError.prototype = Error.prototype; + return RuntimeError; + }()), + + OperationNotAllowedException: (function() { + + function OperationNotAllowedException(code) { + this.code = code; + this.name = 'OperationNotAllowedException'; + } + + Basic.extend(OperationNotAllowedException, { + NOT_ALLOWED_ERR: 1 + }); + + OperationNotAllowedException.prototype = Error.prototype; + + return OperationNotAllowedException; + }()), + + ImageError: (function() { + var namecodes = { + WRONG_FORMAT: 1, + MAX_RESOLUTION_ERR: 2, + INVALID_META_ERR: 3 + }; + + function ImageError(code) { + this.code = code; + this.name = _findKey(namecodes, code); + this.message = this.name + ": ImageError " + this.code; + } + + Basic.extend(ImageError, namecodes); + ImageError.prototype = Error.prototype; + + return ImageError; + }()), + + FileException: (function() { + var namecodes = { + NOT_FOUND_ERR: 1, + SECURITY_ERR: 2, + ABORT_ERR: 3, + NOT_READABLE_ERR: 4, + ENCODING_ERR: 5, + NO_MODIFICATION_ALLOWED_ERR: 6, + INVALID_STATE_ERR: 7, + SYNTAX_ERR: 8 + }; + + function FileException(code) { + this.code = code; + this.name = _findKey(namecodes, code); + this.message = this.name + ": FileException " + this.code; + } + + Basic.extend(FileException, namecodes); + FileException.prototype = Error.prototype; + return FileException; + }()), + + DOMException: (function() { + var namecodes = { + INDEX_SIZE_ERR: 1, + DOMSTRING_SIZE_ERR: 2, + HIERARCHY_REQUEST_ERR: 3, + WRONG_DOCUMENT_ERR: 4, + INVALID_CHARACTER_ERR: 5, + NO_DATA_ALLOWED_ERR: 6, + NO_MODIFICATION_ALLOWED_ERR: 7, + NOT_FOUND_ERR: 8, + NOT_SUPPORTED_ERR: 9, + INUSE_ATTRIBUTE_ERR: 10, + INVALID_STATE_ERR: 11, + SYNTAX_ERR: 12, + INVALID_MODIFICATION_ERR: 13, + NAMESPACE_ERR: 14, + INVALID_ACCESS_ERR: 15, + VALIDATION_ERR: 16, + TYPE_MISMATCH_ERR: 17, + SECURITY_ERR: 18, + NETWORK_ERR: 19, + ABORT_ERR: 20, + URL_MISMATCH_ERR: 21, + QUOTA_EXCEEDED_ERR: 22, + TIMEOUT_ERR: 23, + INVALID_NODE_TYPE_ERR: 24, + DATA_CLONE_ERR: 25 + }; + + function DOMException(code) { + this.code = code; + this.name = _findKey(namecodes, code); + this.message = this.name + ": DOMException " + this.code; + } + + Basic.extend(DOMException, namecodes); + DOMException.prototype = Error.prototype; + return DOMException; + }()), + + EventException: (function() { + function EventException(code) { + this.code = code; + this.name = 'EventException'; + } + + Basic.extend(EventException, { + UNSPECIFIED_EVENT_TYPE_ERR: 0 + }); + + EventException.prototype = Error.prototype; + + return EventException; + }()) + }; +}); + +// Included from: src/javascript/core/utils/Dom.js + +/** + * Dom.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +define('moxie/core/utils/Dom', ['moxie/core/utils/Env'], function(Env) { + + /** + Get DOM Element by it's id. + + @method get + @for Utils + @param {String} id Identifier of the DOM Element + @return {DOMElement} + */ + var get = function(id) { + if (typeof id !== 'string') { + return id; + } + return document.getElementById(id); + }; + + /** + Checks if specified DOM element has specified class. + + @method hasClass + @static + @param {Object} obj DOM element like object to add handler to. + @param {String} name Class name + */ + var hasClass = function(obj, name) { + if (!obj.className) { + return false; + } + + var regExp = new RegExp("(^|\\s+)"+name+"(\\s+|$)"); + return regExp.test(obj.className); + }; + + /** + Adds specified className to specified DOM element. + + @method addClass + @static + @param {Object} obj DOM element like object to add handler to. + @param {String} name Class name + */ + var addClass = function(obj, name) { + if (!hasClass(obj, name)) { + obj.className = !obj.className ? name : obj.className.replace(/\s+$/, '') + ' ' + name; + } + }; + + /** + Removes specified className from specified DOM element. + + @method removeClass + @static + @param {Object} obj DOM element like object to add handler to. + @param {String} name Class name + */ + var removeClass = function(obj, name) { + if (obj.className) { + var regExp = new RegExp("(^|\\s+)"+name+"(\\s+|$)"); + obj.className = obj.className.replace(regExp, function($0, $1, $2) { + return $1 === ' ' && $2 === ' ' ? ' ' : ''; + }); + } + }; + + /** + Returns a given computed style of a DOM element. + + @method getStyle + @static + @param {Object} obj DOM element like object. + @param {String} name Style you want to get from the DOM element + */ + var getStyle = function(obj, name) { + if (obj.currentStyle) { + return obj.currentStyle[name]; + } else if (window.getComputedStyle) { + return window.getComputedStyle(obj, null)[name]; + } + }; + + + /** + Returns the absolute x, y position of an Element. The position will be returned in a object with x, y fields. + + @method getPos + @static + @param {Element} node HTML element or element id to get x, y position from. + @param {Element} root Optional root element to stop calculations at. + @return {object} Absolute position of the specified element object with x, y fields. + */ + var getPos = function(node, root) { + var x = 0, y = 0, parent, doc = document, nodeRect, rootRect; + + node = node; + root = root || doc.body; + + // Returns the x, y cordinate for an element on IE 6 and IE 7 + function getIEPos(node) { + var bodyElm, rect, x = 0, y = 0; + + if (node) { + rect = node.getBoundingClientRect(); + bodyElm = doc.compatMode === "CSS1Compat" ? doc.documentElement : doc.body; + x = rect.left + bodyElm.scrollLeft; + y = rect.top + bodyElm.scrollTop; + } + + return { + x : x, + y : y + }; + } + + // Use getBoundingClientRect on IE 6 and IE 7 but not on IE 8 in standards mode + if (node && node.getBoundingClientRect && Env.browser === 'IE' && (!doc.documentMode || doc.documentMode < 8)) { + nodeRect = getIEPos(node); + rootRect = getIEPos(root); + + return { + x : nodeRect.x - rootRect.x, + y : nodeRect.y - rootRect.y + }; + } + + parent = node; + while (parent && parent != root && parent.nodeType) { + x += parent.offsetLeft || 0; + y += parent.offsetTop || 0; + parent = parent.offsetParent; + } + + parent = node.parentNode; + while (parent && parent != root && parent.nodeType) { + x -= parent.scrollLeft || 0; + y -= parent.scrollTop || 0; + parent = parent.parentNode; + } + + return { + x : x, + y : y + }; + }; + + /** + Returns the size of the specified node in pixels. + + @method getSize + @static + @param {Node} node Node to get the size of. + @return {Object} Object with a w and h property. + */ + var getSize = function(node) { + return { + w : node.offsetWidth || node.clientWidth, + h : node.offsetHeight || node.clientHeight + }; + }; + + return { + get: get, + hasClass: hasClass, + addClass: addClass, + removeClass: removeClass, + getStyle: getStyle, + getPos: getPos, + getSize: getSize + }; +}); + +// Included from: src/javascript/core/EventTarget.js + +/** + * EventTarget.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +define('moxie/core/EventTarget', [ + 'moxie/core/utils/Env', + 'moxie/core/Exceptions', + 'moxie/core/utils/Basic' +], function(Env, x, Basic) { + + // hash of event listeners by object uid + var eventpool = {}; + + /** + Parent object for all event dispatching components and objects + + @class moxie/core/EventTarget + @constructor EventTarget + */ + function EventTarget() { + /** + Unique id of the event dispatcher, usually overriden by children + + @property uid + @type String + */ + this.uid = Basic.guid(); + } + + + Basic.extend(EventTarget.prototype, { + + /** + Can be called from within a child in order to acquire uniqie id in automated manner + + @method init + */ + init: function() { + if (!this.uid) { + this.uid = Basic.guid('uid_'); + } + }, + + /** + Register a handler to a specific event dispatched by the object + + @method addEventListener + @param {String} type Type or basically a name of the event to subscribe to + @param {Function} fn Callback function that will be called when event happens + @param {Number} [priority=0] Priority of the event handler - handlers with higher priorities will be called first + @param {Object} [scope=this] A scope to invoke event handler in + */ + addEventListener: function(type, fn, priority, scope) { + var self = this, list; + + // without uid no event handlers can be added, so make sure we got one + if (!this.hasOwnProperty('uid')) { + this.uid = Basic.guid('uid_'); + } + + type = Basic.trim(type); + + if (/\s/.test(type)) { + // multiple event types were passed for one handler + Basic.each(type.split(/\s+/), function(type) { + self.addEventListener(type, fn, priority, scope); + }); + return; + } + + type = type.toLowerCase(); + priority = parseInt(priority, 10) || 0; + + list = eventpool[this.uid] && eventpool[this.uid][type] || []; + list.push({fn : fn, priority : priority, scope : scope || this}); + + if (!eventpool[this.uid]) { + eventpool[this.uid] = {}; + } + eventpool[this.uid][type] = list; + }, + + /** + Check if any handlers were registered to the specified event + + @method hasEventListener + @param {String} [type] Type or basically a name of the event to check + @return {Mixed} Returns a handler if it was found and false, if - not + */ + hasEventListener: function(type) { + var list; + if (type) { + type = type.toLowerCase(); + list = eventpool[this.uid] && eventpool[this.uid][type]; + } else { + list = eventpool[this.uid]; + } + return list ? list : false; + }, + + /** + Unregister the handler from the event, or if former was not specified - unregister all handlers + + @method removeEventListener + @param {String} type Type or basically a name of the event + @param {Function} [fn] Handler to unregister + */ + removeEventListener: function(type, fn) { + var self = this, list, i; + + type = type.toLowerCase(); + + if (/\s/.test(type)) { + // multiple event types were passed for one handler + Basic.each(type.split(/\s+/), function(type) { + self.removeEventListener(type, fn); + }); + return; + } + + list = eventpool[this.uid] && eventpool[this.uid][type]; + + if (list) { + if (fn) { + for (i = list.length - 1; i >= 0; i--) { + if (list[i].fn === fn) { + list.splice(i, 1); + break; + } + } + } else { + list = []; + } + + // delete event list if it has become empty + if (!list.length) { + delete eventpool[this.uid][type]; + + // and object specific entry in a hash if it has no more listeners attached + if (Basic.isEmptyObj(eventpool[this.uid])) { + delete eventpool[this.uid]; + } + } + } + }, + + /** + Remove all event handlers from the object + + @method removeAllEventListeners + */ + removeAllEventListeners: function() { + if (eventpool[this.uid]) { + delete eventpool[this.uid]; + } + }, + + /** + Dispatch the event + + @method dispatchEvent + @param {String/Object} Type of event or event object to dispatch + @param {Mixed} [...] Variable number of arguments to be passed to a handlers + @return {Boolean} true by default and false if any handler returned false + */ + dispatchEvent: function(type) { + var uid, list, args, tmpEvt, evt = {}, result = true, undef; + + if (Basic.typeOf(type) !== 'string') { + // we can't use original object directly (because of Silverlight) + tmpEvt = type; + + if (Basic.typeOf(tmpEvt.type) === 'string') { + type = tmpEvt.type; + + if (tmpEvt.total !== undef && tmpEvt.loaded !== undef) { // progress event + evt.total = tmpEvt.total; + evt.loaded = tmpEvt.loaded; + } + evt.async = tmpEvt.async || false; + } else { + throw new x.EventException(x.EventException.UNSPECIFIED_EVENT_TYPE_ERR); + } + } + + // check if event is meant to be dispatched on an object having specific uid + if (type.indexOf('::') !== -1) { + (function(arr) { + uid = arr[0]; + type = arr[1]; + }(type.split('::'))); + } else { + uid = this.uid; + } + + type = type.toLowerCase(); + + list = eventpool[uid] && eventpool[uid][type]; + + if (list) { + // sort event list by prority + list.sort(function(a, b) { return b.priority - a.priority; }); + + args = [].slice.call(arguments); + + // first argument will be pseudo-event object + args.shift(); + evt.type = type; + args.unshift(evt); + + if (MXI_DEBUG && Env.debug.events) { + Env.log("Event '%s' fired on %u", evt.type, uid); + } + + // Dispatch event to all listeners + var queue = []; + Basic.each(list, function(handler) { + // explicitly set the target, otherwise events fired from shims do not get it + args[0].target = handler.scope; + // if event is marked as async, detach the handler + if (evt.async) { + queue.push(function(cb) { + setTimeout(function() { + cb(handler.fn.apply(handler.scope, args) === false); + }, 1); + }); + } else { + queue.push(function(cb) { + cb(handler.fn.apply(handler.scope, args) === false); // if handler returns false stop propagation + }); + } + }); + if (queue.length) { + Basic.inSeries(queue, function(err) { + result = !err; + }); + } + } + return result; + }, + + /** + Register a handler to the event type that will run only once + + @method bindOnce + @since >1.4.1 + @param {String} type Type or basically a name of the event to subscribe to + @param {Function} fn Callback function that will be called when event happens + @param {Number} [priority=0] Priority of the event handler - handlers with higher priorities will be called first + @param {Object} [scope=this] A scope to invoke event handler in + */ + bindOnce: function(type, fn, priority, scope) { + var self = this; + self.bind.call(this, type, function cb() { + self.unbind(type, cb); + return fn.apply(this, arguments); + }, priority, scope); + }, + + /** + Alias for addEventListener + + @method bind + @protected + */ + bind: function() { + this.addEventListener.apply(this, arguments); + }, + + /** + Alias for removeEventListener + + @method unbind + @protected + */ + unbind: function() { + this.removeEventListener.apply(this, arguments); + }, + + /** + Alias for removeAllEventListeners + + @method unbindAll + @protected + */ + unbindAll: function() { + this.removeAllEventListeners.apply(this, arguments); + }, + + /** + Alias for dispatchEvent + + @method trigger + @protected + */ + trigger: function() { + return this.dispatchEvent.apply(this, arguments); + }, + + + /** + Handle properties of on[event] type. + + @method handleEventProps + @private + */ + handleEventProps: function(dispatches) { + var self = this; + + this.bind(dispatches.join(' '), function(e) { + var prop = 'on' + e.type.toLowerCase(); + if (Basic.typeOf(this[prop]) === 'function') { + this[prop].apply(this, arguments); + } + }); + + // object must have defined event properties, even if it doesn't make use of them + Basic.each(dispatches, function(prop) { + prop = 'on' + prop.toLowerCase(prop); + if (Basic.typeOf(self[prop]) === 'undefined') { + self[prop] = null; + } + }); + } + + }); + + + EventTarget.instance = new EventTarget(); + + return EventTarget; +}); + +// Included from: src/javascript/runtime/Runtime.js + +/** + * Runtime.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +define('moxie/runtime/Runtime', [ + "moxie/core/utils/Env", + "moxie/core/utils/Basic", + "moxie/core/utils/Dom", + "moxie/core/EventTarget" +], function(Env, Basic, Dom, EventTarget) { + var runtimeConstructors = {}, runtimes = {}; + + /** + Common set of methods and properties for every runtime instance + + @class moxie/runtime/Runtime + + @param {Object} options + @param {String} type Sanitized name of the runtime + @param {Object} [caps] Set of capabilities that differentiate specified runtime + @param {Object} [modeCaps] Set of capabilities that do require specific operational mode + @param {String} [preferredMode='browser'] Preferred operational mode to choose if no required capabilities were requested + */ + function Runtime(options, type, caps, modeCaps, preferredMode) { + /** + Dispatched when runtime is initialized and ready. + Results in RuntimeInit on a connected component. + + @event Init + */ + + /** + Dispatched when runtime fails to initialize. + Results in RuntimeError on a connected component. + + @event Error + */ + + var self = this + , _shim + , _uid = Basic.guid(type + '_') + , defaultMode = preferredMode || 'browser' + ; + + options = options || {}; + + // register runtime in private hash + runtimes[_uid] = this; + + /** + Default set of capabilities, which can be redifined later by specific runtime + + @private + @property caps + @type Object + */ + caps = Basic.extend({ + // Runtime can: + // provide access to raw binary data of the file + access_binary: false, + // provide access to raw binary data of the image (image extension is optional) + access_image_binary: false, + // display binary data as thumbs for example + display_media: false, + // make cross-domain requests + do_cors: false, + // accept files dragged and dropped from the desktop + drag_and_drop: false, + // filter files in selection dialog by their extensions + filter_by_extension: true, + // resize image (and manipulate it raw data of any file in general) + resize_image: false, + // periodically report how many bytes of total in the file were uploaded (loaded) + report_upload_progress: false, + // provide access to the headers of http response + return_response_headers: false, + // support response of specific type, which should be passed as an argument + // e.g. runtime.can('return_response_type', 'blob') + return_response_type: false, + // return http status code of the response + return_status_code: true, + // send custom http header with the request + send_custom_headers: false, + // pick up the files from a dialog + select_file: false, + // select whole folder in file browse dialog + select_folder: false, + // select multiple files at once in file browse dialog + select_multiple: true, + // send raw binary data, that is generated after image resizing or manipulation of other kind + send_binary_string: false, + // send cookies with http request and therefore retain session + send_browser_cookies: true, + // send data formatted as multipart/form-data + send_multipart: true, + // slice the file or blob to smaller parts + slice_blob: false, + // upload file without preloading it to memory, stream it out directly from disk + stream_upload: false, + // programmatically trigger file browse dialog + summon_file_dialog: false, + // upload file of specific size, size should be passed as argument + // e.g. runtime.can('upload_filesize', '500mb') + upload_filesize: true, + // initiate http request with specific http method, method should be passed as argument + // e.g. runtime.can('use_http_method', 'put') + use_http_method: true + }, caps); + + + // default to the mode that is compatible with preferred caps + if (options.preferred_caps) { + defaultMode = Runtime.getMode(modeCaps, options.preferred_caps, defaultMode); + } + + if (MXI_DEBUG && Env.debug.runtime) { + Env.log("\tdefault mode: %s", defaultMode); + } + + // small extension factory here (is meant to be extended with actual extensions constructors) + _shim = (function() { + var objpool = {}; + return { + exec: function(uid, comp, fn, args) { + if (_shim[comp]) { + if (!objpool[uid]) { + objpool[uid] = { + context: this, + instance: new _shim[comp]() + }; + } + if (objpool[uid].instance[fn]) { + return objpool[uid].instance[fn].apply(this, args); + } + } + }, + + removeInstance: function(uid) { + delete objpool[uid]; + }, + + removeAllInstances: function() { + var self = this; + Basic.each(objpool, function(obj, uid) { + if (Basic.typeOf(obj.instance.destroy) === 'function') { + obj.instance.destroy.call(obj.context); + } + self.removeInstance(uid); + }); + } + }; + }()); + + + // public methods + Basic.extend(this, { + /** + Specifies whether runtime instance was initialized or not + + @property initialized + @type {Boolean} + @default false + */ + initialized: false, // shims require this flag to stop initialization retries + + /** + Unique ID of the runtime + + @property uid + @type {String} + */ + uid: _uid, + + /** + Runtime type (e.g. flash, html5, etc) + + @property type + @type {String} + */ + type: type, + + /** + Runtime (not native one) may operate in browser or client mode. + + @property mode + @private + @type {String|Boolean} current mode or false, if none possible + */ + mode: Runtime.getMode(modeCaps, (options.required_caps), defaultMode), + + /** + id of the DOM container for the runtime (if available) + + @property shimid + @type {String} + */ + shimid: _uid + '_container', + + /** + Number of connected clients. If equal to zero, runtime can be destroyed + + @property clients + @type {Number} + */ + clients: 0, + + /** + Runtime initialization options + + @property options + @type {Object} + */ + options: options, + + /** + Checks if the runtime has specific capability + + @method can + @param {String} cap Name of capability to check + @param {Mixed} [value] If passed, capability should somehow correlate to the value + @param {Object} [refCaps] Set of capabilities to check the specified cap against (defaults to internal set) + @return {Boolean} true if runtime has such capability and false, if - not + */ + can: function(cap, value) { + var refCaps = arguments[2] || caps; + + // if cap var is a comma-separated list of caps, convert it to object (key/value) + if (Basic.typeOf(cap) === 'string' && Basic.typeOf(value) === 'undefined') { + cap = Runtime.parseCaps(cap); + } + + if (Basic.typeOf(cap) === 'object') { + for (var key in cap) { + if (!this.can(key, cap[key], refCaps)) { + return false; + } + } + return true; + } + + // check the individual cap + if (Basic.typeOf(refCaps[cap]) === 'function') { + return refCaps[cap].call(this, value); + } else { + return (value === refCaps[cap]); + } + }, + + /** + Returns container for the runtime as DOM element + + @method getShimContainer + @return {DOMElement} + */ + getShimContainer: function() { + var container, shimContainer = Dom.get(this.shimid); + + // if no container for shim, create one + if (!shimContainer) { + container = Dom.get(this.options.container) || document.body; + + // create shim container and insert it at an absolute position into the outer container + shimContainer = document.createElement('div'); + shimContainer.id = this.shimid; + shimContainer.className = 'moxie-shim moxie-shim-' + this.type; + + Basic.extend(shimContainer.style, { + position: 'absolute', + top: '0px', + left: '0px', + width: '1px', + height: '1px', + overflow: 'hidden' + }); + + container.appendChild(shimContainer); + container = null; + } + + return shimContainer; + }, + + /** + Returns runtime as DOM element (if appropriate) + + @method getShim + @return {DOMElement} + */ + getShim: function() { + return _shim; + }, + + /** + Invokes a method within the runtime itself (might differ across the runtimes) + + @method shimExec + @param {Mixed} [] + @protected + @return {Mixed} Depends on the action and component + */ + shimExec: function(component, action) { + var args = [].slice.call(arguments, 2); + return self.getShim().exec.call(this, this.uid, component, action, args); + }, + + /** + Operaional interface that is used by components to invoke specific actions on the runtime + (is invoked in the scope of component) + + @method exec + @param {Mixed} []* + @protected + @return {Mixed} Depends on the action and component + */ + exec: function(component, action) { // this is called in the context of component, not runtime + var args = [].slice.call(arguments, 2); + + if (self[component] && self[component][action]) { + return self[component][action].apply(this, args); + } + return self.shimExec.apply(this, arguments); + }, + + /** + Destroys the runtime (removes all events and deletes DOM structures) + + @method destroy + */ + destroy: function() { + if (!self) { + return; // obviously already destroyed + } + + var shimContainer = Dom.get(this.shimid); + if (shimContainer) { + shimContainer.parentNode.removeChild(shimContainer); + } + + if (_shim) { + _shim.removeAllInstances(); + } + + this.unbindAll(); + delete runtimes[this.uid]; + this.uid = null; // mark this runtime as destroyed + _uid = self = _shim = shimContainer = null; + } + }); + + // once we got the mode, test against all caps + if (this.mode && options.required_caps && !this.can(options.required_caps)) { + this.mode = false; + } + } + + + /** + Default order to try different runtime types + + @property order + @type String + @static + */ + Runtime.order = 'html5,flash,silverlight,html4'; + + + /** + Retrieves runtime from private hash by it's uid + + @method getRuntime + @private + @static + @param {String} uid Unique identifier of the runtime + @return {Runtime|Boolean} Returns runtime, if it exists and false, if - not + */ + Runtime.getRuntime = function(uid) { + return runtimes[uid] ? runtimes[uid] : false; + }; + + + /** + Register constructor for the Runtime of new (or perhaps modified) type + + @method addConstructor + @static + @param {String} type Runtime type (e.g. flash, html5, etc) + @param {Function} construct Constructor for the Runtime type + */ + Runtime.addConstructor = function(type, constructor) { + constructor.prototype = EventTarget.instance; + runtimeConstructors[type] = constructor; + }; + + + /** + Get the constructor for the specified type. + + method getConstructor + @static + @param {String} type Runtime type (e.g. flash, html5, etc) + @return {Function} Constructor for the Runtime type + */ + Runtime.getConstructor = function(type) { + return runtimeConstructors[type] || null; + }; + + + /** + Get info about the runtime (uid, type, capabilities) + + @method getInfo + @static + @param {String} uid Unique identifier of the runtime + @return {Mixed} Info object or null if runtime doesn't exist + */ + Runtime.getInfo = function(uid) { + var runtime = Runtime.getRuntime(uid); + + if (runtime) { + return { + uid: runtime.uid, + type: runtime.type, + mode: runtime.mode, + can: function() { + return runtime.can.apply(runtime, arguments); + } + }; + } + return null; + }; + + + /** + Convert caps represented by a comma-separated string to the object representation. + + @method parseCaps + @static + @param {String} capStr Comma-separated list of capabilities + @return {Object} + */ + Runtime.parseCaps = function(capStr) { + var capObj = {}; + + if (Basic.typeOf(capStr) !== 'string') { + return capStr || {}; + } + + Basic.each(capStr.split(','), function(key) { + capObj[key] = true; // we assume it to be - true + }); + + return capObj; + }; + + /** + Test the specified runtime for specific capabilities. + + @method can + @static + @param {String} type Runtime type (e.g. flash, html5, etc) + @param {String|Object} caps Set of capabilities to check + @return {Boolean} Result of the test + */ + Runtime.can = function(type, caps) { + var runtime + , constructor = Runtime.getConstructor(type) + , mode + ; + if (constructor) { + runtime = new constructor({ + required_caps: caps + }); + mode = runtime.mode; + runtime.destroy(); + return !!mode; + } + return false; + }; + + + /** + Figure out a runtime that supports specified capabilities. + + @method thatCan + @static + @param {String|Object} caps Set of capabilities to check + @param {String} [runtimeOrder] Comma-separated list of runtimes to check against + @return {String} Usable runtime identifier or null + */ + Runtime.thatCan = function(caps, runtimeOrder) { + var types = (runtimeOrder || Runtime.order).split(/\s*,\s*/); + for (var i in types) { + if (Runtime.can(types[i], caps)) { + return types[i]; + } + } + return null; + }; + + + /** + Figure out an operational mode for the specified set of capabilities. + + @method getMode + @static + @param {Object} modeCaps Set of capabilities that depend on particular runtime mode + @param {Object} [requiredCaps] Supplied set of capabilities to find operational mode for + @param {String|Boolean} [defaultMode='browser'] Default mode to use + @return {String|Boolean} Compatible operational mode + */ + Runtime.getMode = function(modeCaps, requiredCaps, defaultMode) { + var mode = null; + + if (Basic.typeOf(defaultMode) === 'undefined') { // only if not specified + defaultMode = 'browser'; + } + + if (requiredCaps && !Basic.isEmptyObj(modeCaps)) { + // loop over required caps and check if they do require the same mode + Basic.each(requiredCaps, function(value, cap) { + if (modeCaps.hasOwnProperty(cap)) { + var capMode = modeCaps[cap](value); + + // make sure we always have an array + if (typeof(capMode) === 'string') { + capMode = [capMode]; + } + + if (!mode) { + mode = capMode; + } else if (!(mode = Basic.arrayIntersect(mode, capMode))) { + // if cap requires conflicting mode - runtime cannot fulfill required caps + + if (MXI_DEBUG && Env.debug.runtime) { + Env.log("\t\t%c: %v (conflicting mode requested: %s)", cap, value, capMode); + } + + return (mode = false); + } + } + + if (MXI_DEBUG && Env.debug.runtime) { + Env.log("\t\t%c: %v (compatible modes: %s)", cap, value, mode); + } + }); + + if (mode) { + return Basic.inArray(defaultMode, mode) !== -1 ? defaultMode : mode[0]; + } else if (mode === false) { + return false; + } + } + return defaultMode; + }; + + + /** + Capability check that always returns true + + @private + @static + @return {True} + */ + Runtime.capTrue = function() { + return true; + }; + + /** + Capability check that always returns false + + @private + @static + @return {False} + */ + Runtime.capFalse = function() { + return false; + }; + + /** + Evaluate the expression to boolean value and create a function that always returns it. + + @private + @static + @param {Mixed} expr Expression to evaluate + @return {Function} Function returning the result of evaluation + */ + Runtime.capTest = function(expr) { + return function() { + return !!expr; + }; + }; + + return Runtime; +}); + +// Included from: src/javascript/runtime/RuntimeClient.js + +/** + * RuntimeClient.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +define('moxie/runtime/RuntimeClient', [ + 'moxie/core/utils/Env', + 'moxie/core/Exceptions', + 'moxie/core/utils/Basic', + 'moxie/runtime/Runtime' +], function(Env, x, Basic, Runtime) { + /** + Set of methods and properties, required by a component to acquire ability to connect to a runtime + + @class moxie/runtime/RuntimeClient + */ + return function RuntimeClient() { + var runtime; + + Basic.extend(this, { + /** + Connects to the runtime specified by the options. Will either connect to existing runtime or create a new one. + Increments number of clients connected to the specified runtime. + + @private + @method connectRuntime + @param {Mixed} options Can be a runtme uid or a set of key-value pairs defining requirements and pre-requisites + */ + connectRuntime: function(options) { + var comp = this, ruid; + + function initialize(items) { + var type, constructor; + + // if we ran out of runtimes + if (!items.length) { + comp.trigger('RuntimeError', new x.RuntimeError(x.RuntimeError.NOT_INIT_ERR)); + runtime = null; + return; + } + + type = items.shift().toLowerCase(); + constructor = Runtime.getConstructor(type); + if (!constructor) { + if (MXI_DEBUG && Env.debug.runtime) { + Env.log("Constructor for '%s' runtime is not available.", type); + } + initialize(items); + return; + } + + if (MXI_DEBUG && Env.debug.runtime) { + Env.log("Trying runtime: %s", type); + Env.log(options); + } + + // try initializing the runtime + runtime = new constructor(options); + + runtime.bind('Init', function() { + // mark runtime as initialized + runtime.initialized = true; + + if (MXI_DEBUG && Env.debug.runtime) { + Env.log("Runtime '%s' initialized", runtime.type); + } + + // jailbreak ... + setTimeout(function() { + runtime.clients++; + comp.ruid = runtime.uid; + // this will be triggered on component + comp.trigger('RuntimeInit', runtime); + }, 1); + }); + + runtime.bind('Error', function() { + if (MXI_DEBUG && Env.debug.runtime) { + Env.log("Runtime '%s' failed to initialize", runtime.type); + } + + runtime.destroy(); // runtime cannot destroy itself from inside at a right moment, thus we do it here + initialize(items); + }); + + runtime.bind('Exception', function(e, err) { + var message = err.name + "(#" + err.code + ")" + (err.message ? ", from: " + err.message : ''); + + if (MXI_DEBUG && Env.debug.runtime) { + Env.log("Runtime '%s' has thrown an exception: %s", this.type, message); + } + comp.trigger('RuntimeError', new x.RuntimeError(x.RuntimeError.EXCEPTION_ERR, message)); + }); + + if (MXI_DEBUG && Env.debug.runtime) { + Env.log("\tselected mode: %s", runtime.mode); + } + + // check if runtime managed to pick-up operational mode + if (!runtime.mode) { + runtime.trigger('Error'); + return; + } + + runtime.init(); + } + + // check if a particular runtime was requested + if (Basic.typeOf(options) === 'string') { + ruid = options; + } else if (Basic.typeOf(options.ruid) === 'string') { + ruid = options.ruid; + } + + if (ruid) { + runtime = Runtime.getRuntime(ruid); + if (runtime) { + comp.ruid = ruid; + runtime.clients++; + return runtime; + } else { + // there should be a runtime and there's none - weird case + throw new x.RuntimeError(x.RuntimeError.NOT_INIT_ERR); + } + } + + // initialize a fresh one, that fits runtime list and required features best + initialize((options.runtime_order || Runtime.order).split(/\s*,\s*/)); + }, + + + /** + Disconnects from the runtime. Decrements number of clients connected to the specified runtime. + + @private + @method disconnectRuntime + */ + disconnectRuntime: function() { + if (runtime && --runtime.clients <= 0) { + runtime.destroy(); + } + + // once the component is disconnected, it shouldn't have access to the runtime + runtime = null; + }, + + + /** + Returns the runtime to which the client is currently connected. + + @method getRuntime + @return {Runtime} Runtime or null if client is not connected + */ + getRuntime: function() { + if (runtime && runtime.uid) { + return runtime; + } + return runtime = null; // make sure we do not leave zombies rambling around + }, + + + /** + Handy shortcut to safely invoke runtime extension methods. + + @private + @method exec + @return {Mixed} Whatever runtime extension method returns + */ + exec: function() { + return runtime ? runtime.exec.apply(this, arguments) : null; + }, + + + /** + Test runtime client for specific capability + + @method can + @param {String} cap + @return {Bool} + */ + can: function(cap) { + return runtime ? runtime.can(cap) : false; + } + + }); + }; + + +}); + +// Included from: src/javascript/file/Blob.js + +/** + * Blob.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +define('moxie/file/Blob', [ + 'moxie/core/utils/Basic', + 'moxie/core/utils/Encode', + 'moxie/runtime/RuntimeClient' +], function(Basic, Encode, RuntimeClient) { + + var blobpool = {}; + + /** + @class moxie/file/Blob + @constructor + @param {String} ruid Unique id of the runtime, to which this blob belongs to + @param {Object} blob Object "Native" blob object, as it is represented in the runtime + */ + function Blob(ruid, blob) { + + function _sliceDetached(start, end, type) { + var blob, data = blobpool[this.uid]; + + if (Basic.typeOf(data) !== 'string' || !data.length) { + return null; // or throw exception + } + + blob = new Blob(null, { + type: type, + size: end - start + }); + blob.detach(data.substr(start, blob.size)); + + return blob; + } + + RuntimeClient.call(this); + + if (ruid) { + this.connectRuntime(ruid); + } + + if (!blob) { + blob = {}; + } else if (Basic.typeOf(blob) === 'string') { // dataUrl or binary string + blob = { data: blob }; + } + + Basic.extend(this, { + + /** + Unique id of the component + + @property uid + @type {String} + */ + uid: blob.uid || Basic.guid('uid_'), + + /** + Unique id of the connected runtime, if falsy, then runtime will have to be initialized + before this Blob can be used, modified or sent + + @property ruid + @type {String} + */ + ruid: ruid, + + /** + Size of blob + + @property size + @type {Number} + @default 0 + */ + size: blob.size || 0, + + /** + Mime type of blob + + @property type + @type {String} + @default '' + */ + type: blob.type || '', + + /** + @method slice + @param {Number} [start=0] + */ + slice: function(start, end, type) { + if (this.isDetached()) { + return _sliceDetached.apply(this, arguments); + } + return this.getRuntime().exec.call(this, 'Blob', 'slice', this.getSource(), start, end, type); + }, + + /** + Returns "native" blob object (as it is represented in connected runtime) or null if not found + + @method getSource + @return {Blob} Returns "native" blob object or null if not found + */ + getSource: function() { + if (!blobpool[this.uid]) { + return null; + } + return blobpool[this.uid]; + }, + + /** + Detaches blob from any runtime that it depends on and initialize with standalone value + + @method detach + @protected + @param {DOMString} [data=''] Standalone value + */ + detach: function(data) { + if (this.ruid) { + this.getRuntime().exec.call(this, 'Blob', 'destroy'); + this.disconnectRuntime(); + this.ruid = null; + } + + data = data || ''; + + // if dataUrl, convert to binary string + if (data.substr(0, 5) == 'data:') { + var base64Offset = data.indexOf(';base64,'); + this.type = data.substring(5, base64Offset); + data = Encode.atob(data.substring(base64Offset + 8)); + } + + this.size = data.length; + + blobpool[this.uid] = data; + }, + + /** + Checks if blob is standalone (detached of any runtime) + + @method isDetached + @protected + @return {Boolean} + */ + isDetached: function() { + return !this.ruid && Basic.typeOf(blobpool[this.uid]) === 'string'; + }, + + /** + Destroy Blob and free any resources it was using + + @method destroy + */ + destroy: function() { + this.detach(); + delete blobpool[this.uid]; + } + }); + + + if (blob.data) { + this.detach(blob.data); // auto-detach if payload has been passed + } else { + blobpool[this.uid] = blob; + } + } + + return Blob; +}); + +// Included from: src/javascript/core/I18n.js + +/** + * I18n.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +define("moxie/core/I18n", [ + "moxie/core/utils/Basic" +], function(Basic) { + var i18n = {}; + + /** + @class moxie/core/I18n + */ + return { + /** + * Extends the language pack object with new items. + * + * @param {Object} pack Language pack items to add. + * @return {Object} Extended language pack object. + */ + addI18n: function(pack) { + return Basic.extend(i18n, pack); + }, + + /** + * Translates the specified string by checking for the english string in the language pack lookup. + * + * @param {String} str String to look for. + * @return {String} Translated string or the input string if it wasn't found. + */ + translate: function(str) { + return i18n[str] || str; + }, + + /** + * Shortcut for translate function + * + * @param {String} str String to look for. + * @return {String} Translated string or the input string if it wasn't found. + */ + _: function(str) { + return this.translate(str); + }, + + /** + * Pseudo sprintf implementation - simple way to replace tokens with specified values. + * + * @param {String} str String with tokens + * @return {String} String with replaced tokens + */ + sprintf: function(str) { + var args = [].slice.call(arguments, 1); + + return str.replace(/%[a-z]/g, function() { + var value = args.shift(); + return Basic.typeOf(value) !== 'undefined' ? value : ''; + }); + } + }; +}); + +// Included from: src/javascript/core/utils/Mime.js + +/** + * Mime.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +define("moxie/core/utils/Mime", [ + "moxie/core/utils/Basic", + "moxie/core/I18n" +], function(Basic, I18n) { + + var mimeData = "" + + "application/msword,doc dot," + + "application/pdf,pdf," + + "application/pgp-signature,pgp," + + "application/postscript,ps ai eps," + + "application/rtf,rtf," + + "application/vnd.ms-excel,xls xlb," + + "application/vnd.ms-powerpoint,ppt pps pot," + + "application/zip,zip," + + "application/x-shockwave-flash,swf swfl," + + "application/vnd.openxmlformats-officedocument.wordprocessingml.document,docx," + + "application/vnd.openxmlformats-officedocument.wordprocessingml.template,dotx," + + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,xlsx," + + "application/vnd.openxmlformats-officedocument.presentationml.presentation,pptx," + + "application/vnd.openxmlformats-officedocument.presentationml.template,potx," + + "application/vnd.openxmlformats-officedocument.presentationml.slideshow,ppsx," + + "application/x-javascript,js," + + "application/json,json," + + "audio/mpeg,mp3 mpga mpega mp2," + + "audio/x-wav,wav," + + "audio/x-m4a,m4a," + + "audio/ogg,oga ogg," + + "audio/aiff,aiff aif," + + "audio/flac,flac," + + "audio/aac,aac," + + "audio/ac3,ac3," + + "audio/x-ms-wma,wma," + + "image/bmp,bmp," + + "image/gif,gif," + + "image/jpeg,jpg jpeg jpe," + + "image/photoshop,psd," + + "image/png,png," + + "image/svg+xml,svg svgz," + + "image/tiff,tiff tif," + + "text/plain,asc txt text diff log," + + "text/html,htm html xhtml," + + "text/css,css," + + "text/csv,csv," + + "text/rtf,rtf," + + "video/mpeg,mpeg mpg mpe m2v," + + "video/quicktime,qt mov," + + "video/mp4,mp4," + + "video/x-m4v,m4v," + + "video/x-flv,flv," + + "video/x-ms-wmv,wmv," + + "video/avi,avi," + + "video/webm,webm," + + "video/3gpp,3gpp 3gp," + + "video/3gpp2,3g2," + + "video/vnd.rn-realvideo,rv," + + "video/ogg,ogv," + + "video/x-matroska,mkv," + + "application/vnd.oasis.opendocument.formula-template,otf," + + "application/octet-stream,exe"; + + + var Mime = { + + mimes: {}, + + extensions: {}, + + // Parses the default mime types string into a mimes and extensions lookup maps + addMimeType: function (mimeData) { + var items = mimeData.split(/,/), i, ii, ext; + + for (i = 0; i < items.length; i += 2) { + ext = items[i + 1].split(/ /); + + // extension to mime lookup + for (ii = 0; ii < ext.length; ii++) { + this.mimes[ext[ii]] = items[i]; + } + // mime to extension lookup + this.extensions[items[i]] = ext; + } + }, + + + extList2mimes: function (filters, addMissingExtensions) { + var self = this, ext, i, ii, type, mimes = []; + + // convert extensions to mime types list + for (i = 0; i < filters.length; i++) { + ext = filters[i].extensions.toLowerCase().split(/\s*,\s*/); + + for (ii = 0; ii < ext.length; ii++) { + + // if there's an asterisk in the list, then accept attribute is not required + if (ext[ii] === '*') { + return []; + } + + type = self.mimes[ext[ii]]; + + // future browsers should filter by extension, finally + if (addMissingExtensions && /^\w+$/.test(ext[ii])) { + mimes.push('.' + ext[ii]); + } else if (type && Basic.inArray(type, mimes) === -1) { + mimes.push(type); + } else if (!type) { + // if we have no type in our map, then accept all + return []; + } + } + } + return mimes; + }, + + + mimes2exts: function(mimes) { + var self = this, exts = []; + + Basic.each(mimes, function(mime) { + mime = mime.toLowerCase(); + + if (mime === '*') { + exts = []; + return false; + } + + // check if this thing looks like mime type + var m = mime.match(/^(\w+)\/(\*|\w+)$/); + if (m) { + if (m[2] === '*') { + // wildcard mime type detected + Basic.each(self.extensions, function(arr, mime) { + if ((new RegExp('^' + m[1] + '/')).test(mime)) { + [].push.apply(exts, self.extensions[mime]); + } + }); + } else if (self.extensions[mime]) { + [].push.apply(exts, self.extensions[mime]); + } + } + }); + return exts; + }, + + + mimes2extList: function(mimes) { + var accept = [], exts = []; + + if (Basic.typeOf(mimes) === 'string') { + mimes = Basic.trim(mimes).split(/\s*,\s*/); + } + + exts = this.mimes2exts(mimes); + + accept.push({ + title: I18n.translate('Files'), + extensions: exts.length ? exts.join(',') : '*' + }); + + // save original mimes string + accept.mimes = mimes; + + return accept; + }, + + + getFileExtension: function(fileName) { + var matches = fileName && fileName.match(/\.([^.]+)$/); + if (matches) { + return matches[1].toLowerCase(); + } + return ''; + }, + + getFileMime: function(fileName) { + return this.mimes[this.getFileExtension(fileName)] || ''; + } + }; + + Mime.addMimeType(mimeData); + + return Mime; +}); + +// Included from: src/javascript/file/FileInput.js + +/** + * FileInput.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +define('moxie/file/FileInput', [ + 'moxie/core/utils/Basic', + 'moxie/core/utils/Env', + 'moxie/core/utils/Mime', + 'moxie/core/utils/Dom', + 'moxie/core/Exceptions', + 'moxie/core/EventTarget', + 'moxie/core/I18n', + 'moxie/runtime/Runtime', + 'moxie/runtime/RuntimeClient' +], function(Basic, Env, Mime, Dom, x, EventTarget, I18n, Runtime, RuntimeClient) { + /** + Provides a convenient way to create cross-browser file-picker. Generates file selection dialog on click, + converts selected files to _File_ objects, to be used in conjunction with _Image_, preloaded in memory + with _FileReader_ or uploaded to a server through _XMLHttpRequest_. + + @class moxie/file/FileInput + @constructor + @extends EventTarget + @uses RuntimeClient + @param {Object|String|DOMElement} options If options is string or node, argument is considered as _browse\_button_. + @param {String|DOMElement} options.browse_button DOM Element to turn into file picker. + @param {Array} [options.accept] Array of mime types to accept. By default accepts all. + @param {Boolean} [options.multiple=false] Enable selection of multiple files. + @param {Boolean} [options.directory=false] Turn file input into the folder input (cannot be both at the same time). + @param {String|DOMElement} [options.container] DOM Element to use as a container for file-picker. Defaults to parentNode + for _browse\_button_. + @param {Object|String} [options.required_caps] Set of required capabilities, that chosen runtime must support. + + @example +
+ Browse... +
+ + + */ + var dispatches = [ + /** + Dispatched when runtime is connected and file-picker is ready to be used. + + @event ready + @param {Object} event + */ + 'ready', + + /** + Dispatched right after [ready](#event_ready) event, and whenever [refresh()](#method_refresh) is invoked. + Check [corresponding documentation entry](#method_refresh) for more info. + + @event refresh + @param {Object} event + */ + + /** + Dispatched when selection of files in the dialog is complete. + + @event change + @param {Object} event + */ + 'change', + + 'cancel', // TODO: might be useful + + /** + Dispatched when mouse cursor enters file-picker area. Can be used to style element + accordingly. + + @event mouseenter + @param {Object} event + */ + 'mouseenter', + + /** + Dispatched when mouse cursor leaves file-picker area. Can be used to style element + accordingly. + + @event mouseleave + @param {Object} event + */ + 'mouseleave', + + /** + Dispatched when functional mouse button is pressed on top of file-picker area. + + @event mousedown + @param {Object} event + */ + 'mousedown', + + /** + Dispatched when functional mouse button is released on top of file-picker area. + + @event mouseup + @param {Object} event + */ + 'mouseup' + ]; + + function FileInput(options) { + if (MXI_DEBUG) { + Env.log("Instantiating FileInput..."); + } + + var container, browseButton, defaults; + + // if flat argument passed it should be browse_button id + if (Basic.inArray(Basic.typeOf(options), ['string', 'node']) !== -1) { + options = { browse_button : options }; + } + + // this will help us to find proper default container + browseButton = Dom.get(options.browse_button); + if (!browseButton) { + // browse button is required + throw new x.DOMException(x.DOMException.NOT_FOUND_ERR); + } + + // figure out the options + defaults = { + accept: [{ + title: I18n.translate('All Files'), + extensions: '*' + }], + multiple: false, + required_caps: false, + container: browseButton.parentNode || document.body + }; + + options = Basic.extend({}, defaults, options); + + // convert to object representation + if (typeof(options.required_caps) === 'string') { + options.required_caps = Runtime.parseCaps(options.required_caps); + } + + // normalize accept option (could be list of mime types or array of title/extensions pairs) + if (typeof(options.accept) === 'string') { + options.accept = Mime.mimes2extList(options.accept); + } + + container = Dom.get(options.container); + // make sure we have container + if (!container) { + container = document.body; + } + + // make container relative, if it's not + if (Dom.getStyle(container, 'position') === 'static') { + container.style.position = 'relative'; + } + + container = browseButton = null; // IE + + RuntimeClient.call(this); + + Basic.extend(this, { + /** + Unique id of the component + + @property uid + @protected + @readOnly + @type {String} + @default UID + */ + uid: Basic.guid('uid_'), + + /** + Unique id of the connected runtime, if any. + + @property ruid + @protected + @type {String} + */ + ruid: null, + + /** + Unique id of the runtime container. Useful to get hold of it for various manipulations. + + @property shimid + @protected + @type {String} + */ + shimid: null, + + /** + Array of selected mOxie.File objects + + @property files + @type {Array} + @default null + */ + files: null, + + /** + Initializes the file-picker, connects it to runtime and dispatches event ready when done. + + @method init + */ + init: function() { + var self = this; + + self.bind('RuntimeInit', function(e, runtime) { + self.ruid = runtime.uid; + self.shimid = runtime.shimid; + + self.bind("Ready", function() { + self.trigger("Refresh"); + }, 999); + + // re-position and resize shim container + self.bind('Refresh', function() { + var pos, size, browseButton, shimContainer, zIndex; + + browseButton = Dom.get(options.browse_button); + shimContainer = Dom.get(runtime.shimid); // do not use runtime.getShimContainer(), since it will create container if it doesn't exist + + if (browseButton) { + pos = Dom.getPos(browseButton, Dom.get(options.container)); + size = Dom.getSize(browseButton); + zIndex = parseInt(Dom.getStyle(browseButton, 'z-index'), 10) || 0; + + if (shimContainer) { + Basic.extend(shimContainer.style, { + top: pos.y + 'px', + left: pos.x + 'px', + width: size.w + 'px', + height: size.h + 'px', + zIndex: zIndex + 1 + }); + } + } + shimContainer = browseButton = null; + }); + + runtime.exec.call(self, 'FileInput', 'init', options); + }); + + // runtime needs: options.required_features, options.runtime_order and options.container + self.connectRuntime(Basic.extend({}, options, { + required_caps: { + select_file: true + } + })); + }, + + + /** + * Get current option value by its name + * + * @method getOption + * @param name + * @return {Mixed} + */ + getOption: function(name) { + return options[name]; + }, + + + /** + * Sets a new value for the option specified by name + * + * @method setOption + * @param name + * @param value + */ + setOption: function(name, value) { + if (!options.hasOwnProperty(name)) { + return; + } + + var oldValue = options[name]; + + switch (name) { + case 'accept': + if (typeof(value) === 'string') { + value = Mime.mimes2extList(value); + } + break; + + case 'container': + case 'required_caps': + throw new x.FileException(x.FileException.NO_MODIFICATION_ALLOWED_ERR); + } + + options[name] = value; + this.exec('FileInput', 'setOption', name, value); + + this.trigger('OptionChanged', name, value, oldValue); + }, + + /** + Disables file-picker element, so that it doesn't react to mouse clicks. + + @method disable + @param {Boolean} [state=true] Disable component if - true, enable if - false + */ + disable: function(state) { + var runtime = this.getRuntime(); + if (runtime) { + this.exec('FileInput', 'disable', Basic.typeOf(state) === 'undefined' ? true : state); + } + }, + + + /** + Reposition and resize dialog trigger to match the position and size of browse_button element. + + @method refresh + */ + refresh: function() { + this.trigger("Refresh"); + }, + + + /** + Destroy component. + + @method destroy + */ + destroy: function() { + var runtime = this.getRuntime(); + if (runtime) { + runtime.exec.call(this, 'FileInput', 'destroy'); + this.disconnectRuntime(); + } + + if (Basic.typeOf(this.files) === 'array') { + // no sense in leaving associated files behind + Basic.each(this.files, function(file) { + file.destroy(); + }); + } + this.files = null; + + this.unbindAll(); + } + }); + + this.handleEventProps(dispatches); + } + + FileInput.prototype = EventTarget.instance; + + return FileInput; +}); + +// Included from: src/javascript/file/File.js + +/** + * File.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +define('moxie/file/File', [ + 'moxie/core/utils/Basic', + 'moxie/core/utils/Mime', + 'moxie/file/Blob' +], function(Basic, Mime, Blob) { + /** + @class moxie/file/File + @extends Blob + @constructor + @param {String} ruid Unique id of the runtime, to which this blob belongs to + @param {Object} file Object "Native" file object, as it is represented in the runtime + */ + function File(ruid, file) { + if (!file) { // avoid extra errors in case we overlooked something + file = {}; + } + + Blob.apply(this, arguments); + + if (!this.type) { + this.type = Mime.getFileMime(file.name); + } + + // sanitize file name or generate new one + var name; + if (file.name) { + name = file.name.replace(/\\/g, '/'); + name = name.substr(name.lastIndexOf('/') + 1); + } else if (this.type) { + var prefix = this.type.split('/')[0]; + name = Basic.guid((prefix !== '' ? prefix : 'file') + '_'); + + if (Mime.extensions[this.type]) { + name += '.' + Mime.extensions[this.type][0]; // append proper extension if possible + } + } + + + Basic.extend(this, { + /** + File name + + @property name + @type {String} + @default UID + */ + name: name || Basic.guid('file_'), + + /** + Relative path to the file inside a directory + + @property relativePath + @type {String} + @default '' + */ + relativePath: '', + + /** + Date of last modification + + @property lastModifiedDate + @type {String} + @default now + */ + lastModifiedDate: file.lastModifiedDate || (new Date()).toLocaleString() // Thu Aug 23 2012 19:40:00 GMT+0400 (GET) + }); + } + + File.prototype = Blob.prototype; + + return File; +}); + +// Included from: src/javascript/file/FileDrop.js + +/** + * FileDrop.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +define('moxie/file/FileDrop', [ + 'moxie/core/I18n', + 'moxie/core/utils/Dom', + 'moxie/core/Exceptions', + 'moxie/core/utils/Basic', + 'moxie/core/utils/Env', + 'moxie/file/File', + 'moxie/runtime/RuntimeClient', + 'moxie/core/EventTarget', + 'moxie/core/utils/Mime' +], function(I18n, Dom, x, Basic, Env, File, RuntimeClient, EventTarget, Mime) { + /** + Turn arbitrary DOM element to a drop zone accepting files. Converts selected files to _File_ objects, to be used + in conjunction with _Image_, preloaded in memory with _FileReader_ or uploaded to a server through + _XMLHttpRequest_. + + @example +
+ Drop files here +
+
+
+ + + + @class moxie/file/FileDrop + @constructor + @extends EventTarget + @uses RuntimeClient + @param {Object|String} options If options has typeof string, argument is considered as options.drop_zone + @param {String|DOMElement} options.drop_zone DOM Element to turn into a drop zone + @param {Array} [options.accept] Array of mime types to accept. By default accepts all + @param {Object|String} [options.required_caps] Set of required capabilities, that chosen runtime must support + */ + var dispatches = [ + /** + Dispatched when runtime is connected and drop zone is ready to accept files. + + @event ready + @param {Object} event + */ + 'ready', + + /** + Dispatched when dragging cursor enters the drop zone. + + @event dragenter + @param {Object} event + */ + 'dragenter', + + /** + Dispatched when dragging cursor leaves the drop zone. + + @event dragleave + @param {Object} event + */ + 'dragleave', + + /** + Dispatched when file is dropped onto the drop zone. + + @event drop + @param {Object} event + */ + 'drop', + + /** + Dispatched if error occurs. + + @event error + @param {Object} event + */ + 'error' + ]; + + function FileDrop(options) { + if (MXI_DEBUG) { + Env.log("Instantiating FileDrop..."); + } + + var self = this, defaults; + + // if flat argument passed it should be drop_zone id + if (typeof(options) === 'string') { + options = { drop_zone : options }; + } + + // figure out the options + defaults = { + accept: [{ + title: I18n.translate('All Files'), + extensions: '*' + }], + required_caps: { + drag_and_drop: true + } + }; + + options = typeof(options) === 'object' ? Basic.extend({}, defaults, options) : defaults; + + // this will help us to find proper default container + options.container = Dom.get(options.drop_zone) || document.body; + + // make container relative, if it is not + if (Dom.getStyle(options.container, 'position') === 'static') { + options.container.style.position = 'relative'; + } + + // normalize accept option (could be list of mime types or array of title/extensions pairs) + if (typeof(options.accept) === 'string') { + options.accept = Mime.mimes2extList(options.accept); + } + + RuntimeClient.call(self); + + Basic.extend(self, { + uid: Basic.guid('uid_'), + + ruid: null, + + files: null, + + init: function() { + self.bind('RuntimeInit', function(e, runtime) { + self.ruid = runtime.uid; + runtime.exec.call(self, 'FileDrop', 'init', options); + self.dispatchEvent('ready'); + }); + + // runtime needs: options.required_features, options.runtime_order and options.container + self.connectRuntime(options); // throws RuntimeError + }, + + destroy: function() { + var runtime = this.getRuntime(); + if (runtime) { + runtime.exec.call(this, 'FileDrop', 'destroy'); + this.disconnectRuntime(); + } + this.files = null; + + this.unbindAll(); + } + }); + + this.handleEventProps(dispatches); + } + + FileDrop.prototype = EventTarget.instance; + + return FileDrop; +}); + +// Included from: src/javascript/file/FileReader.js + +/** + * FileReader.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +define('moxie/file/FileReader', [ + 'moxie/core/utils/Basic', + 'moxie/core/utils/Encode', + 'moxie/core/Exceptions', + 'moxie/core/EventTarget', + 'moxie/file/Blob', + 'moxie/runtime/RuntimeClient' +], function(Basic, Encode, x, EventTarget, Blob, RuntimeClient) { + /** + Utility for preloading o.Blob/o.File objects in memory. By design closely follows [W3C FileReader](http://www.w3.org/TR/FileAPI/#dfn-filereader) + interface. Where possible uses native FileReader, where - not falls back to shims. + + @class moxie/file/FileReader + @constructor FileReader + @extends EventTarget + @uses RuntimeClient + */ + var dispatches = [ + + /** + Dispatched when the read starts. + + @event loadstart + @param {Object} event + */ + 'loadstart', + + /** + Dispatched while reading (and decoding) blob, and reporting partial Blob data (progess.loaded/progress.total). + + @event progress + @param {Object} event + */ + 'progress', + + /** + Dispatched when the read has successfully completed. + + @event load + @param {Object} event + */ + 'load', + + /** + Dispatched when the read has been aborted. For instance, by invoking the abort() method. + + @event abort + @param {Object} event + */ + 'abort', + + /** + Dispatched when the read has failed. + + @event error + @param {Object} event + */ + 'error', + + /** + Dispatched when the request has completed (either in success or failure). + + @event loadend + @param {Object} event + */ + 'loadend' + ]; + + function FileReader() { + + RuntimeClient.call(this); + + Basic.extend(this, { + /** + UID of the component instance. + + @property uid + @type {String} + */ + uid: Basic.guid('uid_'), + + /** + Contains current state of FileReader object. Can take values of FileReader.EMPTY, FileReader.LOADING + and FileReader.DONE. + + @property readyState + @type {Number} + @default FileReader.EMPTY + */ + readyState: FileReader.EMPTY, + + /** + Result of the successful read operation. + + @property result + @type {String} + */ + result: null, + + /** + Stores the error of failed asynchronous read operation. + + @property error + @type {DOMError} + */ + error: null, + + /** + Initiates reading of File/Blob object contents to binary string. + + @method readAsBinaryString + @param {Blob|File} blob Object to preload + */ + readAsBinaryString: function(blob) { + _read.call(this, 'readAsBinaryString', blob); + }, + + /** + Initiates reading of File/Blob object contents to dataURL string. + + @method readAsDataURL + @param {Blob|File} blob Object to preload + */ + readAsDataURL: function(blob) { + _read.call(this, 'readAsDataURL', blob); + }, + + /** + Initiates reading of File/Blob object contents to string. + + @method readAsText + @param {Blob|File} blob Object to preload + */ + readAsText: function(blob) { + _read.call(this, 'readAsText', blob); + }, + + /** + Aborts preloading process. + + @method abort + */ + abort: function() { + this.result = null; + + if (Basic.inArray(this.readyState, [FileReader.EMPTY, FileReader.DONE]) !== -1) { + return; + } else if (this.readyState === FileReader.LOADING) { + this.readyState = FileReader.DONE; + } + + this.exec('FileReader', 'abort'); + + this.trigger('abort'); + this.trigger('loadend'); + }, + + /** + Destroy component and release resources. + + @method destroy + */ + destroy: function() { + this.abort(); + this.exec('FileReader', 'destroy'); + this.disconnectRuntime(); + this.unbindAll(); + } + }); + + // uid must already be assigned + this.handleEventProps(dispatches); + + this.bind('Error', function(e, err) { + this.readyState = FileReader.DONE; + this.error = err; + }, 999); + + this.bind('Load', function(e) { + this.readyState = FileReader.DONE; + }, 999); + + + function _read(op, blob) { + var self = this; + + this.trigger('loadstart'); + + if (this.readyState === FileReader.LOADING) { + this.trigger('error', new x.DOMException(x.DOMException.INVALID_STATE_ERR)); + this.trigger('loadend'); + return; + } + + // if source is not o.Blob/o.File + if (!(blob instanceof Blob)) { + this.trigger('error', new x.DOMException(x.DOMException.NOT_FOUND_ERR)); + this.trigger('loadend'); + return; + } + + this.result = null; + this.readyState = FileReader.LOADING; + + if (blob.isDetached()) { + var src = blob.getSource(); + switch (op) { + case 'readAsText': + case 'readAsBinaryString': + this.result = src; + break; + case 'readAsDataURL': + this.result = 'data:' + blob.type + ';base64,' + Encode.btoa(src); + break; + } + this.readyState = FileReader.DONE; + this.trigger('load'); + this.trigger('loadend'); + } else { + this.connectRuntime(blob.ruid); + this.exec('FileReader', 'read', op, blob); + } + } + } + + /** + Initial FileReader state + + @property EMPTY + @type {Number} + @final + @static + @default 0 + */ + FileReader.EMPTY = 0; + + /** + FileReader switches to this state when it is preloading the source + + @property LOADING + @type {Number} + @final + @static + @default 1 + */ + FileReader.LOADING = 1; + + /** + Preloading is complete, this is a final state + + @property DONE + @type {Number} + @final + @static + @default 2 + */ + FileReader.DONE = 2; + + FileReader.prototype = EventTarget.instance; + + return FileReader; +}); + +// Included from: src/javascript/core/utils/Url.js + +/** + * Url.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +define('moxie/core/utils/Url', [ + 'moxie/core/utils/Basic' +], function(Basic) { + /** + Parse url into separate components and fill in absent parts with parts from current url, + based on https://raw.github.com/kvz/phpjs/master/functions/url/parse_url.js + + @method parseUrl + @for Utils + @static + @param {String} url Url to parse (defaults to empty string if undefined) + @return {Object} Hash containing extracted uri components + */ + var parseUrl = function(url, currentUrl) { + var key = ['source', 'scheme', 'authority', 'userInfo', 'user', 'pass', 'host', 'port', 'relative', 'path', 'directory', 'file', 'query', 'fragment'] + , i = key.length + , ports = { + http: 80, + https: 443 + } + , uri = {} + , regex = /^(?:([^:\/?#]+):)?(?:\/\/()(?:(?:()(?:([^:@\/]*):?([^:@\/]*))?@)?(\[[\da-fA-F:]+\]|[^:\/?#]*)(?::(\d*))?))?()(?:(()(?:(?:[^?#\/]*\/)*)()(?:[^?#]*))(?:\\?([^#]*))?(?:#(.*))?)/ + , m = regex.exec(url || '') + , isRelative + , isSchemeLess = /^\/\/\w/.test(url) + ; + + switch (Basic.typeOf(currentUrl)) { + case 'undefined': + currentUrl = parseUrl(document.location.href, false); + break; + + case 'string': + currentUrl = parseUrl(currentUrl, false); + break; + } + + while (i--) { + if (m[i]) { + uri[key[i]] = m[i]; + } + } + + isRelative = !isSchemeLess && !uri.scheme; + + if (isSchemeLess || isRelative) { + uri.scheme = currentUrl.scheme; + } + + // when url is relative, we set the origin and the path ourselves + if (isRelative) { + uri.host = currentUrl.host; + uri.port = currentUrl.port; + + var path = ''; + // for urls without trailing slash we need to figure out the path + if (/^[^\/]/.test(uri.path)) { + path = currentUrl.path; + // if path ends with a filename, strip it + if (/\/[^\/]*\.[^\/]*$/.test(path)) { + path = path.replace(/\/[^\/]+$/, '/'); + } else { + // avoid double slash at the end (see #127) + path = path.replace(/\/?$/, '/'); + } + } + uri.path = path + (uri.path || ''); // site may reside at domain.com or domain.com/subdir + } + + if (!uri.port) { + uri.port = ports[uri.scheme] || 80; + } + + uri.port = parseInt(uri.port, 10); + + if (!uri.path) { + uri.path = "/"; + } + + delete uri.source; + + return uri; + }; + + /** + Resolve url - among other things will turn relative url to absolute + + @method resolveUrl + @static + @param {String|Object} url Either absolute or relative, or a result of parseUrl call + @return {String} Resolved, absolute url + */ + var resolveUrl = function(url) { + var ports = { // we ignore default ports + http: 80, + https: 443 + } + , urlp = typeof(url) === 'object' ? url : parseUrl(url); + ; + + return urlp.scheme + '://' + urlp.host + (urlp.port !== ports[urlp.scheme] ? ':' + urlp.port : '') + urlp.path + (urlp.query ? urlp.query : ''); + }; + + /** + Check if specified url has the same origin as the current document + + @method hasSameOrigin + @param {String|Object} url + @return {Boolean} + */ + var hasSameOrigin = function(url) { + function origin(url) { + return [url.scheme, url.host, url.port].join('/'); + } + + if (typeof url === 'string') { + url = parseUrl(url); + } + + return origin(parseUrl()) === origin(url); + }; + + return { + parseUrl: parseUrl, + resolveUrl: resolveUrl, + hasSameOrigin: hasSameOrigin + }; +}); + +// Included from: src/javascript/runtime/RuntimeTarget.js + +/** + * RuntimeTarget.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +define('moxie/runtime/RuntimeTarget', [ + 'moxie/core/utils/Basic', + 'moxie/runtime/RuntimeClient', + "moxie/core/EventTarget" +], function(Basic, RuntimeClient, EventTarget) { + /** + Instance of this class can be used as a target for the events dispatched by shims, + when allowing them onto components is for either reason inappropriate + + @class moxie/runtime/RuntimeTarget + @constructor + @protected + @extends EventTarget + */ + function RuntimeTarget() { + this.uid = Basic.guid('uid_'); + + RuntimeClient.call(this); + + this.destroy = function() { + this.disconnectRuntime(); + this.unbindAll(); + }; + } + + RuntimeTarget.prototype = EventTarget.instance; + + return RuntimeTarget; +}); + +// Included from: src/javascript/file/FileReaderSync.js + +/** + * FileReaderSync.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +define('moxie/file/FileReaderSync', [ + 'moxie/core/utils/Basic', + 'moxie/runtime/RuntimeClient', + 'moxie/core/utils/Encode' +], function(Basic, RuntimeClient, Encode) { + /** + Synchronous FileReader implementation. Something like this is available in WebWorkers environment, here + it can be used to read only preloaded blobs/files and only below certain size (not yet sure what that'd be, + but probably < 1mb). Not meant to be used directly by user. + + @class moxie/file/FileReaderSync + @private + @constructor + */ + return function() { + RuntimeClient.call(this); + + Basic.extend(this, { + uid: Basic.guid('uid_'), + + readAsBinaryString: function(blob) { + return _read.call(this, 'readAsBinaryString', blob); + }, + + readAsDataURL: function(blob) { + return _read.call(this, 'readAsDataURL', blob); + }, + + /*readAsArrayBuffer: function(blob) { + return _read.call(this, 'readAsArrayBuffer', blob); + },*/ + + readAsText: function(blob) { + return _read.call(this, 'readAsText', blob); + } + }); + + function _read(op, blob) { + if (blob.isDetached()) { + var src = blob.getSource(); + switch (op) { + case 'readAsBinaryString': + return src; + case 'readAsDataURL': + return 'data:' + blob.type + ';base64,' + Encode.btoa(src); + case 'readAsText': + var txt = ''; + for (var i = 0, length = src.length; i < length; i++) { + txt += String.fromCharCode(src[i]); + } + return txt; + } + } else { + var result = this.connectRuntime(blob.ruid).exec.call(this, 'FileReaderSync', 'read', op, blob); + this.disconnectRuntime(); + return result; + } + } + }; +}); + +// Included from: src/javascript/xhr/FormData.js + +/** + * FormData.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +define("moxie/xhr/FormData", [ + "moxie/core/Exceptions", + "moxie/core/utils/Basic", + "moxie/file/Blob" +], function(x, Basic, Blob) { + /** + FormData + + @class moxie/xhr/FormData + @constructor + */ + function FormData() { + var _blob, _fields = []; + + Basic.extend(this, { + /** + Append another key-value pair to the FormData object + + @method append + @param {String} name Name for the new field + @param {String|Blob|Array|Object} value Value for the field + */ + append: function(name, value) { + var self = this, valueType = Basic.typeOf(value); + + // according to specs value might be either Blob or String + if (value instanceof Blob) { + _blob = { + name: name, + value: value // unfortunately we can only send single Blob in one FormData + }; + } else if ('array' === valueType) { + name += '[]'; + + Basic.each(value, function(value) { + self.append(name, value); + }); + } else if ('object' === valueType) { + Basic.each(value, function(value, key) { + self.append(name + '[' + key + ']', value); + }); + } else if ('null' === valueType || 'undefined' === valueType || 'number' === valueType && isNaN(value)) { + self.append(name, "false"); + } else { + _fields.push({ + name: name, + value: value.toString() + }); + } + }, + + /** + Checks if FormData contains Blob. + + @method hasBlob + @return {Boolean} + */ + hasBlob: function() { + return !!this.getBlob(); + }, + + /** + Retrieves blob. + + @method getBlob + @return {Object} Either Blob if found or null + */ + getBlob: function() { + return _blob && _blob.value || null; + }, + + /** + Retrieves blob field name. + + @method getBlobName + @return {String} Either Blob field name or null + */ + getBlobName: function() { + return _blob && _blob.name || null; + }, + + /** + Loop over the fields in FormData and invoke the callback for each of them. + + @method each + @param {Function} cb Callback to call for each field + */ + each: function(cb) { + Basic.each(_fields, function(field) { + cb(field.value, field.name); + }); + + if (_blob) { + cb(_blob.value, _blob.name); + } + }, + + destroy: function() { + _blob = null; + _fields = []; + } + }); + } + + return FormData; +}); + +// Included from: src/javascript/xhr/XMLHttpRequest.js + +/** + * XMLHttpRequest.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +define("moxie/xhr/XMLHttpRequest", [ + "moxie/core/utils/Basic", + "moxie/core/Exceptions", + "moxie/core/EventTarget", + "moxie/core/utils/Encode", + "moxie/core/utils/Url", + "moxie/runtime/Runtime", + "moxie/runtime/RuntimeTarget", + "moxie/file/Blob", + "moxie/file/FileReaderSync", + "moxie/xhr/FormData", + "moxie/core/utils/Env", + "moxie/core/utils/Mime" +], function(Basic, x, EventTarget, Encode, Url, Runtime, RuntimeTarget, Blob, FileReaderSync, FormData, Env, Mime) { + + var httpCode = { + 100: 'Continue', + 101: 'Switching Protocols', + 102: 'Processing', + + 200: 'OK', + 201: 'Created', + 202: 'Accepted', + 203: 'Non-Authoritative Information', + 204: 'No Content', + 205: 'Reset Content', + 206: 'Partial Content', + 207: 'Multi-Status', + 226: 'IM Used', + + 300: 'Multiple Choices', + 301: 'Moved Permanently', + 302: 'Found', + 303: 'See Other', + 304: 'Not Modified', + 305: 'Use Proxy', + 306: 'Reserved', + 307: 'Temporary Redirect', + + 400: 'Bad Request', + 401: 'Unauthorized', + 402: 'Payment Required', + 403: 'Forbidden', + 404: 'Not Found', + 405: 'Method Not Allowed', + 406: 'Not Acceptable', + 407: 'Proxy Authentication Required', + 408: 'Request Timeout', + 409: 'Conflict', + 410: 'Gone', + 411: 'Length Required', + 412: 'Precondition Failed', + 413: 'Request Entity Too Large', + 414: 'Request-URI Too Long', + 415: 'Unsupported Media Type', + 416: 'Requested Range Not Satisfiable', + 417: 'Expectation Failed', + 422: 'Unprocessable Entity', + 423: 'Locked', + 424: 'Failed Dependency', + 426: 'Upgrade Required', + + 500: 'Internal Server Error', + 501: 'Not Implemented', + 502: 'Bad Gateway', + 503: 'Service Unavailable', + 504: 'Gateway Timeout', + 505: 'HTTP Version Not Supported', + 506: 'Variant Also Negotiates', + 507: 'Insufficient Storage', + 510: 'Not Extended' + }; + + function XMLHttpRequestUpload() { + this.uid = Basic.guid('uid_'); + } + + XMLHttpRequestUpload.prototype = EventTarget.instance; + + /** + Implementation of XMLHttpRequest + + @class moxie/xhr/XMLHttpRequest + @constructor + @uses RuntimeClient + @extends EventTarget + */ + var dispatches = [ + 'loadstart', + + 'progress', + + 'abort', + + 'error', + + 'load', + + 'timeout', + + 'loadend' + + // readystatechange (for historical reasons) + ]; + + var NATIVE = 1, RUNTIME = 2; + + function XMLHttpRequest() { + var self = this, + // this (together with _p() @see below) is here to gracefully upgrade to setter/getter syntax where possible + props = { + /** + The amount of milliseconds a request can take before being terminated. Initially zero. Zero means there is no timeout. + + @property timeout + @type Number + @default 0 + */ + timeout: 0, + + /** + Current state, can take following values: + UNSENT (numeric value 0) + The object has been constructed. + + OPENED (numeric value 1) + The open() method has been successfully invoked. During this state request headers can be set using setRequestHeader() and the request can be made using the send() method. + + HEADERS_RECEIVED (numeric value 2) + All redirects (if any) have been followed and all HTTP headers of the final response have been received. Several response members of the object are now available. + + LOADING (numeric value 3) + The response entity body is being received. + + DONE (numeric value 4) + + @property readyState + @type Number + @default 0 (UNSENT) + */ + readyState: XMLHttpRequest.UNSENT, + + /** + True when user credentials are to be included in a cross-origin request. False when they are to be excluded + in a cross-origin request and when cookies are to be ignored in its response. Initially false. + + @property withCredentials + @type Boolean + @default false + */ + withCredentials: false, + + /** + Returns the HTTP status code. + + @property status + @type Number + @default 0 + */ + status: 0, + + /** + Returns the HTTP status text. + + @property statusText + @type String + */ + statusText: "", + + /** + Returns the response type. Can be set to change the response type. Values are: + the empty string (default), "arraybuffer", "blob", "document", "json", and "text". + + @property responseType + @type String + */ + responseType: "", + + /** + Returns the document response entity body. + + Throws an "InvalidStateError" exception if responseType is not the empty string or "document". + + @property responseXML + @type Document + */ + responseXML: null, + + /** + Returns the text response entity body. + + Throws an "InvalidStateError" exception if responseType is not the empty string or "text". + + @property responseText + @type String + */ + responseText: null, + + /** + Returns the response entity body (http://www.w3.org/TR/XMLHttpRequest/#response-entity-body). + Can become: ArrayBuffer, Blob, Document, JSON, Text + + @property response + @type Mixed + */ + response: null + }, + + _async = true, + _url, + _method, + _headers = {}, + _user, + _password, + _encoding = null, + _mimeType = null, + + // flags + _sync_flag = false, + _send_flag = false, + _upload_events_flag = false, + _upload_complete_flag = false, + _error_flag = false, + _same_origin_flag = false, + + // times + _start_time, + _timeoutset_time, + + _finalMime = null, + _finalCharset = null, + + _options = {}, + _xhr, + _responseHeaders = '', + _responseHeadersBag + ; + + + Basic.extend(this, props, { + /** + Unique id of the component + + @property uid + @type String + */ + uid: Basic.guid('uid_'), + + /** + Target for Upload events + + @property upload + @type XMLHttpRequestUpload + */ + upload: new XMLHttpRequestUpload(), + + + /** + Sets the request method, request URL, synchronous flag, request username, and request password. + + Throws a "SyntaxError" exception if one of the following is true: + + method is not a valid HTTP method. + url cannot be resolved. + url contains the "user:password" format in the userinfo production. + Throws a "SecurityError" exception if method is a case-insensitive match for CONNECT, TRACE or TRACK. + + Throws an "InvalidAccessError" exception if one of the following is true: + + Either user or password is passed as argument and the origin of url does not match the XMLHttpRequest origin. + There is an associated XMLHttpRequest document and either the timeout attribute is not zero, + the withCredentials attribute is true, or the responseType attribute is not the empty string. + + + @method open + @param {String} method HTTP method to use on request + @param {String} url URL to request + @param {Boolean} [async=true] If false request will be done in synchronous manner. Asynchronous by default. + @param {String} [user] Username to use in HTTP authentication process on server-side + @param {String} [password] Password to use in HTTP authentication process on server-side + */ + open: function(method, url, async, user, password) { + var urlp; + + // first two arguments are required + if (!method || !url) { + throw new x.DOMException(x.DOMException.SYNTAX_ERR); + } + + // 2 - check if any code point in method is higher than U+00FF or after deflating method it does not match the method + if (/[\u0100-\uffff]/.test(method) || Encode.utf8_encode(method) !== method) { + throw new x.DOMException(x.DOMException.SYNTAX_ERR); + } + + // 3 + if (!!~Basic.inArray(method.toUpperCase(), ['CONNECT', 'DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT', 'TRACE', 'TRACK'])) { + _method = method.toUpperCase(); + } + + + // 4 - allowing these methods poses a security risk + if (!!~Basic.inArray(_method, ['CONNECT', 'TRACE', 'TRACK'])) { + throw new x.DOMException(x.DOMException.SECURITY_ERR); + } + + // 5 + url = Encode.utf8_encode(url); + + // 6 - Resolve url relative to the XMLHttpRequest base URL. If the algorithm returns an error, throw a "SyntaxError". + urlp = Url.parseUrl(url); + + _same_origin_flag = Url.hasSameOrigin(urlp); + + // 7 - manually build up absolute url + _url = Url.resolveUrl(url); + + // 9-10, 12-13 + if ((user || password) && !_same_origin_flag) { + throw new x.DOMException(x.DOMException.INVALID_ACCESS_ERR); + } + + _user = user || urlp.user; + _password = password || urlp.pass; + + // 11 + _async = async || true; + + if (_async === false && (_p('timeout') || _p('withCredentials') || _p('responseType') !== "")) { + throw new x.DOMException(x.DOMException.INVALID_ACCESS_ERR); + } + + // 14 - terminate abort() + + // 15 - terminate send() + + // 18 + _sync_flag = !_async; + _send_flag = false; + _headers = {}; + _reset.call(this); + + // 19 + _p('readyState', XMLHttpRequest.OPENED); + + // 20 + this.dispatchEvent('readystatechange'); + }, + + /** + Appends an header to the list of author request headers, or if header is already + in the list of author request headers, combines its value with value. + + Throws an "InvalidStateError" exception if the state is not OPENED or if the send() flag is set. + Throws a "SyntaxError" exception if header is not a valid HTTP header field name or if value + is not a valid HTTP header field value. + + @method setRequestHeader + @param {String} header + @param {String|Number} value + */ + setRequestHeader: function(header, value) { + var uaHeaders = [ // these headers are controlled by the user agent + "accept-charset", + "accept-encoding", + "access-control-request-headers", + "access-control-request-method", + "connection", + "content-length", + "cookie", + "cookie2", + "content-transfer-encoding", + "date", + "expect", + "host", + "keep-alive", + "origin", + "referer", + "te", + "trailer", + "transfer-encoding", + "upgrade", + "user-agent", + "via" + ]; + + // 1-2 + if (_p('readyState') !== XMLHttpRequest.OPENED || _send_flag) { + throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); + } + + // 3 + if (/[\u0100-\uffff]/.test(header) || Encode.utf8_encode(header) !== header) { + throw new x.DOMException(x.DOMException.SYNTAX_ERR); + } + + // 4 + /* this step is seemingly bypassed in browsers, probably to allow various unicode characters in header values + if (/[\u0100-\uffff]/.test(value) || Encode.utf8_encode(value) !== value) { + throw new x.DOMException(x.DOMException.SYNTAX_ERR); + }*/ + + header = Basic.trim(header).toLowerCase(); + + // setting of proxy-* and sec-* headers is prohibited by spec + if (!!~Basic.inArray(header, uaHeaders) || /^(proxy\-|sec\-)/.test(header)) { + return false; + } + + // camelize + // browsers lowercase header names (at least for custom ones) + // header = header.replace(/\b\w/g, function($1) { return $1.toUpperCase(); }); + + if (!_headers[header]) { + _headers[header] = value; + } else { + // http://tools.ietf.org/html/rfc2616#section-4.2 (last paragraph) + _headers[header] += ', ' + value; + } + return true; + }, + + /** + * Test if the specified header is already set on this request. + * Returns a header value or boolean false if it's not yet set. + * + * @method hasRequestHeader + * @param {String} header Name of the header to test + * @return {Boolean|String} + */ + hasRequestHeader: function(header) { + return header && _headers[header.toLowerCase()] || false; + }, + + /** + Returns all headers from the response, with the exception of those whose field name is Set-Cookie or Set-Cookie2. + + @method getAllResponseHeaders + @return {String} reponse headers or empty string + */ + getAllResponseHeaders: function() { + return _responseHeaders || ''; + }, + + /** + Returns the header field value from the response of which the field name matches header, + unless the field name is Set-Cookie or Set-Cookie2. + + @method getResponseHeader + @param {String} header + @return {String} value(s) for the specified header or null + */ + getResponseHeader: function(header) { + header = header.toLowerCase(); + + if (_error_flag || !!~Basic.inArray(header, ['set-cookie', 'set-cookie2'])) { + return null; + } + + if (_responseHeaders && _responseHeaders !== '') { + // if we didn't parse response headers until now, do it and keep for later + if (!_responseHeadersBag) { + _responseHeadersBag = {}; + Basic.each(_responseHeaders.split(/\r\n/), function(line) { + var pair = line.split(/:\s+/); + if (pair.length === 2) { // last line might be empty, omit + pair[0] = Basic.trim(pair[0]); // just in case + _responseHeadersBag[pair[0].toLowerCase()] = { // simply to retain header name in original form + header: pair[0], + value: Basic.trim(pair[1]) + }; + } + }); + } + if (_responseHeadersBag.hasOwnProperty(header)) { + return _responseHeadersBag[header].header + ': ' + _responseHeadersBag[header].value; + } + } + return null; + }, + + /** + Sets the Content-Type header for the response to mime. + Throws an "InvalidStateError" exception if the state is LOADING or DONE. + Throws a "SyntaxError" exception if mime is not a valid media type. + + @method overrideMimeType + @param String mime Mime type to set + */ + overrideMimeType: function(mime) { + var matches, charset; + + // 1 + if (!!~Basic.inArray(_p('readyState'), [XMLHttpRequest.LOADING, XMLHttpRequest.DONE])) { + throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); + } + + // 2 + mime = Basic.trim(mime.toLowerCase()); + + if (/;/.test(mime) && (matches = mime.match(/^([^;]+)(?:;\scharset\=)?(.*)$/))) { + mime = matches[1]; + if (matches[2]) { + charset = matches[2]; + } + } + + if (!Mime.mimes[mime]) { + throw new x.DOMException(x.DOMException.SYNTAX_ERR); + } + + // 3-4 + _finalMime = mime; + _finalCharset = charset; + }, + + /** + Initiates the request. The optional argument provides the request entity body. + The argument is ignored if request method is GET or HEAD. + + Throws an "InvalidStateError" exception if the state is not OPENED or if the send() flag is set. + + @method send + @param {Blob|Document|String|FormData} [data] Request entity body + @param {Object} [options] Set of requirements and pre-requisities for runtime initialization + */ + send: function(data, options) { + if (Basic.typeOf(options) === 'string') { + _options = { ruid: options }; + } else if (!options) { + _options = {}; + } else { + _options = options; + } + + // 1-2 + if (this.readyState !== XMLHttpRequest.OPENED || _send_flag) { + throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); + } + + // 3 + // sending Blob + if (data instanceof Blob) { + _options.ruid = data.ruid; + _mimeType = data.type || 'application/octet-stream'; + } + + // FormData + else if (data instanceof FormData) { + if (data.hasBlob()) { + var blob = data.getBlob(); + _options.ruid = blob.ruid; + _mimeType = blob.type || 'application/octet-stream'; + } + } + + // DOMString + else if (typeof data === 'string') { + _encoding = 'UTF-8'; + _mimeType = 'text/plain;charset=UTF-8'; + + // data should be converted to Unicode and encoded as UTF-8 + data = Encode.utf8_encode(data); + } + + // if withCredentials not set, but requested, set it automatically + if (!this.withCredentials) { + this.withCredentials = (_options.required_caps && _options.required_caps.send_browser_cookies) && !_same_origin_flag; + } + + // 4 - storage mutex + // 5 + _upload_events_flag = (!_sync_flag && this.upload.hasEventListener()); // DSAP + // 6 + _error_flag = false; + // 7 + _upload_complete_flag = !data; + // 8 - Asynchronous steps + if (!_sync_flag) { + // 8.1 + _send_flag = true; + // 8.2 + // this.dispatchEvent('loadstart'); // will be dispatched either by native or runtime xhr + // 8.3 + //if (!_upload_complete_flag) { + // this.upload.dispatchEvent('loadstart'); // will be dispatched either by native or runtime xhr + //} + } + // 8.5 - Return the send() method call, but continue running the steps in this algorithm. + _doXHR.call(this, data); + }, + + /** + Cancels any network activity. + + @method abort + */ + abort: function() { + _error_flag = true; + _sync_flag = false; + + if (!~Basic.inArray(_p('readyState'), [XMLHttpRequest.UNSENT, XMLHttpRequest.OPENED, XMLHttpRequest.DONE])) { + _p('readyState', XMLHttpRequest.DONE); + _send_flag = false; + + if (_xhr) { + _xhr.getRuntime().exec.call(_xhr, 'XMLHttpRequest', 'abort', _upload_complete_flag); + } else { + throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); + } + + _upload_complete_flag = true; + } else { + _p('readyState', XMLHttpRequest.UNSENT); + } + }, + + destroy: function() { + if (_xhr) { + if (Basic.typeOf(_xhr.destroy) === 'function') { + _xhr.destroy(); + } + _xhr = null; + } + + this.unbindAll(); + + if (this.upload) { + this.upload.unbindAll(); + this.upload = null; + } + } + }); + + this.handleEventProps(dispatches.concat(['readystatechange'])); // for historical reasons + this.upload.handleEventProps(dispatches); + + /* this is nice, but maybe too lengthy + + // if supported by JS version, set getters/setters for specific properties + o.defineProperty(this, 'readyState', { + configurable: false, + + get: function() { + return _p('readyState'); + } + }); + + o.defineProperty(this, 'timeout', { + configurable: false, + + get: function() { + return _p('timeout'); + }, + + set: function(value) { + + if (_sync_flag) { + throw new x.DOMException(x.DOMException.INVALID_ACCESS_ERR); + } + + // timeout still should be measured relative to the start time of request + _timeoutset_time = (new Date).getTime(); + + _p('timeout', value); + } + }); + + // the withCredentials attribute has no effect when fetching same-origin resources + o.defineProperty(this, 'withCredentials', { + configurable: false, + + get: function() { + return _p('withCredentials'); + }, + + set: function(value) { + // 1-2 + if (!~o.inArray(_p('readyState'), [XMLHttpRequest.UNSENT, XMLHttpRequest.OPENED]) || _send_flag) { + throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); + } + + // 3-4 + if (_anonymous_flag || _sync_flag) { + throw new x.DOMException(x.DOMException.INVALID_ACCESS_ERR); + } + + // 5 + _p('withCredentials', value); + } + }); + + o.defineProperty(this, 'status', { + configurable: false, + + get: function() { + return _p('status'); + } + }); + + o.defineProperty(this, 'statusText', { + configurable: false, + + get: function() { + return _p('statusText'); + } + }); + + o.defineProperty(this, 'responseType', { + configurable: false, + + get: function() { + return _p('responseType'); + }, + + set: function(value) { + // 1 + if (!!~o.inArray(_p('readyState'), [XMLHttpRequest.LOADING, XMLHttpRequest.DONE])) { + throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); + } + + // 2 + if (_sync_flag) { + throw new x.DOMException(x.DOMException.INVALID_ACCESS_ERR); + } + + // 3 + _p('responseType', value.toLowerCase()); + } + }); + + o.defineProperty(this, 'responseText', { + configurable: false, + + get: function() { + // 1 + if (!~o.inArray(_p('responseType'), ['', 'text'])) { + throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); + } + + // 2-3 + if (_p('readyState') !== XMLHttpRequest.DONE && _p('readyState') !== XMLHttpRequest.LOADING || _error_flag) { + throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); + } + + return _p('responseText'); + } + }); + + o.defineProperty(this, 'responseXML', { + configurable: false, + + get: function() { + // 1 + if (!~o.inArray(_p('responseType'), ['', 'document'])) { + throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); + } + + // 2-3 + if (_p('readyState') !== XMLHttpRequest.DONE || _error_flag) { + throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); + } + + return _p('responseXML'); + } + }); + + o.defineProperty(this, 'response', { + configurable: false, + + get: function() { + if (!!~o.inArray(_p('responseType'), ['', 'text'])) { + if (_p('readyState') !== XMLHttpRequest.DONE && _p('readyState') !== XMLHttpRequest.LOADING || _error_flag) { + return ''; + } + } + + if (_p('readyState') !== XMLHttpRequest.DONE || _error_flag) { + return null; + } + + return _p('response'); + } + }); + + */ + + function _p(prop, value) { + if (!props.hasOwnProperty(prop)) { + return; + } + if (arguments.length === 1) { // get + return Env.can('define_property') ? props[prop] : self[prop]; + } else { // set + if (Env.can('define_property')) { + props[prop] = value; + } else { + self[prop] = value; + } + } + } + + /* + function _toASCII(str, AllowUnassigned, UseSTD3ASCIIRules) { + // TODO: http://tools.ietf.org/html/rfc3490#section-4.1 + return str.toLowerCase(); + } + */ + + + function _doXHR(data) { + var self = this; + + _start_time = new Date().getTime(); + + _xhr = new RuntimeTarget(); + + function loadEnd() { + if (_xhr) { // it could have been destroyed by now + _xhr.destroy(); + _xhr = null; + } + self.dispatchEvent('loadend'); + self = null; + } + + function exec(runtime) { + _xhr.bind('LoadStart', function(e) { + _p('readyState', XMLHttpRequest.LOADING); + self.dispatchEvent('readystatechange'); + + self.dispatchEvent(e); + + if (_upload_events_flag) { + self.upload.dispatchEvent(e); + } + }); + + _xhr.bind('Progress', function(e) { + if (_p('readyState') !== XMLHttpRequest.LOADING) { + _p('readyState', XMLHttpRequest.LOADING); // LoadStart unreliable (in Flash for example) + self.dispatchEvent('readystatechange'); + } + self.dispatchEvent(e); + }); + + _xhr.bind('UploadProgress', function(e) { + if (_upload_events_flag) { + self.upload.dispatchEvent({ + type: 'progress', + lengthComputable: false, + total: e.total, + loaded: e.loaded + }); + } + }); + + _xhr.bind('Load', function(e) { + _p('readyState', XMLHttpRequest.DONE); + _p('status', Number(runtime.exec.call(_xhr, 'XMLHttpRequest', 'getStatus') || 0)); + _p('statusText', httpCode[_p('status')] || ""); + + _p('response', runtime.exec.call(_xhr, 'XMLHttpRequest', 'getResponse', _p('responseType'))); + + if (!!~Basic.inArray(_p('responseType'), ['text', ''])) { + _p('responseText', _p('response')); + } else if (_p('responseType') === 'document') { + _p('responseXML', _p('response')); + } + + _responseHeaders = runtime.exec.call(_xhr, 'XMLHttpRequest', 'getAllResponseHeaders'); + + self.dispatchEvent('readystatechange'); + + if (_p('status') > 0) { // status 0 usually means that server is unreachable + if (_upload_events_flag) { + self.upload.dispatchEvent(e); + } + self.dispatchEvent(e); + } else { + _error_flag = true; + self.dispatchEvent('error'); + } + loadEnd(); + }); + + _xhr.bind('Abort', function(e) { + self.dispatchEvent(e); + loadEnd(); + }); + + _xhr.bind('Error', function(e) { + _error_flag = true; + _p('readyState', XMLHttpRequest.DONE); + self.dispatchEvent('readystatechange'); + _upload_complete_flag = true; + self.dispatchEvent(e); + loadEnd(); + }); + + runtime.exec.call(_xhr, 'XMLHttpRequest', 'send', { + url: _url, + method: _method, + async: _async, + user: _user, + password: _password, + headers: _headers, + mimeType: _mimeType, + encoding: _encoding, + responseType: self.responseType, + withCredentials: self.withCredentials, + options: _options + }, data); + } + + // clarify our requirements + if (typeof(_options.required_caps) === 'string') { + _options.required_caps = Runtime.parseCaps(_options.required_caps); + } + + _options.required_caps = Basic.extend({}, _options.required_caps, { + return_response_type: self.responseType + }); + + if (data instanceof FormData) { + _options.required_caps.send_multipart = true; + } + + if (!Basic.isEmptyObj(_headers)) { + _options.required_caps.send_custom_headers = true; + } + + if (!_same_origin_flag) { + _options.required_caps.do_cors = true; + } + + + if (_options.ruid) { // we do not need to wait if we can connect directly + exec(_xhr.connectRuntime(_options)); + } else { + _xhr.bind('RuntimeInit', function(e, runtime) { + exec(runtime); + }); + _xhr.bind('RuntimeError', function(e, err) { + self.dispatchEvent('RuntimeError', err); + }); + _xhr.connectRuntime(_options); + } + } + + + function _reset() { + _p('responseText', ""); + _p('responseXML', null); + _p('response', null); + _p('status', 0); + _p('statusText', ""); + _start_time = _timeoutset_time = null; + } + } + + XMLHttpRequest.UNSENT = 0; + XMLHttpRequest.OPENED = 1; + XMLHttpRequest.HEADERS_RECEIVED = 2; + XMLHttpRequest.LOADING = 3; + XMLHttpRequest.DONE = 4; + + XMLHttpRequest.prototype = EventTarget.instance; + + return XMLHttpRequest; +}); + +// Included from: src/javascript/runtime/Transporter.js + +/** + * Transporter.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +define("moxie/runtime/Transporter", [ + "moxie/core/utils/Basic", + "moxie/core/utils/Encode", + "moxie/runtime/RuntimeClient", + "moxie/core/EventTarget" +], function(Basic, Encode, RuntimeClient, EventTarget) { + + /** + @class moxie/runtime/Transporter + @constructor + */ + function Transporter() { + var mod, _runtime, _data, _size, _pos, _chunk_size; + + RuntimeClient.call(this); + + Basic.extend(this, { + uid: Basic.guid('uid_'), + + state: Transporter.IDLE, + + result: null, + + transport: function(data, type, options) { + var self = this; + + options = Basic.extend({ + chunk_size: 204798 + }, options); + + // should divide by three, base64 requires this + if ((mod = options.chunk_size % 3)) { + options.chunk_size += 3 - mod; + } + + _chunk_size = options.chunk_size; + + _reset.call(this); + _data = data; + _size = data.length; + + if (Basic.typeOf(options) === 'string' || options.ruid) { + _run.call(self, type, this.connectRuntime(options)); + } else { + // we require this to run only once + var cb = function(e, runtime) { + self.unbind("RuntimeInit", cb); + _run.call(self, type, runtime); + }; + this.bind("RuntimeInit", cb); + this.connectRuntime(options); + } + }, + + abort: function() { + var self = this; + + self.state = Transporter.IDLE; + if (_runtime) { + _runtime.exec.call(self, 'Transporter', 'clear'); + self.trigger("TransportingAborted"); + } + + _reset.call(self); + }, + + + destroy: function() { + this.unbindAll(); + _runtime = null; + this.disconnectRuntime(); + _reset.call(this); + } + }); + + function _reset() { + _size = _pos = 0; + _data = this.result = null; + } + + function _run(type, runtime) { + var self = this; + + _runtime = runtime; + + //self.unbind("RuntimeInit"); + + self.bind("TransportingProgress", function(e) { + _pos = e.loaded; + + if (_pos < _size && Basic.inArray(self.state, [Transporter.IDLE, Transporter.DONE]) === -1) { + _transport.call(self); + } + }, 999); + + self.bind("TransportingComplete", function() { + _pos = _size; + self.state = Transporter.DONE; + _data = null; // clean a bit + self.result = _runtime.exec.call(self, 'Transporter', 'getAsBlob', type || ''); + }, 999); + + self.state = Transporter.BUSY; + self.trigger("TransportingStarted"); + _transport.call(self); + } + + function _transport() { + var self = this, + chunk, + bytesLeft = _size - _pos; + + if (_chunk_size > bytesLeft) { + _chunk_size = bytesLeft; + } + + chunk = Encode.btoa(_data.substr(_pos, _chunk_size)); + _runtime.exec.call(self, 'Transporter', 'receive', chunk, _size); + } + } + + Transporter.IDLE = 0; + Transporter.BUSY = 1; + Transporter.DONE = 2; + + Transporter.prototype = EventTarget.instance; + + return Transporter; +}); + +// Included from: src/javascript/image/Image.js + +/** + * Image.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +define("moxie/image/Image", [ + "moxie/core/utils/Basic", + "moxie/core/utils/Dom", + "moxie/core/Exceptions", + "moxie/file/FileReaderSync", + "moxie/xhr/XMLHttpRequest", + "moxie/runtime/Runtime", + "moxie/runtime/RuntimeClient", + "moxie/runtime/Transporter", + "moxie/core/utils/Env", + "moxie/core/EventTarget", + "moxie/file/Blob", + "moxie/file/File", + "moxie/core/utils/Encode" +], function(Basic, Dom, x, FileReaderSync, XMLHttpRequest, Runtime, RuntimeClient, Transporter, Env, EventTarget, Blob, File, Encode) { + /** + Image preloading and manipulation utility. Additionally it provides access to image meta info (Exif, GPS) and raw binary data. + + @class moxie/image/Image + @constructor + @extends EventTarget + */ + var dispatches = [ + 'progress', + + /** + Dispatched when loading is complete. + + @event load + @param {Object} event + */ + 'load', + + 'error', + + /** + Dispatched when resize operation is complete. + + @event resize + @param {Object} event + */ + 'resize', + + /** + Dispatched when visual representation of the image is successfully embedded + into the corresponsing container. + + @event embedded + @param {Object} event + */ + 'embedded' + ]; + + function Image() { + + RuntimeClient.call(this); + + Basic.extend(this, { + /** + Unique id of the component + + @property uid + @type {String} + */ + uid: Basic.guid('uid_'), + + /** + Unique id of the connected runtime, if any. + + @property ruid + @type {String} + */ + ruid: null, + + /** + Name of the file, that was used to create an image, if available. If not equals to empty string. + + @property name + @type {String} + @default "" + */ + name: "", + + /** + Size of the image in bytes. Actual value is set only after image is preloaded. + + @property size + @type {Number} + @default 0 + */ + size: 0, + + /** + Width of the image. Actual value is set only after image is preloaded. + + @property width + @type {Number} + @default 0 + */ + width: 0, + + /** + Height of the image. Actual value is set only after image is preloaded. + + @property height + @type {Number} + @default 0 + */ + height: 0, + + /** + Mime type of the image. Currently only image/jpeg and image/png are supported. Actual value is set only after image is preloaded. + + @property type + @type {String} + @default "" + */ + type: "", + + /** + Holds meta info (Exif, GPS). Is populated only for image/jpeg. Actual value is set only after image is preloaded. + + @property meta + @type {Object} + @default {} + */ + meta: {}, + + /** + Alias for load method, that takes another mOxie.Image object as a source (see load). + + @method clone + @param {Image} src Source for the image + @param {Boolean} [exact=false] Whether to activate in-depth clone mode + */ + clone: function() { + this.load.apply(this, arguments); + }, + + /** + Loads image from various sources. Currently the source for new image can be: mOxie.Image, mOxie.Blob/mOxie.File, + native Blob/File, dataUrl or URL. Depending on the type of the source, arguments - differ. When source is URL, + Image will be downloaded from remote destination and loaded in memory. + + @example + var img = new mOxie.Image(); + img.onload = function() { + var blob = img.getAsBlob(); + + var formData = new mOxie.FormData(); + formData.append('file', blob); + + var xhr = new mOxie.XMLHttpRequest(); + xhr.onload = function() { + // upload complete + }; + xhr.open('post', 'upload.php'); + xhr.send(formData); + }; + img.load("http://www.moxiecode.com/images/mox-logo.jpg"); // notice file extension (.jpg) + + + @method load + @param {Image|Blob|File|String} src Source for the image + @param {Boolean|Object} [mixed] + */ + load: function() { + _load.apply(this, arguments); + }, + + + /** + Resizes the image to fit the specified width/height. If crop is specified, image will also be + cropped to the exact dimensions. + + @method resize + @since 3.0 + @param {Object} options + @param {Number} options.width Resulting width + @param {Number} [options.height=width] Resulting height (optional, if not supplied will default to width) + @param {String} [options.type='image/jpeg'] MIME type of the resulting image + @param {Number} [options.quality=90] In the case of JPEG, controls the quality of resulting image + @param {Boolean} [options.crop='cc'] If not falsy, image will be cropped, by default from center + @param {Boolean} [options.fit=true] In case of crop whether to upscale the image to fit the exact dimensions + @param {Boolean} [options.preserveHeaders=true] Whether to preserve meta headers (on JPEGs after resize) + @param {String} [options.resample='default'] Resampling algorithm to use during resize + @param {Boolean} [options.multipass=true] Whether to scale the image in steps (results in better quality) + */ + resize: function(options) { + var self = this; + var orientation; + var scale; + + var srcRect = { + x: 0, + y: 0, + width: self.width, + height: self.height + }; + + var opts = Basic.extendIf({ + width: self.width, + height: self.height, + type: self.type || 'image/jpeg', + quality: 90, + crop: false, + fit: true, + preserveHeaders: true, + resample: 'default', + multipass: true + }, options); + + try { + if (!self.size) { // only preloaded image objects can be used as source + throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); + } + + // no way to reliably intercept the crash due to high resolution, so we simply avoid it + if (self.width > Image.MAX_RESIZE_WIDTH || self.height > Image.MAX_RESIZE_HEIGHT) { + throw new x.ImageError(x.ImageError.MAX_RESOLUTION_ERR); + } + + // take into account orientation tag + orientation = (self.meta && self.meta.tiff && self.meta.tiff.Orientation) || 1; + + if (Basic.inArray(orientation, [5,6,7,8]) !== -1) { // values that require 90 degree rotation + var tmp = opts.width; + opts.width = opts.height; + opts.height = tmp; + } + + if (opts.crop) { + scale = Math.max(opts.width/self.width, opts.height/self.height); + + if (options.fit) { + // first scale it up or down to fit the original image + srcRect.width = Math.min(Math.ceil(opts.width/scale), self.width); + srcRect.height = Math.min(Math.ceil(opts.height/scale), self.height); + + // recalculate the scale for adapted dimensions + scale = opts.width/srcRect.width; + } else { + srcRect.width = Math.min(opts.width, self.width); + srcRect.height = Math.min(opts.height, self.height); + + // now we do not need to scale it any further + scale = 1; + } + + if (typeof(opts.crop) === 'boolean') { + opts.crop = 'cc'; + } + + switch (opts.crop.toLowerCase().replace(/_/, '-')) { + case 'rb': + case 'right-bottom': + srcRect.x = self.width - srcRect.width; + srcRect.y = self.height - srcRect.height; + break; + + case 'cb': + case 'center-bottom': + srcRect.x = Math.floor((self.width - srcRect.width) / 2); + srcRect.y = self.height - srcRect.height; + break; + + case 'lb': + case 'left-bottom': + srcRect.x = 0; + srcRect.y = self.height - srcRect.height; + break; + + case 'lt': + case 'left-top': + srcRect.x = 0; + srcRect.y = 0; + break; + + case 'ct': + case 'center-top': + srcRect.x = Math.floor((self.width - srcRect.width) / 2); + srcRect.y = 0; + break; + + case 'rt': + case 'right-top': + srcRect.x = self.width - srcRect.width; + srcRect.y = 0; + break; + + case 'rc': + case 'right-center': + case 'right-middle': + srcRect.x = self.width - srcRect.width; + srcRect.y = Math.floor((self.height - srcRect.height) / 2); + break; + + + case 'lc': + case 'left-center': + case 'left-middle': + srcRect.x = 0; + srcRect.y = Math.floor((self.height - srcRect.height) / 2); + break; + + case 'cc': + case 'center-center': + case 'center-middle': + default: + srcRect.x = Math.floor((self.width - srcRect.width) / 2); + srcRect.y = Math.floor((self.height - srcRect.height) / 2); + } + + // original image might be smaller than requested crop, so - avoid negative values + srcRect.x = Math.max(srcRect.x, 0); + srcRect.y = Math.max(srcRect.y, 0); + } else { + scale = Math.min(opts.width/self.width, opts.height/self.height); + } + + this.exec('Image', 'resize', srcRect, scale, opts); + } catch(ex) { + // for now simply trigger error event + self.trigger('error', ex.code); + } + }, + + /** + Downsizes the image to fit the specified width/height. If crop is supplied, image will be cropped to exact dimensions. + + @method downsize + @deprecated use resize() + */ + downsize: function(options) { + var defaults = { + width: this.width, + height: this.height, + type: this.type || 'image/jpeg', + quality: 90, + crop: false, + preserveHeaders: true, + resample: 'default' + }, opts; + + if (typeof(options) === 'object') { + opts = Basic.extend(defaults, options); + } else { + // for backward compatibility + opts = Basic.extend(defaults, { + width: arguments[0], + height: arguments[1], + crop: arguments[2], + preserveHeaders: arguments[3] + }); + } + + this.resize(opts); + }, + + /** + Alias for downsize(width, height, true). (see downsize) + + @method crop + @param {Number} width Resulting width + @param {Number} [height=width] Resulting height (optional, if not supplied will default to width) + @param {Boolean} [preserveHeaders=true] Whether to preserve meta headers (on JPEGs after resize) + */ + crop: function(width, height, preserveHeaders) { + this.downsize(width, height, true, preserveHeaders); + }, + + getAsCanvas: function() { + if (!Env.can('create_canvas')) { + throw new x.RuntimeError(x.RuntimeError.NOT_SUPPORTED_ERR); + } + return this.exec('Image', 'getAsCanvas'); + }, + + /** + Retrieves image in it's current state as mOxie.Blob object. Cannot be run on empty or image in progress (throws + DOMException.INVALID_STATE_ERR). + + @method getAsBlob + @param {String} [type="image/jpeg"] Mime type of resulting blob. Can either be image/jpeg or image/png + @param {Number} [quality=90] Applicable only together with mime type image/jpeg + @return {Blob} Image as Blob + */ + getAsBlob: function(type, quality) { + if (!this.size) { + throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); + } + return this.exec('Image', 'getAsBlob', type || 'image/jpeg', quality || 90); + }, + + /** + Retrieves image in it's current state as dataURL string. Cannot be run on empty or image in progress (throws + DOMException.INVALID_STATE_ERR). + + @method getAsDataURL + @param {String} [type="image/jpeg"] Mime type of resulting blob. Can either be image/jpeg or image/png + @param {Number} [quality=90] Applicable only together with mime type image/jpeg + @return {String} Image as dataURL string + */ + getAsDataURL: function(type, quality) { + if (!this.size) { + throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); + } + return this.exec('Image', 'getAsDataURL', type || 'image/jpeg', quality || 90); + }, + + /** + Retrieves image in it's current state as binary string. Cannot be run on empty or image in progress (throws + DOMException.INVALID_STATE_ERR). + + @method getAsBinaryString + @param {String} [type="image/jpeg"] Mime type of resulting blob. Can either be image/jpeg or image/png + @param {Number} [quality=90] Applicable only together with mime type image/jpeg + @return {String} Image as binary string + */ + getAsBinaryString: function(type, quality) { + var dataUrl = this.getAsDataURL(type, quality); + return Encode.atob(dataUrl.substring(dataUrl.indexOf('base64,') + 7)); + }, + + /** + Embeds a visual representation of the image into the specified node. Depending on the runtime, + it might be a canvas, an img node or a thrid party shim object (Flash or SilverLight - very rare, + can be used in legacy browsers that do not have canvas or proper dataURI support). + + @method embed + @param {DOMElement} el DOM element to insert the image object into + @param {Object} [options] + @param {Number} [options.width] The width of an embed (defaults to the image width) + @param {Number} [options.height] The height of an embed (defaults to the image height) + @param {String} [options.type="image/jpeg"] Mime type + @param {Number} [options.quality=90] Quality of an embed, if mime type is image/jpeg + @param {Boolean} [options.crop=false] Whether to crop an embed to the specified dimensions + */ + embed: function(el, options) { + var self = this + , runtime // this has to be outside of all the closures to contain proper runtime + ; + + var opts = Basic.extend({ + width: this.width, + height: this.height, + type: this.type || 'image/jpeg', + quality: 90 + }, options); + + + function render(type, quality) { + var img = this; + + // if possible, embed a canvas element directly + if (Env.can('create_canvas')) { + var canvas = img.getAsCanvas(); + if (canvas) { + el.appendChild(canvas); + canvas = null; + img.destroy(); + self.trigger('embedded'); + return; + } + } + + var dataUrl = img.getAsDataURL(type, quality); + if (!dataUrl) { + throw new x.ImageError(x.ImageError.WRONG_FORMAT); + } + + if (Env.can('use_data_uri_of', dataUrl.length)) { + el.innerHTML = ''; + img.destroy(); + self.trigger('embedded'); + } else { + var tr = new Transporter(); + + tr.bind("TransportingComplete", function() { + runtime = self.connectRuntime(this.result.ruid); + + self.bind("Embedded", function() { + // position and size properly + Basic.extend(runtime.getShimContainer().style, { + //position: 'relative', + top: '0px', + left: '0px', + width: img.width + 'px', + height: img.height + 'px' + }); + + // some shims (Flash/SilverLight) reinitialize, if parent element is hidden, reordered or it's + // position type changes (in Gecko), but since we basically need this only in IEs 6/7 and + // sometimes 8 and they do not have this problem, we can comment this for now + /*tr.bind("RuntimeInit", function(e, runtime) { + tr.destroy(); + runtime.destroy(); + onResize.call(self); // re-feed our image data + });*/ + + runtime = null; // release + }, 999); + + runtime.exec.call(self, "ImageView", "display", this.result.uid, width, height); + img.destroy(); + }); + + tr.transport(Encode.atob(dataUrl.substring(dataUrl.indexOf('base64,') + 7)), type, { + required_caps: { + display_media: true + }, + runtime_order: 'flash,silverlight', + container: el + }); + } + } + + try { + if (!(el = Dom.get(el))) { + throw new x.DOMException(x.DOMException.INVALID_NODE_TYPE_ERR); + } + + if (!this.size) { // only preloaded image objects can be used as source + throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); + } + + // high-resolution images cannot be consistently handled across the runtimes + if (this.width > Image.MAX_RESIZE_WIDTH || this.height > Image.MAX_RESIZE_HEIGHT) { + //throw new x.ImageError(x.ImageError.MAX_RESOLUTION_ERR); + } + + var imgCopy = new Image(); + + imgCopy.bind("Resize", function() { + render.call(this, opts.type, opts.quality); + }); + + imgCopy.bind("Load", function() { + this.downsize(opts); + }); + + // if embedded thumb data is available and dimensions are big enough, use it + if (this.meta.thumb && this.meta.thumb.width >= opts.width && this.meta.thumb.height >= opts.height) { + imgCopy.load(this.meta.thumb.data); + } else { + imgCopy.clone(this, false); + } + + return imgCopy; + } catch(ex) { + // for now simply trigger error event + this.trigger('error', ex.code); + } + }, + + /** + Properly destroys the image and frees resources in use. If any. Recommended way to dispose mOxie.Image object. + + @method destroy + */ + destroy: function() { + if (this.ruid) { + this.getRuntime().exec.call(this, 'Image', 'destroy'); + this.disconnectRuntime(); + } + if (this.meta && this.meta.thumb) { + // thumb is blob, make sure we destroy it first + this.meta.thumb.data.destroy(); + } + this.unbindAll(); + } + }); + + + // this is here, because in order to bind properly, we need uid, which is created above + this.handleEventProps(dispatches); + + this.bind('Load Resize', function() { + return _updateInfo.call(this); // if operation fails (e.g. image is neither PNG nor JPEG) cancel all pending events + }, 999); + + + function _updateInfo(info) { + try { + if (!info) { + info = this.exec('Image', 'getInfo'); + } + + this.size = info.size; + this.width = info.width; + this.height = info.height; + this.type = info.type; + this.meta = info.meta; + + // update file name, only if empty + if (this.name === '') { + this.name = info.name; + } + + return true; + } catch(ex) { + this.trigger('error', ex.code); + return false; + } + } + + + function _load(src) { + var srcType = Basic.typeOf(src); + + try { + // if source is Image + if (src instanceof Image) { + if (!src.size) { // only preloaded image objects can be used as source + throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); + } + _loadFromImage.apply(this, arguments); + } + // if source is o.Blob/o.File + else if (src instanceof Blob) { + if (!~Basic.inArray(src.type, ['image/jpeg', 'image/png'])) { + throw new x.ImageError(x.ImageError.WRONG_FORMAT); + } + _loadFromBlob.apply(this, arguments); + } + // if native blob/file + else if (Basic.inArray(srcType, ['blob', 'file']) !== -1) { + _load.call(this, new File(null, src), arguments[1]); + } + // if String + else if (srcType === 'string') { + // if dataUrl String + if (src.substr(0, 5) === 'data:') { + _load.call(this, new Blob(null, { data: src }), arguments[1]); + } + // else assume Url, either relative or absolute + else { + _loadFromUrl.apply(this, arguments); + } + } + // if source seems to be an img node + else if (srcType === 'node' && src.nodeName.toLowerCase() === 'img') { + _load.call(this, src.src, arguments[1]); + } + else { + throw new x.DOMException(x.DOMException.TYPE_MISMATCH_ERR); + } + } catch(ex) { + // for now simply trigger error event + this.trigger('error', ex.code); + } + } + + + function _loadFromImage(img, exact) { + var runtime = this.connectRuntime(img.ruid); + this.ruid = runtime.uid; + runtime.exec.call(this, 'Image', 'loadFromImage', img, (Basic.typeOf(exact) === 'undefined' ? true : exact)); + } + + + function _loadFromBlob(blob, options) { + var self = this; + + self.name = blob.name || ''; + + function exec(runtime) { + self.ruid = runtime.uid; + runtime.exec.call(self, 'Image', 'loadFromBlob', blob); + } + + if (blob.isDetached()) { + this.bind('RuntimeInit', function(e, runtime) { + exec(runtime); + }); + + // convert to object representation + if (options && typeof(options.required_caps) === 'string') { + options.required_caps = Runtime.parseCaps(options.required_caps); + } + + this.connectRuntime(Basic.extend({ + required_caps: { + access_image_binary: true, + resize_image: true + } + }, options)); + } else { + exec(this.connectRuntime(blob.ruid)); + } + } + + + function _loadFromUrl(url, options) { + var self = this, xhr; + + xhr = new XMLHttpRequest(); + + xhr.open('get', url); + xhr.responseType = 'blob'; + + xhr.onprogress = function(e) { + self.trigger(e); + }; + + xhr.onload = function() { + _loadFromBlob.call(self, xhr.response, true); + }; + + xhr.onerror = function(e) { + self.trigger(e); + }; + + xhr.onloadend = function() { + xhr.destroy(); + }; + + xhr.bind('RuntimeError', function(e, err) { + self.trigger('RuntimeError', err); + }); + + xhr.send(null, options); + } + } + + // virtual world will crash on you if image has a resolution higher than this: + Image.MAX_RESIZE_WIDTH = 8192; + Image.MAX_RESIZE_HEIGHT = 8192; + + Image.prototype = EventTarget.instance; + + return Image; +}); + +// Included from: src/javascript/runtime/html5/Runtime.js + +/** + * Runtime.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/*global File:true */ + +/** +Defines constructor for HTML5 runtime. + +@class moxie/runtime/html5/Runtime +@private +*/ +define("moxie/runtime/html5/Runtime", [ + "moxie/core/utils/Basic", + "moxie/core/Exceptions", + "moxie/runtime/Runtime", + "moxie/core/utils/Env" +], function(Basic, x, Runtime, Env) { + + var type = "html5", extensions = {}; + + function Html5Runtime(options) { + var I = this + , Test = Runtime.capTest + , True = Runtime.capTrue + ; + + var caps = Basic.extend({ + access_binary: Test(window.FileReader || window.File && window.File.getAsDataURL), + access_image_binary: function() { + return I.can('access_binary') && !!extensions.Image; + }, + display_media: Test( + (Env.can('create_canvas') || Env.can('use_data_uri_over32kb')) && + defined('moxie/image/Image') + ), + do_cors: Test(window.XMLHttpRequest && 'withCredentials' in new XMLHttpRequest()), + drag_and_drop: Test(function() { + // this comes directly from Modernizr: http://www.modernizr.com/ + var div = document.createElement('div'); + // IE has support for drag and drop since version 5, but doesn't support dropping files from desktop + return (('draggable' in div) || ('ondragstart' in div && 'ondrop' in div)) && + (Env.browser !== 'IE' || Env.verComp(Env.version, 9, '>')); + }()), + filter_by_extension: Test(function() { // if you know how to feature-detect this, please suggest + return !( + (Env.browser === 'Chrome' && Env.verComp(Env.version, 28, '<')) || + (Env.browser === 'IE' && Env.verComp(Env.version, 10, '<')) || + (Env.browser === 'Safari' && Env.verComp(Env.version, 7, '<')) || + (Env.browser === 'Firefox' && Env.verComp(Env.version, 37, '<')) + ); + }()), + return_response_headers: True, + return_response_type: function(responseType) { + if (responseType === 'json' && !!window.JSON) { // we can fake this one even if it's not supported + return true; + } + return Env.can('return_response_type', responseType); + }, + return_status_code: True, + report_upload_progress: Test(window.XMLHttpRequest && new XMLHttpRequest().upload), + resize_image: function() { + return I.can('access_binary') && Env.can('create_canvas'); + }, + select_file: function() { + return Env.can('use_fileinput') && window.File; + }, + select_folder: function() { + return I.can('select_file') && ( + Env.browser === 'Chrome' && Env.verComp(Env.version, 21, '>=') || + Env.browser === 'Firefox' && Env.verComp(Env.version, 42, '>=') // https://developer.mozilla.org/en-US/Firefox/Releases/42 + ); + }, + select_multiple: function() { + // it is buggy on Safari Windows and iOS + return I.can('select_file') && + !(Env.browser === 'Safari' && Env.os === 'Windows') && + !(Env.os === 'iOS' && Env.verComp(Env.osVersion, "7.0.0", '>') && Env.verComp(Env.osVersion, "8.0.0", '<')); + }, + send_binary_string: Test(window.XMLHttpRequest && (new XMLHttpRequest().sendAsBinary || (window.Uint8Array && window.ArrayBuffer))), + send_custom_headers: Test(window.XMLHttpRequest), + send_multipart: function() { + return !!(window.XMLHttpRequest && new XMLHttpRequest().upload && window.FormData) || I.can('send_binary_string'); + }, + slice_blob: Test(window.File && (File.prototype.mozSlice || File.prototype.webkitSlice || File.prototype.slice)), + stream_upload: function(){ + return I.can('slice_blob') && I.can('send_multipart'); + }, + summon_file_dialog: function() { // yeah... some dirty sniffing here... + return I.can('select_file') && ( + (Env.browser === 'Firefox' && Env.verComp(Env.version, 4, '>=')) || + (Env.browser === 'Opera' && Env.verComp(Env.version, 12, '>=')) || + (Env.browser === 'IE' && Env.verComp(Env.version, 10, '>=')) || + !!~Basic.inArray(Env.browser, ['Chrome', 'Safari', 'Edge']) + ); + }, + upload_filesize: True, + use_http_method: True + }, + arguments[2] + ); + + Runtime.call(this, options, (arguments[1] || type), caps); + + + Basic.extend(this, { + + init : function() { + this.trigger("Init"); + }, + + destroy: (function(destroy) { // extend default destroy method + return function() { + destroy.call(I); + destroy = I = null; + }; + }(this.destroy)) + }); + + Basic.extend(this.getShim(), extensions); + } + + Runtime.addConstructor(type, Html5Runtime); + + return extensions; +}); + +// Included from: src/javascript/runtime/html5/file/Blob.js + +/** + * Blob.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/html5/file/Blob +@private +*/ +define("moxie/runtime/html5/file/Blob", [ + "moxie/runtime/html5/Runtime", + "moxie/file/Blob" +], function(extensions, Blob) { + + function HTML5Blob() { + function w3cBlobSlice(blob, start, end) { + var blobSlice; + + if (window.File.prototype.slice) { + try { + blob.slice(); // depricated version will throw WRONG_ARGUMENTS_ERR exception + return blob.slice(start, end); + } catch (e) { + // depricated slice method + return blob.slice(start, end - start); + } + // slice method got prefixed: https://bugzilla.mozilla.org/show_bug.cgi?id=649672 + } else if ((blobSlice = window.File.prototype.webkitSlice || window.File.prototype.mozSlice)) { + return blobSlice.call(blob, start, end); + } else { + return null; // or throw some exception + } + } + + this.slice = function() { + return new Blob(this.getRuntime().uid, w3cBlobSlice.apply(this, arguments)); + }; + } + + return (extensions.Blob = HTML5Blob); +}); + +// Included from: src/javascript/core/utils/Events.js + +/** + * Events.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +define('moxie/core/utils/Events', [ + 'moxie/core/utils/Basic' +], function(Basic) { + var eventhash = {}, uid = 'moxie_' + Basic.guid(); + + // IE W3C like event funcs + function preventDefault() { + this.returnValue = false; + } + + function stopPropagation() { + this.cancelBubble = true; + } + + /** + Adds an event handler to the specified object and store reference to the handler + in objects internal Plupload registry (@see removeEvent). + + @method addEvent + @for Utils + @static + @param {Object} obj DOM element like object to add handler to. + @param {String} name Name to add event listener to. + @param {Function} callback Function to call when event occurs. + @param {String} [key] that might be used to add specifity to the event record. + */ + var addEvent = function(obj, name, callback, key) { + var func, events; + + name = name.toLowerCase(); + + // Add event listener + if (obj.addEventListener) { + func = callback; + + obj.addEventListener(name, func, false); + } else if (obj.attachEvent) { + func = function() { + var evt = window.event; + + if (!evt.target) { + evt.target = evt.srcElement; + } + + evt.preventDefault = preventDefault; + evt.stopPropagation = stopPropagation; + + callback(evt); + }; + + obj.attachEvent('on' + name, func); + } + + // Log event handler to objects internal mOxie registry + if (!obj[uid]) { + obj[uid] = Basic.guid(); + } + + if (!eventhash.hasOwnProperty(obj[uid])) { + eventhash[obj[uid]] = {}; + } + + events = eventhash[obj[uid]]; + + if (!events.hasOwnProperty(name)) { + events[name] = []; + } + + events[name].push({ + func: func, + orig: callback, // store original callback for IE + key: key + }); + }; + + + /** + Remove event handler from the specified object. If third argument (callback) + is not specified remove all events with the specified name. + + @method removeEvent + @static + @param {Object} obj DOM element to remove event listener(s) from. + @param {String} name Name of event listener to remove. + @param {Function|String} [callback] might be a callback or unique key to match. + */ + var removeEvent = function(obj, name, callback) { + var type, undef; + + name = name.toLowerCase(); + + if (obj[uid] && eventhash[obj[uid]] && eventhash[obj[uid]][name]) { + type = eventhash[obj[uid]][name]; + } else { + return; + } + + for (var i = type.length - 1; i >= 0; i--) { + // undefined or not, key should match + if (type[i].orig === callback || type[i].key === callback) { + if (obj.removeEventListener) { + obj.removeEventListener(name, type[i].func, false); + } else if (obj.detachEvent) { + obj.detachEvent('on'+name, type[i].func); + } + + type[i].orig = null; + type[i].func = null; + type.splice(i, 1); + + // If callback was passed we are done here, otherwise proceed + if (callback !== undef) { + break; + } + } + } + + // If event array got empty, remove it + if (!type.length) { + delete eventhash[obj[uid]][name]; + } + + // If mOxie registry has become empty, remove it + if (Basic.isEmptyObj(eventhash[obj[uid]])) { + delete eventhash[obj[uid]]; + + // IE doesn't let you remove DOM object property with - delete + try { + delete obj[uid]; + } catch(e) { + obj[uid] = undef; + } + } + }; + + + /** + Remove all kind of events from the specified object + + @method removeAllEvents + @static + @param {Object} obj DOM element to remove event listeners from. + @param {String} [key] unique key to match, when removing events. + */ + var removeAllEvents = function(obj, key) { + if (!obj || !obj[uid]) { + return; + } + + Basic.each(eventhash[obj[uid]], function(events, name) { + removeEvent(obj, name, key); + }); + }; + + return { + addEvent: addEvent, + removeEvent: removeEvent, + removeAllEvents: removeAllEvents + }; +}); + +// Included from: src/javascript/runtime/html5/file/FileInput.js + +/** + * FileInput.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/html5/file/FileInput +@private +*/ +define("moxie/runtime/html5/file/FileInput", [ + "moxie/runtime/html5/Runtime", + "moxie/file/File", + "moxie/core/utils/Basic", + "moxie/core/utils/Dom", + "moxie/core/utils/Events", + "moxie/core/utils/Mime", + "moxie/core/utils/Env" +], function(extensions, File, Basic, Dom, Events, Mime, Env) { + + function FileInput() { + var _options, _browseBtnZIndex; // save original z-index + + Basic.extend(this, { + init: function(options) { + var comp = this, I = comp.getRuntime(), input, shimContainer, mimes, browseButton, zIndex, top; + + _options = options; + + // figure out accept string + mimes = _options.accept.mimes || Mime.extList2mimes(_options.accept, I.can('filter_by_extension')); + + shimContainer = I.getShimContainer(); + + shimContainer.innerHTML = ''; + + input = Dom.get(I.uid); + + // prepare file input to be placed underneath the browse_button element + Basic.extend(input.style, { + position: 'absolute', + top: 0, + left: 0, + width: '100%', + height: '100%' + }); + + + browseButton = Dom.get(_options.browse_button); + _browseBtnZIndex = Dom.getStyle(browseButton, 'z-index') || 'auto'; + + // Route click event to the input[type=file] element for browsers that support such behavior + if (I.can('summon_file_dialog')) { + if (Dom.getStyle(browseButton, 'position') === 'static') { + browseButton.style.position = 'relative'; + } + + Events.addEvent(browseButton, 'click', function(e) { + var input = Dom.get(I.uid); + if (input && !input.disabled) { // for some reason FF (up to 8.0.1 so far) lets to click disabled input[type=file] + input.click(); + } + e.preventDefault(); + }, comp.uid); + + comp.bind('Refresh', function() { + zIndex = parseInt(_browseBtnZIndex, 10) || 1; + + Dom.get(_options.browse_button).style.zIndex = zIndex; + this.getRuntime().getShimContainer().style.zIndex = zIndex - 1; + }); + } + + /* Since we have to place input[type=file] on top of the browse_button for some browsers, + browse_button loses interactivity, so we restore it here */ + top = I.can('summon_file_dialog') ? browseButton : shimContainer; + + Events.addEvent(top, 'mouseover', function() { + comp.trigger('mouseenter'); + }, comp.uid); + + Events.addEvent(top, 'mouseout', function() { + comp.trigger('mouseleave'); + }, comp.uid); + + Events.addEvent(top, 'mousedown', function() { + comp.trigger('mousedown'); + }, comp.uid); + + Events.addEvent(Dom.get(_options.container), 'mouseup', function() { + comp.trigger('mouseup'); + }, comp.uid); + + + input.onchange = function onChange(e) { // there should be only one handler for this + comp.files = []; + + Basic.each(this.files, function(file) { + var relativePath = ''; + + if (_options.directory) { + // folders are represented by dots, filter them out (Chrome 11+) + if (file.name == ".") { + // if it looks like a folder... + return true; + } + } + + if (file.webkitRelativePath) { + relativePath = '/' + file.webkitRelativePath.replace(/^\//, ''); + } + + file = new File(I.uid, file); + file.relativePath = relativePath; + + comp.files.push(file); + }); + + // clearing the value enables the user to select the same file again if they want to + if (Env.browser !== 'IE' && Env.browser !== 'IEMobile') { + this.value = ''; + } else { + // in IE input[type="file"] is read-only so the only way to reset it is to re-insert it + var clone = this.cloneNode(true); + this.parentNode.replaceChild(clone, this); + clone.onchange = onChange; + } + + if (comp.files.length) { + comp.trigger('change'); + } + }; + + // ready event is perfectly asynchronous + comp.trigger({ + type: 'ready', + async: true + }); + + shimContainer = null; + }, + + + setOption: function(name, value) { + var I = this.getRuntime(); + var input = Dom.get(I.uid); + + switch (name) { + case 'accept': + if (value) { + var mimes = value.mimes || Mime.extList2mimes(value, I.can('filter_by_extension')); + input.setAttribute('accept', mimes.join(',')); + } else { + input.removeAttribute('accept'); + } + break; + + case 'directory': + if (value && I.can('select_folder')) { + input.setAttribute('directory', ''); + input.setAttribute('webkitdirectory', ''); + } else { + input.removeAttribute('directory'); + input.removeAttribute('webkitdirectory'); + } + break; + + case 'multiple': + if (value && I.can('select_multiple')) { + input.setAttribute('multiple', ''); + } else { + input.removeAttribute('multiple'); + } + + } + }, + + + disable: function(state) { + var I = this.getRuntime(), input; + + if ((input = Dom.get(I.uid))) { + input.disabled = !!state; + } + }, + + destroy: function() { + var I = this.getRuntime() + , shim = I.getShim() + , shimContainer = I.getShimContainer() + , container = _options && Dom.get(_options.container) + , browseButton = _options && Dom.get(_options.browse_button) + ; + + if (container) { + Events.removeAllEvents(container, this.uid); + } + + if (browseButton) { + Events.removeAllEvents(browseButton, this.uid); + browseButton.style.zIndex = _browseBtnZIndex; // reset to original value + } + + if (shimContainer) { + Events.removeAllEvents(shimContainer, this.uid); + shimContainer.innerHTML = ''; + } + + shim.removeInstance(this.uid); + + _options = shimContainer = container = browseButton = shim = null; + } + }); + } + + return (extensions.FileInput = FileInput); +}); + +// Included from: src/javascript/runtime/html5/file/FileDrop.js + +/** + * FileDrop.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/html5/file/FileDrop +@private +*/ +define("moxie/runtime/html5/file/FileDrop", [ + "moxie/runtime/html5/Runtime", + 'moxie/file/File', + "moxie/core/utils/Basic", + "moxie/core/utils/Dom", + "moxie/core/utils/Events", + "moxie/core/utils/Mime" +], function(extensions, File, Basic, Dom, Events, Mime) { + + function FileDrop() { + var _files = [], _allowedExts = [], _options, _ruid; + + Basic.extend(this, { + init: function(options) { + var comp = this, dropZone; + + _options = options; + _ruid = comp.ruid; // every dropped-in file should have a reference to the runtime + _allowedExts = _extractExts(_options.accept); + dropZone = _options.container; + + Events.addEvent(dropZone, 'dragover', function(e) { + if (!_hasFiles(e)) { + return; + } + e.preventDefault(); + e.dataTransfer.dropEffect = 'copy'; + }, comp.uid); + + Events.addEvent(dropZone, 'drop', function(e) { + if (!_hasFiles(e)) { + return; + } + e.preventDefault(); + + _files = []; + + // Chrome 21+ accepts folders via Drag'n'Drop + if (e.dataTransfer.items && e.dataTransfer.items[0].webkitGetAsEntry) { + _readItems(e.dataTransfer.items, function() { + comp.files = _files; + comp.trigger("drop"); + }); + } else { + Basic.each(e.dataTransfer.files, function(file) { + _addFile(file); + }); + comp.files = _files; + comp.trigger("drop"); + } + }, comp.uid); + + Events.addEvent(dropZone, 'dragenter', function(e) { + comp.trigger("dragenter"); + }, comp.uid); + + Events.addEvent(dropZone, 'dragleave', function(e) { + comp.trigger("dragleave"); + }, comp.uid); + }, + + destroy: function() { + Events.removeAllEvents(_options && Dom.get(_options.container), this.uid); + _ruid = _files = _allowedExts = _options = null; + } + }); + + + function _hasFiles(e) { + if (!e.dataTransfer || !e.dataTransfer.types) { // e.dataTransfer.files is not available in Gecko during dragover + return false; + } + + var types = Basic.toArray(e.dataTransfer.types || []); + + return Basic.inArray("Files", types) !== -1 || + Basic.inArray("public.file-url", types) !== -1 || // Safari < 5 + Basic.inArray("application/x-moz-file", types) !== -1 // Gecko < 1.9.2 (< Firefox 3.6) + ; + } + + + function _addFile(file, relativePath) { + if (_isAcceptable(file)) { + var fileObj = new File(_ruid, file); + fileObj.relativePath = relativePath || ''; + _files.push(fileObj); + } + } + + + function _extractExts(accept) { + var exts = []; + for (var i = 0; i < accept.length; i++) { + [].push.apply(exts, accept[i].extensions.split(/\s*,\s*/)); + } + return Basic.inArray('*', exts) === -1 ? exts : []; + } + + + function _isAcceptable(file) { + if (!_allowedExts.length) { + return true; + } + var ext = Mime.getFileExtension(file.name); + return !ext || Basic.inArray(ext, _allowedExts) !== -1; + } + + + function _readItems(items, cb) { + var entries = []; + Basic.each(items, function(item) { + var entry = item.webkitGetAsEntry(); + // Address #998 (https://code.google.com/p/chromium/issues/detail?id=332579) + if (entry) { + // file() fails on OSX when the filename contains a special character (e.g. umlaut): see #61 + if (entry.isFile) { + _addFile(item.getAsFile(), entry.fullPath); + } else { + entries.push(entry); + } + } + }); + + if (entries.length) { + _readEntries(entries, cb); + } else { + cb(); + } + } + + + function _readEntries(entries, cb) { + var queue = []; + Basic.each(entries, function(entry) { + queue.push(function(cbcb) { + _readEntry(entry, cbcb); + }); + }); + Basic.inSeries(queue, function() { + cb(); + }); + } + + + function _readEntry(entry, cb) { + if (entry.isFile) { + entry.file(function(file) { + _addFile(file, entry.fullPath); + cb(); + }, function() { + // fire an error event maybe + cb(); + }); + } else if (entry.isDirectory) { + _readDirEntry(entry, cb); + } else { + cb(); // not file, not directory? what then?.. + } + } + + + function _readDirEntry(dirEntry, cb) { + var entries = [], dirReader = dirEntry.createReader(); + + // keep quering recursively till no more entries + function getEntries(cbcb) { + dirReader.readEntries(function(moreEntries) { + if (moreEntries.length) { + [].push.apply(entries, moreEntries); + getEntries(cbcb); + } else { + cbcb(); + } + }, cbcb); + } + + // ...and you thought FileReader was crazy... + getEntries(function() { + _readEntries(entries, cb); + }); + } + } + + return (extensions.FileDrop = FileDrop); +}); + +// Included from: src/javascript/runtime/html5/file/FileReader.js + +/** + * FileReader.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/html5/file/FileReader +@private +*/ +define("moxie/runtime/html5/file/FileReader", [ + "moxie/runtime/html5/Runtime", + "moxie/core/utils/Encode", + "moxie/core/utils/Basic" +], function(extensions, Encode, Basic) { + + function FileReader() { + var _fr, _convertToBinary = false; + + Basic.extend(this, { + + read: function(op, blob) { + var comp = this; + + comp.result = ''; + + _fr = new window.FileReader(); + + _fr.addEventListener('progress', function(e) { + comp.trigger(e); + }); + + _fr.addEventListener('load', function(e) { + comp.result = _convertToBinary ? _toBinary(_fr.result) : _fr.result; + comp.trigger(e); + }); + + _fr.addEventListener('error', function(e) { + comp.trigger(e, _fr.error); + }); + + _fr.addEventListener('loadend', function(e) { + _fr = null; + comp.trigger(e); + }); + + if (Basic.typeOf(_fr[op]) === 'function') { + _convertToBinary = false; + _fr[op](blob.getSource()); + } else if (op === 'readAsBinaryString') { // readAsBinaryString is depricated in general and never existed in IE10+ + _convertToBinary = true; + _fr.readAsDataURL(blob.getSource()); + } + }, + + abort: function() { + if (_fr) { + _fr.abort(); + } + }, + + destroy: function() { + _fr = null; + } + }); + + function _toBinary(str) { + return Encode.atob(str.substring(str.indexOf('base64,') + 7)); + } + } + + return (extensions.FileReader = FileReader); +}); + +// Included from: src/javascript/runtime/html5/xhr/XMLHttpRequest.js + +/** + * XMLHttpRequest.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/*global ActiveXObject:true */ + +/** +@class moxie/runtime/html5/xhr/XMLHttpRequest +@private +*/ +define("moxie/runtime/html5/xhr/XMLHttpRequest", [ + "moxie/runtime/html5/Runtime", + "moxie/core/utils/Basic", + "moxie/core/utils/Mime", + "moxie/core/utils/Url", + "moxie/file/File", + "moxie/file/Blob", + "moxie/xhr/FormData", + "moxie/core/Exceptions", + "moxie/core/utils/Env" +], function(extensions, Basic, Mime, Url, File, Blob, FormData, x, Env) { + + function XMLHttpRequest() { + var self = this + , _xhr + , _filename + ; + + Basic.extend(this, { + send: function(meta, data) { + var target = this + , isGecko2_5_6 = (Env.browser === 'Mozilla' && Env.verComp(Env.version, 4, '>=') && Env.verComp(Env.version, 7, '<')) + , isAndroidBrowser = Env.browser === 'Android Browser' + , mustSendAsBinary = false + ; + + // extract file name + _filename = meta.url.replace(/^.+?\/([\w\-\.]+)$/, '$1').toLowerCase(); + + _xhr = _getNativeXHR(); + _xhr.open(meta.method, meta.url, meta.async, meta.user, meta.password); + + + // prepare data to be sent + if (data instanceof Blob) { + if (data.isDetached()) { + mustSendAsBinary = true; + } + data = data.getSource(); + } else if (data instanceof FormData) { + + if (data.hasBlob()) { + if (data.getBlob().isDetached()) { + data = _prepareMultipart.call(target, data); // _xhr must be instantiated and be in OPENED state + mustSendAsBinary = true; + } else if ((isGecko2_5_6 || isAndroidBrowser) && Basic.typeOf(data.getBlob().getSource()) === 'blob' && window.FileReader) { + // Gecko 2/5/6 can't send blob in FormData: https://bugzilla.mozilla.org/show_bug.cgi?id=649150 + // Android browsers (default one and Dolphin) seem to have the same issue, see: #613 + _preloadAndSend.call(target, meta, data); + return; // _preloadAndSend will reinvoke send() with transmutated FormData =%D + } + } + + // transfer fields to real FormData + if (data instanceof FormData) { // if still a FormData, e.g. not mangled by _prepareMultipart() + var fd = new window.FormData(); + data.each(function(value, name) { + if (value instanceof Blob) { + fd.append(name, value.getSource()); + } else { + fd.append(name, value); + } + }); + data = fd; + } + } + + + // if XHR L2 + if (_xhr.upload) { + if (meta.withCredentials) { + _xhr.withCredentials = true; + } + + _xhr.addEventListener('load', function(e) { + target.trigger(e); + }); + + _xhr.addEventListener('error', function(e) { + target.trigger(e); + }); + + // additionally listen to progress events + _xhr.addEventListener('progress', function(e) { + target.trigger(e); + }); + + _xhr.upload.addEventListener('progress', function(e) { + target.trigger({ + type: 'UploadProgress', + loaded: e.loaded, + total: e.total + }); + }); + // ... otherwise simulate XHR L2 + } else { + _xhr.onreadystatechange = function onReadyStateChange() { + + // fake Level 2 events + switch (_xhr.readyState) { + + case 1: // XMLHttpRequest.OPENED + // readystatechanged is fired twice for OPENED state (in IE and Mozilla) - neu + break; + + // looks like HEADERS_RECEIVED (state 2) is not reported in Opera (or it's old versions) - neu + case 2: // XMLHttpRequest.HEADERS_RECEIVED + break; + + case 3: // XMLHttpRequest.LOADING + // try to fire progress event for not XHR L2 + var total, loaded; + + try { + if (Url.hasSameOrigin(meta.url)) { // Content-Length not accessible for cross-domain on some browsers + total = _xhr.getResponseHeader('Content-Length') || 0; // old Safari throws an exception here + } + + if (_xhr.responseText) { // responseText was introduced in IE7 + loaded = _xhr.responseText.length; + } + } catch(ex) { + total = loaded = 0; + } + + target.trigger({ + type: 'progress', + lengthComputable: !!total, + total: parseInt(total, 10), + loaded: loaded + }); + break; + + case 4: // XMLHttpRequest.DONE + // release readystatechange handler (mostly for IE) + _xhr.onreadystatechange = function() {}; + + // usually status 0 is returned when server is unreachable, but FF also fails to status 0 for 408 timeout + if (_xhr.status === 0) { + target.trigger('error'); + } else { + target.trigger('load'); + } + break; + } + }; + } + + + // set request headers + if (!Basic.isEmptyObj(meta.headers)) { + Basic.each(meta.headers, function(value, header) { + _xhr.setRequestHeader(header, value); + }); + } + + // request response type + if ("" !== meta.responseType && 'responseType' in _xhr) { + if ('json' === meta.responseType && !Env.can('return_response_type', 'json')) { // we can fake this one + _xhr.responseType = 'text'; + } else { + _xhr.responseType = meta.responseType; + } + } + + // send ... + if (!mustSendAsBinary) { + _xhr.send(data); + } else { + if (_xhr.sendAsBinary) { // Gecko + _xhr.sendAsBinary(data); + } else { // other browsers having support for typed arrays + (function() { + // mimic Gecko's sendAsBinary + var ui8a = new Uint8Array(data.length); + for (var i = 0; i < data.length; i++) { + ui8a[i] = (data.charCodeAt(i) & 0xff); + } + _xhr.send(ui8a.buffer); + }()); + } + } + + target.trigger('loadstart'); + }, + + getStatus: function() { + // according to W3C spec it should return 0 for readyState < 3, but instead it throws an exception + try { + if (_xhr) { + return _xhr.status; + } + } catch(ex) {} + return 0; + }, + + getResponse: function(responseType) { + var I = this.getRuntime(); + + try { + switch (responseType) { + case 'blob': + var file = new File(I.uid, _xhr.response); + + // try to extract file name from content-disposition if possible (might be - not, if CORS for example) + var disposition = _xhr.getResponseHeader('Content-Disposition'); + if (disposition) { + // extract filename from response header if available + var match = disposition.match(/filename=([\'\"'])([^\1]+)\1/); + if (match) { + _filename = match[2]; + } + } + file.name = _filename; + + // pre-webkit Opera doesn't set type property on the blob response + if (!file.type) { + file.type = Mime.getFileMime(_filename); + } + return file; + + case 'json': + if (!Env.can('return_response_type', 'json')) { + return _xhr.status === 200 && !!window.JSON ? JSON.parse(_xhr.responseText) : null; + } + return _xhr.response; + + case 'document': + return _getDocument(_xhr); + + default: + return _xhr.responseText !== '' ? _xhr.responseText : null; // against the specs, but for consistency across the runtimes + } + } catch(ex) { + return null; + } + }, + + getAllResponseHeaders: function() { + try { + return _xhr.getAllResponseHeaders(); + } catch(ex) {} + return ''; + }, + + abort: function() { + if (_xhr) { + _xhr.abort(); + } + }, + + destroy: function() { + self = _filename = null; + } + }); + + + // here we go... ugly fix for ugly bug + function _preloadAndSend(meta, data) { + var target = this, blob, fr; + + // get original blob + blob = data.getBlob().getSource(); + + // preload blob in memory to be sent as binary string + fr = new window.FileReader(); + fr.onload = function() { + // overwrite original blob + data.append(data.getBlobName(), new Blob(null, { + type: blob.type, + data: fr.result + })); + // invoke send operation again + self.send.call(target, meta, data); + }; + fr.readAsBinaryString(blob); + } + + + function _getNativeXHR() { + if (window.XMLHttpRequest && !(Env.browser === 'IE' && Env.verComp(Env.version, 8, '<'))) { // IE7 has native XHR but it's buggy + return new window.XMLHttpRequest(); + } else { + return (function() { + var progIDs = ['Msxml2.XMLHTTP.6.0', 'Microsoft.XMLHTTP']; // if 6.0 available, use it, otherwise failback to default 3.0 + for (var i = 0; i < progIDs.length; i++) { + try { + return new ActiveXObject(progIDs[i]); + } catch (ex) {} + } + })(); + } + } + + // @credits Sergey Ilinsky (http://www.ilinsky.com/) + function _getDocument(xhr) { + var rXML = xhr.responseXML; + var rText = xhr.responseText; + + // Try parsing responseText (@see: http://www.ilinsky.com/articles/XMLHttpRequest/#bugs-ie-responseXML-content-type) + if (Env.browser === 'IE' && rText && rXML && !rXML.documentElement && /[^\/]+\/[^\+]+\+xml/.test(xhr.getResponseHeader("Content-Type"))) { + rXML = new window.ActiveXObject("Microsoft.XMLDOM"); + rXML.async = false; + rXML.validateOnParse = false; + rXML.loadXML(rText); + } + + // Check if there is no error in document + if (rXML) { + if ((Env.browser === 'IE' && rXML.parseError !== 0) || !rXML.documentElement || rXML.documentElement.tagName === "parsererror") { + return null; + } + } + return rXML; + } + + + function _prepareMultipart(fd) { + var boundary = '----moxieboundary' + new Date().getTime() + , dashdash = '--' + , crlf = '\r\n' + , multipart = '' + , I = this.getRuntime() + ; + + if (!I.can('send_binary_string')) { + throw new x.RuntimeError(x.RuntimeError.NOT_SUPPORTED_ERR); + } + + _xhr.setRequestHeader('Content-Type', 'multipart/form-data; boundary=' + boundary); + + // append multipart parameters + fd.each(function(value, name) { + // Firefox 3.6 failed to convert multibyte characters to UTF-8 in sendAsBinary(), + // so we try it here ourselves with: unescape(encodeURIComponent(value)) + if (value instanceof Blob) { + // Build RFC2388 blob + multipart += dashdash + boundary + crlf + + 'Content-Disposition: form-data; name="' + name + '"; filename="' + unescape(encodeURIComponent(value.name || 'blob')) + '"' + crlf + + 'Content-Type: ' + (value.type || 'application/octet-stream') + crlf + crlf + + value.getSource() + crlf; + } else { + multipart += dashdash + boundary + crlf + + 'Content-Disposition: form-data; name="' + name + '"' + crlf + crlf + + unescape(encodeURIComponent(value)) + crlf; + } + }); + + multipart += dashdash + boundary + dashdash + crlf; + + return multipart; + } + } + + return (extensions.XMLHttpRequest = XMLHttpRequest); +}); + +// Included from: src/javascript/runtime/html5/utils/BinaryReader.js + +/** + * BinaryReader.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/html5/utils/BinaryReader +@private +*/ +define("moxie/runtime/html5/utils/BinaryReader", [ + "moxie/core/utils/Basic" +], function(Basic) { + + + function BinaryReader(data) { + if (data instanceof ArrayBuffer) { + ArrayBufferReader.apply(this, arguments); + } else { + UTF16StringReader.apply(this, arguments); + } + } + + Basic.extend(BinaryReader.prototype, { + + littleEndian: false, + + + read: function(idx, size) { + var sum, mv, i; + + if (idx + size > this.length()) { + throw new Error("You are trying to read outside the source boundaries."); + } + + mv = this.littleEndian + ? 0 + : -8 * (size - 1) + ; + + for (i = 0, sum = 0; i < size; i++) { + sum |= (this.readByteAt(idx + i) << Math.abs(mv + i*8)); + } + return sum; + }, + + + write: function(idx, num, size) { + var mv, i, str = ''; + + if (idx > this.length()) { + throw new Error("You are trying to write outside the source boundaries."); + } + + mv = this.littleEndian + ? 0 + : -8 * (size - 1) + ; + + for (i = 0; i < size; i++) { + this.writeByteAt(idx + i, (num >> Math.abs(mv + i*8)) & 255); + } + }, + + + BYTE: function(idx) { + return this.read(idx, 1); + }, + + + SHORT: function(idx) { + return this.read(idx, 2); + }, + + + LONG: function(idx) { + return this.read(idx, 4); + }, + + + SLONG: function(idx) { // 2's complement notation + var num = this.read(idx, 4); + return (num > 2147483647 ? num - 4294967296 : num); + }, + + + CHAR: function(idx) { + return String.fromCharCode(this.read(idx, 1)); + }, + + + STRING: function(idx, count) { + return this.asArray('CHAR', idx, count).join(''); + }, + + + asArray: function(type, idx, count) { + var values = []; + + for (var i = 0; i < count; i++) { + values[i] = this[type](idx + i); + } + return values; + } + }); + + + function ArrayBufferReader(data) { + var _dv = new DataView(data); + + Basic.extend(this, { + + readByteAt: function(idx) { + return _dv.getUint8(idx); + }, + + + writeByteAt: function(idx, value) { + _dv.setUint8(idx, value); + }, + + + SEGMENT: function(idx, size, value) { + switch (arguments.length) { + case 2: + return data.slice(idx, idx + size); + + case 1: + return data.slice(idx); + + case 3: + if (value === null) { + value = new ArrayBuffer(); + } + + if (value instanceof ArrayBuffer) { + var arr = new Uint8Array(this.length() - size + value.byteLength); + if (idx > 0) { + arr.set(new Uint8Array(data.slice(0, idx)), 0); + } + arr.set(new Uint8Array(value), idx); + arr.set(new Uint8Array(data.slice(idx + size)), idx + value.byteLength); + + this.clear(); + data = arr.buffer; + _dv = new DataView(data); + break; + } + + default: return data; + } + }, + + + length: function() { + return data ? data.byteLength : 0; + }, + + + clear: function() { + _dv = data = null; + } + }); + } + + + function UTF16StringReader(data) { + Basic.extend(this, { + + readByteAt: function(idx) { + return data.charCodeAt(idx); + }, + + + writeByteAt: function(idx, value) { + putstr(String.fromCharCode(value), idx, 1); + }, + + + SEGMENT: function(idx, length, segment) { + switch (arguments.length) { + case 1: + return data.substr(idx); + case 2: + return data.substr(idx, length); + case 3: + putstr(segment !== null ? segment : '', idx, length); + break; + default: return data; + } + }, + + + length: function() { + return data ? data.length : 0; + }, + + clear: function() { + data = null; + } + }); + + + function putstr(segment, idx, length) { + length = arguments.length === 3 ? length : data.length - idx - 1; + data = data.substr(0, idx) + segment + data.substr(length + idx); + } + } + + + return BinaryReader; +}); + +// Included from: src/javascript/runtime/html5/image/JPEGHeaders.js + +/** + * JPEGHeaders.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/html5/image/JPEGHeaders +@private +*/ +define("moxie/runtime/html5/image/JPEGHeaders", [ + "moxie/runtime/html5/utils/BinaryReader", + "moxie/core/Exceptions" +], function(BinaryReader, x) { + + return function JPEGHeaders(data) { + var headers = [], _br, idx, marker, length = 0; + + _br = new BinaryReader(data); + + // Check if data is jpeg + if (_br.SHORT(0) !== 0xFFD8) { + _br.clear(); + throw new x.ImageError(x.ImageError.WRONG_FORMAT); + } + + idx = 2; + + while (idx <= _br.length()) { + marker = _br.SHORT(idx); + + // omit RST (restart) markers + if (marker >= 0xFFD0 && marker <= 0xFFD7) { + idx += 2; + continue; + } + + // no headers allowed after SOS marker + if (marker === 0xFFDA || marker === 0xFFD9) { + break; + } + + length = _br.SHORT(idx + 2) + 2; + + // APPn marker detected + if (marker >= 0xFFE1 && marker <= 0xFFEF) { + headers.push({ + hex: marker, + name: 'APP' + (marker & 0x000F), + start: idx, + length: length, + segment: _br.SEGMENT(idx, length) + }); + } + + idx += length; + } + + _br.clear(); + + return { + headers: headers, + + restore: function(data) { + var max, i, br; + + br = new BinaryReader(data); + + idx = br.SHORT(2) == 0xFFE0 ? 4 + br.SHORT(4) : 2; + + for (i = 0, max = headers.length; i < max; i++) { + br.SEGMENT(idx, 0, headers[i].segment); + idx += headers[i].length; + } + + data = br.SEGMENT(); + br.clear(); + return data; + }, + + strip: function(data) { + var br, headers, jpegHeaders, i; + + jpegHeaders = new JPEGHeaders(data); + headers = jpegHeaders.headers; + jpegHeaders.purge(); + + br = new BinaryReader(data); + + i = headers.length; + while (i--) { + br.SEGMENT(headers[i].start, headers[i].length, ''); + } + + data = br.SEGMENT(); + br.clear(); + return data; + }, + + get: function(name) { + var array = []; + + for (var i = 0, max = headers.length; i < max; i++) { + if (headers[i].name === name.toUpperCase()) { + array.push(headers[i].segment); + } + } + return array; + }, + + set: function(name, segment) { + var array = [], i, ii, max; + + if (typeof(segment) === 'string') { + array.push(segment); + } else { + array = segment; + } + + for (i = ii = 0, max = headers.length; i < max; i++) { + if (headers[i].name === name.toUpperCase()) { + headers[i].segment = array[ii]; + headers[i].length = array[ii].length; + ii++; + } + if (ii >= array.length) { + break; + } + } + }, + + purge: function() { + this.headers = headers = []; + } + }; + }; +}); + +// Included from: src/javascript/runtime/html5/image/ExifParser.js + +/** + * ExifParser.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/html5/image/ExifParser +@private +*/ +define("moxie/runtime/html5/image/ExifParser", [ + "moxie/core/utils/Basic", + "moxie/runtime/html5/utils/BinaryReader", + "moxie/core/Exceptions" +], function(Basic, BinaryReader, x) { + + function ExifParser(data) { + var __super__, tags, tagDescs, offsets, idx, Tiff; + + BinaryReader.call(this, data); + + tags = { + tiff: { + /* + The image orientation viewed in terms of rows and columns. + + 1 = The 0th row is at the visual top of the image, and the 0th column is the visual left-hand side. + 2 = The 0th row is at the visual top of the image, and the 0th column is the visual right-hand side. + 3 = The 0th row is at the visual bottom of the image, and the 0th column is the visual right-hand side. + 4 = The 0th row is at the visual bottom of the image, and the 0th column is the visual left-hand side. + 5 = The 0th row is the visual left-hand side of the image, and the 0th column is the visual top. + 6 = The 0th row is the visual right-hand side of the image, and the 0th column is the visual top. + 7 = The 0th row is the visual right-hand side of the image, and the 0th column is the visual bottom. + 8 = The 0th row is the visual left-hand side of the image, and the 0th column is the visual bottom. + */ + 0x0112: 'Orientation', + 0x010E: 'ImageDescription', + 0x010F: 'Make', + 0x0110: 'Model', + 0x0131: 'Software', + 0x8769: 'ExifIFDPointer', + 0x8825: 'GPSInfoIFDPointer' + }, + exif: { + 0x9000: 'ExifVersion', + 0xA001: 'ColorSpace', + 0xA002: 'PixelXDimension', + 0xA003: 'PixelYDimension', + 0x9003: 'DateTimeOriginal', + 0x829A: 'ExposureTime', + 0x829D: 'FNumber', + 0x8827: 'ISOSpeedRatings', + 0x9201: 'ShutterSpeedValue', + 0x9202: 'ApertureValue' , + 0x9207: 'MeteringMode', + 0x9208: 'LightSource', + 0x9209: 'Flash', + 0x920A: 'FocalLength', + 0xA402: 'ExposureMode', + 0xA403: 'WhiteBalance', + 0xA406: 'SceneCaptureType', + 0xA404: 'DigitalZoomRatio', + 0xA408: 'Contrast', + 0xA409: 'Saturation', + 0xA40A: 'Sharpness' + }, + gps: { + 0x0000: 'GPSVersionID', + 0x0001: 'GPSLatitudeRef', + 0x0002: 'GPSLatitude', + 0x0003: 'GPSLongitudeRef', + 0x0004: 'GPSLongitude' + }, + + thumb: { + 0x0201: 'JPEGInterchangeFormat', + 0x0202: 'JPEGInterchangeFormatLength' + } + }; + + tagDescs = { + 'ColorSpace': { + 1: 'sRGB', + 0: 'Uncalibrated' + }, + + 'MeteringMode': { + 0: 'Unknown', + 1: 'Average', + 2: 'CenterWeightedAverage', + 3: 'Spot', + 4: 'MultiSpot', + 5: 'Pattern', + 6: 'Partial', + 255: 'Other' + }, + + 'LightSource': { + 1: 'Daylight', + 2: 'Fliorescent', + 3: 'Tungsten', + 4: 'Flash', + 9: 'Fine weather', + 10: 'Cloudy weather', + 11: 'Shade', + 12: 'Daylight fluorescent (D 5700 - 7100K)', + 13: 'Day white fluorescent (N 4600 -5400K)', + 14: 'Cool white fluorescent (W 3900 - 4500K)', + 15: 'White fluorescent (WW 3200 - 3700K)', + 17: 'Standard light A', + 18: 'Standard light B', + 19: 'Standard light C', + 20: 'D55', + 21: 'D65', + 22: 'D75', + 23: 'D50', + 24: 'ISO studio tungsten', + 255: 'Other' + }, + + 'Flash': { + 0x0000: 'Flash did not fire', + 0x0001: 'Flash fired', + 0x0005: 'Strobe return light not detected', + 0x0007: 'Strobe return light detected', + 0x0009: 'Flash fired, compulsory flash mode', + 0x000D: 'Flash fired, compulsory flash mode, return light not detected', + 0x000F: 'Flash fired, compulsory flash mode, return light detected', + 0x0010: 'Flash did not fire, compulsory flash mode', + 0x0018: 'Flash did not fire, auto mode', + 0x0019: 'Flash fired, auto mode', + 0x001D: 'Flash fired, auto mode, return light not detected', + 0x001F: 'Flash fired, auto mode, return light detected', + 0x0020: 'No flash function', + 0x0041: 'Flash fired, red-eye reduction mode', + 0x0045: 'Flash fired, red-eye reduction mode, return light not detected', + 0x0047: 'Flash fired, red-eye reduction mode, return light detected', + 0x0049: 'Flash fired, compulsory flash mode, red-eye reduction mode', + 0x004D: 'Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected', + 0x004F: 'Flash fired, compulsory flash mode, red-eye reduction mode, return light detected', + 0x0059: 'Flash fired, auto mode, red-eye reduction mode', + 0x005D: 'Flash fired, auto mode, return light not detected, red-eye reduction mode', + 0x005F: 'Flash fired, auto mode, return light detected, red-eye reduction mode' + }, + + 'ExposureMode': { + 0: 'Auto exposure', + 1: 'Manual exposure', + 2: 'Auto bracket' + }, + + 'WhiteBalance': { + 0: 'Auto white balance', + 1: 'Manual white balance' + }, + + 'SceneCaptureType': { + 0: 'Standard', + 1: 'Landscape', + 2: 'Portrait', + 3: 'Night scene' + }, + + 'Contrast': { + 0: 'Normal', + 1: 'Soft', + 2: 'Hard' + }, + + 'Saturation': { + 0: 'Normal', + 1: 'Low saturation', + 2: 'High saturation' + }, + + 'Sharpness': { + 0: 'Normal', + 1: 'Soft', + 2: 'Hard' + }, + + // GPS related + 'GPSLatitudeRef': { + N: 'North latitude', + S: 'South latitude' + }, + + 'GPSLongitudeRef': { + E: 'East longitude', + W: 'West longitude' + } + }; + + offsets = { + tiffHeader: 10 + }; + + idx = offsets.tiffHeader; + + __super__ = { + clear: this.clear + }; + + // Public functions + Basic.extend(this, { + + read: function() { + try { + return ExifParser.prototype.read.apply(this, arguments); + } catch (ex) { + throw new x.ImageError(x.ImageError.INVALID_META_ERR); + } + }, + + + write: function() { + try { + return ExifParser.prototype.write.apply(this, arguments); + } catch (ex) { + throw new x.ImageError(x.ImageError.INVALID_META_ERR); + } + }, + + + UNDEFINED: function() { + return this.BYTE.apply(this, arguments); + }, + + + RATIONAL: function(idx) { + return this.LONG(idx) / this.LONG(idx + 4) + }, + + + SRATIONAL: function(idx) { + return this.SLONG(idx) / this.SLONG(idx + 4) + }, + + ASCII: function(idx) { + return this.CHAR(idx); + }, + + TIFF: function() { + return Tiff || null; + }, + + + EXIF: function() { + var Exif = null; + + if (offsets.exifIFD) { + try { + Exif = extractTags.call(this, offsets.exifIFD, tags.exif); + } catch(ex) { + return null; + } + + // Fix formatting of some tags + if (Exif.ExifVersion && Basic.typeOf(Exif.ExifVersion) === 'array') { + for (var i = 0, exifVersion = ''; i < Exif.ExifVersion.length; i++) { + exifVersion += String.fromCharCode(Exif.ExifVersion[i]); + } + Exif.ExifVersion = exifVersion; + } + } + + return Exif; + }, + + + GPS: function() { + var GPS = null; + + if (offsets.gpsIFD) { + try { + GPS = extractTags.call(this, offsets.gpsIFD, tags.gps); + } catch (ex) { + return null; + } + + // iOS devices (and probably some others) do not put in GPSVersionID tag (why?..) + if (GPS.GPSVersionID && Basic.typeOf(GPS.GPSVersionID) === 'array') { + GPS.GPSVersionID = GPS.GPSVersionID.join('.'); + } + } + + return GPS; + }, + + + thumb: function() { + if (offsets.IFD1) { + try { + var IFD1Tags = extractTags.call(this, offsets.IFD1, tags.thumb); + + if ('JPEGInterchangeFormat' in IFD1Tags) { + return this.SEGMENT(offsets.tiffHeader + IFD1Tags.JPEGInterchangeFormat, IFD1Tags.JPEGInterchangeFormatLength); + } + } catch (ex) {} + } + return null; + }, + + + setExif: function(tag, value) { + // Right now only setting of width/height is possible + if (tag !== 'PixelXDimension' && tag !== 'PixelYDimension') { return false; } + + return setTag.call(this, 'exif', tag, value); + }, + + + clear: function() { + __super__.clear(); + data = tags = tagDescs = Tiff = offsets = __super__ = null; + } + }); + + + // Check if that's APP1 and that it has EXIF + if (this.SHORT(0) !== 0xFFE1 || this.STRING(4, 5).toUpperCase() !== "EXIF\0") { + throw new x.ImageError(x.ImageError.INVALID_META_ERR); + } + + // Set read order of multi-byte data + this.littleEndian = (this.SHORT(idx) == 0x4949); + + // Check if always present bytes are indeed present + if (this.SHORT(idx+=2) !== 0x002A) { + throw new x.ImageError(x.ImageError.INVALID_META_ERR); + } + + offsets.IFD0 = offsets.tiffHeader + this.LONG(idx += 2); + Tiff = extractTags.call(this, offsets.IFD0, tags.tiff); + + if ('ExifIFDPointer' in Tiff) { + offsets.exifIFD = offsets.tiffHeader + Tiff.ExifIFDPointer; + delete Tiff.ExifIFDPointer; + } + + if ('GPSInfoIFDPointer' in Tiff) { + offsets.gpsIFD = offsets.tiffHeader + Tiff.GPSInfoIFDPointer; + delete Tiff.GPSInfoIFDPointer; + } + + if (Basic.isEmptyObj(Tiff)) { + Tiff = null; + } + + // check if we have a thumb as well + var IFD1Offset = this.LONG(offsets.IFD0 + this.SHORT(offsets.IFD0) * 12 + 2); + if (IFD1Offset) { + offsets.IFD1 = offsets.tiffHeader + IFD1Offset; + } + + + function extractTags(IFD_offset, tags2extract) { + var data = this; + var length, i, tag, type, count, size, offset, value, values = [], hash = {}; + + var types = { + 1 : 'BYTE', + 7 : 'UNDEFINED', + 2 : 'ASCII', + 3 : 'SHORT', + 4 : 'LONG', + 5 : 'RATIONAL', + 9 : 'SLONG', + 10: 'SRATIONAL' + }; + + var sizes = { + 'BYTE' : 1, + 'UNDEFINED' : 1, + 'ASCII' : 1, + 'SHORT' : 2, + 'LONG' : 4, + 'RATIONAL' : 8, + 'SLONG' : 4, + 'SRATIONAL' : 8 + }; + + length = data.SHORT(IFD_offset); + + // The size of APP1 including all these elements shall not exceed the 64 Kbytes specified in the JPEG standard. + + for (i = 0; i < length; i++) { + values = []; + + // Set binary reader pointer to beginning of the next tag + offset = IFD_offset + 2 + i*12; + + tag = tags2extract[data.SHORT(offset)]; + + if (tag === undefined) { + continue; // Not the tag we requested + } + + type = types[data.SHORT(offset+=2)]; + count = data.LONG(offset+=2); + size = sizes[type]; + + if (!size) { + throw new x.ImageError(x.ImageError.INVALID_META_ERR); + } + + offset += 4; + + // tag can only fit 4 bytes of data, if data is larger we should look outside + if (size * count > 4) { + // instead of data tag contains an offset of the data + offset = data.LONG(offset) + offsets.tiffHeader; + } + + // in case we left the boundaries of data throw an early exception + if (offset + size * count >= this.length()) { + throw new x.ImageError(x.ImageError.INVALID_META_ERR); + } + + // special care for the string + if (type === 'ASCII') { + hash[tag] = Basic.trim(data.STRING(offset, count).replace(/\0$/, '')); // strip trailing NULL + continue; + } else { + values = data.asArray(type, offset, count); + value = (count == 1 ? values[0] : values); + + if (tagDescs.hasOwnProperty(tag) && typeof value != 'object') { + hash[tag] = tagDescs[tag][value]; + } else { + hash[tag] = value; + } + } + } + + return hash; + } + + // At the moment only setting of simple (LONG) values, that do not require offset recalculation, is supported + function setTag(ifd, tag, value) { + var offset, length, tagOffset, valueOffset = 0; + + // If tag name passed translate into hex key + if (typeof(tag) === 'string') { + var tmpTags = tags[ifd.toLowerCase()]; + for (var hex in tmpTags) { + if (tmpTags[hex] === tag) { + tag = hex; + break; + } + } + } + offset = offsets[ifd.toLowerCase() + 'IFD']; + length = this.SHORT(offset); + + for (var i = 0; i < length; i++) { + tagOffset = offset + 12 * i + 2; + + if (this.SHORT(tagOffset) == tag) { + valueOffset = tagOffset + 8; + break; + } + } + + if (!valueOffset) { + return false; + } + + try { + this.write(valueOffset, value, 4); + } catch(ex) { + return false; + } + + return true; + } + } + + ExifParser.prototype = BinaryReader.prototype; + + return ExifParser; +}); + +// Included from: src/javascript/runtime/html5/image/JPEG.js + +/** + * JPEG.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/html5/image/JPEG +@private +*/ +define("moxie/runtime/html5/image/JPEG", [ + "moxie/core/utils/Basic", + "moxie/core/Exceptions", + "moxie/runtime/html5/image/JPEGHeaders", + "moxie/runtime/html5/utils/BinaryReader", + "moxie/runtime/html5/image/ExifParser" +], function(Basic, x, JPEGHeaders, BinaryReader, ExifParser) { + + function JPEG(data) { + var _br, _hm, _ep, _info; + + _br = new BinaryReader(data); + + // check if it is jpeg + if (_br.SHORT(0) !== 0xFFD8) { + throw new x.ImageError(x.ImageError.WRONG_FORMAT); + } + + // backup headers + _hm = new JPEGHeaders(data); + + // extract exif info + try { + _ep = new ExifParser(_hm.get('app1')[0]); + } catch(ex) {} + + // get dimensions + _info = _getDimensions.call(this); + + Basic.extend(this, { + type: 'image/jpeg', + + size: _br.length(), + + width: _info && _info.width || 0, + + height: _info && _info.height || 0, + + setExif: function(tag, value) { + if (!_ep) { + return false; // or throw an exception + } + + if (Basic.typeOf(tag) === 'object') { + Basic.each(tag, function(value, tag) { + _ep.setExif(tag, value); + }); + } else { + _ep.setExif(tag, value); + } + + // update internal headers + _hm.set('app1', _ep.SEGMENT()); + }, + + writeHeaders: function() { + if (!arguments.length) { + // if no arguments passed, update headers internally + return _hm.restore(data); + } + return _hm.restore(arguments[0]); + }, + + stripHeaders: function(data) { + return _hm.strip(data); + }, + + purge: function() { + _purge.call(this); + } + }); + + if (_ep) { + this.meta = { + tiff: _ep.TIFF(), + exif: _ep.EXIF(), + gps: _ep.GPS(), + thumb: _getThumb() + }; + } + + + function _getDimensions(br) { + var idx = 0 + , marker + , length + ; + + if (!br) { + br = _br; + } + + // examine all through the end, since some images might have very large APP segments + while (idx <= br.length()) { + marker = br.SHORT(idx += 2); + + if (marker >= 0xFFC0 && marker <= 0xFFC3) { // SOFn + idx += 5; // marker (2 bytes) + length (2 bytes) + Sample precision (1 byte) + return { + height: br.SHORT(idx), + width: br.SHORT(idx += 2) + }; + } + length = br.SHORT(idx += 2); + idx += length - 2; + } + return null; + } + + + function _getThumb() { + var data = _ep.thumb() + , br + , info + ; + + if (data) { + br = new BinaryReader(data); + info = _getDimensions(br); + br.clear(); + + if (info) { + info.data = data; + return info; + } + } + return null; + } + + + function _purge() { + if (!_ep || !_hm || !_br) { + return; // ignore any repeating purge requests + } + _ep.clear(); + _hm.purge(); + _br.clear(); + _info = _hm = _ep = _br = null; + } + } + + return JPEG; +}); + +// Included from: src/javascript/runtime/html5/image/PNG.js + +/** + * PNG.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/html5/image/PNG +@private +*/ +define("moxie/runtime/html5/image/PNG", [ + "moxie/core/Exceptions", + "moxie/core/utils/Basic", + "moxie/runtime/html5/utils/BinaryReader" +], function(x, Basic, BinaryReader) { + + function PNG(data) { + var _br, _hm, _ep, _info; + + _br = new BinaryReader(data); + + // check if it's png + (function() { + var idx = 0, i = 0 + , signature = [0x8950, 0x4E47, 0x0D0A, 0x1A0A] + ; + + for (i = 0; i < signature.length; i++, idx += 2) { + if (signature[i] != _br.SHORT(idx)) { + throw new x.ImageError(x.ImageError.WRONG_FORMAT); + } + } + }()); + + function _getDimensions() { + var chunk, idx; + + chunk = _getChunkAt.call(this, 8); + + if (chunk.type == 'IHDR') { + idx = chunk.start; + return { + width: _br.LONG(idx), + height: _br.LONG(idx += 4) + }; + } + return null; + } + + function _purge() { + if (!_br) { + return; // ignore any repeating purge requests + } + _br.clear(); + data = _info = _hm = _ep = _br = null; + } + + _info = _getDimensions.call(this); + + Basic.extend(this, { + type: 'image/png', + + size: _br.length(), + + width: _info.width, + + height: _info.height, + + purge: function() { + _purge.call(this); + } + }); + + // for PNG we can safely trigger purge automatically, as we do not keep any data for later + _purge.call(this); + + function _getChunkAt(idx) { + var length, type, start, CRC; + + length = _br.LONG(idx); + type = _br.STRING(idx += 4, 4); + start = idx += 4; + CRC = _br.LONG(idx + length); + + return { + length: length, + type: type, + start: start, + CRC: CRC + }; + } + } + + return PNG; +}); + +// Included from: src/javascript/runtime/html5/image/ImageInfo.js + +/** + * ImageInfo.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/html5/image/ImageInfo +@private +*/ +define("moxie/runtime/html5/image/ImageInfo", [ + "moxie/core/utils/Basic", + "moxie/core/Exceptions", + "moxie/runtime/html5/image/JPEG", + "moxie/runtime/html5/image/PNG" +], function(Basic, x, JPEG, PNG) { + /** + Optional image investigation tool for HTML5 runtime. Provides the following features: + - ability to distinguish image type (JPEG or PNG) by signature + - ability to extract image width/height directly from it's internals, without preloading in memory (fast) + - ability to extract APP headers from JPEGs (Exif, GPS, etc) + - ability to replace width/height tags in extracted JPEG headers + - ability to restore APP headers, that were for example stripped during image manipulation + + @class ImageInfo + @constructor + @param {String} data Image source as binary string + */ + return function(data) { + var _cs = [JPEG, PNG], _img; + + // figure out the format, throw: ImageError.WRONG_FORMAT if not supported + _img = (function() { + for (var i = 0; i < _cs.length; i++) { + try { + return new _cs[i](data); + } catch (ex) { + // console.info(ex); + } + } + throw new x.ImageError(x.ImageError.WRONG_FORMAT); + }()); + + Basic.extend(this, { + /** + Image Mime Type extracted from it's depths + + @property type + @type {String} + @default '' + */ + type: '', + + /** + Image size in bytes + + @property size + @type {Number} + @default 0 + */ + size: 0, + + /** + Image width extracted from image source + + @property width + @type {Number} + @default 0 + */ + width: 0, + + /** + Image height extracted from image source + + @property height + @type {Number} + @default 0 + */ + height: 0, + + /** + Sets Exif tag. Currently applicable only for width and height tags. Obviously works only with JPEGs. + + @method setExif + @param {String} tag Tag to set + @param {Mixed} value Value to assign to the tag + */ + setExif: function() {}, + + /** + Restores headers to the source. + + @method writeHeaders + @param {String} data Image source as binary string + @return {String} Updated binary string + */ + writeHeaders: function(data) { + return data; + }, + + /** + Strip all headers from the source. + + @method stripHeaders + @param {String} data Image source as binary string + @return {String} Updated binary string + */ + stripHeaders: function(data) { + return data; + }, + + /** + Dispose resources. + + @method purge + */ + purge: function() { + data = null; + } + }); + + Basic.extend(this, _img); + + this.purge = function() { + _img.purge(); + _img = null; + }; + }; +}); + +// Included from: src/javascript/runtime/html5/image/ResizerCanvas.js + +/** + * ResizerCanvas.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** + * Resizes image/canvas using canvas + */ +define("moxie/runtime/html5/image/ResizerCanvas", [], function() { + + function scale(image, ratio) { + var sW = image.width; + var dW = Math.floor(sW * ratio); + var scaleCapped = false; + + if (ratio < 0.5 || ratio > 2) { + ratio = ratio < 0.5 ? 0.5 : 2; + scaleCapped = true; + } + + var tCanvas = _scale(image, ratio); + + if (scaleCapped) { + return scale(tCanvas, dW / tCanvas.width); + } else { + return tCanvas; + } + } + + + function _scale(image, ratio) { + var sW = image.width; + var sH = image.height; + var dW = Math.floor(sW * ratio); + var dH = Math.floor(sH * ratio); + + var canvas = document.createElement('canvas'); + canvas.width = dW; + canvas.height = dH; + canvas.getContext("2d").drawImage(image, 0, 0, sW, sH, 0, 0, dW, dH); + + image = null; // just in case + return canvas; + } + + return { + scale: scale + }; + +}); + +// Included from: src/javascript/runtime/html5/image/Image.js + +/** + * Image.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/html5/image/Image +@private +*/ +define("moxie/runtime/html5/image/Image", [ + "moxie/runtime/html5/Runtime", + "moxie/core/utils/Basic", + "moxie/core/Exceptions", + "moxie/core/utils/Encode", + "moxie/file/Blob", + "moxie/file/File", + "moxie/runtime/html5/image/ImageInfo", + "moxie/runtime/html5/image/ResizerCanvas", + "moxie/core/utils/Mime", + "moxie/core/utils/Env" +], function(extensions, Basic, x, Encode, Blob, File, ImageInfo, ResizerCanvas, Mime, Env) { + + function HTML5Image() { + var me = this + , _img, _imgInfo, _canvas, _binStr, _blob + , _modified = false // is set true whenever image is modified + , _preserveHeaders = true + ; + + Basic.extend(this, { + loadFromBlob: function(blob) { + var I = this.getRuntime() + , asBinary = arguments.length > 1 ? arguments[1] : true + ; + + if (!I.can('access_binary')) { + throw new x.RuntimeError(x.RuntimeError.NOT_SUPPORTED_ERR); + } + + _blob = blob; + + if (blob.isDetached()) { + _binStr = blob.getSource(); + _preload.call(this, _binStr); + return; + } else { + _readAsDataUrl.call(this, blob.getSource(), function(dataUrl) { + if (asBinary) { + _binStr = _toBinary(dataUrl); + } + _preload.call(this, dataUrl); + }); + } + }, + + loadFromImage: function(img, exact) { + this.meta = img.meta; + + _blob = new File(null, { + name: img.name, + size: img.size, + type: img.type + }); + + _preload.call(this, exact ? (_binStr = img.getAsBinaryString()) : img.getAsDataURL()); + }, + + getInfo: function() { + var I = this.getRuntime(), info; + + if (!_imgInfo && _binStr && I.can('access_image_binary')) { + _imgInfo = new ImageInfo(_binStr); + } + + // this stuff below is definitely having fun with itself + info = { + width: _getImg().width || 0, + height: _getImg().height || 0, + type: _blob.type || Mime.getFileMime(_blob.name), + size: _binStr && _binStr.length || _blob.size || 0, + name: _blob.name || '', + meta: null + }; + + if (_preserveHeaders) { + info.meta = _imgInfo && _imgInfo.meta || this.meta || {}; + + // if data was taken from ImageInfo it will be a binary string, so we convert it to blob + if (info.meta && info.meta.thumb && !(info.meta.thumb.data instanceof Blob)) { + info.meta.thumb.data = new Blob(null, { + type: 'image/jpeg', + data: info.meta.thumb.data + }); + } + } + + return info; + }, + + + resize: function(rect, ratio, options) { + var canvas = document.createElement('canvas'); + canvas.width = rect.width; + canvas.height = rect.height; + + canvas.getContext("2d").drawImage(_getImg(), rect.x, rect.y, rect.width, rect.height, 0, 0, canvas.width, canvas.height); + + _canvas = ResizerCanvas.scale(canvas, ratio); + + _preserveHeaders = options.preserveHeaders; + + // rotate if required, according to orientation tag + if (!_preserveHeaders) { + var orientation = (this.meta && this.meta.tiff && this.meta.tiff.Orientation) || 1; + _canvas = _rotateToOrientaion(_canvas, orientation); + } + + this.width = _canvas.width; + this.height = _canvas.height; + + _modified = true; + + this.trigger('Resize'); + }, + + getAsCanvas: function() { + if (!_canvas) { + _canvas = _getCanvas(); + } + _canvas.id = this.uid + '_canvas'; + return _canvas; + }, + + getAsBlob: function(type, quality) { + if (type !== this.type) { + _modified = true; // reconsider the state + return new File(null, { + name: _blob.name || '', + type: type, + data: me.getAsDataURL(type, quality) + }); + } + return new File(null, { + name: _blob.name || '', + type: type, + data: me.getAsBinaryString(type, quality) + }); + }, + + getAsDataURL: function(type) { + var quality = arguments[1] || 90; + + // if image has not been modified, return the source right away + if (!_modified) { + return _img.src; + } + + // make sure we have a canvas to work with + _getCanvas(); + + if ('image/jpeg' !== type) { + return _canvas.toDataURL('image/png'); + } else { + try { + // older Geckos used to result in an exception on quality argument + return _canvas.toDataURL('image/jpeg', quality/100); + } catch (ex) { + return _canvas.toDataURL('image/jpeg'); + } + } + }, + + getAsBinaryString: function(type, quality) { + // if image has not been modified, return the source right away + if (!_modified) { + // if image was not loaded from binary string + if (!_binStr) { + _binStr = _toBinary(me.getAsDataURL(type, quality)); + } + return _binStr; + } + + if ('image/jpeg' !== type) { + _binStr = _toBinary(me.getAsDataURL(type, quality)); + } else { + var dataUrl; + + // if jpeg + if (!quality) { + quality = 90; + } + + // make sure we have a canvas to work with + _getCanvas(); + + try { + // older Geckos used to result in an exception on quality argument + dataUrl = _canvas.toDataURL('image/jpeg', quality/100); + } catch (ex) { + dataUrl = _canvas.toDataURL('image/jpeg'); + } + + _binStr = _toBinary(dataUrl); + + if (_imgInfo) { + _binStr = _imgInfo.stripHeaders(_binStr); + + if (_preserveHeaders) { + // update dimensions info in exif + if (_imgInfo.meta && _imgInfo.meta.exif) { + _imgInfo.setExif({ + PixelXDimension: this.width, + PixelYDimension: this.height + }); + } + + // re-inject the headers + _binStr = _imgInfo.writeHeaders(_binStr); + } + + // will be re-created from fresh on next getInfo call + _imgInfo.purge(); + _imgInfo = null; + } + } + + _modified = false; + + return _binStr; + }, + + destroy: function() { + me = null; + _purge.call(this); + this.getRuntime().getShim().removeInstance(this.uid); + } + }); + + + function _getImg() { + if (!_canvas && !_img) { + throw new x.ImageError(x.DOMException.INVALID_STATE_ERR); + } + return _canvas || _img; + } + + + function _getCanvas() { + var canvas = _getImg(); + if (canvas.nodeName.toLowerCase() == 'canvas') { + return canvas; + } + _canvas = document.createElement('canvas'); + _canvas.width = canvas.width; + _canvas.height = canvas.height; + _canvas.getContext("2d").drawImage(canvas, 0, 0); + return _canvas; + } + + + function _toBinary(str) { + return Encode.atob(str.substring(str.indexOf('base64,') + 7)); + } + + + function _toDataUrl(str, type) { + return 'data:' + (type || '') + ';base64,' + Encode.btoa(str); + } + + + function _preload(str) { + var comp = this; + + _img = new Image(); + _img.onerror = function() { + _purge.call(this); + comp.trigger('error', x.ImageError.WRONG_FORMAT); + }; + _img.onload = function() { + comp.trigger('load'); + }; + + _img.src = str.substr(0, 5) == 'data:' ? str : _toDataUrl(str, _blob.type); + } + + + function _readAsDataUrl(file, callback) { + var comp = this, fr; + + // use FileReader if it's available + if (window.FileReader) { + fr = new FileReader(); + fr.onload = function() { + callback.call(comp, this.result); + }; + fr.onerror = function() { + comp.trigger('error', x.ImageError.WRONG_FORMAT); + }; + fr.readAsDataURL(file); + } else { + return callback.call(this, file.getAsDataURL()); + } + } + + /** + * Transform canvas coordination according to specified frame size and orientation + * Orientation value is from EXIF tag + * @author Shinichi Tomita + */ + function _rotateToOrientaion(img, orientation) { + var RADIANS = Math.PI/180; + var canvas = document.createElement('canvas'); + var ctx = canvas.getContext('2d'); + var width = img.width; + var height = img.height; + + if (Basic.inArray(orientation, [5,6,7,8]) > -1) { + canvas.width = height; + canvas.height = width; + } else { + canvas.width = width; + canvas.height = height; + } + + /** + 1 = The 0th row is at the visual top of the image, and the 0th column is the visual left-hand side. + 2 = The 0th row is at the visual top of the image, and the 0th column is the visual right-hand side. + 3 = The 0th row is at the visual bottom of the image, and the 0th column is the visual right-hand side. + 4 = The 0th row is at the visual bottom of the image, and the 0th column is the visual left-hand side. + 5 = The 0th row is the visual left-hand side of the image, and the 0th column is the visual top. + 6 = The 0th row is the visual right-hand side of the image, and the 0th column is the visual top. + 7 = The 0th row is the visual right-hand side of the image, and the 0th column is the visual bottom. + 8 = The 0th row is the visual left-hand side of the image, and the 0th column is the visual bottom. + */ + switch (orientation) { + case 2: + // horizontal flip + ctx.translate(width, 0); + ctx.scale(-1, 1); + break; + case 3: + // 180 rotate left + ctx.translate(width, height); + ctx.rotate(180 * RADIANS); + break; + case 4: + // vertical flip + ctx.translate(0, height); + ctx.scale(1, -1); + break; + case 5: + // vertical flip + 90 rotate right + ctx.rotate(90 * RADIANS); + ctx.scale(1, -1); + break; + case 6: + // 90 rotate right + ctx.rotate(90 * RADIANS); + ctx.translate(0, -height); + break; + case 7: + // horizontal flip + 90 rotate right + ctx.rotate(90 * RADIANS); + ctx.translate(width, -height); + ctx.scale(-1, 1); + break; + case 8: + // 90 rotate left + ctx.rotate(-90 * RADIANS); + ctx.translate(-width, 0); + break; + } + + ctx.drawImage(img, 0, 0, width, height); + return canvas; + } + + + function _purge() { + if (_imgInfo) { + _imgInfo.purge(); + _imgInfo = null; + } + + _binStr = _img = _canvas = _blob = null; + _modified = false; + } + } + + return (extensions.Image = HTML5Image); +}); + +// Included from: src/javascript/runtime/flash/Runtime.js + +/** + * Runtime.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/*global ActiveXObject:true */ + +/** +Defines constructor for Flash runtime. + +@class moxie/runtime/flash/Runtime +@private +*/ +define("moxie/runtime/flash/Runtime", [ + "moxie/core/utils/Basic", + "moxie/core/utils/Env", + "moxie/core/utils/Dom", + "moxie/core/Exceptions", + "moxie/runtime/Runtime" +], function(Basic, Env, Dom, x, Runtime) { + + var type = 'flash', extensions = {}; + + /** + Get the version of the Flash Player + + @method getShimVersion + @private + @return {Number} Flash Player version + */ + function getShimVersion() { + var version; + + try { + version = navigator.plugins['Shockwave Flash']; + version = version.description; + } catch (e1) { + try { + version = new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version'); + } catch (e2) { + version = '0.0'; + } + } + version = version.match(/\d+/g); + return parseFloat(version[0] + '.' + version[1]); + } + + + /** + Cross-browser SWF removal + - Especially needed to safely and completely remove a SWF in Internet Explorer + + Originated from SWFObject v2.2 + */ + function removeSWF(id) { + var obj = Dom.get(id); + if (obj && obj.nodeName == "OBJECT") { + if (Env.browser === 'IE') { + obj.style.display = "none"; + (function onInit(){ + // http://msdn.microsoft.com/en-us/library/ie/ms534360(v=vs.85).aspx + if (obj.readyState == 4) { + removeObjectInIE(id); + } + else { + setTimeout(onInit, 10); + } + })(); + } + else { + obj.parentNode.removeChild(obj); + } + } + } + + + function removeObjectInIE(id) { + var obj = Dom.get(id); + if (obj) { + for (var i in obj) { + if (typeof obj[i] == "function") { + obj[i] = null; + } + } + obj.parentNode.removeChild(obj); + } + } + + /** + Constructor for the Flash Runtime + + @class FlashRuntime + @extends Runtime + */ + function FlashRuntime(options) { + var I = this, initTimer; + + options = Basic.extend({ swf_url: Env.swf_url }, options); + + Runtime.call(this, options, type, { + access_binary: function(value) { + return value && I.mode === 'browser'; + }, + access_image_binary: function(value) { + return value && I.mode === 'browser'; + }, + display_media: Runtime.capTest(defined('moxie/image/Image')), + do_cors: Runtime.capTrue, + drag_and_drop: false, + report_upload_progress: function() { + return I.mode === 'client'; + }, + resize_image: Runtime.capTrue, + return_response_headers: false, + return_response_type: function(responseType) { + if (responseType === 'json' && !!window.JSON) { + return true; + } + return !Basic.arrayDiff(responseType, ['', 'text', 'document']) || I.mode === 'browser'; + }, + return_status_code: function(code) { + return I.mode === 'browser' || !Basic.arrayDiff(code, [200, 404]); + }, + select_file: Runtime.capTrue, + select_multiple: Runtime.capTrue, + send_binary_string: function(value) { + return value && I.mode === 'browser'; + }, + send_browser_cookies: function(value) { + return value && I.mode === 'browser'; + }, + send_custom_headers: function(value) { + return value && I.mode === 'browser'; + }, + send_multipart: Runtime.capTrue, + slice_blob: function(value) { + return value && I.mode === 'browser'; + }, + stream_upload: function(value) { + return value && I.mode === 'browser'; + }, + summon_file_dialog: false, + upload_filesize: function(size) { + return Basic.parseSizeStr(size) <= 2097152 || I.mode === 'client'; + }, + use_http_method: function(methods) { + return !Basic.arrayDiff(methods, ['GET', 'POST']); + } + }, { + // capabilities that require specific mode + access_binary: function(value) { + return value ? 'browser' : 'client'; + }, + access_image_binary: function(value) { + return value ? 'browser' : 'client'; + }, + report_upload_progress: function(value) { + return value ? 'browser' : 'client'; + }, + return_response_type: function(responseType) { + return Basic.arrayDiff(responseType, ['', 'text', 'json', 'document']) ? 'browser' : ['client', 'browser']; + }, + return_status_code: function(code) { + return Basic.arrayDiff(code, [200, 404]) ? 'browser' : ['client', 'browser']; + }, + send_binary_string: function(value) { + return value ? 'browser' : 'client'; + }, + send_browser_cookies: function(value) { + return value ? 'browser' : 'client'; + }, + send_custom_headers: function(value) { + return value ? 'browser' : 'client'; + }, + slice_blob: function(value) { + return value ? 'browser' : 'client'; + }, + stream_upload: function(value) { + return value ? 'client' : 'browser'; + }, + upload_filesize: function(size) { + return Basic.parseSizeStr(size) >= 2097152 ? 'client' : 'browser'; + } + }, 'client'); + + + // minimal requirement for Flash Player version + if (getShimVersion() < 11.3) { + if (MXI_DEBUG && Env.debug.runtime) { + Env.log("\tFlash didn't meet minimal version requirement (11.3)."); + } + + this.mode = false; // with falsy mode, runtime won't operable, no matter what the mode was before + } + + + Basic.extend(this, { + + getShim: function() { + return Dom.get(this.uid); + }, + + shimExec: function(component, action) { + var args = [].slice.call(arguments, 2); + return I.getShim().exec(this.uid, component, action, args); + }, + + init: function() { + var html, el, container; + + container = this.getShimContainer(); + + // if not the minimal height, shims are not initialized in older browsers (e.g FF3.6, IE6,7,8, Safari 4.0,5.0, etc) + Basic.extend(container.style, { + position: 'absolute', + top: '-8px', + left: '-8px', + width: '9px', + height: '9px', + overflow: 'hidden' + }); + + // insert flash object + html = '' + + '' + + '' + + '' + + ''; + + if (Env.browser === 'IE') { + el = document.createElement('div'); + container.appendChild(el); + el.outerHTML = html; + el = container = null; // just in case + } else { + container.innerHTML = html; + } + + // Init is dispatched by the shim + initTimer = setTimeout(function() { + if (I && !I.initialized) { // runtime might be already destroyed by this moment + I.trigger("Error", new x.RuntimeError(x.RuntimeError.NOT_INIT_ERR)); + + if (MXI_DEBUG && Env.debug.runtime) { + Env.log("\tFlash failed to initialize within a specified period of time (typically 5s)."); + } + } + }, 5000); + }, + + destroy: (function(destroy) { // extend default destroy method + return function() { + removeSWF(I.uid); // SWF removal requires special care in IE + + destroy.call(I); + clearTimeout(initTimer); // initialization check might be still onwait + options = initTimer = destroy = I = null; + }; + }(this.destroy)) + + }, extensions); + } + + Runtime.addConstructor(type, FlashRuntime); + + return extensions; +}); + +// Included from: src/javascript/runtime/flash/file/Blob.js + +/** + * Blob.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/flash/file/Blob +@private +*/ +define("moxie/runtime/flash/file/Blob", [ + "moxie/runtime/flash/Runtime", + "moxie/file/Blob" +], function(extensions, Blob) { + + var FlashBlob = { + slice: function(blob, start, end, type) { + var self = this.getRuntime(); + + if (start < 0) { + start = Math.max(blob.size + start, 0); + } else if (start > 0) { + start = Math.min(start, blob.size); + } + + if (end < 0) { + end = Math.max(blob.size + end, 0); + } else if (end > 0) { + end = Math.min(end, blob.size); + } + + blob = self.shimExec.call(this, 'Blob', 'slice', start, end, type || ''); + + if (blob) { + blob = new Blob(self.uid, blob); + } + return blob; + } + }; + + return (extensions.Blob = FlashBlob); +}); + +// Included from: src/javascript/runtime/flash/file/FileInput.js + +/** + * FileInput.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/flash/file/FileInput +@private +*/ +define("moxie/runtime/flash/file/FileInput", [ + "moxie/runtime/flash/Runtime", + "moxie/file/File", + "moxie/core/utils/Basic" +], function(extensions, File, Basic) { + + var FileInput = { + init: function(options) { + var comp = this, I = this.getRuntime(); + + this.bind("Change", function() { + var files = I.shimExec.call(comp, 'FileInput', 'getFiles'); + comp.files = []; + Basic.each(files, function(file) { + comp.files.push(new File(I.uid, file)); + }); + }, 999); + + this.getRuntime().shimExec.call(this, 'FileInput', 'init', { + accept: options.accept, + multiple: options.multiple + }); + + this.trigger('ready'); + } + }; + + return (extensions.FileInput = FileInput); +}); + +// Included from: src/javascript/runtime/flash/file/FileReader.js + +/** + * FileReader.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/flash/file/FileReader +@private +*/ +define("moxie/runtime/flash/file/FileReader", [ + "moxie/runtime/flash/Runtime", + "moxie/core/utils/Encode" +], function(extensions, Encode) { + + function _formatData(data, op) { + switch (op) { + case 'readAsText': + return Encode.atob(data, 'utf8'); + case 'readAsBinaryString': + return Encode.atob(data); + case 'readAsDataURL': + return data; + } + return null; + } + + var FileReader = { + read: function(op, blob) { + var comp = this; + + comp.result = ''; + + // special prefix for DataURL read mode + if (op === 'readAsDataURL') { + comp.result = 'data:' + (blob.type || '') + ';base64,'; + } + + comp.bind('Progress', function(e, data) { + if (data) { + comp.result += _formatData(data, op); + } + }, 999); + + return comp.getRuntime().shimExec.call(this, 'FileReader', 'readAsBase64', blob.uid); + } + }; + + return (extensions.FileReader = FileReader); +}); + +// Included from: src/javascript/runtime/flash/file/FileReaderSync.js + +/** + * FileReaderSync.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/flash/file/FileReaderSync +@private +*/ +define("moxie/runtime/flash/file/FileReaderSync", [ + "moxie/runtime/flash/Runtime", + "moxie/core/utils/Encode" +], function(extensions, Encode) { + + function _formatData(data, op) { + switch (op) { + case 'readAsText': + return Encode.atob(data, 'utf8'); + case 'readAsBinaryString': + return Encode.atob(data); + case 'readAsDataURL': + return data; + } + return null; + } + + var FileReaderSync = { + read: function(op, blob) { + var result, self = this.getRuntime(); + + result = self.shimExec.call(this, 'FileReaderSync', 'readAsBase64', blob.uid); + if (!result) { + return null; // or throw ex + } + + // special prefix for DataURL read mode + if (op === 'readAsDataURL') { + result = 'data:' + (blob.type || '') + ';base64,' + result; + } + + return _formatData(result, op, blob.type); + } + }; + + return (extensions.FileReaderSync = FileReaderSync); +}); + +// Included from: src/javascript/runtime/flash/runtime/Transporter.js + +/** + * Transporter.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/flash/runtime/Transporter +@private +*/ +define("moxie/runtime/flash/runtime/Transporter", [ + "moxie/runtime/flash/Runtime", + "moxie/file/Blob" +], function(extensions, Blob) { + + var Transporter = { + getAsBlob: function(type) { + var self = this.getRuntime() + , blob = self.shimExec.call(this, 'Transporter', 'getAsBlob', type) + ; + if (blob) { + return new Blob(self.uid, blob); + } + return null; + } + }; + + return (extensions.Transporter = Transporter); +}); + +// Included from: src/javascript/runtime/flash/xhr/XMLHttpRequest.js + +/** + * XMLHttpRequest.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/flash/xhr/XMLHttpRequest +@private +*/ +define("moxie/runtime/flash/xhr/XMLHttpRequest", [ + "moxie/runtime/flash/Runtime", + "moxie/core/utils/Basic", + "moxie/file/Blob", + "moxie/file/File", + "moxie/file/FileReaderSync", + "moxie/runtime/flash/file/FileReaderSync", + "moxie/xhr/FormData", + "moxie/runtime/Transporter", + "moxie/runtime/flash/runtime/Transporter" +], function(extensions, Basic, Blob, File, FileReaderSync, FileReaderSyncFlash, FormData, Transporter, TransporterFlash) { + + var XMLHttpRequest = { + + send: function(meta, data) { + var target = this, self = target.getRuntime(); + + function send() { + meta.transport = self.mode; + self.shimExec.call(target, 'XMLHttpRequest', 'send', meta, data); + } + + + function appendBlob(name, blob) { + self.shimExec.call(target, 'XMLHttpRequest', 'appendBlob', name, blob.uid); + data = null; + send(); + } + + + function attachBlob(blob, cb) { + var tr = new Transporter(); + + tr.bind("TransportingComplete", function() { + cb(this.result); + }); + + tr.transport(blob.getSource(), blob.type, { + ruid: self.uid + }); + } + + // copy over the headers if any + if (!Basic.isEmptyObj(meta.headers)) { + Basic.each(meta.headers, function(value, header) { + self.shimExec.call(target, 'XMLHttpRequest', 'setRequestHeader', header, value.toString()); // Silverlight doesn't accept integers into the arguments of type object + }); + } + + // transfer over multipart params and blob itself + if (data instanceof FormData) { + var blobField; + data.each(function(value, name) { + if (value instanceof Blob) { + blobField = name; + } else { + self.shimExec.call(target, 'XMLHttpRequest', 'append', name, value); + } + }); + + if (!data.hasBlob()) { + data = null; + send(); + } else { + var blob = data.getBlob(); + if (blob.isDetached()) { + attachBlob(blob, function(attachedBlob) { + blob.destroy(); + appendBlob(blobField, attachedBlob); + }); + } else { + appendBlob(blobField, blob); + } + } + } else if (data instanceof Blob) { + if (data.isDetached()) { + attachBlob(data, function(attachedBlob) { + data.destroy(); + data = attachedBlob.uid; + send(); + }); + } else { + data = data.uid; + send(); + } + } else { + send(); + } + }, + + getResponse: function(responseType) { + var frs, blob, self = this.getRuntime(); + + blob = self.shimExec.call(this, 'XMLHttpRequest', 'getResponseAsBlob'); + + if (blob) { + blob = new File(self.uid, blob); + + if ('blob' === responseType) { + return blob; + } + + try { + frs = new FileReaderSync(); + + if (!!~Basic.inArray(responseType, ["", "text"])) { + return frs.readAsText(blob); + } else if ('json' === responseType && !!window.JSON) { + return JSON.parse(frs.readAsText(blob)); + } + } finally { + blob.destroy(); + } + } + return null; + }, + + abort: function(upload_complete_flag) { + var self = this.getRuntime(); + + self.shimExec.call(this, 'XMLHttpRequest', 'abort'); + + this.dispatchEvent('readystatechange'); + // this.dispatchEvent('progress'); + this.dispatchEvent('abort'); + + //if (!upload_complete_flag) { + // this.dispatchEvent('uploadprogress'); + //} + } + }; + + return (extensions.XMLHttpRequest = XMLHttpRequest); +}); + +// Included from: src/javascript/runtime/flash/image/Image.js + +/** + * Image.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/flash/image/Image +@private +*/ +define("moxie/runtime/flash/image/Image", [ + "moxie/runtime/flash/Runtime", + "moxie/core/utils/Basic", + "moxie/runtime/Transporter", + "moxie/file/Blob", + "moxie/file/FileReaderSync" +], function(extensions, Basic, Transporter, Blob, FileReaderSync) { + + var Image = { + loadFromBlob: function(blob) { + var comp = this, self = comp.getRuntime(); + + function exec(srcBlob) { + self.shimExec.call(comp, 'Image', 'loadFromBlob', srcBlob.uid); + comp = self = null; + } + + if (blob.isDetached()) { // binary string + var tr = new Transporter(); + tr.bind("TransportingComplete", function() { + exec(tr.result.getSource()); + }); + tr.transport(blob.getSource(), blob.type, { ruid: self.uid }); + } else { + exec(blob.getSource()); + } + }, + + loadFromImage: function(img) { + var self = this.getRuntime(); + return self.shimExec.call(this, 'Image', 'loadFromImage', img.uid); + }, + + getInfo: function() { + var self = this.getRuntime() + , info = self.shimExec.call(this, 'Image', 'getInfo') + ; + + if (info.meta && info.meta.thumb && info.meta.thumb.data && !(self.meta.thumb.data instanceof Blob)) { + info.meta.thumb.data = new Blob(self.uid, info.meta.thumb.data); + } + return info; + }, + + getAsBlob: function(type, quality) { + var self = this.getRuntime() + , blob = self.shimExec.call(this, 'Image', 'getAsBlob', type, quality) + ; + if (blob) { + return new Blob(self.uid, blob); + } + return null; + }, + + getAsDataURL: function() { + var self = this.getRuntime() + , blob = self.Image.getAsBlob.apply(this, arguments) + , frs + ; + if (!blob) { + return null; + } + frs = new FileReaderSync(); + return frs.readAsDataURL(blob); + } + }; + + return (extensions.Image = Image); +}); + +// Included from: src/javascript/runtime/silverlight/Runtime.js + +/** + * RunTime.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/*global ActiveXObject:true */ + +/** +Defines constructor for Silverlight runtime. + +@class moxie/runtime/silverlight/Runtime +@private +*/ +define("moxie/runtime/silverlight/Runtime", [ + "moxie/core/utils/Basic", + "moxie/core/utils/Env", + "moxie/core/utils/Dom", + "moxie/core/Exceptions", + "moxie/runtime/Runtime" +], function(Basic, Env, Dom, x, Runtime) { + + var type = "silverlight", extensions = {}; + + function isInstalled(version) { + var isVersionSupported = false, control = null, actualVer, + actualVerArray, reqVerArray, requiredVersionPart, actualVersionPart, index = 0; + + try { + try { + control = new ActiveXObject('AgControl.AgControl'); + + if (control.IsVersionSupported(version)) { + isVersionSupported = true; + } + + control = null; + } catch (e) { + var plugin = navigator.plugins["Silverlight Plug-In"]; + + if (plugin) { + actualVer = plugin.description; + + if (actualVer === "1.0.30226.2") { + actualVer = "2.0.30226.2"; + } + + actualVerArray = actualVer.split("."); + + while (actualVerArray.length > 3) { + actualVerArray.pop(); + } + + while ( actualVerArray.length < 4) { + actualVerArray.push(0); + } + + reqVerArray = version.split("."); + + while (reqVerArray.length > 4) { + reqVerArray.pop(); + } + + do { + requiredVersionPart = parseInt(reqVerArray[index], 10); + actualVersionPart = parseInt(actualVerArray[index], 10); + index++; + } while (index < reqVerArray.length && requiredVersionPart === actualVersionPart); + + if (requiredVersionPart <= actualVersionPart && !isNaN(requiredVersionPart)) { + isVersionSupported = true; + } + } + } + } catch (e2) { + isVersionSupported = false; + } + + return isVersionSupported; + } + + /** + Constructor for the Silverlight Runtime + + @class SilverlightRuntime + @extends Runtime + */ + function SilverlightRuntime(options) { + var I = this, initTimer; + + options = Basic.extend({ xap_url: Env.xap_url }, options); + + Runtime.call(this, options, type, { + access_binary: Runtime.capTrue, + access_image_binary: Runtime.capTrue, + display_media: Runtime.capTest(defined('moxie/image/Image')), + do_cors: Runtime.capTrue, + drag_and_drop: false, + report_upload_progress: Runtime.capTrue, + resize_image: Runtime.capTrue, + return_response_headers: function(value) { + return value && I.mode === 'client'; + }, + return_response_type: function(responseType) { + if (responseType !== 'json') { + return true; + } else { + return !!window.JSON; + } + }, + return_status_code: function(code) { + return I.mode === 'client' || !Basic.arrayDiff(code, [200, 404]); + }, + select_file: Runtime.capTrue, + select_multiple: Runtime.capTrue, + send_binary_string: Runtime.capTrue, + send_browser_cookies: function(value) { + return value && I.mode === 'browser'; + }, + send_custom_headers: function(value) { + return value && I.mode === 'client'; + }, + send_multipart: Runtime.capTrue, + slice_blob: Runtime.capTrue, + stream_upload: true, + summon_file_dialog: false, + upload_filesize: Runtime.capTrue, + use_http_method: function(methods) { + return I.mode === 'client' || !Basic.arrayDiff(methods, ['GET', 'POST']); + } + }, { + // capabilities that require specific mode + return_response_headers: function(value) { + return value ? 'client' : 'browser'; + }, + return_status_code: function(code) { + return Basic.arrayDiff(code, [200, 404]) ? 'client' : ['client', 'browser']; + }, + send_browser_cookies: function(value) { + return value ? 'browser' : 'client'; + }, + send_custom_headers: function(value) { + return value ? 'client' : 'browser'; + }, + use_http_method: function(methods) { + return Basic.arrayDiff(methods, ['GET', 'POST']) ? 'client' : ['client', 'browser']; + } + }); + + + // minimal requirement + if (!isInstalled('2.0.31005.0') || Env.browser === 'Opera') { + if (MXI_DEBUG && Env.debug.runtime) { + Env.log("\tSilverlight is not installed or minimal version (2.0.31005.0) requirement not met (not likely)."); + } + + this.mode = false; + } + + + Basic.extend(this, { + getShim: function() { + return Dom.get(this.uid).content.Moxie; + }, + + shimExec: function(component, action) { + var args = [].slice.call(arguments, 2); + return I.getShim().exec(this.uid, component, action, args); + }, + + init : function() { + var container; + + container = this.getShimContainer(); + + container.innerHTML = '' + + '' + + '' + + '' + + '' + + '' + + ''; + + // Init is dispatched by the shim + initTimer = setTimeout(function() { + if (I && !I.initialized) { // runtime might be already destroyed by this moment + I.trigger("Error", new x.RuntimeError(x.RuntimeError.NOT_INIT_ERR)); + + if (MXI_DEBUG && Env.debug.runtime) { + Env.log("\Silverlight failed to initialize within a specified period of time (5-10s)."); + } + } + }, Env.OS !== 'Windows'? 10000 : 5000); // give it more time to initialize in non Windows OS (like Mac) + }, + + destroy: (function(destroy) { // extend default destroy method + return function() { + destroy.call(I); + clearTimeout(initTimer); // initialization check might be still onwait + options = initTimer = destroy = I = null; + }; + }(this.destroy)) + + }, extensions); + } + + Runtime.addConstructor(type, SilverlightRuntime); + + return extensions; +}); + +// Included from: src/javascript/runtime/silverlight/file/Blob.js + +/** + * Blob.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/silverlight/file/Blob +@private +*/ +define("moxie/runtime/silverlight/file/Blob", [ + "moxie/runtime/silverlight/Runtime", + "moxie/core/utils/Basic", + "moxie/runtime/flash/file/Blob" +], function(extensions, Basic, Blob) { + return (extensions.Blob = Basic.extend({}, Blob)); +}); + +// Included from: src/javascript/runtime/silverlight/file/FileInput.js + +/** + * FileInput.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/silverlight/file/FileInput +@private +*/ +define("moxie/runtime/silverlight/file/FileInput", [ + "moxie/runtime/silverlight/Runtime", + "moxie/file/File", + "moxie/core/utils/Basic" +], function(extensions, File, Basic) { + + function toFilters(accept) { + var filter = ''; + for (var i = 0; i < accept.length; i++) { + filter += (filter !== '' ? '|' : '') + accept[i].title + " | *." + accept[i].extensions.replace(/,/g, ';*.'); + } + return filter; + } + + + var FileInput = { + init: function(options) { + var comp = this, I = this.getRuntime(); + + this.bind("Change", function() { + var files = I.shimExec.call(comp, 'FileInput', 'getFiles'); + comp.files = []; + Basic.each(files, function(file) { + comp.files.push(new File(I.uid, file)); + }); + }, 999); + + I.shimExec.call(this, 'FileInput', 'init', toFilters(options.accept), options.multiple); + this.trigger('ready'); + }, + + setOption: function(name, value) { + if (name == 'accept') { + value = toFilters(value); + } + this.getRuntime().shimExec.call(this, 'FileInput', 'setOption', name, value); + } + }; + + return (extensions.FileInput = FileInput); +}); + +// Included from: src/javascript/runtime/silverlight/file/FileDrop.js + +/** + * FileDrop.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/silverlight/file/FileDrop +@private +*/ +define("moxie/runtime/silverlight/file/FileDrop", [ + "moxie/runtime/silverlight/Runtime", + "moxie/core/utils/Dom", + "moxie/core/utils/Events" +], function(extensions, Dom, Events) { + + // not exactly useful, since works only in safari (...crickets...) + var FileDrop = { + init: function() { + var comp = this, self = comp.getRuntime(), dropZone; + + dropZone = self.getShimContainer(); + + Events.addEvent(dropZone, 'dragover', function(e) { + e.preventDefault(); + e.stopPropagation(); + e.dataTransfer.dropEffect = 'copy'; + }, comp.uid); + + Events.addEvent(dropZone, 'dragenter', function(e) { + e.preventDefault(); + var flag = Dom.get(self.uid).dragEnter(e); + // If handled, then stop propagation of event in DOM + if (flag) { + e.stopPropagation(); + } + }, comp.uid); + + Events.addEvent(dropZone, 'drop', function(e) { + e.preventDefault(); + var flag = Dom.get(self.uid).dragDrop(e); + // If handled, then stop propagation of event in DOM + if (flag) { + e.stopPropagation(); + } + }, comp.uid); + + return self.shimExec.call(this, 'FileDrop', 'init'); + } + }; + + return (extensions.FileDrop = FileDrop); +}); + +// Included from: src/javascript/runtime/silverlight/file/FileReader.js + +/** + * FileReader.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/silverlight/file/FileReader +@private +*/ +define("moxie/runtime/silverlight/file/FileReader", [ + "moxie/runtime/silverlight/Runtime", + "moxie/core/utils/Basic", + "moxie/runtime/flash/file/FileReader" +], function(extensions, Basic, FileReader) { + return (extensions.FileReader = Basic.extend({}, FileReader)); +}); + +// Included from: src/javascript/runtime/silverlight/file/FileReaderSync.js + +/** + * FileReaderSync.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/silverlight/file/FileReaderSync +@private +*/ +define("moxie/runtime/silverlight/file/FileReaderSync", [ + "moxie/runtime/silverlight/Runtime", + "moxie/core/utils/Basic", + "moxie/runtime/flash/file/FileReaderSync" +], function(extensions, Basic, FileReaderSync) { + return (extensions.FileReaderSync = Basic.extend({}, FileReaderSync)); +}); + +// Included from: src/javascript/runtime/silverlight/runtime/Transporter.js + +/** + * Transporter.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/silverlight/runtime/Transporter +@private +*/ +define("moxie/runtime/silverlight/runtime/Transporter", [ + "moxie/runtime/silverlight/Runtime", + "moxie/core/utils/Basic", + "moxie/runtime/flash/runtime/Transporter" +], function(extensions, Basic, Transporter) { + return (extensions.Transporter = Basic.extend({}, Transporter)); +}); + +// Included from: src/javascript/runtime/silverlight/xhr/XMLHttpRequest.js + +/** + * XMLHttpRequest.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/silverlight/xhr/XMLHttpRequest +@private +*/ +define("moxie/runtime/silverlight/xhr/XMLHttpRequest", [ + "moxie/runtime/silverlight/Runtime", + "moxie/core/utils/Basic", + "moxie/runtime/flash/xhr/XMLHttpRequest", + "moxie/runtime/silverlight/file/FileReaderSync", + "moxie/runtime/silverlight/runtime/Transporter" +], function(extensions, Basic, XMLHttpRequest, FileReaderSyncSilverlight, TransporterSilverlight) { + return (extensions.XMLHttpRequest = Basic.extend({}, XMLHttpRequest)); +}); + +// Included from: src/javascript/runtime/silverlight/image/Image.js + +/** + * Image.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/silverlight/image/Image +@private +*/ +define("moxie/runtime/silverlight/image/Image", [ + "moxie/runtime/silverlight/Runtime", + "moxie/core/utils/Basic", + "moxie/file/Blob", + "moxie/runtime/flash/image/Image" +], function(extensions, Basic, Blob, Image) { + return (extensions.Image = Basic.extend({}, Image, { + + getInfo: function() { + var self = this.getRuntime() + , grps = ['tiff', 'exif', 'gps', 'thumb'] + , info = { meta: {} } + , rawInfo = self.shimExec.call(this, 'Image', 'getInfo') + ; + + if (rawInfo.meta) { + Basic.each(grps, function(grp) { + var meta = rawInfo.meta[grp] + , tag + , i + , length + , value + ; + if (meta && meta.keys) { + info.meta[grp] = {}; + for (i = 0, length = meta.keys.length; i < length; i++) { + tag = meta.keys[i]; + value = meta[tag]; + if (value) { + // convert numbers + if (/^(\d|[1-9]\d+)$/.test(value)) { // integer (make sure doesn't start with zero) + value = parseInt(value, 10); + } else if (/^\d*\.\d+$/.test(value)) { // double + value = parseFloat(value); + } + info.meta[grp][tag] = value; + } + } + } + }); + + // save thumb data as blob + if (info.meta && info.meta.thumb && info.meta.thumb.data && !(self.meta.thumb.data instanceof Blob)) { + info.meta.thumb.data = new Blob(self.uid, info.meta.thumb.data); + } + } + + info.width = parseInt(rawInfo.width, 10); + info.height = parseInt(rawInfo.height, 10); + info.size = parseInt(rawInfo.size, 10); + info.type = rawInfo.type; + info.name = rawInfo.name; + + return info; + }, + + resize: function(rect, ratio, opts) { + this.getRuntime().shimExec.call(this, 'Image', 'resize', rect.x, rect.y, rect.width, rect.height, ratio, opts.preserveHeaders, opts.resample); + } + })); +}); + +// Included from: src/javascript/runtime/html4/Runtime.js + +/** + * Runtime.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/*global File:true */ + +/** +Defines constructor for HTML4 runtime. + +@class moxie/runtime/html4/Runtime +@private +*/ +define("moxie/runtime/html4/Runtime", [ + "moxie/core/utils/Basic", + "moxie/core/Exceptions", + "moxie/runtime/Runtime", + "moxie/core/utils/Env" +], function(Basic, x, Runtime, Env) { + + var type = 'html4', extensions = {}; + + function Html4Runtime(options) { + var I = this + , Test = Runtime.capTest + , True = Runtime.capTrue + ; + + Runtime.call(this, options, type, { + access_binary: Test(window.FileReader || window.File && File.getAsDataURL), + access_image_binary: false, + display_media: Test( + (Env.can('create_canvas') || Env.can('use_data_uri_over32kb')) && + defined('moxie/image/Image') + ), + do_cors: false, + drag_and_drop: false, + filter_by_extension: Test(function() { // if you know how to feature-detect this, please suggest + return !( + (Env.browser === 'Chrome' && Env.verComp(Env.version, 28, '<')) || + (Env.browser === 'IE' && Env.verComp(Env.version, 10, '<')) || + (Env.browser === 'Safari' && Env.verComp(Env.version, 7, '<')) || + (Env.browser === 'Firefox' && Env.verComp(Env.version, 37, '<')) + ); + }()), + resize_image: function() { + return extensions.Image && I.can('access_binary') && Env.can('create_canvas'); + }, + report_upload_progress: false, + return_response_headers: false, + return_response_type: function(responseType) { + if (responseType === 'json' && !!window.JSON) { + return true; + } + return !!~Basic.inArray(responseType, ['text', 'document', '']); + }, + return_status_code: function(code) { + return !Basic.arrayDiff(code, [200, 404]); + }, + select_file: function() { + return Env.can('use_fileinput'); + }, + select_multiple: false, + send_binary_string: false, + send_custom_headers: false, + send_multipart: true, + slice_blob: false, + stream_upload: function() { + return I.can('select_file'); + }, + summon_file_dialog: function() { // yeah... some dirty sniffing here... + return I.can('select_file') && ( + (Env.browser === 'Firefox' && Env.verComp(Env.version, 4, '>=')) || + (Env.browser === 'Opera' && Env.verComp(Env.version, 12, '>=')) || + (Env.browser === 'IE' && Env.verComp(Env.version, 10, '>=')) || + !!~Basic.inArray(Env.browser, ['Chrome', 'Safari']) + ); + }, + upload_filesize: True, + use_http_method: function(methods) { + return !Basic.arrayDiff(methods, ['GET', 'POST']); + } + }); + + + Basic.extend(this, { + init : function() { + this.trigger("Init"); + }, + + destroy: (function(destroy) { // extend default destroy method + return function() { + destroy.call(I); + destroy = I = null; + }; + }(this.destroy)) + }); + + Basic.extend(this.getShim(), extensions); + } + + Runtime.addConstructor(type, Html4Runtime); + + return extensions; +}); + +// Included from: src/javascript/runtime/html4/file/FileInput.js + +/** + * FileInput.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/html4/file/FileInput +@private +*/ +define("moxie/runtime/html4/file/FileInput", [ + "moxie/runtime/html4/Runtime", + "moxie/file/File", + "moxie/core/utils/Basic", + "moxie/core/utils/Dom", + "moxie/core/utils/Events", + "moxie/core/utils/Mime", + "moxie/core/utils/Env" +], function(extensions, File, Basic, Dom, Events, Mime, Env) { + + function FileInput() { + var _uid, _mimes = [], _options, _browseBtnZIndex; // save original z-index; + + function addInput() { + var comp = this, I = comp.getRuntime(), shimContainer, browseButton, currForm, form, input, uid; + + uid = Basic.guid('uid_'); + + shimContainer = I.getShimContainer(); // we get new ref every time to avoid memory leaks in IE + + if (_uid) { // move previous form out of the view + currForm = Dom.get(_uid + '_form'); + if (currForm) { + Basic.extend(currForm.style, { top: '100%' }); + } + } + + // build form in DOM, since innerHTML version not able to submit file for some reason + form = document.createElement('form'); + form.setAttribute('id', uid + '_form'); + form.setAttribute('method', 'post'); + form.setAttribute('enctype', 'multipart/form-data'); + form.setAttribute('encoding', 'multipart/form-data'); + + Basic.extend(form.style, { + overflow: 'hidden', + position: 'absolute', + top: 0, + left: 0, + width: '100%', + height: '100%' + }); + + input = document.createElement('input'); + input.setAttribute('id', uid); + input.setAttribute('type', 'file'); + input.setAttribute('accept', _mimes.join(',')); + + Basic.extend(input.style, { + fontSize: '999px', + opacity: 0 + }); + + form.appendChild(input); + shimContainer.appendChild(form); + + // prepare file input to be placed underneath the browse_button element + Basic.extend(input.style, { + position: 'absolute', + top: 0, + left: 0, + width: '100%', + height: '100%' + }); + + if (Env.browser === 'IE' && Env.verComp(Env.version, 10, '<')) { + Basic.extend(input.style, { + filter : "progid:DXImageTransform.Microsoft.Alpha(opacity=0)" + }); + } + + input.onchange = function() { // there should be only one handler for this + var file; + + if (!this.value) { + return; + } + + if (this.files) { // check if browser is fresh enough + file = this.files[0]; + + // ignore empty files (IE10 for example hangs if you try to send them via XHR) + if (file.size === 0) { + form.parentNode.removeChild(form); + return; + } + } else { + file = { + name: this.value + }; + } + + file = new File(I.uid, file); + + // clear event handler + this.onchange = function() {}; + addInput.call(comp); + + comp.files = [file]; + + // substitute all ids with file uids (consider file.uid read-only - we cannot do it the other way around) + input.setAttribute('id', file.uid); + form.setAttribute('id', file.uid + '_form'); + + comp.trigger('change'); + + input = form = null; + }; + + + // route click event to the input + if (I.can('summon_file_dialog')) { + browseButton = Dom.get(_options.browse_button); + Events.removeEvent(browseButton, 'click', comp.uid); + Events.addEvent(browseButton, 'click', function(e) { + if (input && !input.disabled) { // for some reason FF (up to 8.0.1 so far) lets to click disabled input[type=file] + input.click(); + } + e.preventDefault(); + }, comp.uid); + } + + _uid = uid; + + shimContainer = currForm = browseButton = null; + } + + Basic.extend(this, { + init: function(options) { + var comp = this, I = comp.getRuntime(), shimContainer; + + // figure out accept string + _options = options; + _mimes = options.accept.mimes || Mime.extList2mimes(options.accept, I.can('filter_by_extension')); + + shimContainer = I.getShimContainer(); + + (function() { + var browseButton, zIndex, top; + + browseButton = Dom.get(options.browse_button); + _browseBtnZIndex = Dom.getStyle(browseButton, 'z-index') || 'auto'; + + // Route click event to the input[type=file] element for browsers that support such behavior + if (I.can('summon_file_dialog')) { + if (Dom.getStyle(browseButton, 'position') === 'static') { + browseButton.style.position = 'relative'; + } + + comp.bind('Refresh', function() { + zIndex = parseInt(_browseBtnZIndex, 10) || 1; + + Dom.get(_options.browse_button).style.zIndex = zIndex; + this.getRuntime().getShimContainer().style.zIndex = zIndex - 1; + }); + } + + /* Since we have to place input[type=file] on top of the browse_button for some browsers, + browse_button loses interactivity, so we restore it here */ + top = I.can('summon_file_dialog') ? browseButton : shimContainer; + + Events.addEvent(top, 'mouseover', function() { + comp.trigger('mouseenter'); + }, comp.uid); + + Events.addEvent(top, 'mouseout', function() { + comp.trigger('mouseleave'); + }, comp.uid); + + Events.addEvent(top, 'mousedown', function() { + comp.trigger('mousedown'); + }, comp.uid); + + Events.addEvent(Dom.get(options.container), 'mouseup', function() { + comp.trigger('mouseup'); + }, comp.uid); + + browseButton = null; + }()); + + addInput.call(this); + + shimContainer = null; + + // trigger ready event asynchronously + comp.trigger({ + type: 'ready', + async: true + }); + }, + + setOption: function(name, value) { + var I = this.getRuntime(); + var input; + + if (name == 'accept') { + _mimes = value.mimes || Mime.extList2mimes(value, I.can('filter_by_extension')); + } + + // update current input + input = Dom.get(_uid) + if (input) { + input.setAttribute('accept', _mimes.join(',')); + } + }, + + + disable: function(state) { + var input; + + if ((input = Dom.get(_uid))) { + input.disabled = !!state; + } + }, + + destroy: function() { + var I = this.getRuntime() + , shim = I.getShim() + , shimContainer = I.getShimContainer() + , container = _options && Dom.get(_options.container) + , browseButton = _options && Dom.get(_options.browse_button) + ; + + if (container) { + Events.removeAllEvents(container, this.uid); + } + + if (browseButton) { + Events.removeAllEvents(browseButton, this.uid); + browseButton.style.zIndex = _browseBtnZIndex; // reset to original value + } + + if (shimContainer) { + Events.removeAllEvents(shimContainer, this.uid); + shimContainer.innerHTML = ''; + } + + shim.removeInstance(this.uid); + + _uid = _mimes = _options = shimContainer = container = browseButton = shim = null; + } + }); + } + + return (extensions.FileInput = FileInput); +}); + +// Included from: src/javascript/runtime/html4/file/FileReader.js + +/** + * FileReader.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/html4/file/FileReader +@private +*/ +define("moxie/runtime/html4/file/FileReader", [ + "moxie/runtime/html4/Runtime", + "moxie/runtime/html5/file/FileReader" +], function(extensions, FileReader) { + return (extensions.FileReader = FileReader); +}); + +// Included from: src/javascript/runtime/html4/xhr/XMLHttpRequest.js + +/** + * XMLHttpRequest.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/html4/xhr/XMLHttpRequest +@private +*/ +define("moxie/runtime/html4/xhr/XMLHttpRequest", [ + "moxie/runtime/html4/Runtime", + "moxie/core/utils/Basic", + "moxie/core/utils/Dom", + "moxie/core/utils/Url", + "moxie/core/Exceptions", + "moxie/core/utils/Events", + "moxie/file/Blob", + "moxie/xhr/FormData" +], function(extensions, Basic, Dom, Url, x, Events, Blob, FormData) { + + function XMLHttpRequest() { + var _status, _response, _iframe; + + function cleanup(cb) { + var target = this, uid, form, inputs, i, hasFile = false; + + if (!_iframe) { + return; + } + + uid = _iframe.id.replace(/_iframe$/, ''); + + form = Dom.get(uid + '_form'); + if (form) { + inputs = form.getElementsByTagName('input'); + i = inputs.length; + + while (i--) { + switch (inputs[i].getAttribute('type')) { + case 'hidden': + inputs[i].parentNode.removeChild(inputs[i]); + break; + case 'file': + hasFile = true; // flag the case for later + break; + } + } + inputs = []; + + if (!hasFile) { // we need to keep the form for sake of possible retries + form.parentNode.removeChild(form); + } + form = null; + } + + // without timeout, request is marked as canceled (in console) + setTimeout(function() { + Events.removeEvent(_iframe, 'load', target.uid); + if (_iframe.parentNode) { // #382 + _iframe.parentNode.removeChild(_iframe); + } + + // check if shim container has any other children, if - not, remove it as well + var shimContainer = target.getRuntime().getShimContainer(); + if (!shimContainer.children.length) { + shimContainer.parentNode.removeChild(shimContainer); + } + + shimContainer = _iframe = null; + cb(); + }, 1); + } + + Basic.extend(this, { + send: function(meta, data) { + var target = this, I = target.getRuntime(), uid, form, input, blob; + + _status = _response = null; + + function createIframe() { + var container = I.getShimContainer() || document.body + , temp = document.createElement('div') + ; + + // IE 6 won't be able to set the name using setAttribute or iframe.name + temp.innerHTML = ''; + _iframe = temp.firstChild; + container.appendChild(_iframe); + + /* _iframe.onreadystatechange = function() { + console.info(_iframe.readyState); + };*/ + + Events.addEvent(_iframe, 'load', function() { // _iframe.onload doesn't work in IE lte 8 + var el; + + try { + el = _iframe.contentWindow.document || _iframe.contentDocument || window.frames[_iframe.id].document; + + // try to detect some standard error pages + if (/^4(0[0-9]|1[0-7]|2[2346])\s/.test(el.title)) { // test if title starts with 4xx HTTP error + _status = el.title.replace(/^(\d+).*$/, '$1'); + } else { + _status = 200; + // get result + _response = Basic.trim(el.body.innerHTML); + + // we need to fire these at least once + target.trigger({ + type: 'progress', + loaded: _response.length, + total: _response.length + }); + + if (blob) { // if we were uploading a file + target.trigger({ + type: 'uploadprogress', + loaded: blob.size || 1025, + total: blob.size || 1025 + }); + } + } + } catch (ex) { + if (Url.hasSameOrigin(meta.url)) { + // if response is sent with error code, iframe in IE gets redirected to res://ieframe.dll/http_x.htm + // which obviously results to cross domain error (wtf?) + _status = 404; + } else { + cleanup.call(target, function() { + target.trigger('error'); + }); + return; + } + } + + cleanup.call(target, function() { + target.trigger('load'); + }); + }, target.uid); + } // end createIframe + + // prepare data to be sent and convert if required + if (data instanceof FormData && data.hasBlob()) { + blob = data.getBlob(); + uid = blob.uid; + input = Dom.get(uid); + form = Dom.get(uid + '_form'); + if (!form) { + throw new x.DOMException(x.DOMException.NOT_FOUND_ERR); + } + } else { + uid = Basic.guid('uid_'); + + form = document.createElement('form'); + form.setAttribute('id', uid + '_form'); + form.setAttribute('method', meta.method); + form.setAttribute('enctype', 'multipart/form-data'); + form.setAttribute('encoding', 'multipart/form-data'); + + I.getShimContainer().appendChild(form); + } + + // set upload target + form.setAttribute('target', uid + '_iframe'); + + if (data instanceof FormData) { + data.each(function(value, name) { + if (value instanceof Blob) { + if (input) { + input.setAttribute('name', name); + } + } else { + var hidden = document.createElement('input'); + + Basic.extend(hidden, { + type : 'hidden', + name : name, + value : value + }); + + // make sure that input[type="file"], if it's there, comes last + if (input) { + form.insertBefore(hidden, input); + } else { + form.appendChild(hidden); + } + } + }); + } + + // set destination url + form.setAttribute("action", meta.url); + + createIframe(); + form.submit(); + target.trigger('loadstart'); + }, + + getStatus: function() { + return _status; + }, + + getResponse: function(responseType) { + if ('json' === responseType) { + // strip off
..
tags that might be enclosing the response + if (Basic.typeOf(_response) === 'string' && !!window.JSON) { + try { + return JSON.parse(_response.replace(/^\s*]*>/, '').replace(/<\/pre>\s*$/, '')); + } catch (ex) { + return null; + } + } + } else if ('document' === responseType) { + + } + return _response; + }, + + abort: function() { + var target = this; + + if (_iframe && _iframe.contentWindow) { + if (_iframe.contentWindow.stop) { // FireFox/Safari/Chrome + _iframe.contentWindow.stop(); + } else if (_iframe.contentWindow.document.execCommand) { // IE + _iframe.contentWindow.document.execCommand('Stop'); + } else { + _iframe.src = "about:blank"; + } + } + + cleanup.call(this, function() { + // target.dispatchEvent('readystatechange'); + target.dispatchEvent('abort'); + }); + } + }); + } + + return (extensions.XMLHttpRequest = XMLHttpRequest); +}); + +// Included from: src/javascript/runtime/html4/image/Image.js + +/** + * Image.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/html4/image/Image +@private +*/ +define("moxie/runtime/html4/image/Image", [ + "moxie/runtime/html4/Runtime", + "moxie/runtime/html5/image/Image" +], function(extensions, Image) { + return (extensions.Image = Image); +}); + +expose(["moxie/core/utils/Basic","moxie/core/utils/Encode","moxie/core/utils/Env","moxie/core/Exceptions","moxie/core/utils/Dom","moxie/core/EventTarget","moxie/runtime/Runtime","moxie/runtime/RuntimeClient","moxie/file/Blob","moxie/core/I18n","moxie/core/utils/Mime","moxie/file/FileInput","moxie/file/File","moxie/file/FileDrop","moxie/file/FileReader","moxie/core/utils/Url","moxie/runtime/RuntimeTarget","moxie/xhr/FormData","moxie/xhr/XMLHttpRequest","moxie/runtime/Transporter","moxie/image/Image","moxie/core/utils/Events","moxie/runtime/html5/image/ResizerCanvas"]); +})(this); +})); \ No newline at end of file diff --git a/static/js/uploader/plupload.dev.js b/static/js/uploader/plupload.dev.js new file mode 100644 index 00000000..24fc8565 --- /dev/null +++ b/static/js/uploader/plupload.dev.js @@ -0,0 +1,2476 @@ +/** + * Plupload - multi-runtime File Uploader + * v2.3.1 + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + * + * Date: 2017-02-06 + */ +;(function (global, factory) { + var extract = function() { + var ctx = {}; + factory.apply(ctx, arguments); + return ctx.plupload; + }; + + if (typeof define === "function" && define.amd) { + define("plupload", ['./moxie'], extract); + } else if (typeof module === "object" && module.exports) { + module.exports = extract(require('../../../js-sdk-master 2/src/moxie')); + } else { + global.plupload = extract(global.moxie); + } +}(this || window, function(moxie) { +/** + * Plupload.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +;(function(exports, o, undef) { + +var delay = window.setTimeout; +var fileFilters = {}; +var u = o.core.utils; +var Runtime = o.runtime.Runtime; + +// convert plupload features to caps acceptable by mOxie +function normalizeCaps(settings) { + var features = settings.required_features, caps = {}; + + function resolve(feature, value, strict) { + // Feature notation is deprecated, use caps (this thing here is required for backward compatibility) + var map = { + chunks: 'slice_blob', + jpgresize: 'send_binary_string', + pngresize: 'send_binary_string', + progress: 'report_upload_progress', + multi_selection: 'select_multiple', + dragdrop: 'drag_and_drop', + drop_element: 'drag_and_drop', + headers: 'send_custom_headers', + urlstream_upload: 'send_binary_string', + canSendBinary: 'send_binary', + triggerDialog: 'summon_file_dialog' + }; + + if (map[feature]) { + caps[map[feature]] = value; + } else if (!strict) { + caps[feature] = value; + } + } + + if (typeof(features) === 'string') { + plupload.each(features.split(/\s*,\s*/), function(feature) { + resolve(feature, true); + }); + } else if (typeof(features) === 'object') { + plupload.each(features, function(value, feature) { + resolve(feature, value); + }); + } else if (features === true) { + // check settings for required features + if (settings.chunk_size && settings.chunk_size > 0) { + caps.slice_blob = true; + } + + if (!plupload.isEmptyObj(settings.resize) || settings.multipart === false) { + caps.send_binary_string = true; + } + + if (settings.http_method) { + caps.use_http_method = settings.http_method; + } + + plupload.each(settings, function(value, feature) { + resolve(feature, !!value, true); // strict check + }); + } + + return caps; +} + +/** + * @module plupload + * @static + */ +var plupload = { + /** + * Plupload version will be replaced on build. + * + * @property VERSION + * @for Plupload + * @static + * @final + */ + VERSION : '2.3.1', + + /** + * The state of the queue before it has started and after it has finished + * + * @property STOPPED + * @static + * @final + */ + STOPPED : 1, + + /** + * Upload process is running + * + * @property STARTED + * @static + * @final + */ + STARTED : 2, + + /** + * File is queued for upload + * + * @property QUEUED + * @static + * @final + */ + QUEUED : 1, + + /** + * File is being uploaded + * + * @property UPLOADING + * @static + * @final + */ + UPLOADING : 2, + + /** + * File has failed to be uploaded + * + * @property FAILED + * @static + * @final + */ + FAILED : 4, + + /** + * File has been uploaded successfully + * + * @property DONE + * @static + * @final + */ + DONE : 5, + + // Error constants used by the Error event + + /** + * Generic error for example if an exception is thrown inside Silverlight. + * + * @property GENERIC_ERROR + * @static + * @final + */ + GENERIC_ERROR : -100, + + /** + * HTTP transport error. For example if the server produces a HTTP status other than 200. + * + * @property HTTP_ERROR + * @static + * @final + */ + HTTP_ERROR : -200, + + /** + * Generic I/O error. For example if it wasn't possible to open the file stream on local machine. + * + * @property IO_ERROR + * @static + * @final + */ + IO_ERROR : -300, + + /** + * @property SECURITY_ERROR + * @static + * @final + */ + SECURITY_ERROR : -400, + + /** + * Initialization error. Will be triggered if no runtime was initialized. + * + * @property INIT_ERROR + * @static + * @final + */ + INIT_ERROR : -500, + + /** + * File size error. If the user selects a file that is too large it will be blocked and an error of this type will be triggered. + * + * @property FILE_SIZE_ERROR + * @static + * @final + */ + FILE_SIZE_ERROR : -600, + + /** + * File extension error. If the user selects a file that isn't valid according to the filters setting. + * + * @property FILE_EXTENSION_ERROR + * @static + * @final + */ + FILE_EXTENSION_ERROR : -601, + + /** + * Duplicate file error. If prevent_duplicates is set to true and user selects the same file again. + * + * @property FILE_DUPLICATE_ERROR + * @static + * @final + */ + FILE_DUPLICATE_ERROR : -602, + + /** + * Runtime will try to detect if image is proper one. Otherwise will throw this error. + * + * @property IMAGE_FORMAT_ERROR + * @static + * @final + */ + IMAGE_FORMAT_ERROR : -700, + + /** + * While working on files runtime may run out of memory and will throw this error. + * + * @since 2.1.2 + * @property MEMORY_ERROR + * @static + * @final + */ + MEMORY_ERROR : -701, + + /** + * Each runtime has an upper limit on a dimension of the image it can handle. If bigger, will throw this error. + * + * @property IMAGE_DIMENSIONS_ERROR + * @static + * @final + */ + IMAGE_DIMENSIONS_ERROR : -702, + + /** + * Mime type lookup table. + * + * @property mimeTypes + * @type Object + * @final + */ + mimeTypes : u.Mime.mimes, + + /** + * In some cases sniffing is the only way around :( + */ + ua: u.Env, + + /** + * Gets the true type of the built-in object (better version of typeof). + * @credits Angus Croll (http://javascriptweblog.wordpress.com/) + * + * @method typeOf + * @static + * @param {Object} o Object to check. + * @return {String} Object [[Class]] + */ + typeOf: u.Basic.typeOf, + + /** + * Extends the specified object with another object. + * + * @method extend + * @static + * @param {Object} target Object to extend. + * @param {Object..} obj Multiple objects to extend with. + * @return {Object} Same as target, the extended object. + */ + extend : u.Basic.extend, + + /** + * Generates an unique ID. This is 99.99% unique since it takes the current time and 5 random numbers. + * The only way a user would be able to get the same ID is if the two persons at the same exact millisecond manages + * to get 5 the same random numbers between 0-65535 it also uses a counter so each call will be guaranteed to be page unique. + * It's more probable for the earth to be hit with an asteriod. You can also if you want to be 100% sure set the plupload.guidPrefix property + * to an user unique key. + * + * @method guid + * @static + * @return {String} Virtually unique id. + */ + guid : u.Basic.guid, + + /** + * Get array of DOM Elements by their ids. + * + * @method get + * @param {String} id Identifier of the DOM Element + * @return {Array} + */ + getAll : function get(ids) { + var els = [], el; + + if (plupload.typeOf(ids) !== 'array') { + ids = [ids]; + } + + var i = ids.length; + while (i--) { + el = plupload.get(ids[i]); + if (el) { + els.push(el); + } + } + + return els.length ? els : null; + }, + + /** + Get DOM element by id + + @method get + @param {String} id Identifier of the DOM Element + @return {Node} + */ + get: u.Dom.get, + + /** + * Executes the callback function for each item in array/object. If you return false in the + * callback it will break the loop. + * + * @method each + * @static + * @param {Object} obj Object to iterate. + * @param {function} callback Callback function to execute for each item. + */ + each : u.Basic.each, + + /** + * Returns the absolute x, y position of an Element. The position will be returned in a object with x, y fields. + * + * @method getPos + * @static + * @param {Element} node HTML element or element id to get x, y position from. + * @param {Element} root Optional root element to stop calculations at. + * @return {object} Absolute position of the specified element object with x, y fields. + */ + getPos : u.Dom.getPos, + + /** + * Returns the size of the specified node in pixels. + * + * @method getSize + * @static + * @param {Node} node Node to get the size of. + * @return {Object} Object with a w and h property. + */ + getSize : u.Dom.getSize, + + /** + * Encodes the specified string. + * + * @method xmlEncode + * @static + * @param {String} s String to encode. + * @return {String} Encoded string. + */ + xmlEncode : function(str) { + var xmlEncodeChars = {'<' : 'lt', '>' : 'gt', '&' : 'amp', '"' : 'quot', '\'' : '#39'}, xmlEncodeRegExp = /[<>&\"\']/g; + + return str ? ('' + str).replace(xmlEncodeRegExp, function(chr) { + return xmlEncodeChars[chr] ? '&' + xmlEncodeChars[chr] + ';' : chr; + }) : str; + }, + + /** + * Forces anything into an array. + * + * @method toArray + * @static + * @param {Object} obj Object with length field. + * @return {Array} Array object containing all items. + */ + toArray : u.Basic.toArray, + + /** + * Find an element in array and return its index if present, otherwise return -1. + * + * @method inArray + * @static + * @param {mixed} needle Element to find + * @param {Array} array + * @return {Int} Index of the element, or -1 if not found + */ + inArray : u.Basic.inArray, + + /** + Recieve an array of functions (usually async) to call in sequence, each function + receives a callback as first argument that it should call, when it completes. Finally, + after everything is complete, main callback is called. Passing truthy value to the + callback as a first argument will interrupt the sequence and invoke main callback + immediately. + + @method inSeries + @static + @param {Array} queue Array of functions to call in sequence + @param {Function} cb Main callback that is called in the end, or in case of error + */ + inSeries: u.Basic.inSeries, + + /** + * Extends the language pack object with new items. + * + * @method addI18n + * @static + * @param {Object} pack Language pack items to add. + * @return {Object} Extended language pack object. + */ + addI18n : o.core.I18n.addI18n, + + /** + * Translates the specified string by checking for the english string in the language pack lookup. + * + * @method translate + * @static + * @param {String} str String to look for. + * @return {String} Translated string or the input string if it wasn't found. + */ + translate : o.core.I18n.translate, + + /** + * Pseudo sprintf implementation - simple way to replace tokens with specified values. + * + * @param {String} str String with tokens + * @return {String} String with replaced tokens + */ + sprintf : u.Basic.sprintf, + + /** + * Checks if object is empty. + * + * @method isEmptyObj + * @static + * @param {Object} obj Object to check. + * @return {Boolean} + */ + isEmptyObj : u.Basic.isEmptyObj, + + /** + * Checks if specified DOM element has specified class. + * + * @method hasClass + * @static + * @param {Object} obj DOM element like object to add handler to. + * @param {String} name Class name + */ + hasClass : u.Dom.hasClass, + + /** + * Adds specified className to specified DOM element. + * + * @method addClass + * @static + * @param {Object} obj DOM element like object to add handler to. + * @param {String} name Class name + */ + addClass : u.Dom.addClass, + + /** + * Removes specified className from specified DOM element. + * + * @method removeClass + * @static + * @param {Object} obj DOM element like object to add handler to. + * @param {String} name Class name + */ + removeClass : u.Dom.removeClass, + + /** + * Returns a given computed style of a DOM element. + * + * @method getStyle + * @static + * @param {Object} obj DOM element like object. + * @param {String} name Style you want to get from the DOM element + */ + getStyle : u.Dom.getStyle, + + /** + * Adds an event handler to the specified object and store reference to the handler + * in objects internal Plupload registry (@see removeEvent). + * + * @method addEvent + * @static + * @param {Object} obj DOM element like object to add handler to. + * @param {String} name Name to add event listener to. + * @param {Function} callback Function to call when event occurs. + * @param {String} (optional) key that might be used to add specifity to the event record. + */ + addEvent : u.Events.addEvent, + + /** + * Remove event handler from the specified object. If third argument (callback) + * is not specified remove all events with the specified name. + * + * @method removeEvent + * @static + * @param {Object} obj DOM element to remove event listener(s) from. + * @param {String} name Name of event listener to remove. + * @param {Function|String} (optional) might be a callback or unique key to match. + */ + removeEvent: u.Events.removeEvent, + + /** + * Remove all kind of events from the specified object + * + * @method removeAllEvents + * @static + * @param {Object} obj DOM element to remove event listeners from. + * @param {String} (optional) unique key to match, when removing events. + */ + removeAllEvents: u.Events.removeAllEvents, + + /** + * Cleans the specified name from national characters (diacritics). The result will be a name with only a-z, 0-9 and _. + * + * @method cleanName + * @static + * @param {String} s String to clean up. + * @return {String} Cleaned string. + */ + cleanName : function(name) { + var i, lookup; + + // Replace diacritics + lookup = [ + /[\300-\306]/g, 'A', /[\340-\346]/g, 'a', + /\307/g, 'C', /\347/g, 'c', + /[\310-\313]/g, 'E', /[\350-\353]/g, 'e', + /[\314-\317]/g, 'I', /[\354-\357]/g, 'i', + /\321/g, 'N', /\361/g, 'n', + /[\322-\330]/g, 'O', /[\362-\370]/g, 'o', + /[\331-\334]/g, 'U', /[\371-\374]/g, 'u' + ]; + + for (i = 0; i < lookup.length; i += 2) { + name = name.replace(lookup[i], lookup[i + 1]); + } + + // Replace whitespace + name = name.replace(/\s+/g, '_'); + + // Remove anything else + name = name.replace(/[^a-z0-9_\-\.]+/gi, ''); + + return name; + }, + + /** + * Builds a full url out of a base URL and an object with items to append as query string items. + * + * @method buildUrl + * @static + * @param {String} url Base URL to append query string items to. + * @param {Object} items Name/value object to serialize as a querystring. + * @return {String} String with url + serialized query string items. + */ + buildUrl: function(url, items) { + var query = ''; + + plupload.each(items, function(value, name) { + query += (query ? '&' : '') + encodeURIComponent(name) + '=' + encodeURIComponent(value); + }); + + if (query) { + url += (url.indexOf('?') > 0 ? '&' : '?') + query; + } + + return url; + }, + + /** + * Formats the specified number as a size string for example 1024 becomes 1 KB. + * + * @method formatSize + * @static + * @param {Number} size Size to format as string. + * @return {String} Formatted size string. + */ + formatSize : function(size) { + + if (size === undef || /\D/.test(size)) { + return plupload.translate('N/A'); + } + + function round(num, precision) { + return Math.round(num * Math.pow(10, precision)) / Math.pow(10, precision); + } + + var boundary = Math.pow(1024, 4); + + // TB + if (size > boundary) { + return round(size / boundary, 1) + " " + plupload.translate('tb'); + } + + // GB + if (size > (boundary/=1024)) { + return round(size / boundary, 1) + " " + plupload.translate('gb'); + } + + // MB + if (size > (boundary/=1024)) { + return round(size / boundary, 1) + " " + plupload.translate('mb'); + } + + // KB + if (size > 1024) { + return Math.round(size / 1024) + " " + plupload.translate('kb'); + } + + return size + " " + plupload.translate('b'); + }, + + + /** + * Parses the specified size string into a byte value. For example 10kb becomes 10240. + * + * @method parseSize + * @static + * @param {String|Number} size String to parse or number to just pass through. + * @return {Number} Size in bytes. + */ + parseSize : u.Basic.parseSizeStr, + + + /** + * A way to predict what runtime will be choosen in the current environment with the + * specified settings. + * + * @method predictRuntime + * @static + * @param {Object|String} config Plupload settings to check + * @param {String} [runtimes] Comma-separated list of runtimes to check against + * @return {String} Type of compatible runtime + */ + predictRuntime : function(config, runtimes) { + var up, runtime; + + up = new plupload.Uploader(config); + runtime = Runtime.thatCan(up.getOption().required_features, runtimes || config.runtimes); + up.destroy(); + return runtime; + }, + + /** + * Registers a filter that will be executed for each file added to the queue. + * If callback returns false, file will not be added. + * + * Callback receives two arguments: a value for the filter as it was specified in settings.filters + * and a file to be filtered. Callback is executed in the context of uploader instance. + * + * @method addFileFilter + * @static + * @param {String} name Name of the filter by which it can be referenced in settings.filters + * @param {String} cb Callback - the actual routine that every added file must pass + */ + addFileFilter: function(name, cb) { + fileFilters[name] = cb; + } +}; + + +plupload.addFileFilter('mime_types', function(filters, file, cb) { + if (filters.length && !filters.regexp.test(file.name)) { + this.trigger('Error', { + code : plupload.FILE_EXTENSION_ERROR, + message : plupload.translate('File extension error.'), + file : file + }); + cb(false); + } else { + cb(true); + } +}); + + +plupload.addFileFilter('max_file_size', function(maxSize, file, cb) { + var undef; + + maxSize = plupload.parseSize(maxSize); + + // Invalid file size + if (file.size !== undef && maxSize && file.size > maxSize) { + this.trigger('Error', { + code : plupload.FILE_SIZE_ERROR, + message : plupload.translate('File size error.'), + file : file + }); + cb(false); + } else { + cb(true); + } +}); + + +plupload.addFileFilter('prevent_duplicates', function(value, file, cb) { + if (value) { + var ii = this.files.length; + while (ii--) { + // Compare by name and size (size might be 0 or undefined, but still equivalent for both) + if (file.name === this.files[ii].name && file.size === this.files[ii].size) { + this.trigger('Error', { + code : plupload.FILE_DUPLICATE_ERROR, + message : plupload.translate('Duplicate file error.'), + file : file + }); + cb(false); + return; + } + } + } + cb(true); +}); + + +/** +@class Uploader +@constructor + +@param {Object} settings For detailed information about each option check documentation. + @param {String|DOMElement} settings.browse_button id of the DOM element or DOM element itself to use as file dialog trigger. + @param {Number|String} [settings.chunk_size=0] Chunk size in bytes to slice the file into. Shorcuts with b, kb, mb, gb, tb suffixes also supported. `e.g. 204800 or "204800b" or "200kb"`. By default - disabled. + @param {String|DOMElement} [settings.container] id of the DOM element or DOM element itself that will be used to wrap uploader structures. Defaults to immediate parent of the `browse_button` element. + @param {String|DOMElement} [settings.drop_element] id of the DOM element or DOM element itself to use as a drop zone for Drag-n-Drop. + @param {String} [settings.file_data_name="file"] Name for the file field in Multipart formated message. + @param {Object} [settings.filters={}] Set of file type filters. + @param {String|Number} [settings.filters.max_file_size=0] Maximum file size that the user can pick, in bytes. Optionally supports b, kb, mb, gb, tb suffixes. `e.g. "10mb" or "1gb"`. By default - not set. Dispatches `plupload.FILE_SIZE_ERROR`. + @param {Array} [settings.filters.mime_types=[]] List of file types to accept, each one defined by title and list of extensions. `e.g. {title : "Image files", extensions : "jpg,jpeg,gif,png"}`. Dispatches `plupload.FILE_EXTENSION_ERROR` + @param {Boolean} [settings.filters.prevent_duplicates=false] Do not let duplicates into the queue. Dispatches `plupload.FILE_DUPLICATE_ERROR`. + @param {String} [settings.flash_swf_url] URL of the Flash swf. + @param {Object} [settings.headers] Custom headers to send with the upload. Hash of name/value pairs. + @param {String} [settings.http_method="POST"] HTTP method to use during upload (only PUT or POST allowed). + @param {Number} [settings.max_retries=0] How many times to retry the chunk or file, before triggering Error event. + @param {Boolean} [settings.multipart=true] Whether to send file and additional parameters as Multipart formated message. + @param {Object} [settings.multipart_params] Hash of key/value pairs to send with every file upload. + @param {Boolean} [settings.multi_selection=true] Enable ability to select multiple files at once in file dialog. + @param {String|Object} [settings.required_features] Either comma-separated list or hash of required features that chosen runtime should absolutely possess. + @param {Object} [settings.resize] Enable resizng of images on client-side. Applies to `image/jpeg` and `image/png` only. `e.g. {width : 200, height : 200, quality : 90, crop: true}` + @param {Number} [settings.resize.width] If image is bigger, it will be resized. + @param {Number} [settings.resize.height] If image is bigger, it will be resized. + @param {Number} [settings.resize.quality=90] Compression quality for jpegs (1-100). + @param {Boolean} [settings.resize.crop=false] Whether to crop images to exact dimensions. By default they will be resized proportionally. + @param {String} [settings.runtimes="html5,flash,silverlight,html4"] Comma separated list of runtimes, that Plupload will try in turn, moving to the next if previous fails. + @param {String} [settings.silverlight_xap_url] URL of the Silverlight xap. + @param {Boolean} [settings.send_chunk_number=true] Whether to send chunks and chunk numbers, or total and offset bytes. + @param {Boolean} [settings.send_file_name=true] Whether to send file name as additional argument - 'name' (required for chunked uploads and some other cases where file name cannot be sent via normal ways). + @param {String} settings.url URL of the server-side upload handler. + @param {Boolean} [settings.unique_names=false] If true will generate unique filenames for uploaded files. + +*/ +plupload.Uploader = function(options) { + /** + Fires when the current RunTime has been initialized. + + @event Init + @param {plupload.Uploader} uploader Uploader instance sending the event. + */ + + /** + Fires after the init event incase you need to perform actions there. + + @event PostInit + @param {plupload.Uploader} uploader Uploader instance sending the event. + */ + + /** + Fires when the option is changed in via uploader.setOption(). + + @event OptionChanged + @since 2.1 + @param {plupload.Uploader} uploader Uploader instance sending the event. + @param {String} name Name of the option that was changed + @param {Mixed} value New value for the specified option + @param {Mixed} oldValue Previous value of the option + */ + + /** + Fires when the silverlight/flash or other shim needs to move. + + @event Refresh + @param {plupload.Uploader} uploader Uploader instance sending the event. + */ + + /** + Fires when the overall state is being changed for the upload queue. + + @event StateChanged + @param {plupload.Uploader} uploader Uploader instance sending the event. + */ + + /** + Fires when browse_button is clicked and browse dialog shows. + + @event Browse + @since 2.1.2 + @param {plupload.Uploader} uploader Uploader instance sending the event. + */ + + /** + Fires for every filtered file before it is added to the queue. + + @event FileFiltered + @since 2.1 + @param {plupload.Uploader} uploader Uploader instance sending the event. + @param {plupload.File} file Another file that has to be added to the queue. + */ + + /** + Fires when the file queue is changed. In other words when files are added/removed to the files array of the uploader instance. + + @event QueueChanged + @param {plupload.Uploader} uploader Uploader instance sending the event. + */ + + /** + Fires after files were filtered and added to the queue. + + @event FilesAdded + @param {plupload.Uploader} uploader Uploader instance sending the event. + @param {Array} files Array of file objects that were added to queue by the user. + */ + + /** + Fires when file is removed from the queue. + + @event FilesRemoved + @param {plupload.Uploader} uploader Uploader instance sending the event. + @param {Array} files Array of files that got removed. + */ + + /** + Fires just before a file is uploaded. Can be used to cancel the upload for the specified file + by returning false from the handler. + + @event BeforeUpload + @param {plupload.Uploader} uploader Uploader instance sending the event. + @param {plupload.File} file File to be uploaded. + */ + + /** + Fires when a file is to be uploaded by the runtime. + + @event UploadFile + @param {plupload.Uploader} uploader Uploader instance sending the event. + @param {plupload.File} file File to be uploaded. + */ + + /** + Fires while a file is being uploaded. Use this event to update the current file upload progress. + + @event UploadProgress + @param {plupload.Uploader} uploader Uploader instance sending the event. + @param {plupload.File} file File that is currently being uploaded. + */ + + /** + * Fires just before a chunk is uploaded. This event enables you to override settings + * on the uploader instance before the chunk is uploaded. + * + * @event BeforeChunkUpload + * @param {plupload.Uploader} uploader Uploader instance sending the event. + * @param {plupload.File} file File to be uploaded. + * @param {Object} args POST params to be sent. + * @param {Blob} chunkBlob Current blob. + * @param {offset} offset Current offset. + */ + + /** + Fires when file chunk is uploaded. + + @event ChunkUploaded + @param {plupload.Uploader} uploader Uploader instance sending the event. + @param {plupload.File} file File that the chunk was uploaded for. + @param {Object} result Object with response properties. + @param {Number} result.offset The amount of bytes the server has received so far, including this chunk. + @param {Number} result.total The size of the file. + @param {String} result.response The response body sent by the server. + @param {Number} result.status The HTTP status code sent by the server. + @param {String} result.responseHeaders All the response headers as a single string. + */ + + /** + Fires when a file is successfully uploaded. + + @event FileUploaded + @param {plupload.Uploader} uploader Uploader instance sending the event. + @param {plupload.File} file File that was uploaded. + @param {Object} result Object with response properties. + @param {String} result.response The response body sent by the server. + @param {Number} result.status The HTTP status code sent by the server. + @param {String} result.responseHeaders All the response headers as a single string. + */ + + /** + Fires when all files in a queue are uploaded. + + @event UploadComplete + @param {plupload.Uploader} uploader Uploader instance sending the event. + @param {Array} files Array of file objects that was added to queue/selected by the user. + */ + + /** + Fires when a error occurs. + + @event Error + @param {plupload.Uploader} uploader Uploader instance sending the event. + @param {Object} error Contains code, message and sometimes file and other details. + @param {Number} error.code The plupload error code. + @param {String} error.message Description of the error (uses i18n). + */ + + /** + Fires when destroy method is called. + + @event Destroy + @param {plupload.Uploader} uploader Uploader instance sending the event. + */ + var uid = plupload.guid() + , settings + , files = [] + , preferred_caps = {} + , fileInputs = [] + , fileDrops = [] + , startTime + , total + , disabled = false + , xhr + ; + + + // Private methods + function uploadNext() { + var file, count = 0, i; + + if (this.state == plupload.STARTED) { + // Find first QUEUED file + for (i = 0; i < files.length; i++) { + if (!file && files[i].status == plupload.QUEUED) { + file = files[i]; + if (this.trigger("BeforeUpload", file)) { + file.status = plupload.UPLOADING; + this.trigger("UploadFile", file); + } + } else { + count++; + } + } + + // All files are DONE or FAILED + if (count == files.length) { + if (this.state !== plupload.STOPPED) { + this.state = plupload.STOPPED; + this.trigger("StateChanged"); + } + this.trigger("UploadComplete", files); + } + } + } + + + function calcFile(file) { + file.percent = file.size > 0 ? Math.ceil(file.loaded / file.size * 100) : 100; + calc(); + } + + + function calc() { + var i, file; + var loaded; + var loadedDuringCurrentSession = 0; + + // Reset stats + total.reset(); + + // Check status, size, loaded etc on all files + for (i = 0; i < files.length; i++) { + file = files[i]; + + if (file.size !== undef) { + // We calculate totals based on original file size + total.size += file.origSize; + + // Since we cannot predict file size after resize, we do opposite and + // interpolate loaded amount to match magnitude of total + loaded = file.loaded * file.origSize / file.size; + + if (!file.completeTimestamp || file.completeTimestamp > startTime) { + loadedDuringCurrentSession += loaded; + } + + total.loaded += loaded; + } else { + total.size = undef; + } + + if (file.status == plupload.DONE) { + total.uploaded++; + } else if (file.status == plupload.FAILED) { + total.failed++; + } else { + total.queued++; + } + } + + // If we couldn't calculate a total file size then use the number of files to calc percent + if (total.size === undef) { + total.percent = files.length > 0 ? Math.ceil(total.uploaded / files.length * 100) : 0; + } else { + total.bytesPerSec = Math.ceil(loadedDuringCurrentSession / ((+new Date() - startTime || 1) / 1000.0)); + total.percent = total.size > 0 ? Math.ceil(total.loaded / total.size * 100) : 0; + } + } + + + function getRUID() { + var ctrl = fileInputs[0] || fileDrops[0]; + if (ctrl) { + return ctrl.getRuntime().uid; + } + return false; + } + + + function runtimeCan(file, cap) { + if (file.ruid) { + var info = Runtime.getInfo(file.ruid); + if (info) { + return info.can(cap); + } + } + return false; + } + + + function bindEventListeners() { + this.bind('FilesAdded FilesRemoved', function(up) { + up.trigger('QueueChanged'); + up.refresh(); + }); + + this.bind('CancelUpload', onCancelUpload); + + this.bind('BeforeUpload', onBeforeUpload); + + this.bind('UploadFile', onUploadFile); + + this.bind('UploadProgress', onUploadProgress); + + this.bind('StateChanged', onStateChanged); + + this.bind('QueueChanged', calc); + + this.bind('Error', onError); + + this.bind('FileUploaded', onFileUploaded); + + this.bind('Destroy', onDestroy); + } + + + function initControls(settings, cb) { + var self = this, inited = 0, queue = []; + + // common settings + var options = { + runtime_order: settings.runtimes, + required_caps: settings.required_features, + preferred_caps: preferred_caps, + swf_url: settings.flash_swf_url, + xap_url: settings.silverlight_xap_url + }; + + // add runtime specific options if any + plupload.each(settings.runtimes.split(/\s*,\s*/), function(runtime) { + if (settings[runtime]) { + options[runtime] = settings[runtime]; + } + }); + + // initialize file pickers - there can be many + if (settings.browse_button) { + plupload.each(settings.browse_button, function(el) { + queue.push(function(cb) { + var fileInput = new o.file.FileInput(plupload.extend({}, options, { + accept: settings.filters.mime_types, + name: settings.file_data_name, + multiple: settings.multi_selection, + container: settings.container, + browse_button: el + })); + + fileInput.onready = function() { + var info = Runtime.getInfo(this.ruid); + + // for backward compatibility + plupload.extend(self.features, { + chunks: info.can('slice_blob'), + multipart: info.can('send_multipart'), + multi_selection: info.can('select_multiple') + }); + + inited++; + fileInputs.push(this); + cb(); + }; + + fileInput.onchange = function() { + self.addFile(this.files); + }; + + fileInput.bind('mouseenter mouseleave mousedown mouseup', function(e) { + if (!disabled) { + if (settings.browse_button_hover) { + if ('mouseenter' === e.type) { + plupload.addClass(el, settings.browse_button_hover); + } else if ('mouseleave' === e.type) { + plupload.removeClass(el, settings.browse_button_hover); + } + } + + if (settings.browse_button_active) { + if ('mousedown' === e.type) { + plupload.addClass(el, settings.browse_button_active); + } else if ('mouseup' === e.type) { + plupload.removeClass(el, settings.browse_button_active); + } + } + } + }); + + fileInput.bind('mousedown', function() { + self.trigger('Browse'); + }); + + fileInput.bind('error runtimeerror', function() { + fileInput = null; + cb(); + }); + + fileInput.init(); + }); + }); + } + + // initialize drop zones + if (settings.drop_element) { + plupload.each(settings.drop_element, function(el) { + queue.push(function(cb) { + var fileDrop = new o.file.FileDrop(plupload.extend({}, options, { + drop_zone: el + })); + + fileDrop.onready = function() { + var info = Runtime.getInfo(this.ruid); + + // for backward compatibility + plupload.extend(self.features, { + chunks: info.can('slice_blob'), + multipart: info.can('send_multipart'), + dragdrop: info.can('drag_and_drop') + }); + + inited++; + fileDrops.push(this); + cb(); + }; + + fileDrop.ondrop = function() { + self.addFile(this.files); + }; + + fileDrop.bind('error runtimeerror', function() { + fileDrop = null; + cb(); + }); + + fileDrop.init(); + }); + }); + } + + + plupload.inSeries(queue, function() { + if (typeof(cb) === 'function') { + cb(inited); + } + }); + } + + + function resizeImage(blob, params, cb) { + var img = new o.image.Image(); + + try { + img.onload = function() { + // no manipulation required if... + if (params.width > this.width && + params.height > this.height && + params.quality === undef && + params.preserve_headers && + !params.crop + ) { + this.destroy(); + return cb(blob); + } + // otherwise downsize + img.downsize(params.width, params.height, params.crop, params.preserve_headers); + }; + + img.onresize = function() { + cb(this.getAsBlob(blob.type, params.quality)); + this.destroy(); + }; + + img.onerror = function() { + cb(blob); + }; + + img.load(blob); + } catch(ex) { + cb(blob); + } + } + + + function setOption(option, value, init) { + var self = this, reinitRequired = false; + + function _setOption(option, value, init) { + var oldValue = settings[option]; + + switch (option) { + case 'max_file_size': + if (option === 'max_file_size') { + settings.max_file_size = settings.filters.max_file_size = value; + } + break; + + case 'chunk_size': + if (value = plupload.parseSize(value)) { + settings[option] = value; + settings.send_file_name = true; + } + break; + + case 'multipart': + settings[option] = value; + if (!value) { + settings.send_file_name = true; + } + break; + + case 'http_method': + settings[option] = value.toUpperCase() === 'PUT' ? 'PUT' : 'POST'; + break; + + case 'unique_names': + settings[option] = value; + if (value) { + settings.send_file_name = true; + } + break; + + case 'filters': + // for sake of backward compatibility + if (plupload.typeOf(value) === 'array') { + value = { + mime_types: value + }; + } + + if (init) { + plupload.extend(settings.filters, value); + } else { + settings.filters = value; + } + + // if file format filters are being updated, regenerate the matching expressions + if (value.mime_types) { + if (plupload.typeOf(value.mime_types) === 'string') { + value.mime_types = o.core.utils.Mime.mimes2extList(value.mime_types); + } + + value.mime_types.regexp = (function(filters) { + var extensionsRegExp = []; + + plupload.each(filters, function(filter) { + plupload.each(filter.extensions.split(/,/), function(ext) { + if (/^\s*\*\s*$/.test(ext)) { + extensionsRegExp.push('\\.*'); + } else { + extensionsRegExp.push('\\.' + ext.replace(new RegExp('[' + ('/^$.*+?|()[]{}\\'.replace(/./g, '\\$&')) + ']', 'g'), '\\$&')); + } + }); + }); + + return new RegExp('(' + extensionsRegExp.join('|') + ')$', 'i'); + }(value.mime_types)); + + settings.filters.mime_types = value.mime_types; + } + break; + + case 'resize': + if (value) { + settings.resize = plupload.extend({ + preserve_headers: true, + crop: false + }, value); + } else { + settings.resize = false; + } + break; + + case 'prevent_duplicates': + settings.prevent_duplicates = settings.filters.prevent_duplicates = !!value; + break; + + // options that require reinitialisation + case 'container': + case 'browse_button': + case 'drop_element': + value = 'container' === option + ? plupload.get(value) + : plupload.getAll(value) + ; + + case 'runtimes': + case 'multi_selection': + case 'flash_swf_url': + case 'silverlight_xap_url': + settings[option] = value; + if (!init) { + reinitRequired = true; + } + break; + + default: + settings[option] = value; + } + + if (!init) { + self.trigger('OptionChanged', option, value, oldValue); + } + } + + if (typeof(option) === 'object') { + plupload.each(option, function(value, option) { + _setOption(option, value, init); + }); + } else { + _setOption(option, value, init); + } + + if (init) { + // Normalize the list of required capabilities + settings.required_features = normalizeCaps(plupload.extend({}, settings)); + + // Come up with the list of capabilities that can affect default mode in a multi-mode runtimes + preferred_caps = normalizeCaps(plupload.extend({}, settings, { + required_features: true + })); + } else if (reinitRequired) { + self.trigger('Destroy'); + + initControls.call(self, settings, function(inited) { + if (inited) { + self.runtime = Runtime.getInfo(getRUID()).type; + self.trigger('Init', { runtime: self.runtime }); + self.trigger('PostInit'); + } else { + self.trigger('Error', { + code : plupload.INIT_ERROR, + message : plupload.translate('Init error.') + }); + } + }); + } + } + + + // Internal event handlers + function onBeforeUpload(up, file) { + // Generate unique target filenames + if (up.settings.unique_names) { + var matches = file.name.match(/\.([^.]+)$/), ext = "part"; + if (matches) { + ext = matches[1]; + } + file.target_name = file.id + '.' + ext; + } + } + + + function onUploadFile(up, file) { + var url = up.settings.url + , chunkSize = up.settings.chunk_size + , retries = up.settings.max_retries + , features = up.features + , offset = 0 + , blob + ; + + // make sure we start at a predictable offset + if (file.loaded) { + offset = file.loaded = chunkSize ? chunkSize * Math.floor(file.loaded / chunkSize) : 0; + } + + function handleError() { + if (retries-- > 0) { + delay(uploadNextChunk, 1000); + } else { + file.loaded = offset; // reset all progress + + up.trigger('Error', { + code : plupload.HTTP_ERROR, + message : plupload.translate('HTTP Error.'), + file : file, + response : xhr.responseText, + status : xhr.status, + responseHeaders: xhr.getAllResponseHeaders() + }); + } + } + + function uploadNextChunk() { + var chunkBlob, args = {}, curChunkSize; + + // make sure that file wasn't cancelled and upload is not stopped in general + if (file.status !== plupload.UPLOADING || up.state === plupload.STOPPED) { + return; + } + + // send additional 'name' parameter only if required + if (up.settings.send_file_name) { + args.name = file.target_name || file.name; + } + + if (chunkSize && features.chunks && blob.size > chunkSize) { // blob will be of type string if it was loaded in memory + curChunkSize = Math.min(chunkSize, blob.size - offset); + chunkBlob = blob.slice(offset, offset + curChunkSize); + } else { + curChunkSize = blob.size; + chunkBlob = blob; + } + + // If chunking is enabled add corresponding args, no matter if file is bigger than chunk or smaller + if (chunkSize && features.chunks) { + // Setup query string arguments + if (up.settings.send_chunk_number) { + args.chunk = Math.ceil(offset / chunkSize); + args.chunks = Math.ceil(blob.size / chunkSize); + } else { // keep support for experimental chunk format, just in case + args.offset = offset; + args.total = blob.size; + } + } + + if (up.trigger('BeforeChunkUpload', file, args, chunkBlob, offset)) { + uploadChunk(args, chunkBlob, curChunkSize); + } + } + + function uploadChunk(args, chunkBlob, curChunkSize) { + var formData; + + xhr = new o.xhr.XMLHttpRequest(); + + // Do we have upload progress support + if (xhr.upload) { + xhr.upload.onprogress = function(e) { + file.loaded = Math.min(file.size, offset + e.loaded); + up.trigger('UploadProgress', file); + }; + } + + xhr.onload = function() { + // check if upload made itself through + if (xhr.status >= 400) { + handleError(); + return; + } + + retries = up.settings.max_retries; // reset the counter + + // Handle chunk response + if (curChunkSize < blob.size) { + chunkBlob.destroy(); + + offset += curChunkSize; + file.loaded = Math.min(offset, blob.size); + + up.trigger('ChunkUploaded', file, { + offset : file.loaded, + total : blob.size, + response : xhr.responseText, + status : xhr.status, + responseHeaders: xhr.getAllResponseHeaders() + }); + + // stock Android browser doesn't fire upload progress events, but in chunking mode we can fake them + if (plupload.ua.browser === 'Android Browser') { + // doesn't harm in general, but is not required anywhere else + up.trigger('UploadProgress', file); + } + } else { + file.loaded = file.size; + } + + chunkBlob = formData = null; // Free memory + + // Check if file is uploaded + if (!offset || offset >= blob.size) { + // If file was modified, destory the copy + if (file.size != file.origSize) { + blob.destroy(); + blob = null; + } + + up.trigger('UploadProgress', file); + + file.status = plupload.DONE; + file.completeTimestamp = +new Date(); + + up.trigger('FileUploaded', file, { + response : xhr.responseText, + status : xhr.status, + responseHeaders: xhr.getAllResponseHeaders() + }); + } else { + // Still chunks left + delay(uploadNextChunk, 1); // run detached, otherwise event handlers interfere + } + }; + + xhr.onerror = function() { + handleError(); + }; + + xhr.onloadend = function() { + this.destroy(); + xhr = null; + }; + + // Build multipart request + if (up.settings.multipart && features.multipart) { + xhr.open(up.settings.http_method, url, true); + + // Set custom headers + plupload.each(up.settings.headers, function(value, name) { + xhr.setRequestHeader(name, value); + }); + + formData = new o.xhr.FormData(); + + // Add multipart params + plupload.each(plupload.extend(args, up.settings.multipart_params), function(value, name) { + formData.append(name, value); + }); + + // Add file and send it + formData.append(up.settings.file_data_name, chunkBlob); + xhr.send(formData, { + runtime_order: up.settings.runtimes, + required_caps: up.settings.required_features, + preferred_caps: preferred_caps, + swf_url: up.settings.flash_swf_url, + xap_url: up.settings.silverlight_xap_url + }); + } else { + // if no multipart, send as binary stream + url = plupload.buildUrl(up.settings.url, plupload.extend(args, up.settings.multipart_params)); + + xhr.open(up.settings.http_method, url, true); + + // Set custom headers + plupload.each(up.settings.headers, function(value, name) { + xhr.setRequestHeader(name, value); + }); + + // do not set Content-Type, if it was defined previously (see #1203) + if (!xhr.hasRequestHeader('Content-Type')) { + xhr.setRequestHeader('Content-Type', 'application/octet-stream'); // Binary stream header + } + + xhr.send(chunkBlob, { + runtime_order: up.settings.runtimes, + required_caps: up.settings.required_features, + preferred_caps: preferred_caps, + swf_url: up.settings.flash_swf_url, + xap_url: up.settings.silverlight_xap_url + }); + } + } + + + blob = file.getSource(); + + // Start uploading chunks + if (!plupload.isEmptyObj(up.settings.resize) && runtimeCan(blob, 'send_binary_string') && plupload.inArray(blob.type, ['image/jpeg', 'image/png']) !== -1) { + // Resize if required + resizeImage.call(this, blob, up.settings.resize, function(resizedBlob) { + blob = resizedBlob; + file.size = resizedBlob.size; + uploadNextChunk(); + }); + } else { + uploadNextChunk(); + } + } + + + function onUploadProgress(up, file) { + calcFile(file); + } + + + function onStateChanged(up) { + if (up.state == plupload.STARTED) { + // Get start time to calculate bps + startTime = (+new Date()); + } else if (up.state == plupload.STOPPED) { + // Reset currently uploading files + for (var i = up.files.length - 1; i >= 0; i--) { + if (up.files[i].status == plupload.UPLOADING) { + up.files[i].status = plupload.QUEUED; + calc(); + } + } + } + } + + + function onCancelUpload() { + if (xhr) { + xhr.abort(); + } + } + + + function onFileUploaded(up) { + calc(); + + // Upload next file but detach it from the error event + // since other custom listeners might want to stop the queue + delay(function() { + uploadNext.call(up); + }, 1); + } + + + function onError(up, err) { + if (err.code === plupload.INIT_ERROR) { + up.destroy(); + } + // Set failed status if an error occured on a file + else if (err.code === plupload.HTTP_ERROR) { + err.file.status = plupload.FAILED; + err.file.completeTimestamp = +new Date(); + calcFile(err.file); + + // Upload next file but detach it from the error event + // since other custom listeners might want to stop the queue + if (up.state == plupload.STARTED) { // upload in progress + up.trigger('CancelUpload'); + delay(function() { + uploadNext.call(up); + }, 1); + } + } + } + + + function onDestroy(up) { + up.stop(); + + // Purge the queue + plupload.each(files, function(file) { + file.destroy(); + }); + files = []; + + if (fileInputs.length) { + plupload.each(fileInputs, function(fileInput) { + fileInput.destroy(); + }); + fileInputs = []; + } + + if (fileDrops.length) { + plupload.each(fileDrops, function(fileDrop) { + fileDrop.destroy(); + }); + fileDrops = []; + } + + preferred_caps = {}; + disabled = false; + startTime = xhr = null; + total.reset(); + } + + + // Default settings + settings = { + chunk_size: 0, + file_data_name: 'file', + filters: { + mime_types: [], + prevent_duplicates: false, + max_file_size: 0 + }, + flash_swf_url: 'js/Moxie.swf', + http_method: 'POST', + max_retries: 0, + multipart: true, + multi_selection: true, + resize: false, + runtimes: Runtime.order, + send_file_name: true, + send_chunk_number: true, + silverlight_xap_url: 'js/Moxie.xap' + }; + + + setOption.call(this, options, null, true); + + // Inital total state + total = new plupload.QueueProgress(); + + // Add public methods + plupload.extend(this, { + + /** + * Unique id for the Uploader instance. + * + * @property id + * @type String + */ + id : uid, + uid : uid, // mOxie uses this to differentiate between event targets + + /** + * Current state of the total uploading progress. This one can either be plupload.STARTED or plupload.STOPPED. + * These states are controlled by the stop/start methods. The default value is STOPPED. + * + * @property state + * @type Number + */ + state : plupload.STOPPED, + + /** + * Map of features that are available for the uploader runtime. Features will be filled + * before the init event is called, these features can then be used to alter the UI for the end user. + * Some of the current features that might be in this map is: dragdrop, chunks, jpgresize, pngresize. + * + * @property features + * @type Object + */ + features : {}, + + /** + * Current runtime name. + * + * @property runtime + * @type String + */ + runtime : null, + + /** + * Current upload queue, an array of File instances. + * + * @property files + * @type Array + * @see plupload.File + */ + files : files, + + /** + * Object with name/value settings. + * + * @property settings + * @type Object + */ + settings : settings, + + /** + * Total progess information. How many files has been uploaded, total percent etc. + * + * @property total + * @type plupload.QueueProgress + */ + total : total, + + + /** + * Initializes the Uploader instance and adds internal event listeners. + * + * @method init + */ + init : function() { + var self = this, opt, preinitOpt, err; + + preinitOpt = self.getOption('preinit'); + if (typeof(preinitOpt) == "function") { + preinitOpt(self); + } else { + plupload.each(preinitOpt, function(func, name) { + self.bind(name, func); + }); + } + + bindEventListeners.call(self); + + // Check for required options + plupload.each(['container', 'browse_button', 'drop_element'], function(el) { + if (self.getOption(el) === null) { + err = { + code : plupload.INIT_ERROR, + message : plupload.sprintf(plupload.translate("%s specified, but cannot be found."), el) + } + return false; + } + }); + + if (err) { + return self.trigger('Error', err); + } + + + if (!settings.browse_button && !settings.drop_element) { + return self.trigger('Error', { + code : plupload.INIT_ERROR, + message : plupload.translate("You must specify either browse_button or drop_element.") + }); + } + + + initControls.call(self, settings, function(inited) { + var initOpt = self.getOption('init'); + if (typeof(initOpt) == "function") { + initOpt(self); + } else { + plupload.each(initOpt, function(func, name) { + self.bind(name, func); + }); + } + + if (inited) { + self.runtime = Runtime.getInfo(getRUID()).type; + self.trigger('Init', { runtime: self.runtime }); + self.trigger('PostInit'); + } else { + self.trigger('Error', { + code : plupload.INIT_ERROR, + message : plupload.translate('Init error.') + }); + } + }); + }, + + /** + * Set the value for the specified option(s). + * + * @method setOption + * @since 2.1 + * @param {String|Object} option Name of the option to change or the set of key/value pairs + * @param {Mixed} [value] Value for the option (is ignored, if first argument is object) + */ + setOption: function(option, value) { + setOption.call(this, option, value, !this.runtime); // until runtime not set we do not need to reinitialize + }, + + /** + * Get the value for the specified option or the whole configuration, if not specified. + * + * @method getOption + * @since 2.1 + * @param {String} [option] Name of the option to get + * @return {Mixed} Value for the option or the whole set + */ + getOption: function(option) { + if (!option) { + return settings; + } + return settings[option]; + }, + + /** + * Refreshes the upload instance by dispatching out a refresh event to all runtimes. + * This would for example reposition flash/silverlight shims on the page. + * + * @method refresh + */ + refresh : function() { + if (fileInputs.length) { + plupload.each(fileInputs, function(fileInput) { + fileInput.trigger('Refresh'); + }); + } + this.trigger('Refresh'); + }, + + /** + * Starts uploading the queued files. + * + * @method start + */ + start : function() { + if (this.state != plupload.STARTED) { + this.state = plupload.STARTED; + this.trigger('StateChanged'); + + uploadNext.call(this); + } + }, + + /** + * Stops the upload of the queued files. + * + * @method stop + */ + stop : function() { + if (this.state != plupload.STOPPED) { + this.state = plupload.STOPPED; + this.trigger('StateChanged'); + this.trigger('CancelUpload'); + } + }, + + + /** + * Disables/enables browse button on request. + * + * @method disableBrowse + * @param {Boolean} disable Whether to disable or enable (default: true) + */ + disableBrowse : function() { + disabled = arguments[0] !== undef ? arguments[0] : true; + + if (fileInputs.length) { + plupload.each(fileInputs, function(fileInput) { + fileInput.disable(disabled); + }); + } + + this.trigger('DisableBrowse', disabled); + }, + + /** + * Returns the specified file object by id. + * + * @method getFile + * @param {String} id File id to look for. + * @return {plupload.File} File object or undefined if it wasn't found; + */ + getFile : function(id) { + var i; + for (i = files.length - 1; i >= 0; i--) { + if (files[i].id === id) { + return files[i]; + } + } + }, + + /** + * Adds file to the queue programmatically. Can be native file, instance of Plupload.File, + * instance of mOxie.File, input[type="file"] element, or array of these. Fires FilesAdded, + * if any files were added to the queue. Otherwise nothing happens. + * + * @method addFile + * @since 2.0 + * @param {plupload.File|mOxie.File|File|Node|Array} file File or files to add to the queue. + * @param {String} [fileName] If specified, will be used as a name for the file + */ + addFile : function(file, fileName) { + var self = this + , queue = [] + , filesAdded = [] + , ruid + ; + + function filterFile(file, cb) { + var queue = []; + plupload.each(self.settings.filters, function(rule, name) { + if (fileFilters[name]) { + queue.push(function(cb) { + fileFilters[name].call(self, rule, file, function(res) { + cb(!res); + }); + }); + } + }); + plupload.inSeries(queue, cb); + } + + /** + * @method resolveFile + * @private + * @param {moxie.file.File|moxie.file.Blob|plupload.File|File|Blob|input[type="file"]} file + */ + function resolveFile(file) { + var type = plupload.typeOf(file); + + // moxie.file.File + if (file instanceof o.file.File) { + if (!file.ruid && !file.isDetached()) { + if (!ruid) { // weird case + return false; + } + file.ruid = ruid; + file.connectRuntime(ruid); + } + resolveFile(new plupload.File(file)); + } + // moxie.file.Blob + else if (file instanceof o.file.Blob) { + resolveFile(file.getSource()); + file.destroy(); + } + // plupload.File - final step for other branches + else if (file instanceof plupload.File) { + if (fileName) { + file.name = fileName; + } + + queue.push(function(cb) { + // run through the internal and user-defined filters, if any + filterFile(file, function(err) { + if (!err) { + // make files available for the filters by updating the main queue directly + files.push(file); + // collect the files that will be passed to FilesAdded event + filesAdded.push(file); + + self.trigger("FileFiltered", file); + } + delay(cb, 1); // do not build up recursions or eventually we might hit the limits + }); + }); + } + // native File or blob + else if (plupload.inArray(type, ['file', 'blob']) !== -1) { + resolveFile(new o.file.File(null, file)); + } + // input[type="file"] + else if (type === 'node' && plupload.typeOf(file.files) === 'filelist') { + // if we are dealing with input[type="file"] + plupload.each(file.files, resolveFile); + } + // mixed array of any supported types (see above) + else if (type === 'array') { + fileName = null; // should never happen, but unset anyway to avoid funny situations + plupload.each(file, resolveFile); + } + } + + ruid = getRUID(); + + resolveFile(file); + + if (queue.length) { + plupload.inSeries(queue, function() { + // if any files left after filtration, trigger FilesAdded + if (filesAdded.length) { + self.trigger("FilesAdded", filesAdded); + } + }); + } + }, + + /** + * Removes a specific file. + * + * @method removeFile + * @param {plupload.File|String} file File to remove from queue. + */ + removeFile : function(file) { + var id = typeof(file) === 'string' ? file : file.id; + + for (var i = files.length - 1; i >= 0; i--) { + if (files[i].id === id) { + return this.splice(i, 1)[0]; + } + } + }, + + /** + * Removes part of the queue and returns the files removed. This will also trigger the FilesRemoved and QueueChanged events. + * + * @method splice + * @param {Number} start (Optional) Start index to remove from. + * @param {Number} length (Optional) Lengh of items to remove. + * @return {Array} Array of files that was removed. + */ + splice : function(start, length) { + // Splice and trigger events + var removed = files.splice(start === undef ? 0 : start, length === undef ? files.length : length); + + // if upload is in progress we need to stop it and restart after files are removed + var restartRequired = false; + if (this.state == plupload.STARTED) { // upload in progress + plupload.each(removed, function(file) { + if (file.status === plupload.UPLOADING) { + restartRequired = true; // do not restart, unless file that is being removed is uploading + return false; + } + }); + + if (restartRequired) { + this.stop(); + } + } + + this.trigger("FilesRemoved", removed); + + // Dispose any resources allocated by those files + plupload.each(removed, function(file) { + file.destroy(); + }); + + if (restartRequired) { + this.start(); + } + + return removed; + }, + + /** + Dispatches the specified event name and its arguments to all listeners. + + @method trigger + @param {String} name Event name to fire. + @param {Object..} Multiple arguments to pass along to the listener functions. + */ + + // override the parent method to match Plupload-like event logic + dispatchEvent: function(type) { + var list, args, result; + + type = type.toLowerCase(); + + list = this.hasEventListener(type); + + if (list) { + // sort event list by priority + list.sort(function(a, b) { return b.priority - a.priority; }); + + // first argument should be current plupload.Uploader instance + args = [].slice.call(arguments); + args.shift(); + args.unshift(this); + + for (var i = 0; i < list.length; i++) { + // Fire event, break chain if false is returned + if (list[i].fn.apply(list[i].scope, args) === false) { + return false; + } + } + } + return true; + }, + + /** + Check whether uploader has any listeners to the specified event. + + @method hasEventListener + @param {String} name Event name to check for. + */ + + + /** + Adds an event listener by name. + + @method bind + @param {String} name Event name to listen for. + @param {function} fn Function to call ones the event gets fired. + @param {Object} [scope] Optional scope to execute the specified function in. + @param {Number} [priority=0] Priority of the event handler - handlers with higher priorities will be called first + */ + bind: function(name, fn, scope, priority) { + // adapt moxie EventTarget style to Plupload-like + plupload.Uploader.prototype.bind.call(this, name, fn, priority, scope); + }, + + /** + Removes the specified event listener. + + @method unbind + @param {String} name Name of event to remove. + @param {function} fn Function to remove from listener. + */ + + /** + Removes all event listeners. + + @method unbindAll + */ + + + /** + * Destroys Plupload instance and cleans after itself. + * + * @method destroy + */ + destroy : function() { + this.trigger('Destroy'); + settings = total = null; // purge these exclusively + this.unbindAll(); + } + }); +}; + +plupload.Uploader.prototype = o.core.EventTarget.instance; + +/** + * Constructs a new file instance. + * + * @class File + * @constructor + * + * @param {Object} file Object containing file properties + * @param {String} file.name Name of the file. + * @param {Number} file.size File size. + */ +plupload.File = (function() { + var filepool = {}; + + function PluploadFile(file) { + + plupload.extend(this, { + + /** + * File id this is a globally unique id for the specific file. + * + * @property id + * @type String + */ + id: plupload.guid(), + + /** + * File name for example "myfile.gif". + * + * @property name + * @type String + */ + name: file.name || file.fileName, + + /** + * File type, `e.g image/jpeg` + * + * @property type + * @type String + */ + type: file.type || '', + + /** + * File size in bytes (may change after client-side manupilation). + * + * @property size + * @type Number + */ + size: file.size || file.fileSize, + + /** + * Original file size in bytes. + * + * @property origSize + * @type Number + */ + origSize: file.size || file.fileSize, + + /** + * Number of bytes uploaded of the files total size. + * + * @property loaded + * @type Number + */ + loaded: 0, + + /** + * Number of percentage uploaded of the file. + * + * @property percent + * @type Number + */ + percent: 0, + + /** + * Status constant matching the plupload states QUEUED, UPLOADING, FAILED, DONE. + * + * @property status + * @type Number + * @see plupload + */ + status: plupload.QUEUED, + + /** + * Date of last modification. + * + * @property lastModifiedDate + * @type {String} + */ + lastModifiedDate: file.lastModifiedDate || (new Date()).toLocaleString(), // Thu Aug 23 2012 19:40:00 GMT+0400 (GET) + + + /** + * Set when file becomes plupload.DONE or plupload.FAILED. Is used to calculate proper plupload.QueueProgress.bytesPerSec. + * @private + * @property completeTimestamp + * @type {Number} + */ + completeTimestamp: 0, + + /** + * Returns native window.File object, when it's available. + * + * @method getNative + * @return {window.File} or null, if plupload.File is of different origin + */ + getNative: function() { + var file = this.getSource().getSource(); + return plupload.inArray(plupload.typeOf(file), ['blob', 'file']) !== -1 ? file : null; + }, + + /** + * Returns mOxie.File - unified wrapper object that can be used across runtimes. + * + * @method getSource + * @return {mOxie.File} or null + */ + getSource: function() { + if (!filepool[this.id]) { + return null; + } + return filepool[this.id]; + }, + + /** + * Destroys plupload.File object. + * + * @method destroy + */ + destroy: function() { + var src = this.getSource(); + if (src) { + src.destroy(); + delete filepool[this.id]; + } + } + }); + + filepool[this.id] = file; + } + + return PluploadFile; +}()); + + +/** + * Constructs a queue progress. + * + * @class QueueProgress + * @constructor + */ + plupload.QueueProgress = function() { + var self = this; // Setup alias for self to reduce code size when it's compressed + + /** + * Total queue file size. + * + * @property size + * @type Number + */ + self.size = 0; + + /** + * Total bytes uploaded. + * + * @property loaded + * @type Number + */ + self.loaded = 0; + + /** + * Number of files uploaded. + * + * @property uploaded + * @type Number + */ + self.uploaded = 0; + + /** + * Number of files failed to upload. + * + * @property failed + * @type Number + */ + self.failed = 0; + + /** + * Number of files yet to be uploaded. + * + * @property queued + * @type Number + */ + self.queued = 0; + + /** + * Total percent of the uploaded bytes. + * + * @property percent + * @type Number + */ + self.percent = 0; + + /** + * Bytes uploaded per second. + * + * @property bytesPerSec + * @type Number + */ + self.bytesPerSec = 0; + + /** + * Resets the progress to its initial values. + * + * @method reset + */ + self.reset = function() { + self.size = self.loaded = self.uploaded = self.failed = self.queued = self.percent = self.bytesPerSec = 0; + }; +}; + +exports.plupload = plupload; + +}(this, moxie)); + +})); \ No newline at end of file diff --git a/static/js/uploader/qiniu.js b/static/js/uploader/qiniu.js new file mode 100644 index 00000000..1f959b2f --- /dev/null +++ b/static/js/uploader/qiniu.js @@ -0,0 +1,1831 @@ +/*! + * qiniu-js-sdk v@VERSION + * + * Copyright 2015 by Qiniu + * Released under GPL V2 License. + * + * GitHub: http://github.com/qiniu/js-sdk + * + * Date: @DATE +*/ +/*! + * + * Rebuild By Aaron@2018 + * +*/ +/*global plupload ,mOxie*/ +/*global ActiveXObject */ +/*exported Qiniu */ +/*exported QiniuJsSDK */ + +function getCookieByString(cookieName){ + var start = document.cookie.indexOf(cookieName+'='); + if (start == -1) return false; + start = start+cookieName.length+1; + var end = document.cookie.indexOf(';', start); + if (end == -1) end=document.cookie.length; + return document.cookie.substring(start, end); +} +;(function( global ){ + +/** + * Creates new cookie or removes cookie with negative expiration + * @param key The key or identifier for the store + * @param value Contents of the store + * @param exp Expiration - creation defaults to 30 days + */ +function createCookie(key, value, exp) { + var date = new Date(); + date.setTime(date.getTime() + (exp * 24 * 60 * 60 * 1000)); + var expires = "; expires=" + date.toGMTString(); + document.cookie = key + "=" + value + expires + "; path=/"; +} + +/** + * Returns contents of cookie + * @param key The key or identifier for the store + */ +function readCookie(key) { + var nameEQ = key + "="; + var ca = document.cookie.split(';'); + for (var i = 0, max = ca.length; i < max; i++) { + var c = ca[i]; + while (c.charAt(0) === ' ') { + c = c.substring(1, c.length); + } + if (c.indexOf(nameEQ) === 0) { + return c.substring(nameEQ.length, c.length); + } + } + return null; +} + +// if current browser is not support localStorage +// use cookie to make a polyfill +if ( !window.localStorage ) { + window.localStorage = { + setItem: function (key, value) { + createCookie(key, value, 30); + }, + getItem: function (key) { + return readCookie(key); + }, + removeItem: function (key) { + createCookie(key, '', -1); + } + }; +} + +function QiniuJsSDK() { + + var that = this; + + /** + * detect IE version + * if current browser is not IE + * it will return false + * else + * it will return version of current IE browser + * @return {Number|Boolean} IE version or false + */ + this.detectIEVersion = function() { + var v = 4, + div = document.createElement('div'), + all = div.getElementsByTagName('i'); + while ( + div.innerHTML = '', + all[0] + ) { + v++; + } + return v > 4 ? v : false; + }; + + var logger = { + MUTE: 0, + FATA: 1, + ERROR: 2, + WARN: 3, + INFO: 4, + DEBUG: 5, + TRACE: 6, + level: 0 + }; + + function log(type, args){ + var header = "[Cloudreve-uploader]["+type+"]"; + var msg = header; + for (var i = 0; i < args.length; i++) { + if (typeof args[i] === "string") { + msg += " " + args[i]; + } else { + msg += " " + that.stringifyJSON(args[i]); + } + } + if (that.detectIEVersion()) { + // http://stackoverflow.com/questions/5538972/console-log-apply-not-working-in-ie9 + //var log = Function.prototype.bind.call(console.log, console); + //log.apply(console, args); + console.log(msg); + }else{ + args.unshift(header); + console.log.apply(console, args); + } + if (document.getElementById('qiniu-js-sdk-log')) { + document.getElementById('qiniu-js-sdk-log').innerHTML += '

'+msg+'

'; + } + } + + function makeLogFunc(code){ + var func = code.toLowerCase(); + logger[func] = function(){ + // logger[func].history = logger[func].history || []; + // logger[func].history.push(arguments); + if(window.console && window.console.log && logger.level>=logger[code]){ + var args = Array.prototype.slice.call(arguments); + log(func,args); + } + }; + } + + for (var property in logger){ + if (logger.hasOwnProperty(property) && (typeof logger[property]) === "number" && !logger.hasOwnProperty(property.toLowerCase())) { + makeLogFunc(property); + } + } + + + var qiniuUploadUrl; + + + /** + * qiniu upload urls + * 'qiniuUploadUrls' is used to change target when current url is not avaliable + * @type {Array} + */ + if(uploadConfig.saveType == "qiniu"){ + if (window.location.protocol === 'https:') { + qiniuUploadUrl = 'https://up.qbox.me'; + } else { + qiniuUploadUrl = 'http://upload.qiniu.com'; + } + var qiniuUploadUrls = [ + "http://upload.qiniu.com", + "http://up.qiniu.com" + ]; + + var qiniuUpHosts = { + "http": [ + "http://upload.qiniu.com", + "http://up.qiniu.com" + ], + "https": [ + "https://up.qbox.me" + ] + }; +}else if(uploadConfig.saveType == "local" || uploadConfig.saveType == "oss" ||uploadConfig.saveType == "upyun"||uploadConfig.saveType == "s3"|| uploadConfig.saveType == "remote"||uploadConfig.saveType == "onedrive"){ + qiniuUploadUrl = uploadConfig.upUrl; + var qiniuUploadUrls = [uploadConfig.upUrl,]; + var qiniuUpHosts = { + "http": [uploadConfig.upUrl,], + "https": [uploadConfig.upUrl,] + } +} + + var changeUrlTimes = 0; + + /** + * reset upload url + * if current page protocal is https + * it will always return 'https://up.qbox.me' + * else + * it will set 'qiniuUploadUrl' value with 'qiniuUploadUrls' looply + */ + this.resetUploadUrl = function(){ + var hosts = window.location.protocol === 'https:' ? qiniuUpHosts.https : qiniuUpHosts.http; + var i = changeUrlTimes % hosts.length; + qiniuUploadUrl = hosts[i]; + changeUrlTimes++; + logger.debug('resetUploadUrl: '+qiniuUploadUrl); + }; + + // this.resetUploadUrl(); + + + /** + * is image + * @param {String} url of a file + * @return {Boolean} file is a image or not + */ + this.isImage = function(url) { + url = url.split(/[?#]/)[0]; + return (/\.(png|jpg|jpeg|gif|bmp)$/i).test(url); + }; + + /** + * get file extension + * @param {String} filename + * @return {String} file extension + * @example + * input: test.txt + * output: txt + */ + this.getFileExtension = function(filename) { + var tempArr = filename.split("."); + var ext; + if (tempArr.length === 1 || (tempArr[0] === "" && tempArr.length === 2)) { + ext = ""; + } else { + ext = tempArr.pop().toLowerCase(); //get the extension and make it lower-case + } + return ext; + }; + + /** + * encode string by utf8 + * @param {String} string to encode + * @return {String} encoded string + */ + this.utf8_encode = function(argString) { + // http://kevin.vanzonneveld.net + // + original by: Webtoolkit.info (http://www.webtoolkit.info/) + // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + improved by: sowberry + // + tweaked by: Jack + // + bugfixed by: Onno Marsman + // + improved by: Yves Sucaet + // + bugfixed by: Onno Marsman + // + bugfixed by: Ulrich + // + bugfixed by: Rafal Kukawski + // + improved by: kirilloid + // + bugfixed by: kirilloid + // * example 1: this.utf8_encode('Kevin van Zonneveld'); + // * returns 1: 'Kevin van Zonneveld' + + if (argString === null || typeof argString === 'undefined') { + return ''; + } + + var string = (argString + ''); // .replace(/\r\n/g, '\n').replace(/\r/g, '\n'); + var utftext = '', + start, end, stringl = 0; + + start = end = 0; + stringl = string.length; + for (var n = 0; n < stringl; n++) { + var c1 = string.charCodeAt(n); + var enc = null; + + if (c1 < 128) { + end++; + } else if (c1 > 127 && c1 < 2048) { + enc = String.fromCharCode( + (c1 >> 6) | 192, (c1 & 63) | 128 + ); + } else if (c1 & 0xF800 ^ 0xD800 > 0) { + enc = String.fromCharCode( + (c1 >> 12) | 224, ((c1 >> 6) & 63) | 128, (c1 & 63) | 128 + ); + } else { // surrogate pairs + if (c1 & 0xFC00 ^ 0xD800 > 0) { + throw new RangeError('Unmatched trail surrogate at ' + n); + } + var c2 = string.charCodeAt(++n); + if (c2 & 0xFC00 ^ 0xDC00 > 0) { + throw new RangeError('Unmatched lead surrogate at ' + (n - 1)); + } + c1 = ((c1 & 0x3FF) << 10) + (c2 & 0x3FF) + 0x10000; + enc = String.fromCharCode( + (c1 >> 18) | 240, ((c1 >> 12) & 63) | 128, ((c1 >> 6) & 63) | 128, (c1 & 63) | 128 + ); + } + if (enc !== null) { + if (end > start) { + utftext += string.slice(start, end); + } + utftext += enc; + start = end = n + 1; + } + } + + if (end > start) { + utftext += string.slice(start, stringl); + } + + return utftext; + }; + + this.base64_decode = function (data) { + // http://kevin.vanzonneveld.net + // + original by: Tyler Akins (http://rumkin.com) + // + improved by: Thunder.m + // + input by: Aman Gupta + // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + bugfixed by: Onno Marsman + // + bugfixed by: Pellentesque Malesuada + // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + input by: Brett Zamir (http://brett-zamir.me) + // + bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // * example 1: base64_decode('S2V2aW4gdmFuIFpvbm5ldmVsZA=='); + // * returns 1: 'Kevin van Zonneveld' + // mozilla has this native + // - but breaks in 2.0.0.12! + //if (typeof this.window['atob'] == 'function') { + // return atob(data); + //} + var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + var o1, o2, o3, h1, h2, h3, h4, bits, i = 0, + ac = 0, + dec = "", + tmp_arr = []; + + if (!data) { + return data; + } + + data += ''; + + do { // unpack four hexets into three octets using index points in b64 + h1 = b64.indexOf(data.charAt(i++)); + h2 = b64.indexOf(data.charAt(i++)); + h3 = b64.indexOf(data.charAt(i++)); + h4 = b64.indexOf(data.charAt(i++)); + + bits = h1 << 18 | h2 << 12 | h3 << 6 | h4; + + o1 = bits >> 16 & 0xff; + o2 = bits >> 8 & 0xff; + o3 = bits & 0xff; + + if (h3 === 64) { + tmp_arr[ac++] = String.fromCharCode(o1); + } else if (h4 === 64) { + tmp_arr[ac++] = String.fromCharCode(o1, o2); + } else { + tmp_arr[ac++] = String.fromCharCode(o1, o2, o3); + } + } while (i < data.length); + + dec = tmp_arr.join(''); + + return dec; + }; + + /** + * encode data by base64 + * @param {String} data to encode + * @return {String} encoded data + */ + this.base64_encode = function(data) { + // http://kevin.vanzonneveld.net + // + original by: Tyler Akins (http://rumkin.com) + // + improved by: Bayron Guevara + // + improved by: Thunder.m + // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + bugfixed by: Pellentesque Malesuada + // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // - depends on: this.utf8_encode + // * example 1: this.base64_encode('Kevin van Zonneveld'); + // * returns 1: 'S2V2aW4gdmFuIFpvbm5ldmVsZA==' + // mozilla has this native + // - but breaks in 2.0.0.12! + //if (typeof this.window['atob'] == 'function') { + // return atob(data); + //} + var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; + var o1, o2, o3, h1, h2, h3, h4, bits, i = 0, + ac = 0, + enc = '', + tmp_arr = []; + + if (!data) { + return data; + } + + data = this.utf8_encode(data + ''); + + do { // pack three octets into four hexets + o1 = data.charCodeAt(i++); + o2 = data.charCodeAt(i++); + o3 = data.charCodeAt(i++); + + bits = o1 << 16 | o2 << 8 | o3; + + h1 = bits >> 18 & 0x3f; + h2 = bits >> 12 & 0x3f; + h3 = bits >> 6 & 0x3f; + h4 = bits & 0x3f; + + // use hexets to index into b64, and append result to encoded string + tmp_arr[ac++] = b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4); + } while (i < data.length); + + enc = tmp_arr.join(''); + + switch (data.length % 3) { + case 1: + enc = enc.slice(0, -2) + '=='; + break; + case 2: + enc = enc.slice(0, -1) + '='; + break; + } + + return enc; + }; + + /** + * encode string in url by base64 + * @param {String} string in url + * @return {String} encoded string + */ + this.URLSafeBase64Encode = function(v) { + v = this.base64_encode(v); + return v.replace(/\//g, '_').replace(/\+/g, '-'); + }; + + this.URLSafeBase64Decode = function(v) { + v = v.replace(/_/g, '/').replace(/-/g, '+'); + return this.base64_decode(v); + }; + + // TODO: use mOxie + /** + * craete object used to AJAX + * @return {Object} + */ + this.createAjax = function(argument) { + var xmlhttp = {}; + if (window.XMLHttpRequest) { + xmlhttp = new XMLHttpRequest(); + } else { + xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); + } + return xmlhttp; + }; + + // TODO: enhance IE compatibility + /** + * parse json string to javascript object + * @param {String} json string + * @return {Object} object + */ + this.parseJSON = function(data) { + // Attempt to parse using the native JSON parser first + if (window.JSON && window.JSON.parse) { + return window.JSON.parse(data); + } + + //var rx_one = /^[\],:{}\s]*$/, + // rx_two = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, + // rx_three = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, + // rx_four = /(?:^|:|,)(?:\s*\[)+/g, + var rx_dangerous = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g; + + //var json; + + var text = String(data); + rx_dangerous.lastIndex = 0; + if(rx_dangerous.test(text)){ + text = text.replace(rx_dangerous, function(a){ + return '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); + }); + } + + // todo 使用一下判断,增加安全性 + //if ( + // rx_one.test( + // text + // .replace(rx_two, '@') + // .replace(rx_three, ']') + // .replace(rx_four, '') + // ) + //) { + // return eval('(' + text + ')'); + //} + + return eval('('+text+')'); + }; + + /** + * parse javascript object to json string + * @param {Object} object + * @return {String} json string + */ + this.stringifyJSON = function(obj) { + // Attempt to parse using the native JSON parser first + if (window.JSON && window.JSON.stringify) { + return window.JSON.stringify(obj); + } + switch (typeof (obj)) { + case 'string': + return '"' + obj.replace(/(["\\])/g, '\\$1') + '"'; + case 'array': + return '[' + obj.map(that.stringifyJSON).join(',') + ']'; + case 'object': + if (obj instanceof Array) { + var strArr = []; + var len = obj.length; + for (var i = 0; i < len; i++) { + strArr.push(that.stringifyJSON(obj[i])); + } + return '[' + strArr.join(',') + ']'; + } else if (obj === null) { + return 'null'; + } else { + var string = []; + for (var property in obj) { + if (obj.hasOwnProperty(property)) { + string.push(that.stringifyJSON(property) + ':' + that.stringifyJSON(obj[property])); + } + } + return '{' + string.join(',') + '}'; + } + break; + case 'number': + return obj; + case false: + return obj; + case 'boolean': + return obj; + } + }; + + /** + * trim space beside text + * @param {String} untrimed string + * @return {String} trimed string + */ + this.trim = function(text) { + return text === null ? "" : text.replace(/^\s+|\s+$/g, ''); + }; + + /** + * create a uploader by QiniuJsSDK + * @param {object} options to create a new uploader + * @return {object} uploader + */ + this.uploader = function(op) { + + /********** inner function define start **********/ + + // according the different condition to reset chunk size + // and the upload strategy according with the chunk size + // when chunk size is zero will cause to direct upload + // see the statement binded on 'BeforeUpload' event + var reset_chunk_size = function() { + var ie = that.detectIEVersion(); + var BLOCK_BITS, MAX_CHUNK_SIZE, chunk_size; + // case Safari 5、Windows 7、iOS 7 set isSpecialSafari to true + var isSpecialSafari = (moxie.core.utils.Env.browser === "Safari" && moxie.core.utils.Env.version <= 5 && moxie.core.utils.Env.os === "Windows" && moxie.core.utils.Env.osVersion === "7") || (moxie.core.utils.Env.browser === "Safari" && moxie.core.utils.Env.os === "iOS" && moxie.core.utils.Env.osVersion === "7"); + // case IE 9-,chunk_size is not empty and flash is included in runtimes + // set op.chunk_size to zero + //if (ie && ie < 9 && op.chunk_size && op.runtimes.indexOf('flash') >= 0) { + if (ie && ie < 9 && op.chunk_size && op.runtimes.indexOf('flash') >= 0) { + // link: http://www.plupload.com/docs/Frequently-Asked-Questions#when-to-use-chunking-and-when-not + // when plupload chunk_size setting is't null ,it cause bug in ie8/9 which runs flash runtimes (not support html5) . + op.chunk_size = 0; + } else if (isSpecialSafari) { + // win7 safari / iOS7 safari have bug when in chunk upload mode + // reset chunk_size to 0 + // disable chunk in special version safari + op.chunk_size = 0; + } else { + BLOCK_BITS = 20; + MAX_CHUNK_SIZE = 4 << BLOCK_BITS; //4M + + chunk_size = plupload.parseSize(op.chunk_size); + if (chunk_size > MAX_CHUNK_SIZE) { + op.chunk_size = MAX_CHUNK_SIZE; + } + // qiniu service max_chunk_size is 4m + // reset chunk_size to max_chunk_size(4m) when chunk_size > 4m + } + // if op.chunk_size set 0 will be cause to direct upload + }; + + var getHosts = function(hosts) { + var result = []; + for (var i = 0; i < hosts.length; i++) { + var host = hosts[i]; + if (host.indexOf('-H') === 0) { + result.push(host.split(' ')[2]); + } else { + result.push(host); + } + } + return result; + }; + + var getPutPolicy = function (uptoken) { + if(uploadConfig.saveType =="oss" || uploadConfig.saveType =="upyun"||uploadConfig.saveType =="s3"||uploadConfig.saveType =="remote"){ + return "oss"; + }else{ + var segments = uptoken.split(":"); + var ak = segments[0]; + var putPolicy = that.parseJSON(that.URLSafeBase64Decode(segments[2])); + putPolicy.ak = ak; + if (putPolicy.scope.indexOf(":") >= 0) { + putPolicy.bucket = putPolicy.scope.split(":")[0]; + putPolicy.key = putPolicy.scope.split(":")[1]; + } else { + putPolicy.bucket = putPolicy.scope; + } + return putPolicy; + } + }; + + var getUpHosts = function(uptoken) { + var putPolicy = getPutPolicy(uptoken); + // var uphosts_url = "//uc.qbox.me/v1/query?ak="+ak+"&bucket="+putPolicy.scope; + // IE 9- is not support protocal relative url + var uphosts_url = window.location.protocol + "//uc.qbox.me/v1/query?ak=" + putPolicy.ak + "&bucket=" + putPolicy.bucket; + logger.debug("putPolicy: ", putPolicy); + logger.debug("get uphosts from: ", uphosts_url); + var ie = that.detectIEVersion(); + var ajax; + if (ie && ie <= 9) { + ajax = new moxie.XMLHttpRequest(); + moxie.core.utils.Env.swf_url = op.flash_swf_url; + }else{ + ajax = that.createAjax(); + } + if(uploadConfig.saveType != "qiniu"){ + qiniuUpHosts.http = [uploadConfig.upUrl]; + qiniuUpHosts.http = [uploadConfig.upUrl]; + that.resetUploadUrl(); + }else{ + ajax.open('GET', uphosts_url, false); + var onreadystatechange = function(){ + logger.debug("ajax.readyState: ", ajax.readyState); + if (ajax.readyState === 4) { + logger.debug("ajax.status: ", ajax.status); + if (ajax.status < 400) { + var res = that.parseJSON(ajax.responseText); + qiniuUpHosts.http = getHosts(res.http.up); + qiniuUpHosts.https = getHosts(res.https.up); + logger.debug("get new uphosts: ", qiniuUpHosts); + that.resetUploadUrl(); + } else { + logger.error("get uphosts error: ", ajax.responseText); + } + } + }; + if (ie && ie <= 9) { + ajax.bind('readystatechange', onreadystatechange); + }else{ + ajax.onreadystatechange = onreadystatechange; + } + ajax.send(); + // ajax.send(); + // if (ajax.status < 400) { + // var res = that.parseJSON(ajax.responseText); + // qiniuUpHosts.http = getHosts(res.http.up); + // qiniuUpHosts.https = getHosts(res.https.up); + // logger.debug("get new uphosts: ", qiniuUpHosts); + // that.resetUploadUrl(); + // } else { + // logger.error("get uphosts error: ", ajax.responseText); + // } + } + return; + }; + + var getUptoken = function(file) { + if(uploadConfig.saveType == "remote"){ + return that.token; + } + if (!that.token || (op.uptoken_url && that.tokenInfo.isExpired())) { + return getNewUpToken(file); + } else { + return that.token; + } + }; + + // getNewUptoken maybe called at Init Event or BeforeUpload Event + // case Init Event, the file param of getUptken will be set a null value + // if op.uptoken has value, set uptoken with op.uptoken + // else if op.uptoken_url has value, set uptoken from op.uptoken_url + // else if op.uptoken_func has value, set uptoken by result of op.uptoken_func + var getNewUpToken = function(file) { + if (op.uptoken) { + that.token = op.uptoken; + } else if (op.uptoken_url) { + logger.debug("get uptoken from: ", that.uptoken_url); + // TODO: use mOxie + var ajax = that.createAjax(); + ajax.open('GET', that.uptoken_url, false); + ajax.setRequestHeader("If-Modified-Since", "0"); + // ajax.onreadystatechange = function() { + // if (ajax.readyState === 4 && ajax.status === 200) { + // var res = that.parseJSON(ajax.responseText); + // that.token = res.uptoken; + // } + // }; + ajax.send(); + if (ajax.status === 200) { + var res = that.parseJSON(ajax.responseText); + that.token = res.uptoken; + if (uploadConfig.saveType == "oss"){ + var putPolicy = that.token; + that.sign = res.sign; + that.access = res.id; + that.file_name = res.key; + that.callback = res.callback; + }else if(uploadConfig.saveType == "s3"){ + var putPolicy = that.token; + that.sign = res.sign; + that.policy = res.policy; + that.file_name = res.key; + that.credential = res.credential; + that.x_amz_date = res.x_amz_date; + that.surl = res.siteUrl; + that.callbackKey = res.callBackKey; + }else if(uploadConfig.saveType == "upyun"){ + var putPolicy = that.token; + that.token = res.token; + that.policy = res.policy; + }else if(uploadConfig.saveType == "remote"){ + var putPolicy = that.token; + that.policy = res.uptoken; + }else{ + var segments = that.token.split(":"); + var putPolicy = that.parseJSON(that.URLSafeBase64Decode(segments[2])); + if (!that.tokenMap) { + that.tokenMap = {}; + } + var getTimestamp = function(time) { + return Math.ceil(time.getTime()/1000); + }; + var serverTime = getTimestamp(new Date(ajax.getResponseHeader("date"))); + var clientTime = getTimestamp(new Date()); + that.tokenInfo = { + serverDelay: clientTime - serverTime, + deadline: putPolicy.deadline, + isExpired: function() { + var leftTime = this.deadline - getTimestamp(new Date()) + this.serverDelay; + return leftTime < 600; + } + }; + logger.debug("get token info: ", that.tokenInfo); + } + + logger.debug("get new uptoken: ", that.token); + + } else { + logger.error("get uptoken error: ", ajax.responseText); + } + } else if (op.uptoken_func) { + logger.debug("get uptoken from uptoken_func"); + that.token = op.uptoken_func(file); + logger.debug("get new uptoken: ", that.token); + } else { + logger.error("one of [uptoken, uptoken_url, uptoken_func] settings in options is required!"); + } + if (that.token) { + getUpHosts(that.token); + } + return that.token; + }; + + // get file key according with the user passed options + var getFileKey = function(up, file, func) { + // WARNING + // When you set the key in putPolicy by "scope": "bucket:key" + // You should understand the risk of override a file in the bucket + // So the code below that automatically get key from uptoken has been commented + // var putPolicy = getPutPolicy(that.token) + // if (putPolicy.key) { + // logger.debug("key is defined in putPolicy.scope: ", putPolicy.key) + // return putPolicy.key + // } + var key = '', + unique_names = false; + if (!op.save_key) { + unique_names = up.getOption && up.getOption('unique_names'); + unique_names = unique_names || (up.settings && up.settings.unique_names); + if (unique_names) { + var ext = that.getFileExtension(file.name); + key = ext ? file.id + '.' + ext : file.id; + } else if (typeof func === 'function') { + key = func(up, file); + } else { + key = file.name; + } + } + if(uploadConfig.saveType == "qiniu"){ + return ""; + } + return key; + }; + + /********** inner function define end **********/ + + if (op.log_level) { + logger.level = op.log_level; + } + + if (!op.domain) { + throw 'domain setting in options is required!'; + } + + if (!op.browse_button) { + throw 'browse_button setting in options is required!'; + } + + if (!op.uptoken && !op.uptoken_url && !op.uptoken_func) { + throw 'one of [uptoken, uptoken_url, uptoken_func] settings in options is required!'; + } + + logger.debug("init uploader start"); + + logger.debug("environment: ", moxie.core.utils.Env); + + logger.debug("userAgent: ", navigator.userAgent); + + var option = {}; + + // hold the handler from user passed options + var _Error_Handler = op.init && op.init.Error; + var _FileUploaded_Handler = op.init && op.init.FileUploaded; + + // replace the handler for intercept + op.init.Error = function() {}; + op.init.FileUploaded = function() {}; + + that.uptoken_url = op.uptoken_url; + that.token = ''; + that.key_handler = typeof op.init.Key === 'function' ? op.init.Key : ''; + this.domain = op.domain; + // TODO: ctx is global in scope of a uploader instance + // this maybe cause error + var ctx = ''; + var speedCalInfo = { + isResumeUpload: false, + resumeFilesize: 0, + startTime: '', + currentTime: '' + }; + + reset_chunk_size(); + logger.debug("invoke reset_chunk_size()"); + logger.debug("op.chunk_size: ", op.chunk_size); + + var defaultSetting = { + url: qiniuUploadUrl, + multipart_params: { + token: '' + } + }; + var ie = that.detectIEVersion(); + // case IE 9- + // add accept in multipart params + if (ie && ie <= 9) { + defaultSetting.multipart_params.accept = 'text/plain; charset=utf-8'; + logger.debug("add accept text/plain in multipart params"); + } + + // compose options with user passed options and default setting + plupload.extend(option, op, defaultSetting); + + logger.debug("option: ", option); + + // create a new uploader with composed options + var uploader = new plupload.Uploader(option); + + logger.debug("new plupload.Uploader(option)"); + + // bind getNewUpToken to 'Init' event + uploader.bind('Init', function(up, params) { + logger.debug("Init event activated"); + // if op.get_new_uptoken is not true + // invoke getNewUptoken when uploader init + // else + // getNewUptoken everytime before a new file upload + if(!op.get_new_uptoken){ + getNewUpToken(null); + } + //getNewUpToken(null); + }); + + logger.debug("bind Init event"); + + // bind 'FilesAdded' event + // when file be added and auto_start has set value + // uploader will auto start upload the file + uploader.bind('FilesAdded', function(up, files) { + logger.debug("FilesAdded event activated"); + var auto_start = up.getOption && up.getOption('auto_start'); + auto_start = auto_start || (up.settings && up.settings.auto_start); + logger.debug("auto_start: ", auto_start); + logger.debug("files: ", files); + + + for (var i = 0; i < files.length; i++) { + var file = files[i]; + file.path = decodeURIComponent(getCookieByString("path_tmp")); + + } + + // detect is iOS + var is_ios = function (){ + if(moxie.core.utils.Env.OS.toLowerCase()==="ios") { + return true; + } else { + return false; + } + }; + + // if current env os is iOS change file name to [time].[ext] + if (is_ios()) { + for (var i = 0; i < files.length; i++) { + var file = files[i]; + var ext = that.getFileExtension(file.name); + file.name = file.id + "." + ext; + } + } + + if (auto_start) { + setTimeout(function(){ + up.start(); + logger.debug("invoke up.start()"); + }, 0); + // up.start(); + // plupload.each(files, function(i, file) { + // up.start(); + // logger.debug("invoke up.start()") + // logger.debug("file: ", file); + // }); + } + up.refresh(); // Reposition Flash/Silverlight + }); + + logger.debug("bind FilesAdded event"); + + // bind 'BeforeUpload' event + // intercept the process of upload + // - prepare uptoken + // - according the chunk size to make differnt upload strategy + // - resume upload with the last breakpoint of file + uploader.bind('BeforeUpload', function(up, file) { + logger.debug("BeforeUpload event activated"); + getNewUpToken(file); + // add a key named speed for file object + file.speed = file.speed || 0; + ctx = ''; + + var directUpload = function(up, file, func) { + speedCalInfo.startTime = new Date().getTime(); + + + + var multipart_params_obj; + if (op.save_key) { + multipart_params_obj = { + 'token': that.token + }; + } else { + multipart_params_obj = { + 'key': getFileKey(up, file, func), + 'token': that.token + }; + if(uploadConfig.saveType == "qiniu"){ + multipart_params_obj = { + 'token': that.token, + 'x:path': file.path + }; + }else if(uploadConfig.saveType == "local"||uploadConfig.saveType == "onedrive"){ + multipart_params_obj = { + 'path': file.path + }; + }else if(uploadConfig.saveType == "remote"){ + multipart_params_obj = { + 'path': file.path, + "token" :that.policy, + "MAX_FILE_SIZE":4194304, + }; + }else if(uploadConfig.saveType == "oss"){ + multipart_params_obj = { + 'policy': that.token, + 'x:path': file.path, + "signature":that.sign, + "OSSAccessKeyId":that.access, + 'x:fname':file.name, + "key" :that.file_name.replace("${filename}", file.name), + "callback":that.callback, + }; + }else if(uploadConfig.saveType == "s3"){ + multipart_params_obj = { + 'policy': that.policy, + "key" :that.file_name+"/"+(file.path.replace(",","/") == "" ? "" : file.path.replace(",","/")+"/")+file.name, + "success_action_redirect" :that.surl+"Callback/S3/key/"+that.callbackKey, + "x-amz-algorithm":"AWS4-HMAC-SHA256", + "x-amz-credential":that.credential, + "x-amz-date":that.x_amz_date, + "x-amz-signature":that.sign, + "Content-Type":file.type, + }; + }else if(uploadConfig.saveType == "upyun"){ + multipart_params_obj = { + 'authorization': that.token, + 'policy': that.policy, + }; + } + } + var ie = that.detectIEVersion(); + // case IE 9- + // add accept in multipart params + if (ie && ie <= 9) { + multipart_params_obj.accept = 'text/plain; charset=utf-8'; + logger.debug("add accept text/plain in multipart params"); + } + + logger.debug("directUpload multipart_params_obj: ", multipart_params_obj); + + var x_vars = op.x_vars; + if (x_vars !== undefined && typeof x_vars === 'object') { + for (var x_key in x_vars) { + if (x_vars.hasOwnProperty(x_key)) { + if (typeof x_vars[x_key] === 'function') { + multipart_params_obj['x:' + x_key] = x_vars[x_key](up, file); + } else if (typeof x_vars[x_key] !== 'object') { + multipart_params_obj['x:' + x_key] = x_vars[x_key]; + } + } + } + } + + up.setOption({ + 'url': qiniuUploadUrl, + 'multipart': true, + 'chunk_size': is_android_weixin_or_qq() ? op.max_file_size : undefined, + 'multipart_params': multipart_params_obj + }); + }; + + // detect is weixin or qq inner browser + var is_android_weixin_or_qq = function (){ + var ua = navigator.userAgent.toLowerCase(); + if((ua.match(/MicroMessenger/i) || moxie.core.utils.Env.browser === "QQBrowser" || ua.match(/V1_AND_SQ/i)) && moxie.core.utils.Env.OS.toLowerCase()==="android") { + return true; + } else { + return false; + } + }; + + var chunk_size = up.getOption && up.getOption('chunk_size'); + chunk_size = chunk_size || (up.settings && up.settings.chunk_size); + + logger.debug("uploader.runtime: ",uploader.runtime); + logger.debug("chunk_size: ",chunk_size); + + // TODO: flash support chunk upload + if ((uploader.runtime === 'html5' || uploader.runtime === 'flash') && chunk_size) { + if (file.size < chunk_size || is_android_weixin_or_qq()) { + logger.debug("directUpload because file.size < chunk_size || is_android_weixin_or_qq()"); + // direct upload if file size is less then the chunk size + directUpload(up, file, that.key_handler); + } else { + // TODO: need a polifill to make it work in IE 9- + // ISSUE: if file.name is existed in localStorage + // but not the same file maybe cause error + var localFileInfo = localStorage.getItem(file.name); + var blockSize = chunk_size; + if (localFileInfo) { + // TODO: although only the html5 runtime will enter this statement + // but need uniform way to make convertion between string and json + localFileInfo = that.parseJSON(localFileInfo); + var now = (new Date()).getTime(); + var before = localFileInfo.time || 0; + var aDay = 24 * 60 * 60 * 1000; // milliseconds of one day + // if the last upload time is within one day + // will upload continuously follow the last breakpoint + // else + // will reupload entire file + if (now - before < aDay) { + + if (localFileInfo.percent !== 100) { + if (file.size === localFileInfo.total) { + // TODO: if file.name and file.size is the same + // but not the same file will cause error + file.percent = localFileInfo.percent; + file.loaded = localFileInfo.offset; + ctx = localFileInfo.ctx; + + // set speed info + speedCalInfo.isResumeUpload = true; + speedCalInfo.resumeFilesize = localFileInfo.offset; + + // set block size + if (localFileInfo.offset + blockSize > file.size) { + blockSize = file.size - localFileInfo.offset; + } + } else { + // remove file info when file.size is conflict with file info + localStorage.removeItem(file.name); + } + + } else { + // remove file info when upload percent is 100% + // avoid 499 bug + localStorage.removeItem(file.name); + } + } else { + // remove file info when last upload time is over one day + localStorage.removeItem(file.name); + } + } + speedCalInfo.startTime = new Date().getTime(); + var multipart_params_obj = {}; + var ie = that.detectIEVersion(); + // case IE 9- + // add accept in multipart params + if (ie && ie <= 9) { + multipart_params_obj.accept = 'text/plain; charset=utf-8'; + logger.debug("add accept text/plain in multipart params"); + } + // TODO: to support bput + // http://developer.qiniu.com/docs/v6/api/reference/up/bput.html + if(uploadConfig.saveType == "remote"){ + up.setOption({ + 'url': qiniuUploadUrl + 'chunk.php', + 'multipart': false, + 'chunk_size': chunk_size, + 'required_features': "chunks", + 'headers': { + 'Authorization': getUptoken(file) + }, + 'multipart_params': multipart_params_obj + }); + }else{ + up.setOption({ + 'url': qiniuUploadUrl + '/mkblk/' + blockSize, + 'multipart': false, + 'chunk_size': chunk_size, + 'required_features': "chunks", + 'headers': { + 'Authorization': 'UpToken ' + getUptoken(file) + }, + 'multipart_params': multipart_params_obj + }); + } + } + } else { + logger.debug("directUpload because uploader.runtime !== 'html5' || uploader.runtime !== 'flash' || !chunk_size"); + // direct upload if runtime is not html5 + directUpload(up, file, that.key_handler); + } + }); + + logger.debug("bind BeforeUpload event"); + + // bind 'UploadProgress' event + // calculate upload speed + uploader.bind('UploadProgress', function(up, file) { + logger.trace("UploadProgress event activated"); + speedCalInfo.currentTime = new Date().getTime(); + var timeUsed = speedCalInfo.currentTime - speedCalInfo.startTime; // ms + var fileUploaded = file.loaded || 0; + if (speedCalInfo.isResumeUpload) { + fileUploaded = file.loaded - speedCalInfo.resumeFilesize; + } + file.speed = (fileUploaded / timeUsed * 1000).toFixed(0) || 0; // unit: byte/s + }); + + logger.debug("bind UploadProgress event"); + + // bind 'ChunkUploaded' event + // store the chunk upload info and set next chunk upload url + uploader.bind('ChunkUploaded', function(up, file, info) { + logger.debug("ChunkUploaded event activated"); + logger.debug("file: ", file); + logger.debug("info: ", info); + var res = that.parseJSON(info.response); + logger.debug("res: ", res); + // ctx should look like '[chunk01_ctx],[chunk02_ctx],[chunk03_ctx],...' + ctx = ctx ? ctx + ',' + res.ctx : res.ctx; + var leftSize = info.total - info.offset; + var chunk_size = up.getOption && up.getOption('chunk_size'); + chunk_size = chunk_size || (up.settings && up.settings.chunk_size); + if (leftSize < chunk_size) { + up.setOption({ + 'url': qiniuUploadUrl + '/mkblk/' + leftSize + }); + if(uploadConfig.saveType == "remote"){ + up.setOption({ + 'url': qiniuUploadUrl + 'chunk.php' + }); + } + logger.debug("up.setOption url: ", qiniuUploadUrl + '/mkblk/' + leftSize); + } + if(uploadConfig.saveType == "remote"){ + up.setOption({ + 'headers': { + 'Authorization': getUptoken(file) + } + }); + }else{ + up.setOption({ + 'headers': { + 'Authorization': 'UpToken ' + getUptoken(file) + } + }); + } + localStorage.setItem(file.name, that.stringifyJSON({ + ctx: ctx, + percent: file.percent, + total: info.total, + offset: info.offset, + time: (new Date()).getTime() + })); + }); + + logger.debug("bind ChunkUploaded event"); + + var retries = qiniuUploadUrls.length; + + // if error is unkown switch upload url and retry + var unknow_error_retry = function(file){ + if (retries-- > 0) { + setTimeout(function(){ + that.resetUploadUrl(); + file.status = plupload.QUEUED; + uploader.stop(); + uploader.start(); + }, 0); + return true; + }else{ + retries = qiniuUploadUrls.length; + return false; + } + }; + + // bind 'Error' event + // check the err.code and return the errTip + uploader.bind('Error', (function(_Error_Handler) { + return function(up, err) { + logger.error("Error event activated"); + logger.error("err: ", err); + var errTip = ''; + var file = err.file; + if (file) { + switch (err.code) { + case plupload.FAILED: + errTip = '上传失败。请稍后再试。'; + break; + case plupload.FILE_SIZE_ERROR: + var max_file_size = up.getOption && up.getOption('max_file_size'); + max_file_size = max_file_size || (up.settings && up.settings.max_file_size); + errTip = '文件过大,您当前用户组最多可上传' + max_file_size + '的文件'; + break; + case plupload.FILE_EXTENSION_ERROR: + errTip = '您当前的用户组不可上传此文件'; + break; + case plupload.HTTP_ERROR: + if (err.response === '') { + // Fix parseJSON error ,when http error is like net::ERR_ADDRESS_UNREACHABLE + errTip = err.message || '未知网络错误。'; + if (!unknow_error_retry(file)) { + return; + } + break; + } + if(uploadConfig.saveType == "oss"){ + var str = err.response + var a = $.parseXML(str); + $(a).find('Error').each(function () { + errTip = $(this).children('Message').text(); + var errorText = "Error"; + }); + if(err.status == 203){ + errTip = "上传失败,请检查空间容量、是否重名"; + } + }else if(uploadConfig.saveType == "s3" && err.status!=401){ + var str = err.response + var a = $.parseXML(str); + $(a).find('Error').each(function () { + errTip = $(this).children('Message').text(); + var errorText = "Error"; + }); + }else{ + var errorObj = that.parseJSON(err.response); + var errorText = errorObj.error; + if (err.status==579){ + var errorObj2 = that.parseJSON(errorText); + errorText=errorObj2.error; + } + switch (err.status) { + case 400: + errTip = "请求报文格式错误。"; + break; + case 401: + errTip = "客户端认证授权失败。请重试或提交反馈。"; + break; + case 405: + errTip = "客户端请求错误。请重试或提交反馈。"; + break; + case 579: + errTip = "资源上传成功,但回调失败。"; + break; + case 599: + errTip = "网络连接异常。请重试或提交反馈。"; + if (!unknow_error_retry(file)) { + return; + } + break; + case 614: + errTip = "文件已存在。"; + try { + errorObj = that.parseJSON(errorObj.error); + errorText = errorObj.error || 'file exists'; + } catch (e) { + errorText = errorObj.error || 'file exists'; + } + break; + case 631: + errTip = "指定空间不存在。"; + break; + case 701: + errTip = "上传数据块校验出错。请重试或提交反馈。"; + break; + default: + errTip = "未知错误。"; + if (!unknow_error_retry(file)) { + return; + } + break; + } + + } + errTip = errTip + '(' + err.status + ':' + errorText + ')'; + break; + case plupload.SECURITY_ERROR: + errTip = '安全配置错误。请联系网站管理员。'; + break; + case plupload.GENERIC_ERROR: + errTip = '上传失败。请稍后再试。'; + break; + case plupload.IO_ERROR: + errTip = '上传失败。请稍后再试。'; + break; + case plupload.INIT_ERROR: + errTip = '网站配置错误。请联系网站管理员。'; + uploader.destroy(); + break; + default: + errTip = err.message + err.details; + if (!unknow_error_retry(file)) { + return; + } + break; + } + if (_Error_Handler) { + _Error_Handler(up, err, errTip); + } + } + up.refresh(); // Reposition Flash/Silverlight + }; + })(_Error_Handler)); + + logger.debug("bind Error event"); + + // bind 'FileUploaded' event + // intercept the complete of upload + // - get downtoken from downtoken_url if bucket is private + // - invoke mkfile api to compose chunks if upload strategy is chunk upload + uploader.bind('FileUploaded', (function(_FileUploaded_Handler) { + return function(up, file, info) { + logger.debug("FileUploaded event activated"); + logger.debug("file: ", file); + logger.debug("info: ", info); + if(uploadConfig.saveType == "s3"){ + } + var last_step = function(up, file, info) { + if (op.downtoken_url) { + // if op.dowontoken_url is not empty + // need get downtoken before invoke the _FileUploaded_Handler + var ajax_downtoken = that.createAjax(); + ajax_downtoken.open('POST', op.downtoken_url, true); + ajax_downtoken.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); + ajax_downtoken.onreadystatechange = function() { + if (ajax_downtoken.readyState === 4) { + + if (ajax_downtoken.status === 200 || ajax_downtoken.status === 204||ajax_downtoken.status === 303) { + + var res_downtoken; + try { + res_downtoken = that.parseJSON(ajax_downtoken.responseText); + } catch (e) { + throw ('invalid json format'); + } + var info_extended = {}; + plupload.extend(info_extended, that.parseJSON(info), res_downtoken); + if (_FileUploaded_Handler) { + _FileUploaded_Handler(up, file, that.stringifyJSON(info_extended)); + } + + } else { + uploader.trigger('Error', { + status: ajax_downtoken.status, + response: ajax_downtoken.responseText, + file: file, + code: plupload.HTTP_ERROR + }); + } + } + }; + ajax_downtoken.send('key=' + that.parseJSON(info).key + '&domain=' + op.domain); + } else if (_FileUploaded_Handler) { + _FileUploaded_Handler(up, file, info); + } + }; + if(uploadConfig.saveType == "oss" || uploadConfig.saveType == "upyun"){ + ctx = 0; + }else{ + var res = that.parseJSON(info.response); + ctx = ctx ? ctx : res.ctx; + } + // if ctx is not empty + // that means the upload strategy is chunk upload + // befroe the invoke the last_step + // we need request the mkfile to compose all uploaded chunks + // else + // invalke the last_step + logger.debug("ctx: ", ctx); + if (ctx) { + var key = ''; + logger.debug("save_key: ", op.save_key); + if (!op.save_key) { + key = getFileKey(up, file, that.key_handler); + key = key ? '/key/' + that.URLSafeBase64Encode(key) : ''; + } + + var fname = '/fname/' + that.URLSafeBase64Encode(file.name); + if(uploadConfig.saveType=="remote"){ + if (!op.save_key) { + key = getFileKey(up, file, that.key_handler); + key = key ? that.URLSafeBase64Encode(key) : ''; + } + fname = '' + that.URLSafeBase64Encode(file.name); + op.x_vars= { + 'path': file.path, + }; + } + logger.debug("op.x_vars: ", op.x_vars); + if(uploadConfig.saveType == "qiniu"){ + op.x_vars= { + 'path': file.path, + }; + } + var x_vars = op.x_vars, + x_val = '', + x_vars_url = ''; + if (x_vars !== undefined && typeof x_vars === 'object') { + for (var x_key in x_vars) { + if (x_vars.hasOwnProperty(x_key)) { + if (typeof x_vars[x_key] === 'function') { + x_val = that.URLSafeBase64Encode(x_vars[x_key](up, file)); + } else if (typeof x_vars[x_key] !== 'object') { + x_val = that.URLSafeBase64Encode(x_vars[x_key]); + } + x_vars_url += '/x:' + x_key + '/' + x_val; + } + } + } + local_path = ""; + if(uploadConfig.saveType == "local"||uploadConfig.saveType == "onedrive"){ + pathTmp = file.path; + if(file.path == ""){ + pathTmp = "ROOTDIR"; + } + local_path = '/path/'+that.URLSafeBase64Encode(pathTmp); + } + if(uploadConfig.saveType == "remote"){ + pathTmp = file.path; + local_path = that.URLSafeBase64Encode(pathTmp); + var url = qiniuUploadUrl + 'mkfile.php?size=' + file.size +"&key="+ key+"&fname="+ fname +"&path="+local_path; + }else{ + var url = qiniuUploadUrl + '/mkfile/' + file.size + key + fname + x_vars_url+local_path; + } + var ie = that.detectIEVersion(); + var ajax; + if (ie && ie <= 9) { + ajax = new moxie.xhr.XMLHttpRequest(); + moxie.core.utils.Env.swf_url = op.flash_swf_url; + }else{ + ajax = that.createAjax(); + } + ajax.open('POST', url, true); + ajax.setRequestHeader('Content-Type', 'text/plain;charset=UTF-8'); + if(uploadConfig.saveType == "remote"){ + ajax.setRequestHeader('Authorization',that.token); + }else{ + ajax.setRequestHeader('Authorization', 'UpToken ' + that.token); + } + var onreadystatechange = function(){ + logger.debug("ajax.readyState: ", ajax.readyState); + if (ajax.readyState === 4) { + localStorage.removeItem(file.name); + var info; + if (ajax.status === 200) { + info = ajax.responseText; + logger.debug("mkfile is success: ", info); + last_step(up, file, info); + } else { + info = { + status: ajax.status, + response: ajax.responseText, + file: file, + code: -200, + responseHeaders: ajax.getAllResponseHeaders() + }; + logger.debug("mkfile is error: ", info); + uploader.trigger('Error', info); + } + } + }; + if (ie && ie <= 9) { + ajax.bind('readystatechange', onreadystatechange); + }else{ + ajax.onreadystatechange = onreadystatechange; + } + ajax.send(ctx); + logger.debug("mkfile: ", url); + } else { + last_step(up, file, info.response); + } + + }; + })(_FileUploaded_Handler)); + + logger.debug("bind FileUploaded event"); + + // init uploader + uploader.init(); + + logger.debug("invoke uploader.init()"); + + logger.debug("init uploader end"); + + return uploader; + }; + + /** + * get url by key + * @param {String} key of file + * @return {String} url of file + */ + this.getUrl = function(key) { + if (!key) { + return false; + } + key = encodeURI(key); + var domain = this.domain; + if (domain.slice(domain.length - 1) !== '/') { + domain = domain + '/'; + } + return domain + key; + }; + + /** + * invoke the imageView2 api of Qiniu + * @param {Object} api params + * @param {String} key of file + * @return {String} url of processed image + */ + this.imageView2 = function(op, key) { + + if (!/^\d$/.test(op.mode)) { + return false; + } + + var mode = op.mode, + w = op.w || '', + h = op.h || '', + q = op.q || '', + format = op.format || ''; + + if (!w && !h) { + return false; + } + + var imageUrl = 'imageView2/' + mode; + imageUrl += w ? '/w/' + w : ''; + imageUrl += h ? '/h/' + h : ''; + imageUrl += q ? '/q/' + q : ''; + imageUrl += format ? '/format/' + format : ''; + if (key) { + imageUrl = this.getUrl(key) + '?' + imageUrl; + } + return imageUrl; + }; + + /** + * invoke the imageMogr2 api of Qiniu + * @param {Object} api params + * @param {String} key of file + * @return {String} url of processed image + */ + this.imageMogr2 = function(op, key) { + var auto_orient = op['auto-orient'] || '', + thumbnail = op.thumbnail || '', + strip = op.strip || '', + gravity = op.gravity || '', + crop = op.crop || '', + quality = op.quality || '', + rotate = op.rotate || '', + format = op.format || '', + blur = op.blur || ''; + //Todo check option + + var imageUrl = 'imageMogr2'; + + imageUrl += auto_orient ? '/auto-orient' : ''; + imageUrl += thumbnail ? '/thumbnail/' + thumbnail : ''; + imageUrl += strip ? '/strip' : ''; + imageUrl += gravity ? '/gravity/' + gravity : ''; + imageUrl += quality ? '/quality/' + quality : ''; + imageUrl += crop ? '/crop/' + crop : ''; + imageUrl += rotate ? '/rotate/' + rotate : ''; + imageUrl += format ? '/format/' + format : ''; + imageUrl += blur ? '/blur/' + blur : ''; + + if (key) { + imageUrl = this.getUrl(key) + '?' + imageUrl; + } + return imageUrl; + }; + + /** + * invoke the watermark api of Qiniu + * @param {Object} api params + * @param {String} key of file + * @return {String} url of processed image + */ + this.watermark = function(op, key) { + var mode = op.mode; + if (!mode) { + return false; + } + + var imageUrl = 'watermark/' + mode; + + if (mode === 1) { + var image = op.image || ''; + if (!image) { + return false; + } + imageUrl += image ? '/image/' + this.URLSafeBase64Encode(image) : ''; + } else if (mode === 2) { + var text = op.text ? op.text : '', + font = op.font ? op.font : '', + fontsize = op.fontsize ? op.fontsize : '', + fill = op.fill ? op.fill : ''; + if (!text) { + return false; + } + imageUrl += text ? '/text/' + this.URLSafeBase64Encode(text) : ''; + imageUrl += font ? '/font/' + this.URLSafeBase64Encode(font) : ''; + imageUrl += fontsize ? '/fontsize/' + fontsize : ''; + imageUrl += fill ? '/fill/' + this.URLSafeBase64Encode(fill) : ''; + } else { + // Todo mode3 + return false; + } + + var dissolve = op.dissolve || '', + gravity = op.gravity || '', + dx = op.dx || '', + dy = op.dy || ''; + + imageUrl += dissolve ? '/dissolve/' + dissolve : ''; + imageUrl += gravity ? '/gravity/' + gravity : ''; + imageUrl += dx ? '/dx/' + dx : ''; + imageUrl += dy ? '/dy/' + dy : ''; + + if (key) { + imageUrl = this.getUrl(key) + '?' + imageUrl; + } + return imageUrl; + }; + + /** + * invoke the imageInfo api of Qiniu + * @param {String} key of file + * @return {Object} image info + */ + this.imageInfo = function(key) { + if (!key) { + return false; + } + var url = this.getUrl(key) + '?imageInfo'; + var xhr = this.createAjax(); + var info; + var that = this; + xhr.open('GET', url, false); + xhr.onreadystatechange = function() { + if (xhr.readyState === 4 && xhr.status === 200) { + info = that.parseJSON(xhr.responseText); + } + }; + xhr.send(); + return info; + }; + + /** + * invoke the exif api of Qiniu + * @param {String} key of file + * @return {Object} image exif + */ + this.exif = function(key) { + if (!key) { + return false; + } + var url = this.getUrl(key) + '?exif'; + var xhr = this.createAjax(); + var info; + var that = this; + xhr.open('GET', url, false); + xhr.onreadystatechange = function() { + if (xhr.readyState === 4 && xhr.status === 200) { + info = that.parseJSON(xhr.responseText); + } + }; + xhr.send(); + return info; + }; + + /** + * invoke the exif or imageInfo api of Qiniu + * according with type param + * @param {String} ['exif'|'imageInfo']type of info + * @param {String} key of file + * @return {Object} image exif or info + */ + this.get = function(type, key) { + if (!key || !type) { + return false; + } + if (type === 'exif') { + return this.exif(key); + } else if (type === 'imageInfo') { + return this.imageInfo(key); + } + return false; + }; + + /** + * invoke api of Qiniu like a pipeline + * @param {Array of Object} params of a series api call + * each object in array is options of api which name is set as 'fop' property + * each api's output will be next api's input + * @param {String} key of file + * @return {String|Boolean} url of processed image + */ + this.pipeline = function(arr, key) { + var isArray = Object.prototype.toString.call(arr) === '[object Array]'; + var option, errOp, imageUrl = ''; + if (isArray) { + for (var i = 0, len = arr.length; i < len; i++) { + option = arr[i]; + if (!option.fop) { + return false; + } + switch (option.fop) { + case 'watermark': + imageUrl += this.watermark(option) + '|'; + break; + case 'imageView2': + imageUrl += this.imageView2(option) + '|'; + break; + case 'imageMogr2': + imageUrl += this.imageMogr2(option) + '|'; + break; + default: + errOp = true; + break; + } + if (errOp) { + return false; + } + } + if (key) { + imageUrl = this.getUrl(key) + '?' + imageUrl; + var length = imageUrl.length; + if (imageUrl.slice(length - 1) === '|') { + imageUrl = imageUrl.slice(0, length - 1); + } + } + return imageUrl; + } + return false; + }; +} + +var Qiniu = new QiniuJsSDK(); + +global.Qiniu = Qiniu; + +global.QiniuJsSDK = QiniuJsSDK; + +})( window ); \ No newline at end of file diff --git a/static/js/uploader/ui.js b/static/js/uploader/ui.js new file mode 100644 index 00000000..9f78b446 --- /dev/null +++ b/static/js/uploader/ui.js @@ -0,0 +1,278 @@ +/*global plupload */ +/*global qiniu */ +function FileProgress(file, targetID) { + this.fileProgressID = file.id; + this.file = file; + + this.opacity = 100; + this.height = 0; + this.fileProgressWrapper = $('#' + this.fileProgressID); + if (!this.fileProgressWrapper.length) { + //
+ //
+ // 20% Complete + //
+ //
+ + this.fileProgressWrapper = $(''); + var Wrappeer = this.fileProgressWrapper; + Wrappeer.attr('id', this.fileProgressID).addClass('progressContainer'); + + var progressText = $(""); + progressText.addClass('progressName').text(file.name); + + + var fileSize = plupload.formatSize(file.size).toUpperCase(); + var progressSize = $(""); + progressSize.addClass("progressFileSize").text(fileSize); + + var progressBarTd = $(""); + var progressBarBox = $("
"); + progressBarBox.addClass('info'); + var progressBarWrapper = $("
"); + progressBarWrapper.addClass("progress progress-striped"); + + var progressBar = $("
"); + progressBar.addClass("progress-bar progress-bar-info") + .attr('role', 'progressbar') + .attr('aria-valuemax', 100) + .attr('aria-valuenow', 0) + .attr('aria-valuein', 0) + .width('0%'); + + var progressBarPercent = $(''); + progressBarPercent.text(fileSize); + + var progressCancel = $(''); + progressCancel.show().addClass('progressCancel').text('×'); + + progressBar.append(progressBarPercent); + progressBarWrapper.append(progressBar); + progressBarBox.append(progressBarWrapper); + progressText.append(progressCancel); + + var progressBarStatus = $('
'); + progressBarBox.append(progressBarStatus); + progressBarTd.append(progressBarBox); + + Wrappeer.append(progressText); + Wrappeer.append(progressSize); + Wrappeer.append(progressBarTd); + + $('#' + targetID).append(Wrappeer); + } else { + this.reset(); + } + + this.height = this.fileProgressWrapper.offset().top; + this.setTimer(null); +} + +FileProgress.prototype.setTimer = function(timer) { + this.fileProgressWrapper.FP_TIMER = timer; +}; + +FileProgress.prototype.getTimer = function(timer) { + return this.fileProgressWrapper.FP_TIMER || null; +}; + +FileProgress.prototype.reset = function() { + this.fileProgressWrapper.attr('class', "progressContainer"); + this.fileProgressWrapper.find('td .progress .progress-bar-info').attr('aria-valuenow', 0).width('0%').find('span').text(''); + this.appear(); +}; + +FileProgress.prototype.setChunkProgess = function(chunk_size) { + var chunk_amount = Math.ceil(this.file.size / chunk_size); + if (chunk_amount === 1) { + return false; + } + + var viewProgess = $(''); + + var progressBarChunkTr = $(''); + var progressBarChunk = $('
'); + for (var i = 1; i <= chunk_amount; i++) { + var col = $('
'); + var progressBarWrapper = $('
"); + progressBar.addClass("progress-bar progress-bar-info text-left") + .attr('role', 'progressbar') + .attr('aria-valuemax', 100) + .attr('aria-valuenow', 0) + .attr('aria-valuein', 0) + .width('0%') + .attr('id', this.file.id + '_' + i) + .text(''); + + var progressBarStatus = $(''); + progressBarStatus.addClass('chunk-status').text(); + + progressBarWrapper.append(progressBar); + progressBarWrapper.append(progressBarStatus); + + col.append(progressBarWrapper); + progressBarChunk.append(col); + } + + if(!this.fileProgressWrapper.find('td:eq(2) .btn-default').length){ + this.fileProgressWrapper.find('td>div').append(viewProgess); + } + progressBarChunkTr.hide().find('td').append(progressBarChunk); + progressBarChunkTr.insertAfter(this.fileProgressWrapper); + +}; + +FileProgress.prototype.setProgress = function(percentage, speed, chunk_size) { + this.fileProgressWrapper.attr('class', "progressContainer green"); + + var file = this.file; + var uploaded = file.loaded; + + var size = plupload.formatSize(uploaded).toUpperCase(); + var formatSpeed = plupload.formatSize(speed).toUpperCase(); + var progressbar = this.fileProgressWrapper.find('td .progress').find('.progress-bar-info'); + if (this.fileProgressWrapper.find('.status').text() === '取消上传'){ + return; + } + this.fileProgressWrapper.find('.status').text("已上传: " + size + " 上传速度: " + formatSpeed + "/s"); + percentage = parseInt(percentage, 10); + if (file.status !== plupload.DONE && percentage === 100) { + percentage = 99; + } + + progressbar.attr('aria-valuenow', percentage).css('width', percentage + '%'); + + if (chunk_size) { + var chunk_amount = Math.ceil(file.size / chunk_size); + if (chunk_amount === 1) { + return false; + } + var current_uploading_chunk = Math.ceil(uploaded / chunk_size); + var pre_chunk, text; + + for (var index = 0; index < current_uploading_chunk; index++) { + pre_chunk = $('#' + file.id + "_" + index); + pre_chunk.width('100%').removeClass().addClass('alert alert-success').attr('aria-valuenow', 100); + text = "块" + index + "上传进度100%"; + pre_chunk.next().html(text); + } + + var currentProgessBar = $('#' + file.id + "_" + current_uploading_chunk); + var current_chunk_percent; + if (current_uploading_chunk < chunk_amount) { + if (uploaded % chunk_size) { + current_chunk_percent = ((uploaded % chunk_size) / chunk_size * 100).toFixed(2); + } else { + current_chunk_percent = 100; + currentProgessBar.removeClass().addClass('alert alert-success'); + } + } else { + var last_chunk_size = file.size - chunk_size * (chunk_amount - 1); + var left_file_size = file.size - uploaded; + if (left_file_size % last_chunk_size) { + current_chunk_percent = ((uploaded % chunk_size) / last_chunk_size * 100).toFixed(2); + } else { + current_chunk_percent = 100; + currentProgessBar.removeClass().addClass('alert alert-success'); + } + } + currentProgessBar.width(current_chunk_percent + '%'); + currentProgessBar.attr('aria-valuenow', current_chunk_percent); + text = "块" + current_uploading_chunk + "上传进度" + current_chunk_percent + '%'; + currentProgessBar.next().html(text); + } + + this.appear(); +}; + +FileProgress.prototype.setComplete = function(up, info) { + var td = this.fileProgressWrapper.find('td:eq(2)'), + tdProgress = td.find('.progress'); + + var res; + var url; + if(uploadConfig.saveType == "oss"){ + url = "oss"; + str = "
上传成功
"; + }else{ + res = $.parseJSON(info); + if (res.url) { + url = res.url; + str = "
上传成功
"; + } else { + var domain = up.getOption('domain'); + url = domain + encodeURI(res.key); + var link = domain + res.key; + str = "
上传成功
"; + } + } + + tdProgress.html(str).removeClass().next().next('.status').hide(); + this.fileProgressWrapper.find('td:eq(0) .progressCancel').hide(); + td.find('.status').hide(); + angular.element(document.querySelector('angular-filemanager > div')).scope().fileNavigator.refresh(); +}; +FileProgress.prototype.setError = function() { + this.fileProgressWrapper.find('td:eq(2)').attr('class', 'text-warning'); + this.fileProgressWrapper.find('td:eq(2) .progress').css('width', 0).hide(); + this.fileProgressWrapper.find('button').hide(); + this.fileProgressWrapper.next('.chunk-status-tr').hide(); +}; + +FileProgress.prototype.setCancelled = function(manual) { + var progressContainer = 'progressContainer'; + if (!manual) { + progressContainer += ' red'; + } + this.fileProgressWrapper.attr('class', progressContainer); + this.fileProgressWrapper.find('td .progress').remove(); + this.fileProgressWrapper.find('td:eq(2) .btn-default').hide(); + this.fileProgressWrapper.find('td:eq(0) .progressCancel').hide(); +}; + +FileProgress.prototype.setStatus = function(status, isUploading) { + if (!isUploading) { + this.fileProgressWrapper.find('.status').text(status).attr('class', 'status text-left'); + } +}; + +// 绑定取消上传事件 +FileProgress.prototype.bindUploadCancel = function(up) { + var self = this; + if (up) { + self.fileProgressWrapper.find('td:eq(0) .progressCancel').on('click', function(){ + self.setCancelled(false); + self.setStatus("取消上传"); + self.fileProgressWrapper.find('.status').css('left', '0'); + up.removeFile(self.file); + }); + } + +}; + +FileProgress.prototype.appear = function() { + if (this.getTimer() !== null) { + clearTimeout(this.getTimer()); + this.setTimer(null); + } + + if (this.fileProgressWrapper[0].filters) { + try { + this.fileProgressWrapper[0].filters.item("DXImageTransform.Microsoft.Alpha").opacity = 100; + } catch (e) { + // If it is not set initially, the browser will throw an error. This will set it if it is not set yet. + this.fileProgressWrapper.css('filter', "progid:DXImageTransform.Microsoft.Alpha(opacity=100)"); + } + } else { + this.fileProgressWrapper.css('opacity', 1); + } + + this.fileProgressWrapper.css('height', ''); + + this.height = this.fileProgressWrapper.offset().top; + this.opacity = 100; + this.fileProgressWrapper.show(); + +}; diff --git a/thinkphp/.gitignore b/thinkphp/.gitignore new file mode 100644 index 00000000..7e31ef51 --- /dev/null +++ b/thinkphp/.gitignore @@ -0,0 +1,4 @@ +/composer.lock +/vendor +.idea +.DS_Store diff --git a/thinkphp/CONTRIBUTING.md b/thinkphp/CONTRIBUTING.md index 6cefcb38..dc8e91cd 100644 --- a/thinkphp/CONTRIBUTING.md +++ b/thinkphp/CONTRIBUTING.md @@ -7,7 +7,7 @@ ThinkPHP 目前使用 Git 来控制程序版本,如果你想为 ThinkPHP 贡献源代码,请先大致了解 Git 的使用方法。我们目前把项目托管在 GitHub 上,任何 GitHub 用户都可以向我们贡献代码。 -参与的方式很简单,`fork`一份 ThinkPHP 的代码到你的仓库中,修改后提交,并向我们发起`pull request`申请,我们会及时对代码进行审查并处理你的申请并。审查通过后,你的代码将被`merge`进我们的仓库中,这样你就会自动出现在贡献者名单里了,非常方便。 +参与的方式很简单,`fork`一份 ThinkPHP 的代码到你的仓库中,修改后提交,并向我们发起`pull request`申请,我们会及时对代码进行审查并处理你的申请。审查通过后,你的代码将被`merge`进我们的仓库中,这样你就会自动出现在贡献者名单里了,非常方便。 我们希望你贡献的代码符合: @@ -60,7 +60,7 @@ GitHub 提供了 Issue 功能,该功能可以用于: 6. 变基(衍合 `rebase`)你的分支到上游 master 分支; 7. `push` 你的本地仓库到 GitHub; 8. 提交 `pull request`; -9. 等待 CI 验证(若不通过则重复 5~7,GitHub 会自动更新你的 `pull request`); +9. 等待 CI 验证(若不通过则重复 5~7,不需要重新提交 `pull request`,GitHub 会自动更新你的 `pull request`); 10. 等待管理员处理,并及时 `rebase` 你的分支到上游 master 分支(若上游 master 分支有修改)。 *若有必要,可以 `git push -f` 强行推送 rebase 后的分支到自己的 `fork`* diff --git a/thinkphp/LICENSE.txt b/thinkphp/LICENSE.txt index 574a39c4..2cb9a8a9 100644 --- a/thinkphp/LICENSE.txt +++ b/thinkphp/LICENSE.txt @@ -1,6 +1,6 @@ ThinkPHP遵循Apache2开源协议发布,并提供免费使用。 -版权所有Copyright © 2006-2016 by ThinkPHP (http://thinkphp.cn) +版权所有Copyright © 2006-2017 by ThinkPHP (http://thinkphp.cn) All rights reserved。 ThinkPHP® 商标和著作权所有者为上海顶想信息科技有限公司。 diff --git a/thinkphp/README.md b/thinkphp/README.md new file mode 100644 index 00000000..f01fd2b9 --- /dev/null +++ b/thinkphp/README.md @@ -0,0 +1,114 @@ +ThinkPHP 5.0 +=============== + +[![StyleCI](https://styleci.io/repos/48530411/shield?style=flat&branch=master)](https://styleci.io/repos/48530411) +[![Build Status](https://travis-ci.org/top-think/framework.svg?branch=master)](https://travis-ci.org/top-think/framework) +[![codecov.io](http://codecov.io/github/top-think/framework/coverage.svg?branch=master)](http://codecov.io/github/github/top-think/framework?branch=master) +[![Total Downloads](https://poser.pugx.org/topthink/framework/downloads)](https://packagist.org/packages/topthink/framework) +[![Latest Stable Version](https://poser.pugx.org/topthink/framework/v/stable)](https://packagist.org/packages/topthink/framework) +[![Latest Unstable Version](https://poser.pugx.org/topthink/framework/v/unstable)](https://packagist.org/packages/topthink/framework) +[![License](https://poser.pugx.org/topthink/framework/license)](https://packagist.org/packages/topthink/framework) + +ThinkPHP5在保持快速开发和大道至简的核心理念不变的同时,PHP版本要求提升到5.4,优化核心,减少依赖,基于全新的架构思想和命名空间实现,是ThinkPHP突破原有框架思路的颠覆之作,其主要特性包括: + + + 基于命名空间和众多PHP新特性 + + 核心功能组件化 + + 强化路由功能 + + 更灵活的控制器 + + 重构的模型和数据库类 + + 配置文件可分离 + + 重写的自动验证和完成 + + 简化扩展机制 + + API支持完善 + + 改进的Log类 + + 命令行访问支持 + + REST支持 + + 引导文件支持 + + 方便的自动生成定义 + + 真正惰性加载 + + 分布式环境支持 + + 支持Composer + + 支持MongoDb + +> ThinkPHP5的运行环境要求PHP5.4以上。 + +详细开发文档参考 [ThinkPHP5完全开发手册](http://www.kancloud.cn/manual/thinkphp5) 以及[ThinkPHP5入门系列教程](http://www.kancloud.cn/special/thinkphp5_quickstart) + +## 目录结构 + +初始的目录结构如下: + +~~~ +www WEB部署目录(或者子目录) +├─application 应用目录 +│ ├─common 公共模块目录(可以更改) +│ ├─module_name 模块目录 +│ │ ├─config.php 模块配置文件 +│ │ ├─common.php 模块函数文件 +│ │ ├─controller 控制器目录 +│ │ ├─model 模型目录 +│ │ ├─view 视图目录 +│ │ └─ ... 更多类库目录 +│ │ +│ ├─command.php 命令行工具配置文件 +│ ├─common.php 公共函数文件 +│ ├─config.php 公共配置文件 +│ ├─route.php 路由配置文件 +│ ├─tags.php 应用行为扩展定义文件 +│ └─database.php 数据库配置文件 +│ +├─public WEB目录(对外访问目录) +│ ├─index.php 入口文件 +│ ├─router.php 快速测试文件 +│ └─.htaccess 用于apache的重写 +│ +├─thinkphp 框架系统目录 +│ ├─lang 语言文件目录 +│ ├─library 框架类库目录 +│ │ ├─think Think类库包目录 +│ │ └─traits 系统Trait目录 +│ │ +│ ├─tpl 系统模板目录 +│ ├─base.php 基础定义文件 +│ ├─console.php 控制台入口文件 +│ ├─convention.php 框架惯例配置文件 +│ ├─helper.php 助手函数文件 +│ ├─phpunit.xml phpunit配置文件 +│ └─start.php 框架入口文件 +│ +├─extend 扩展类库目录 +├─runtime 应用的运行时目录(可写,可定制) +├─vendor 第三方类库目录(Composer依赖库) +├─build.php 自动生成定义文件(参考) +├─composer.json composer 定义文件 +├─LICENSE.txt 授权说明文件 +├─README.md README 文件 +├─think 命令行入口文件 +~~~ + +> router.php用于php自带webserver支持,可用于快速测试 +> 切换到public目录后,启动命令:php -S localhost:8888 router.php +> 上面的目录结构和名称是可以改变的,这取决于你的入口文件和配置参数。 + +## 命名规范 + +ThinkPHP5的命名规范遵循`PSR-2`规范以及`PSR-4`自动加载规范。 + +## 参与开发 +注册并登录 Github 帐号, fork 本项目并进行改动。 + +更多细节参阅 [CONTRIBUTING.md](CONTRIBUTING.md) + +## 版权信息 + +ThinkPHP遵循Apache2开源协议发布,并提供免费使用。 + +本项目包含的第三方源码和二进制文件之版权信息另行标注。 + +版权所有Copyright © 2006-2018 by ThinkPHP (http://thinkphp.cn) + +All rights reserved。 + +ThinkPHP® 商标和著作权所有者为上海顶想信息科技有限公司。 + +更多细节参阅 [LICENSE.txt](LICENSE.txt) diff --git a/thinkphp/base.php b/thinkphp/base.php index 9744f01d..92c4fa55 100644 --- a/thinkphp/base.php +++ b/thinkphp/base.php @@ -2,14 +2,14 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- -define('THINK_VERSION', '5.0.9'); +define('THINK_VERSION', '5.0.24'); define('THINK_START_TIME', microtime(true)); define('THINK_START_MEM', memory_get_usage()); define('EXT', '.php'); @@ -40,8 +40,10 @@ require CORE_PATH . 'Loader.php'; // 加载环境变量配置文件 if (is_file(ROOT_PATH . '.env')) { $env = parse_ini_file(ROOT_PATH . '.env', true); + foreach ($env as $key => $val) { $name = ENV_PREFIX . strtoupper($key); + if (is_array($val)) { foreach ($val as $k => $v) { $item = $name . '_' . strtoupper($k); diff --git a/thinkphp/convention.php b/thinkphp/convention.php index 801c90a8..31a0a0c1 100644 --- a/thinkphp/convention.php +++ b/thinkphp/convention.php @@ -7,7 +7,7 @@ return [ // 默认Host地址 'app_host' => '', // 应用调试模式 - 'app_debug' => true, + 'app_debug' => false, // 应用Trace 'app_trace' => false, // 应用模式状态 @@ -74,6 +74,8 @@ return [ 'pathinfo_fetch' => ['ORIG_PATH_INFO', 'REDIRECT_PATH_INFO', 'REDIRECT_URL'], // pathinfo分隔符 'pathinfo_depr' => '/', + // HTTPS代理标识 + 'https_agent_name' => '', // URL伪静态后缀 'url_html_suffix' => 'html', // URL普通方式参数 用于自动生成 @@ -114,6 +116,8 @@ return [ // +---------------------------------------------------------------------- 'template' => [ + // 默认模板渲染规则 1 解析为小写+下划线 2 全部转换小写 + 'auto_rule' => 1, // 模板引擎类型 支持 php think 支持扩展 'type' => 'Think', // 视图基础目录,配置目录为所有模块的视图起始目录 @@ -153,6 +157,8 @@ return [ 'show_error_msg' => false, // 异常处理handle类 留空使用 \think\exception\Handle 'exception_handle' => '', + // 是否记录trace信息到日志 + 'record_trace' => false, // +---------------------------------------------------------------------- // | 日志设置 @@ -282,4 +288,11 @@ return [ 'list_rows' => 15, ], + //控制台配置 + 'console' => [ + 'name' => 'Think Console', + 'version' => '0.1', + 'user' => null, + ], + ]; diff --git a/thinkphp/helper.php b/thinkphp/helper.php index a23b6794..12683cfd 100644 --- a/thinkphp/helper.php +++ b/thinkphp/helper.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -127,7 +127,7 @@ if (!function_exists('input')) { if ($pos = strpos($key, '.')) { // 指定参数来源 list($method, $key) = explode('.', $key, 2); - if (!in_array($method, ['get', 'post', 'put', 'patch', 'delete', 'param', 'request', 'session', 'cookie', 'server', 'env', 'path', 'file'])) { + if (!in_array($method, ['get', 'post', 'put', 'patch', 'delete', 'route', 'param', 'request', 'session', 'cookie', 'server', 'env', 'path', 'file'])) { $key = $method . '.' . $key; $method = 'param'; } diff --git a/thinkphp/lang/zh-cn.php b/thinkphp/lang/zh-cn.php index c6c5a50f..eb7a9142 100644 --- a/thinkphp/lang/zh-cn.php +++ b/thinkphp/lang/zh-cn.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -12,57 +12,125 @@ // 核心中文语言包 return [ // 系统错误提示 - 'Undefined variable' => '未定义变量', - 'Undefined index' => '未定义数组索引', - 'Undefined offset' => '未定义数组下标', - 'Parse error' => '语法解析错误', - 'Type error' => '类型错误', - 'Fatal error' => '致命错误', - 'syntax error' => '语法错误', + 'Undefined variable' => '未定义变量', + 'Undefined index' => '未定义数组索引', + 'Undefined offset' => '未定义数组下标', + 'Parse error' => '语法解析错误', + 'Type error' => '类型错误', + 'Fatal error' => '致命错误', + 'syntax error' => '语法错误', // 框架核心错误提示 - 'dispatch type not support' => '不支持的调度类型', - 'method param miss' => '方法参数错误', - 'method not exists' => '方法不存在', - 'module not exists' => '模块不存在', - 'controller not exists' => '控制器不存在', - 'class not exists' => '类不存在', - 'property not exists' => '类的属性不存在', - 'template not exists' => '模板文件不存在', - 'illegal controller name' => '非法的控制器名称', - 'illegal action name' => '非法的操作名称', - 'url suffix deny' => '禁止的URL后缀访问', - 'Route Not Found' => '当前访问路由未定义', - 'Underfined db type' => '未定义数据库类型', - 'variable type error' => '变量类型错误', - 'PSR-4 error' => 'PSR-4 规范错误', - 'not support total' => '简洁模式下不能获取数据总数', - 'not support last' => '简洁模式下不能获取最后一页', - 'error session handler' => '错误的SESSION处理器类', - 'not allow php tag' => '模板不允许使用PHP语法', - 'not support' => '不支持', - 'redisd master' => 'Redisd 主服务器错误', - 'redisd slave' => 'Redisd 从服务器错误', - 'must run at sae' => '必须在SAE运行', - 'memcache init error' => '未开通Memcache服务,请在SAE管理平台初始化Memcache服务', - 'KVDB init error' => '没有初始化KVDB,请在SAE管理平台初始化KVDB服务', - 'fields not exists' => '数据表字段不存在', - 'where express error' => '查询表达式错误', - 'no data to update' => '没有任何数据需要更新', - 'miss data to insert' => '缺少需要写入的数据', - 'miss complex primary data' => '缺少复合主键数据', - 'miss update condition' => '缺少更新条件', - 'model data Not Found' => '模型数据不存在', - 'table data not Found' => '表数据不存在', - 'delete without condition' => '没有条件不会执行删除操作', - 'miss relation data' => '缺少关联表数据', - 'tag attr must' => '模板标签属性必须', - 'tag error' => '模板标签错误', - 'cache write error' => '缓存写入失败', - 'sae mc write error' => 'SAE mc 写入错误', - 'route name not exists' => '路由标识不存在(或参数不够)', - 'invalid request' => '非法请求', - 'bind attr has exists' => '模型的属性已经存在', - 'relation data not exists' => '关联数据不存在', - 'relation not support' => '关联不支持', + 'dispatch type not support' => '不支持的调度类型', + 'method param miss' => '方法参数错误', + 'method not exists' => '方法不存在', + 'module not exists' => '模块不存在', + 'controller not exists' => '控制器不存在', + 'class not exists' => '类不存在', + 'property not exists' => '类的属性不存在', + 'template not exists' => '模板文件不存在', + 'illegal controller name' => '非法的控制器名称', + 'illegal action name' => '非法的操作名称', + 'url suffix deny' => '禁止的URL后缀访问', + 'Route Not Found' => '当前访问路由未定义', + 'Undefined db type' => '未定义数据库类型', + 'variable type error' => '变量类型错误', + 'PSR-4 error' => 'PSR-4 规范错误', + 'not support total' => '简洁模式下不能获取数据总数', + 'not support last' => '简洁模式下不能获取最后一页', + 'error session handler' => '错误的SESSION处理器类', + 'not allow php tag' => '模板不允许使用PHP语法', + 'not support' => '不支持', + 'redisd master' => 'Redisd 主服务器错误', + 'redisd slave' => 'Redisd 从服务器错误', + 'must run at sae' => '必须在SAE运行', + 'memcache init error' => '未开通Memcache服务,请在SAE管理平台初始化Memcache服务', + 'KVDB init error' => '没有初始化KVDB,请在SAE管理平台初始化KVDB服务', + 'fields not exists' => '数据表字段不存在', + 'where express error' => '查询表达式错误', + 'not support data' => '不支持的数据表达式', + 'no data to update' => '没有任何数据需要更新', + 'miss data to insert' => '缺少需要写入的数据', + 'miss complex primary data' => '缺少复合主键数据', + 'miss update condition' => '缺少更新条件', + 'model data Not Found' => '模型数据不存在', + 'table data not Found' => '表数据不存在', + 'delete without condition' => '没有条件不会执行删除操作', + 'miss relation data' => '缺少关联表数据', + 'tag attr must' => '模板标签属性必须', + 'tag error' => '模板标签错误', + 'cache write error' => '缓存写入失败', + 'sae mc write error' => 'SAE mc 写入错误', + 'route name not exists' => '路由标识不存在(或参数不够)', + 'invalid request' => '非法请求', + 'bind attr has exists' => '模型的属性已经存在', + 'relation data not exists' => '关联数据不存在', + 'relation not support' => '关联不支持', + 'chunk not support order' => 'Chunk不支持调用order方法', + 'closure not support cache(true)' => '使用闭包查询不支持cache(true),请指定缓存Key', + + // 上传错误信息 + 'unknown upload error' => '未知上传错误!', + 'file write error' => '文件写入失败!', + 'upload temp dir not found' => '找不到临时文件夹!', + 'no file to uploaded' => '没有文件被上传!', + 'only the portion of file is uploaded' => '文件只有部分被上传!', + 'upload File size exceeds the maximum value' => '上传文件大小超过了最大值!', + 'upload write error' => '文件上传保存错误!', + 'has the same filename: {:filename}' => '存在同名文件:{:filename}', + 'upload illegal files' => '非法上传文件', + 'illegal image files' => '非法图片文件', + 'extensions to upload is not allowed' => '上传文件后缀不允许', + 'mimetype to upload is not allowed' => '上传文件MIME类型不允许!', + 'filesize not match' => '上传文件大小不符!', + 'directory {:path} creation failed' => '目录 {:path} 创建失败!', + + // Validate Error Message + ':attribute require' => ':attribute不能为空', + ':attribute must be numeric' => ':attribute必须是数字', + ':attribute must be integer' => ':attribute必须是整数', + ':attribute must be float' => ':attribute必须是浮点数', + ':attribute must be bool' => ':attribute必须是布尔值', + ':attribute not a valid email address' => ':attribute格式不符', + ':attribute not a valid mobile' => ':attribute格式不符', + ':attribute must be a array' => ':attribute必须是数组', + ':attribute must be yes,on or 1' => ':attribute必须是yes、on或者1', + ':attribute not a valid datetime' => ':attribute不是一个有效的日期或时间格式', + ':attribute not a valid file' => ':attribute不是有效的上传文件', + ':attribute not a valid image' => ':attribute不是有效的图像文件', + ':attribute must be alpha' => ':attribute只能是字母', + ':attribute must be alpha-numeric' => ':attribute只能是字母和数字', + ':attribute must be alpha-numeric, dash, underscore' => ':attribute只能是字母、数字和下划线_及破折号-', + ':attribute not a valid domain or ip' => ':attribute不是有效的域名或者IP', + ':attribute must be chinese' => ':attribute只能是汉字', + ':attribute must be chinese or alpha' => ':attribute只能是汉字、字母', + ':attribute must be chinese,alpha-numeric' => ':attribute只能是汉字、字母和数字', + ':attribute must be chinese,alpha-numeric,underscore, dash' => ':attribute只能是汉字、字母、数字和下划线_及破折号-', + ':attribute not a valid url' => ':attribute不是有效的URL地址', + ':attribute not a valid ip' => ':attribute不是有效的IP地址', + ':attribute must be dateFormat of :rule' => ':attribute必须使用日期格式 :rule', + ':attribute must be in :rule' => ':attribute必须在 :rule 范围内', + ':attribute be notin :rule' => ':attribute不能在 :rule 范围内', + ':attribute must between :1 - :2' => ':attribute只能在 :1 - :2 之间', + ':attribute not between :1 - :2' => ':attribute不能在 :1 - :2 之间', + 'size of :attribute must be :rule' => ':attribute长度不符合要求 :rule', + 'max size of :attribute must be :rule' => ':attribute长度不能超过 :rule', + 'min size of :attribute must be :rule' => ':attribute长度不能小于 :rule', + ':attribute cannot be less than :rule' => ':attribute日期不能小于 :rule', + ':attribute cannot exceed :rule' => ':attribute日期不能超过 :rule', + ':attribute not within :rule' => '不在有效期内 :rule', + 'access IP is not allowed' => '不允许的IP访问', + 'access IP denied' => '禁止的IP访问', + ':attribute out of accord with :2' => ':attribute和确认字段:2不一致', + ':attribute cannot be same with :2' => ':attribute和比较字段:2不能相同', + ':attribute must greater than or equal :rule' => ':attribute必须大于等于 :rule', + ':attribute must greater than :rule' => ':attribute必须大于 :rule', + ':attribute must less than or equal :rule' => ':attribute必须小于等于 :rule', + ':attribute must less than :rule' => ':attribute必须小于 :rule', + ':attribute must equal :rule' => ':attribute必须等于 :rule', + ':attribute has exists' => ':attribute已存在', + ':attribute not conform to the rules' => ':attribute不符合指定规则', + 'invalid Request method' => '无效的请求类型', + 'invalid token' => '令牌数据无效', + 'not conform to the rules' => '规则错误', ]; diff --git a/thinkphp/library/think/App.php b/thinkphp/library/think/App.php index 7b27a15d..f572b907 100644 --- a/thinkphp/library/think/App.php +++ b/thinkphp/library/think/App.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -11,13 +11,14 @@ namespace think; +use think\exception\ClassNotFoundException; use think\exception\HttpException; use think\exception\HttpResponseException; use think\exception\RouteNotFoundException; /** * App 应用管理 - * @author liu21st + * @author liu21st */ class App { @@ -56,24 +57,32 @@ class App */ protected static $routeMust; + /** + * @var array 请求调度分发 + */ protected static $dispatch; + + /** + * @var array 额外加载文件 + */ protected static $file = []; /** * 执行应用程序 * @access public - * @param Request $request Request对象 + * @param Request $request 请求对象 * @return Response * @throws Exception */ public static function run(Request $request = null) { - is_null($request) && $request = Request::instance(); + $request = is_null($request) ? Request::instance() : $request; try { $config = self::initCommon(); + + // 模块/控制器绑定 if (defined('BIND_MODULE')) { - // 模块/控制器绑定 BIND_MODULE && Route::bind(BIND_MODULE); } elseif ($config['auto_bind_module']) { // 入口自动绑定 @@ -87,10 +96,8 @@ class App // 默认语言 Lang::range($config['default_lang']); - if ($config['lang_switch_on']) { - // 开启多语言机制 检测当前语言 - Lang::detect(); - } + // 开启多语言机制 检测当前语言 + $config['lang_switch_on'] && Lang::detect(); $request->langset(Lang::range()); // 加载系统语言包 @@ -99,12 +106,16 @@ class App APP_PATH . 'lang' . DS . $request->langset() . EXT, ]); + // 监听 app_dispatch + Hook::listen('app_dispatch', self::$dispatch); // 获取应用调度信息 $dispatch = self::$dispatch; + + // 未设置调度信息则进行 URL 路由检测 if (empty($dispatch)) { - // 进行URL路由检测 $dispatch = self::routeCheck($request, $config); } + // 记录当前调度信息 $request->dispatch($dispatch); @@ -115,10 +126,15 @@ class App Log::record('[ PARAM ] ' . var_export($request->param(), true), 'info'); } - // 监听app_begin + // 监听 app_begin Hook::listen('app_begin', $dispatch); + // 请求缓存检查 - $request->cache($config['request_cache'], $config['request_cache_expire'], $config['request_cache_except']); + $request->cache( + $config['request_cache'], + $config['request_cache_expire'], + $config['request_cache_except'] + ); $data = self::exec($dispatch, $config); } catch (HttpResponseException $exception) { @@ -133,24 +149,151 @@ class App $response = $data; } elseif (!is_null($data)) { // 默认自动识别响应输出类型 - $isAjax = $request->isAjax(); - $type = $isAjax ? Config::get('default_ajax_return') : Config::get('default_return_type'); + $type = $request->isAjax() ? + Config::get('default_ajax_return') : + Config::get('default_return_type'); + $response = Response::create($data, $type); } else { $response = Response::create(); } - // 监听app_end + // 监听 app_end Hook::listen('app_end', $response); return $response; } + /** + * 初始化应用,并返回配置信息 + * @access public + * @return array + */ + public static function initCommon() + { + if (empty(self::$init)) { + if (defined('APP_NAMESPACE')) { + self::$namespace = APP_NAMESPACE; + } + + Loader::addNamespace(self::$namespace, APP_PATH); + + // 初始化应用 + $config = self::init(); + self::$suffix = $config['class_suffix']; + + // 应用调试模式 + self::$debug = Env::get('app_debug', Config::get('app_debug')); + + if (!self::$debug) { + ini_set('display_errors', 'Off'); + } elseif (!IS_CLI) { + // 重新申请一块比较大的 buffer + if (ob_get_level() > 0) { + $output = ob_get_clean(); + } + + ob_start(); + + if (!empty($output)) { + echo $output; + } + + } + + if (!empty($config['root_namespace'])) { + Loader::addNamespace($config['root_namespace']); + } + + // 加载额外文件 + if (!empty($config['extra_file_list'])) { + foreach ($config['extra_file_list'] as $file) { + $file = strpos($file, '.') ? $file : APP_PATH . $file . EXT; + if (is_file($file) && !isset(self::$file[$file])) { + include $file; + self::$file[$file] = true; + } + } + } + + // 设置系统时区 + date_default_timezone_set($config['default_timezone']); + + // 监听 app_init + Hook::listen('app_init'); + + self::$init = true; + } + + return Config::get(); + } + + /** + * 初始化应用或模块 + * @access public + * @param string $module 模块名 + * @return array + */ + private static function init($module = '') + { + // 定位模块目录 + $module = $module ? $module . DS : ''; + + // 加载初始化文件 + if (is_file(APP_PATH . $module . 'init' . EXT)) { + include APP_PATH . $module . 'init' . EXT; + } elseif (is_file(RUNTIME_PATH . $module . 'init' . EXT)) { + include RUNTIME_PATH . $module . 'init' . EXT; + } else { + // 加载模块配置 + $config = Config::load(CONF_PATH . $module . 'config' . CONF_EXT); + + // 读取数据库配置文件 + $filename = CONF_PATH . $module . 'database' . CONF_EXT; + Config::load($filename, 'database'); + + // 读取扩展配置文件 + if (is_dir(CONF_PATH . $module . 'extra')) { + $dir = CONF_PATH . $module . 'extra'; + $files = scandir($dir); + foreach ($files as $file) { + if ('.' . pathinfo($file, PATHINFO_EXTENSION) === CONF_EXT) { + $filename = $dir . DS . $file; + Config::load($filename, pathinfo($file, PATHINFO_FILENAME)); + } + } + } + + // 加载应用状态配置 + if ($config['app_status']) { + Config::load(CONF_PATH . $module . $config['app_status'] . CONF_EXT); + } + + // 加载行为扩展文件 + if (is_file(CONF_PATH . $module . 'tags' . EXT)) { + Hook::import(include CONF_PATH . $module . 'tags' . EXT); + } + + // 加载公共文件 + $path = APP_PATH . $module; + if (is_file($path . 'common' . EXT)) { + include $path . 'common' . EXT; + } + + // 加载当前模块语言包 + if ($module) { + Lang::load($path . 'lang' . DS . Request::instance()->langset() . EXT); + } + } + + return Config::get(); + } + /** * 设置当前请求的调度信息 * @access public * @param array|string $dispatch 调度信息 - * @param string $type 调度类型 + * @param string $type 调度类型 * @return void */ public static function dispatch($dispatch, $type = 'module') @@ -169,8 +312,10 @@ class App { $reflect = new \ReflectionFunction($function); $args = self::bindParams($reflect, $vars); + // 记录执行信息 self::$debug && Log::record('[ RUN ] ' . $reflect->__toString(), 'info'); + return $reflect->invokeArgs($args); } @@ -190,28 +335,27 @@ class App // 静态方法 $reflect = new \ReflectionMethod($method); } + $args = self::bindParams($reflect, $vars); self::$debug && Log::record('[ RUN ] ' . $reflect->class . '->' . $reflect->name . '[ ' . $reflect->getFileName() . ' ]', 'info'); + return $reflect->invokeArgs(isset($class) ? $class : null, $args); } /** * 调用反射执行类的实例化 支持依赖注入 * @access public - * @param string $class 类名 - * @param array $vars 变量 + * @param string $class 类名 + * @param array $vars 变量 * @return mixed */ public static function invokeClass($class, $vars = []) { $reflect = new \ReflectionClass($class); $constructor = $reflect->getConstructor(); - if ($constructor) { - $args = self::bindParams($constructor, $vars); - } else { - $args = []; - } + $args = $constructor ? self::bindParams($constructor, $vars) : []; + return $reflect->newInstanceArgs($args); } @@ -224,52 +368,58 @@ class App */ private static function bindParams($reflect, $vars = []) { + // 自动获取请求变量 if (empty($vars)) { - // 自动获取请求变量 - if (Config::get('url_param_type')) { - $vars = Request::instance()->route(); - } else { - $vars = Request::instance()->param(); - } + $vars = Config::get('url_param_type') ? + Request::instance()->route() : + Request::instance()->param(); } + $args = []; if ($reflect->getNumberOfParameters() > 0) { // 判断数组类型 数字数组时按顺序绑定参数 reset($vars); - $type = key($vars) === 0 ? 1 : 0; - $params = $reflect->getParameters(); - foreach ($params as $param) { + $type = key($vars) === 0 ? 1 : 0; + + foreach ($reflect->getParameters() as $param) { $args[] = self::getParamValue($param, $vars, $type); } } + return $args; } /** * 获取参数值 * @access private - * @param \ReflectionParameter $param - * @param array $vars 变量 - * @param string $type + * @param \ReflectionParameter $param 参数 + * @param array $vars 变量 + * @param string $type 类别 * @return array */ private static function getParamValue($param, &$vars, $type) { $name = $param->getName(); $class = $param->getClass(); + if ($class) { $className = $class->getName(); $bind = Request::instance()->$name; + if ($bind instanceof $className) { $result = $bind; } else { if (method_exists($className, 'invoke')) { $method = new \ReflectionMethod($className, 'invoke'); + if ($method->isPublic() && $method->isStatic()) { return $className::invoke(Request::instance()); } } - $result = method_exists($className, 'instance') ? $className::instance() : new $className; + + $result = method_exists($className, 'instance') ? + $className::instance() : + new $className; } } elseif (1 == $type && !empty($vars)) { $result = array_shift($vars); @@ -280,65 +430,85 @@ class App } else { throw new \InvalidArgumentException('method param miss:' . $name); } + return $result; } + /** + * 执行调用分发 + * @access protected + * @param array $dispatch 调用信息 + * @param array $config 配置信息 + * @return Response|mixed + * @throws \InvalidArgumentException + */ protected static function exec($dispatch, $config) { switch ($dispatch['type']) { - case 'redirect': - // 执行重定向跳转 - $data = Response::create($dispatch['url'], 'redirect')->code($dispatch['status']); + case 'redirect': // 重定向跳转 + $data = Response::create($dispatch['url'], 'redirect') + ->code($dispatch['status']); break; - case 'module': - // 模块/控制器/操作 - $data = self::module($dispatch['module'], $config, isset($dispatch['convert']) ? $dispatch['convert'] : null); + case 'module': // 模块/控制器/操作 + $data = self::module( + $dispatch['module'], + $config, + isset($dispatch['convert']) ? $dispatch['convert'] : null + ); break; - case 'controller': - // 执行控制器操作 + case 'controller': // 执行控制器操作 $vars = array_merge(Request::instance()->param(), $dispatch['var']); - $data = Loader::action($dispatch['controller'], $vars, $config['url_controller_layer'], $config['controller_suffix']); + $data = Loader::action( + $dispatch['controller'], + $vars, + $config['url_controller_layer'], + $config['controller_suffix'] + ); break; - case 'method': - // 执行回调方法 + case 'method': // 回调方法 $vars = array_merge(Request::instance()->param(), $dispatch['var']); $data = self::invokeMethod($dispatch['method'], $vars); break; - case 'function': - // 执行闭包 + case 'function': // 闭包 $data = self::invokeFunction($dispatch['function']); break; - case 'response': + case 'response': // Response 实例 $data = $dispatch['response']; break; default: throw new \InvalidArgumentException('dispatch type not support'); } + return $data; } /** * 执行模块 * @access public - * @param array $result 模块/控制器/操作 - * @param array $config 配置参数 + * @param array $result 模块/控制器/操作 + * @param array $config 配置参数 * @param bool $convert 是否自动转换控制器和操作名 * @return mixed + * @throws HttpException */ public static function module($result, $config, $convert = null) { if (is_string($result)) { $result = explode('/', $result); } + $request = Request::instance(); + if ($config['app_multi_module']) { // 多模块部署 $module = strip_tags(strtolower($result[0] ?: $config['default_module'])); $bind = Route::getBind('module'); $available = false; + if ($bind) { // 绑定模块 list($bindModule) = explode('/', $bind); + if (empty($result[0])) { $module = $bindModule; $available = true; @@ -354,8 +524,13 @@ class App // 初始化模块 $request->module($module); $config = self::init($module); + // 模块请求缓存检查 - $request->cache($config['request_cache'], $config['request_cache_expire'], $config['request_cache_except']); + $request->cache( + $config['request_cache'], + $config['request_cache_expire'], + $config['request_cache_except'] + ); } else { throw new HttpException(404, 'module not exists:' . $module); } @@ -364,22 +539,32 @@ class App $module = ''; $request->module($module); } + + // 设置默认过滤机制 + $request->filter($config['default_filter']); + // 当前模块路径 App::$modulePath = APP_PATH . ($module ? $module . DS : ''); // 是否自动转换控制器和操作名 $convert = is_bool($convert) ? $convert : $config['url_convert']; + // 获取控制器名 $controller = strip_tags($result[1] ?: $config['default_controller']); - $controller = $convert ? strtolower($controller) : $controller; - + if (!preg_match('/^[A-Za-z](\w|\.)*$/', $controller)) { throw new HttpException(404, 'controller not exists:' . $controller); } - + + $controller = $convert ? strtolower($controller) : $controller; + // 获取操作名 $actionName = strip_tags($result[2] ?: $config['default_action']); - $actionName = $convert ? strtolower($actionName) : $actionName; + if (!empty($config['action_convert'])) { + $actionName = Loader::parseName($actionName, 1); + } else { + $actionName = $convert ? strtolower($actionName) : $actionName; + } // 设置当前请求的控制器、操作 $request->controller(Loader::parseName($controller, 1))->action($actionName); @@ -387,10 +572,17 @@ class App // 监听module_init Hook::listen('module_init', $request); - $instance = Loader::controller($controller, $config['url_controller_layer'], $config['controller_suffix'], $config['empty_controller']); - if (is_null($instance)) { - throw new HttpException(404, 'controller not exists:' . Loader::parseName($controller, 1)); + try { + $instance = Loader::controller( + $controller, + $config['url_controller_layer'], + $config['controller_suffix'], + $config['empty_controller'] + ); + } catch (ClassNotFoundException $e) { + throw new HttpException(404, 'controller not exists:' . $e->getClass()); } + // 获取当前操作名 $action = $actionName . $config['action_suffix']; @@ -398,6 +590,13 @@ class App if (is_callable([$instance, $action])) { // 执行操作方法 $call = [$instance, $action]; + // 严格获取当前操作方法名 + $reflect = new \ReflectionMethod($instance, $action); + $methodName = $reflect->getName(); + $suffix = $config['action_suffix']; + $actionName = $suffix ? substr($methodName, 0, -strlen($suffix)) : $methodName; + $request->action($actionName); + } elseif (is_callable([$instance, '_empty'])) { // 空操作 $call = [$instance, '_empty']; @@ -412,125 +611,11 @@ class App return self::invokeMethod($call, $vars); } - /** - * 初始化应用 - */ - public static function initCommon() - { - if (empty(self::$init)) { - if (defined('APP_NAMESPACE')) { - self::$namespace = APP_NAMESPACE; - } - Loader::addNamespace(self::$namespace, APP_PATH); - - // 初始化应用 - $config = self::init(); - self::$suffix = $config['class_suffix']; - - // 应用调试模式 - self::$debug = Env::get('app_debug', Config::get('app_debug')); - if (!self::$debug) { - ini_set('display_errors', 'Off'); - } elseif (!IS_CLI) { - //重新申请一块比较大的buffer - if (ob_get_level() > 0) { - $output = ob_get_clean(); - } - ob_start(); - if (!empty($output)) { - echo $output; - } - } - - if (!empty($config['root_namespace'])) { - Loader::addNamespace($config['root_namespace']); - } - - // 加载额外文件 - if (!empty($config['extra_file_list'])) { - foreach ($config['extra_file_list'] as $file) { - $file = strpos($file, '.') ? $file : APP_PATH . $file . EXT; - if (is_file($file) && !isset(self::$file[$file])) { - include $file; - self::$file[$file] = true; - } - } - } - - // 设置系统时区 - date_default_timezone_set($config['default_timezone']); - - // 监听app_init - Hook::listen('app_init'); - - self::$init = true; - } - return Config::get(); - } - - /** - * 初始化应用或模块 - * @access public - * @param string $module 模块名 - * @return array - */ - private static function init($module = '') - { - // 定位模块目录 - $module = $module ? $module . DS : ''; - - // 加载初始化文件 - if (is_file(APP_PATH . $module . 'init' . EXT)) { - include APP_PATH . $module . 'init' . EXT; - } elseif (is_file(RUNTIME_PATH . $module . 'init' . EXT)) { - include RUNTIME_PATH . $module . 'init' . EXT; - } else { - $path = APP_PATH . $module; - // 加载模块配置 - $config = Config::load(CONF_PATH . $module . 'config' . CONF_EXT); - // 读取数据库配置文件 - $filename = CONF_PATH . $module . 'database' . CONF_EXT; - Config::load($filename, 'database'); - // 读取扩展配置文件 - if (is_dir(CONF_PATH . $module . 'extra')) { - $dir = CONF_PATH . $module . 'extra'; - $files = scandir($dir); - foreach ($files as $file) { - if ('.' . pathinfo($file, PATHINFO_EXTENSION) === CONF_EXT) { - $filename = $dir . DS . $file; - Config::load($filename, pathinfo($file, PATHINFO_FILENAME)); - } - } - } - - // 加载应用状态配置 - if ($config['app_status']) { - $config = Config::load(CONF_PATH . $module . $config['app_status'] . CONF_EXT); - } - - // 加载行为扩展文件 - if (is_file(CONF_PATH . $module . 'tags' . EXT)) { - Hook::import(include CONF_PATH . $module . 'tags' . EXT); - } - - // 加载公共文件 - if (is_file($path . 'common' . EXT)) { - include $path . 'common' . EXT; - } - - // 加载当前模块语言包 - if ($module) { - Lang::load($path . 'lang' . DS . Request::instance()->langset() . EXT); - } - } - return Config::get(); - } - /** * URL路由检测(根据PATH_INFO) * @access public - * @param \think\Request $request - * @param array $config + * @param \think\Request $request 请求实例 + * @param array $config 配置信息 * @return array * @throws \think\Exception */ @@ -539,6 +624,7 @@ class App $path = $request->path(); $depr = $config['pathinfo_depr']; $result = false; + // 路由检测 $check = !is_null(self::$routeCheck) ? self::$routeCheck : $config['url_route_on']; if ($check) { @@ -546,18 +632,14 @@ class App if (is_file(RUNTIME_PATH . 'route.php')) { // 读取路由缓存 $rules = include RUNTIME_PATH . 'route.php'; - if (is_array($rules)) { - Route::rules($rules); - } + is_array($rules) && Route::rules($rules); } else { $files = $config['route_config_file']; foreach ($files as $file) { if (is_file(CONF_PATH . $file . CONF_EXT)) { // 导入路由配置 $rules = include CONF_PATH . $file . CONF_EXT; - if (is_array($rules)) { - Route::import($rules); - } + is_array($rules) && Route::import($rules); } } } @@ -565,15 +647,18 @@ class App // 路由检测(根据路由定义返回不同的URL调度) $result = Route::check($request, $path, $depr, $config['url_domain_deploy']); $must = !is_null(self::$routeMust) ? self::$routeMust : $config['url_route_must']; + if ($must && false === $result) { // 路由无效 throw new RouteNotFoundException(); } } + + // 路由无效 解析模块/控制器/操作/参数... 支持控制器自动搜索 if (false === $result) { - // 路由无效 解析模块/控制器/操作/参数... 支持控制器自动搜索 $result = Route::parseUrl($path, $depr, $config['controller_auto_search']); } + return $result; } diff --git a/thinkphp/library/think/Build.php b/thinkphp/library/think/Build.php index d08dc50b..de7c3275 100644 --- a/thinkphp/library/think/Build.php +++ b/thinkphp/library/think/Build.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -14,36 +14,44 @@ namespace think; class Build { /** - * 根据传入的build资料创建目录和文件 - * @access protected - * @param array $build build列表 + * 根据传入的 build 资料创建目录和文件 + * @access public + * @param array $build build 列表 * @param string $namespace 应用类库命名空间 - * @param bool $suffix 类库后缀 + * @param bool $suffix 类库后缀 * @return void + * @throws Exception */ public static function run(array $build = [], $namespace = 'app', $suffix = false) { // 锁定 - $lockfile = APP_PATH . 'build.lock'; - if (is_writable($lockfile)) { - return; - } elseif (!touch($lockfile)) { - throw new Exception('应用目录[' . APP_PATH . ']不可写,目录无法自动生成!
请手动生成项目目录~', 10006); - } - foreach ($build as $module => $list) { - if ('__dir__' == $module) { - // 创建目录列表 - self::buildDir($list); - } elseif ('__file__' == $module) { - // 创建文件列表 - self::buildFile($list); - } else { - // 创建模块 - self::module($module, $list, $namespace, $suffix); + $lock = APP_PATH . 'build.lock'; + + // 如果锁定文件不可写(不存在)则进行处理,否则表示已经有程序在处理了 + if (!is_writable($lock)) { + if (!touch($lock)) { + throw new Exception( + '应用目录[' . APP_PATH . ']不可写,目录无法自动生成!
请手动生成项目目录~', + 10006 + ); } + + foreach ($build as $module => $list) { + if ('__dir__' == $module) { + // 创建目录列表 + self::buildDir($list); + } elseif ('__file__' == $module) { + // 创建文件列表 + self::buildFile($list); + } else { + // 创建模块 + self::module($module, $list, $namespace, $suffix); + } + } + + // 解除锁定 + unlink($lock); } - // 解除锁定 - unlink($lockfile); } /** @@ -55,10 +63,8 @@ class Build protected static function buildDir($list) { foreach ($list as $dir) { - if (!is_dir(APP_PATH . $dir)) { - // 创建目录 - mkdir(APP_PATH . $dir, 0755, true); - } + // 目录不存在则创建目录 + !is_dir(APP_PATH . $dir) && mkdir(APP_PATH . $dir, 0755, true); } } @@ -71,12 +77,17 @@ class Build protected static function buildFile($list) { foreach ($list as $file) { + // 先创建目录 if (!is_dir(APP_PATH . dirname($file))) { - // 创建目录 mkdir(APP_PATH . dirname($file), 0755, true); } + + // 再创建文件 if (!is_file(APP_PATH . $file)) { - file_put_contents(APP_PATH . $file, 'php' == pathinfo($file, PATHINFO_EXTENSION) ? " ['config.php', 'common.php'], '__dir__' => ['controller', 'model', 'view'], ]; } + // 创建子目录和文件 foreach ($list as $path => $file) { $modulePath = APP_PATH . $module . DS; + if ('__dir__' == $path) { // 生成子目录 foreach ($file as $dir) { - if (!is_dir($modulePath . $dir)) { - // 创建目录 - mkdir($modulePath . $dir, 0755, true); - } + self::checkDirBuild($modulePath . $dir); } } elseif ('__file__' == $path) { // 生成(空白)文件 foreach ($file as $name) { if (!is_file($modulePath . $name)) { - file_put_contents($modulePath . $name, 'php' == pathinfo($name, PATHINFO_EXTENSION) ? "has($name); } /** * 读取缓存 * @access public - * @param string $name 缓存标识 - * @param mixed $default 默认值 + * @param string $name 缓存标识 + * @param mixed $default 默认值 * @return mixed */ public static function get($name, $default = false) { self::$readTimes++; + return self::init()->get($name, $default); } /** * 写入缓存 * @access public - * @param string $name 缓存标识 - * @param mixed $value 存储数据 - * @param int|null $expire 有效时间 0为永久 + * @param string $name 缓存标识 + * @param mixed $value 存储数据 + * @param int|null $expire 有效时间 0为永久 * @return boolean */ public static function set($name, $value, $expire = null) { self::$writeTimes++; + return self::init()->set($name, $value, $expire); } /** * 自增缓存(针对数值缓存) * @access public - * @param string $name 缓存变量名 - * @param int $step 步长 + * @param string $name 缓存变量名 + * @param int $step 步长 * @return false|int */ public static function inc($name, $step = 1) { self::$writeTimes++; + return self::init()->inc($name, $step); } /** * 自减缓存(针对数值缓存) * @access public - * @param string $name 缓存变量名 - * @param int $step 步长 + * @param string $name 缓存变量名 + * @param int $step 步长 * @return false|int */ public static function dec($name, $step = 1) { self::$writeTimes++; + return self::init()->dec($name, $step); } /** * 删除缓存 * @access public - * @param string $name 缓存标识 + * @param string $name 缓存标识 * @return boolean */ public static function rm($name) { self::$writeTimes++; + return self::init()->rm($name); } /** * 清除缓存 * @access public - * @param string $tag 标签名 + * @param string $tag 标签名 * @return boolean */ public static function clear($tag = null) { self::$writeTimes++; + return self::init()->clear($tag); } /** * 读取缓存并删除 * @access public - * @param string $name 缓存变量名 + * @param string $name 缓存变量名 * @return mixed */ public static function pull($name) { self::$readTimes++; self::$writeTimes++; + return self::init()->pull($name); } /** * 如果不存在则写入缓存 * @access public - * @param string $name 缓存变量名 - * @param mixed $value 存储数据 - * @param int $expire 有效时间 0为永久 + * @param string $name 缓存变量名 + * @param mixed $value 存储数据 + * @param int $expire 有效时间 0为永久 * @return mixed */ public static function remember($name, $value, $expire = null) { self::$readTimes++; + return self::init()->remember($name, $value, $expire); } /** * 缓存标签 * @access public - * @param string $name 标签名 - * @param string|array $keys 缓存标识 - * @param bool $overlay 是否覆盖 + * @param string $name 标签名 + * @param string|array $keys 缓存标识 + * @param bool $overlay 是否覆盖 * @return Driver */ public static function tag($name, $keys = null, $overlay = false) diff --git a/thinkphp/library/think/Collection.php b/thinkphp/library/think/Collection.php index 41b42759..f872476f 100644 --- a/thinkphp/library/think/Collection.php +++ b/thinkphp/library/think/Collection.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -19,20 +19,35 @@ use JsonSerializable; class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSerializable { + /** + * @var array 数据 + */ protected $items = []; + /** + * Collection constructor. + * @access public + * @param array $items 数据 + */ public function __construct($items = []) { $this->items = $this->convertToArray($items); } + /** + * 创建 Collection 实例 + * @access public + * @param array $items 数据 + * @return static + */ public static function make($items = []) { return new static($items); } /** - * 是否为空 + * 判断数据是否为空 + * @access public * @return bool */ public function isEmpty() @@ -40,74 +55,96 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria return empty($this->items); } + /** + * 将数据转成数组 + * @access public + * @return array + */ public function toArray() { return array_map(function ($value) { - return ($value instanceof Model || $value instanceof self) ? $value->toArray() : $value; + return ($value instanceof Model || $value instanceof self) ? + $value->toArray() : + $value; }, $this->items); } + /** + * 获取全部的数据 + * @access public + * @return array + */ public function all() { return $this->items; } /** - * 合并数组 - * - * @param mixed $items + * 交换数组中的键和值 + * @access public * @return static */ - public function merge($items) + public function flip() { - return new static(array_merge($this->items, $this->convertToArray($items))); + return new static(array_flip($this->items)); } /** - * 比较数组,返回差集 - * - * @param mixed $items + * 返回数组中所有的键名组成的新 Collection 实例 + * @access public * @return static */ - public function diff($items) + public function keys() { - return new static(array_diff($this->items, $this->convertToArray($items))); + return new static(array_keys($this->items)); } /** - * 交换数组中的键和值 - * + * 返回数组中所有的值组成的新 Collection 实例 + * @access public * @return static */ - public function flip() + public function values() { - return new static(array_flip($this->items)); + return new static(array_values($this->items)); } /** - * 比较数组,返回交集 - * - * @param mixed $items + * 合并数组并返回一个新的 Collection 实例 + * @access public + * @param mixed $items 新的数据 * @return static */ - public function intersect($items) + public function merge($items) { - return new static(array_intersect($this->items, $this->convertToArray($items))); + return new static(array_merge($this->items, $this->convertToArray($items))); } /** - * 返回数组中所有的键名 - * + * 比较数组,返回差集生成的新 Collection 实例 + * @access public + * @param mixed $items 做比较的数据 * @return static */ - public function keys() + public function diff($items) { - return new static(array_keys($this->items)); + return new static(array_diff($this->items, $this->convertToArray($items))); + } + + /** + * 比较数组,返回交集组成的 Collection 新实例 + * @access public + * @param mixed $items 比较数据 + * @return static + */ + public function intersect($items) + { + return new static(array_intersect($this->items, $this->convertToArray($items))); } /** - * 删除数组的最后一个元素(出栈) - * + * 返回并删除数据中的的最后一个元素(出栈) + * @access public * @return mixed */ public function pop() @@ -116,42 +153,74 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria } /** - * 通过使用用户自定义函数,以字符串返回数组 - * - * @param callable $callback - * @param mixed $initial + * 返回并删除数据中首个元素 + * @access public * @return mixed */ - public function reduce(callable $callback, $initial = null) + public function shift() { - return array_reduce($this->items, $callback, $initial); + return array_shift($this->items); } /** - * 以相反的顺序返回数组。 - * - * @return static + * 在数组开头插入一个元素 + * @access public + * @param mixed $value 值 + * @param mixed $key 键名 + * @return void */ - public function reverse() + public function unshift($value, $key = null) { - return new static(array_reverse($this->items)); + if (is_null($key)) { + array_unshift($this->items, $value); + } else { + $this->items = [$key => $value] + $this->items; + } + } + + /** + * 在数组结尾插入一个元素 + * @access public + * @param mixed $value 值 + * @param mixed $key 键名 + * @return void + */ + public function push($value, $key = null) + { + if (is_null($key)) { + $this->items[] = $value; + } else { + $this->items[$key] = $value; + } } /** - * 删除数组中首个元素,并返回被删除元素的值 - * + * 通过使用用户自定义函数,以字符串返回数组 + * @access public + * @param callable $callback 回调函数 + * @param mixed $initial 初始值 * @return mixed */ - public function shift() + public function reduce(callable $callback, $initial = null) { - return array_shift($this->items); + return array_reduce($this->items, $callback, $initial); + } + + /** + * 以相反的顺序创建一个新的 Collection 实例 + * @access public + * @return static + */ + public function reverse() + { + return new static(array_reverse($this->items)); } /** - * 把一个数组分割为新的数组块. - * - * @param int $size - * @param bool $preserveKeys + * 把数据分割为新的数组块 + * @access public + * @param int $size 分隔长度 + * @param bool $preserveKeys 是否保持原数据索引 * @return static */ public function chunk($size, $preserveKeys = false) @@ -166,78 +235,70 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria } /** - * 在数组开头插入一个元素 - * @param mixed $value - * @param null $key - * @return int - */ - public function unshift($value, $key = null) - { - if (is_null($key)) { - array_unshift($this->items, $value); - } else { - $this->items = [$key => $value] + $this->items; - } - } - - /** - * 给每个元素执行个回调 - * - * @param callable $callback + * 给数据中的每个元素执行回调 + * @access public + * @param callable $callback 回调函数 * @return $this */ public function each(callable $callback) { foreach ($this->items as $key => $item) { - if ($callback($item, $key) === false) { + $result = $callback($item, $key); + + if (false === $result) { break; } + + if (!is_object($item)) { + $this->items[$key] = $result; + } } return $this; } /** - * 用回调函数过滤数组中的元素 - * @param callable|null $callback + * 用回调函数过滤数据中的元素 + * @access public + * @param callable|null $callback 回调函数 * @return static */ public function filter(callable $callback = null) { - if ($callback) { - return new static(array_filter($this->items, $callback)); - } - - return new static(array_filter($this->items)); + return new static(array_filter($this->items, $callback ?: null)); } /** - * 返回数组中指定的一列 - * @param $column_key - * @param null $index_key + * 返回数据中指定的一列 + * @access public + * @param mixed $columnKey 键名 + * @param null $indexKey 作为索引值的列 * @return array */ - public function column($column_key, $index_key = null) + public function column($columnKey, $indexKey = null) { if (function_exists('array_column')) { - return array_column($this->items, $column_key, $index_key); + return array_column($this->items, $columnKey, $indexKey); } $result = []; foreach ($this->items as $row) { - $key = $value = null; + $key = $value = null; $keySet = $valueSet = false; - if (null !== $index_key && array_key_exists($index_key, $row)) { + + if (null !== $indexKey && array_key_exists($indexKey, $row)) { + $key = (string) $row[$indexKey]; $keySet = true; - $key = (string) $row[$index_key]; } - if (null === $column_key) { + + if (null === $columnKey) { $valueSet = true; $value = $row; - } elseif (is_array($row) && array_key_exists($column_key, $row)) { + } elseif (is_array($row) && array_key_exists($columnKey, $row)) { $valueSet = true; - $value = $row[$column_key]; + $value = $row[$columnKey]; } + if ($valueSet) { if ($keySet) { $result[$key] = $value; @@ -246,34 +307,30 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria } } } + return $result; } /** - * 对数组排序 - * - * @param callable|null $callback + * 对数据排序,并返回排序后的数据组成的新 Collection 实例 + * @access public + * @param callable|null $callback 回调函数 * @return static */ public function sort(callable $callback = null) { - $items = $this->items; - - $callback ? uasort($items, $callback) : uasort($items, function ($a, $b) { - - if ($a == $b) { - return 0; - } - - return ($a < $b) ? -1 : 1; - }); + $items = $this->items; + $callback = $callback ?: function ($a, $b) { + return $a == $b ? 0 : (($a < $b) ? -1 : 1); + }; + uasort($items, $callback); return new static($items); } /** - * 将数组打乱 - * + * 将数据打乱后组成新的 Collection 实例 + * @access public * @return static */ public function shuffle() @@ -281,16 +338,15 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria $items = $this->items; shuffle($items); - return new static($items); } /** - * 截取数组 - * - * @param int $offset - * @param int $length - * @param bool $preserveKeys + * 截取数据并返回新的 Collection 实例 + * @access public + * @param int $offset 起始位置 + * @param int $length 截取长度 + * @param bool $preserveKeys 是否保持原先的键名 * @return static */ public function slice($offset, $length = null, $preserveKeys = false) @@ -298,17 +354,35 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria return new static(array_slice($this->items, $offset, $length, $preserveKeys)); } - // ArrayAccess + /** + * 指定的键是否存在 + * @access public + * @param mixed $offset 键名 + * @return bool + */ public function offsetExists($offset) { return array_key_exists($offset, $this->items); } + /** + * 获取指定键对应的值 + * @access public + * @param mixed $offset 键名 + * @return mixed + */ public function offsetGet($offset) { return $this->items[$offset]; } + /** + * 设置键值 + * @access public + * @param mixed $offset 键名 + * @param mixed $value 值 + * @return void + */ public function offsetSet($offset, $value) { if (is_null($offset)) { @@ -318,33 +392,51 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria } } + /** + * 删除指定键值 + * @access public + * @param mixed $offset 键名 + * @return void + */ public function offsetUnset($offset) { unset($this->items[$offset]); } - //Countable + /** + * 统计数据的个数 + * @access public + * @return int + */ public function count() { return count($this->items); } - //IteratorAggregate + /** + * 获取数据的迭代器 + * @access public + * @return ArrayIterator + */ public function getIterator() { return new ArrayIterator($this->items); } - //JsonSerializable + /** + * 将数据反序列化成数组 + * @access public + * @return array + */ public function jsonSerialize() { return $this->toArray(); } /** - * 转换当前数据集为JSON字符串 + * 转换当前数据集为 JSON 字符串 * @access public - * @param integer $options json参数 + * @param integer $options json 参数 * @return string */ public function toJson($options = JSON_UNESCAPED_UNICODE) @@ -352,22 +444,24 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria return json_encode($this->toArray(), $options); } + /** + * 将数据转换成字符串 + * @access public + * @return string + */ public function __toString() { return $this->toJson(); } /** - * 转换成数组 - * - * @param mixed $items + * 将数据转换成数组 + * @access protected + * @param mixed $items 数据 * @return array */ protected function convertToArray($items) { - if ($items instanceof self) { - return $items->all(); - } - return (array) $items; + return $items instanceof self ? $items->all() : (array) $items; } } diff --git a/thinkphp/library/think/Config.php b/thinkphp/library/think/Config.php index 2b808434..8fa668d1 100644 --- a/thinkphp/library/think/Config.php +++ b/thinkphp/library/think/Config.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -13,70 +13,88 @@ namespace think; class Config { - // 配置参数 + /** + * @var array 配置参数 + */ private static $config = []; - // 参数作用域 + + /** + * @var string 参数作用域 + */ private static $range = '_sys_'; - // 设定配置参数的作用域 + /** + * 设定配置参数的作用域 + * @access public + * @param string $range 作用域 + * @return void + */ public static function range($range) { self::$range = $range; - if (!isset(self::$config[$range])) { - self::$config[$range] = []; - } + + if (!isset(self::$config[$range])) self::$config[$range] = []; } /** * 解析配置文件或内容 - * @param string $config 配置文件路径或内容 - * @param string $type 配置解析类型 - * @param string $name 配置名(如设置即表示二级配置) - * @param string $range 作用域 + * @access public + * @param string $config 配置文件路径或内容 + * @param string $type 配置解析类型 + * @param string $name 配置名(如设置即表示二级配置) + * @param string $range 作用域 * @return mixed */ public static function parse($config, $type = '', $name = '', $range = '') { $range = $range ?: self::$range; - if (empty($type)) { - $type = pathinfo($config, PATHINFO_EXTENSION); - } - $class = false !== strpos($type, '\\') ? $type : '\\think\\config\\driver\\' . ucwords($type); + + if (empty($type)) $type = pathinfo($config, PATHINFO_EXTENSION); + + $class = false !== strpos($type, '\\') ? + $type : + '\\think\\config\\driver\\' . ucwords($type); + return self::set((new $class())->parse($config), $name, $range); } /** * 加载配置文件(PHP格式) - * @param string $file 配置文件名 - * @param string $name 配置名(如设置即表示二级配置) - * @param string $range 作用域 + * @access public + * @param string $file 配置文件名 + * @param string $name 配置名(如设置即表示二级配置) + * @param string $range 作用域 * @return mixed */ public static function load($file, $name = '', $range = '') { $range = $range ?: self::$range; - if (!isset(self::$config[$range])) { - self::$config[$range] = []; - } + + if (!isset(self::$config[$range])) self::$config[$range] = []; + if (is_file($file)) { $name = strtolower($name); $type = pathinfo($file, PATHINFO_EXTENSION); + if ('php' == $type) { return self::set(include $file, $name, $range); - } elseif ('yaml' == $type && function_exists('yaml_parse_file')) { + } + + if ('yaml' == $type && function_exists('yaml_parse_file')) { return self::set(yaml_parse_file($file), $name, $range); - } else { - return self::parse($file, $type, $name, $range); } - } else { - return self::$config[$range]; + + return self::parse($file, $type, $name, $range); } + + return self::$config[$range]; } /** * 检测配置是否存在 - * @param string $name 配置参数名(支持二级配置 .号分割) - * @param string $range 作用域 + * @access public + * @param string $name 配置参数名(支持二级配置 . 号分割) + * @param string $range 作用域 * @return bool */ public static function has($name, $range = '') @@ -85,82 +103,108 @@ class Config if (!strpos($name, '.')) { return isset(self::$config[$range][strtolower($name)]); - } else { - // 二维数组设置和获取支持 - $name = explode('.', $name, 2); - return isset(self::$config[$range][strtolower($name[0])][$name[1]]); } + + // 二维数组设置和获取支持 + $name = explode('.', $name, 2); + return isset(self::$config[$range][strtolower($name[0])][$name[1]]); } /** * 获取配置参数 为空则获取所有配置 - * @param string $name 配置参数名(支持二级配置 .号分割) - * @param string $range 作用域 + * @access public + * @param string $name 配置参数名(支持二级配置 . 号分割) + * @param string $range 作用域 * @return mixed */ public static function get($name = null, $range = '') { $range = $range ?: self::$range; + // 无参数时获取所有 if (empty($name) && isset(self::$config[$range])) { return self::$config[$range]; } + // 非二级配置时直接返回 if (!strpos($name, '.')) { $name = strtolower($name); return isset(self::$config[$range][$name]) ? self::$config[$range][$name] : null; - } else { - // 二维数组设置和获取支持 - $name = explode('.', $name, 2); - $name[0] = strtolower($name[0]); - return isset(self::$config[$range][$name[0]][$name[1]]) ? self::$config[$range][$name[0]][$name[1]] : null; } + + // 二维数组设置和获取支持 + $name = explode('.', $name, 2); + $name[0] = strtolower($name[0]); + + if (!isset(self::$config[$range][$name[0]])) { + // 动态载入额外配置 + $module = Request::instance()->module(); + $file = CONF_PATH . ($module ? $module . DS : '') . 'extra' . DS . $name[0] . CONF_EXT; + + is_file($file) && self::load($file, $name[0]); + } + + return isset(self::$config[$range][$name[0]][$name[1]]) ? + self::$config[$range][$name[0]][$name[1]] : + null; } /** - * 设置配置参数 name为数组则为批量设置 - * @param string|array $name 配置参数名(支持二级配置 .号分割) - * @param mixed $value 配置值 - * @param string $range 作用域 + * 设置配置参数 name 为数组则为批量设置 + * @access public + * @param string|array $name 配置参数名(支持二级配置 . 号分割) + * @param mixed $value 配置值 + * @param string $range 作用域 * @return mixed */ public static function set($name, $value = null, $range = '') { $range = $range ?: self::$range; - if (!isset(self::$config[$range])) { - self::$config[$range] = []; - } + + if (!isset(self::$config[$range])) self::$config[$range] = []; + + // 字符串则表示单个配置设置 if (is_string($name)) { if (!strpos($name, '.')) { self::$config[$range][strtolower($name)] = $value; } else { - // 二维数组设置和获取支持 - $name = explode('.', $name, 2); + // 二维数组 + $name = explode('.', $name, 2); self::$config[$range][strtolower($name[0])][$name[1]] = $value; } - return; - } elseif (is_array($name)) { - // 批量设置 + + return $value; + } + + // 数组则表示批量设置 + if (is_array($name)) { if (!empty($value)) { self::$config[$range][$value] = isset(self::$config[$range][$value]) ? - array_merge(self::$config[$range][$value], $name) : - self::$config[$range][$value] = $name; + array_merge(self::$config[$range][$value], $name) : + $name; + return self::$config[$range][$value]; - } else { - return self::$config[$range] = array_merge(self::$config[$range], array_change_key_case($name)); } - } else { - // 为空直接返回 已有配置 - return self::$config[$range]; + + return self::$config[$range] = array_merge( + self::$config[$range], array_change_key_case($name) + ); } + + // 为空直接返回已有配置 + return self::$config[$range]; } /** * 重置配置参数 + * @access public + * @param string $range 作用域 + * @return void */ public static function reset($range = '') { $range = $range ?: self::$range; + if (true === $range) { self::$config = []; } else { diff --git a/thinkphp/library/think/Console.php b/thinkphp/library/think/Console.php index 1d97ab2b..32b25725 100644 --- a/thinkphp/library/think/Console.php +++ b/thinkphp/library/think/Console.php @@ -20,20 +20,49 @@ use think\console\output\driver\Buffer; class Console { - + /** + * @var string 命令名称 + */ private $name; + + /** + * @var string 命令版本 + */ private $version; - /** @var Command[] */ + /** + * @var Command[] 命令 + */ private $commands = []; + /** + * @var bool 是否需要帮助信息 + */ private $wantHelps = false; + /** + * @var bool 是否捕获异常 + */ private $catchExceptions = true; - private $autoExit = true; + + /** + * @var bool 是否自动退出执行 + */ + private $autoExit = true; + + /** + * @var InputDefinition 输入定义 + */ private $definition; + + /** + * @var string 默认执行的命令 + */ private $defaultCommand; + /** + * @var array 默认提供的命令 + */ private static $defaultCommands = [ "think\\console\\command\\Help", "think\\console\\command\\Lists", @@ -47,11 +76,22 @@ class Console "think\\console\\command\\optimize\\Schema", ]; - public function __construct($name = 'UNKNOWN', $version = 'UNKNOWN') + /** + * Console constructor. + * @access public + * @param string $name 名称 + * @param string $version 版本 + * @param null|string $user 执行用户 + */ + public function __construct($name = 'UNKNOWN', $version = 'UNKNOWN', $user = null) { $this->name = $name; $this->version = $version; + if ($user) { + $this->setUser($user); + } + $this->defaultCommand = 'list'; $this->definition = $this->getDefaultInputDefinition(); @@ -60,38 +100,58 @@ class Console } } + /** + * 设置执行用户 + * @param $user + */ + public function setUser($user) + { + $user = posix_getpwnam($user); + if ($user) { + posix_setuid($user['uid']); + posix_setgid($user['gid']); + } + } + + /** + * 初始化 Console + * @access public + * @param bool $run 是否运行 Console + * @return int|Console + */ public static function init($run = true) { static $console; + if (!$console) { - // 实例化console - $console = new self('Think Console', '0.1'); + $config = Config::get('console'); + // 实例化 console + $console = new self($config['name'], $config['version'], $config['user']); + // 读取指令集 if (is_file(CONF_PATH . 'command' . EXT)) { $commands = include CONF_PATH . 'command' . EXT; + if (is_array($commands)) { foreach ($commands as $command) { - if (class_exists($command) && is_subclass_of($command, "\\think\\console\\Command")) { - // 注册指令 - $console->add(new $command()); - } + class_exists($command) && + is_subclass_of($command, "\\think\\console\\Command") && + $console->add(new $command()); // 注册指令 } } } } - if ($run) { - // 运行 - return $console->run(); - } else { - return $console; - } + + return $run ? $console->run() : $console; } /** - * @param $command - * @param array $parameters - * @param string $driver - * @return Output|Buffer + * 调用命令 + * @access public + * @param string $command + * @param array $parameters + * @param string $driver + * @return Output */ public static function call($command, array $parameters = [], $driver = 'buffer') { @@ -110,9 +170,9 @@ class Console /** * 执行当前的指令 + * @access public * @return int * @throws \Exception - * @api */ public function run() { @@ -124,27 +184,21 @@ class Console try { $exitCode = $this->doRun($input, $output); } catch (\Exception $e) { - if (!$this->catchExceptions) { - throw $e; - } + if (!$this->catchExceptions) throw $e; $output->renderException($e); $exitCode = $e->getCode(); + if (is_numeric($exitCode)) { - $exitCode = (int) $exitCode; - if (0 === $exitCode) { - $exitCode = 1; - } + $exitCode = ((int) $exitCode) ?: 1; } else { $exitCode = 1; } } if ($this->autoExit) { - if ($exitCode > 255) { - $exitCode = 255; - } + if ($exitCode > 255) $exitCode = 255; exit($exitCode); } @@ -154,12 +208,14 @@ class Console /** * 执行指令 - * @param Input $input - * @param Output $output + * @access public + * @param Input $input 输入 + * @param Output $output 输出 * @return int */ public function doRun(Input $input, Output $output) { + // 获取版本信息 if (true === $input->hasParameterOption(['--version', '-V'])) { $output->writeln($this->getLongVersion()); @@ -168,6 +224,7 @@ class Console $name = $this->getCommandName($input); + // 获取帮助信息 if (true === $input->hasParameterOption(['--help', '-h'])) { if (!$name) { $name = 'help'; @@ -182,25 +239,26 @@ class Console $input = new Input([$this->defaultCommand]); } - $command = $this->find($name); - - $exitCode = $this->doRunCommand($command, $input, $output); - - return $exitCode; + return $this->doRunCommand($this->find($name), $input, $output); } /** * 设置输入参数定义 - * @param InputDefinition $definition + * @access public + * @param InputDefinition $definition 输入定义 + * @return $this; */ public function setDefinition(InputDefinition $definition) { $this->definition = $definition; + + return $this; } /** * 获取输入参数定义 - * @return InputDefinition The InputDefinition instance + * @access public + * @return InputDefinition */ public function getDefinition() { @@ -208,8 +266,9 @@ class Console } /** - * Gets the help message. - * @return string A help message. + * 获取帮助信息 + * @access public + * @return string */ public function getHelp() { @@ -217,27 +276,34 @@ class Console } /** - * 是否捕获异常 - * @param bool $boolean - * @api + * 设置是否捕获异常 + * @access public + * @param bool $boolean 是否捕获 + * @return $this */ public function setCatchExceptions($boolean) { $this->catchExceptions = (bool) $boolean; + + return $this; } /** - * 是否自动退出 - * @param bool $boolean - * @api + * 设置是否自动退出 + * @access public + * @param bool $boolean 是否自动退出 + * @return $this */ public function setAutoExit($boolean) { $this->autoExit = (bool) $boolean; + + return $this; } /** * 获取名称 + * @access public * @return string */ public function getName() @@ -247,17 +313,21 @@ class Console /** * 设置名称 - * @param string $name + * @access public + * @param string $name 名称 + * @return $this */ public function setName($name) { $this->name = $name; + + return $this; } /** * 获取版本 + * @access public * @return string - * @api */ public function getVersion() { @@ -266,21 +336,30 @@ class Console /** * 设置版本 - * @param string $version + * @access public + * @param string $version 版本信息 + * @return $this */ public function setVersion($version) { $this->version = $version; + + return $this; } /** * 获取完整的版本号 + * @access public * @return string */ public function getLongVersion() { if ('UNKNOWN' !== $this->getName() && 'UNKNOWN' !== $this->getVersion()) { - return sprintf('%s version %s', $this->getName(), $this->getVersion()); + return sprintf( + '%s version %s', + $this->getName(), + $this->getVersion() + ); } return 'Console Tool'; @@ -288,7 +367,8 @@ class Console /** * 注册一个指令 - * @param string $name + * @access public + * @param string $name 指令名称 * @return Command */ public function register($name) @@ -297,32 +377,37 @@ class Console } /** - * 添加指令 - * @param Command[] $commands + * 批量添加指令 + * @access public + * @param Command[] $commands 指令实例 + * @return $this */ public function addCommands(array $commands) { - foreach ($commands as $command) { - $this->add($command); - } + foreach ($commands as $command) $this->add($command); + + return $this; } /** * 添加一个指令 - * @param Command $command - * @return Command + * @access public + * @param Command $command 命令实例 + * @return Command|bool */ public function add(Command $command) { - $command->setConsole($this); - if (!$command->isEnabled()) { $command->setConsole(null); - return; + return false; } + $command->setConsole($this); + if (null === $command->getDefinition()) { - throw new \LogicException(sprintf('Command class "%s" is not correctly initialized. You probably forgot to call the parent constructor.', get_class($command))); + throw new \LogicException( + sprintf('Command class "%s" is not correctly initialized. You probably forgot to call the parent constructor.', get_class($command)) + ); } $this->commands[$command->getName()] = $command; @@ -336,14 +421,17 @@ class Console /** * 获取指令 - * @param string $name 指令名称 + * @access public + * @param string $name 指令名称 * @return Command * @throws \InvalidArgumentException */ public function get($name) { if (!isset($this->commands[$name])) { - throw new \InvalidArgumentException(sprintf('The command "%s" does not exist.', $name)); + throw new \InvalidArgumentException( + sprintf('The command "%s" does not exist.', $name) + ); } $command = $this->commands[$name]; @@ -363,7 +451,8 @@ class Console /** * 某个指令是否存在 - * @param string $name 指令名称 + * @access public + * @param string $name 指令名称 * @return bool */ public function has($name) @@ -373,16 +462,22 @@ class Console /** * 获取所有的命名空间 + * @access public * @return array */ public function getNamespaces() { $namespaces = []; + foreach ($this->commands as $command) { - $namespaces = array_merge($namespaces, $this->extractAllNamespaces($command->getName())); + $namespaces = array_merge( + $namespaces, $this->extractAllNamespaces($command->getName()) + ); foreach ($command->getAliases() as $alias) { - $namespaces = array_merge($namespaces, $this->extractAllNamespaces($alias)); + $namespaces = array_merge( + $namespaces, $this->extractAllNamespaces($alias) + ); } } @@ -390,21 +485,25 @@ class Console } /** - * 查找注册命名空间中的名称或缩写。 + * 查找注册命名空间中的名称或缩写 + * @access public * @param string $namespace * @return string * @throws \InvalidArgumentException */ public function findNamespace($namespace) { - $allNamespaces = $this->getNamespaces(); - $expr = preg_replace_callback('{([^:]+|)}', function ($matches) { + $expr = preg_replace_callback('{([^:]+|)}', function ($matches) { return preg_quote($matches[1]) . '[^:]*'; }, $namespace); - $namespaces = preg_grep('{^' . $expr . '}', $allNamespaces); + + $allNamespaces = $this->getNamespaces(); + $namespaces = preg_grep('{^' . $expr . '}', $allNamespaces); if (empty($namespaces)) { - $message = sprintf('There are no commands defined in the "%s" namespace.', $namespace); + $message = sprintf( + 'There are no commands defined in the "%s" namespace.', $namespace + ); if ($alternatives = $this->findAlternatives($namespace, $allNamespaces)) { if (1 == count($alternatives)) { @@ -420,8 +519,14 @@ class Console } $exact = in_array($namespace, $namespaces, true); + if (count($namespaces) > 1 && !$exact) { - throw new \InvalidArgumentException(sprintf('The namespace "%s" is ambiguous (%s).', $namespace, $this->getAbbreviationSuggestions(array_values($namespaces)))); + throw new \InvalidArgumentException( + sprintf( + 'The namespace "%s" is ambiguous (%s).', + $namespace, + $this->getAbbreviationSuggestions(array_values($namespaces))) + ); } return $exact ? $namespace : reset($namespaces); @@ -429,20 +534,22 @@ class Console /** * 查找指令 - * @param string $name 名称或者别名 + * @access public + * @param string $name 名称或者别名 * @return Command * @throws \InvalidArgumentException */ public function find($name) { - $allCommands = array_keys($this->commands); - $expr = preg_replace_callback('{([^:]+|)}', function ($matches) { + $expr = preg_replace_callback('{([^:]+|)}', function ($matches) { return preg_quote($matches[1]) . '[^:]*'; }, $name); - $commands = preg_grep('{^' . $expr . '}', $allCommands); + + $allCommands = array_keys($this->commands); + $commands = preg_grep('{^' . $expr . '}', $allCommands); if (empty($commands) || count(preg_grep('{^' . $expr . '$}', $commands)) < 1) { - if (false !== $pos = strrpos($name, ':')) { + if (false !== ($pos = strrpos($name, ':'))) { $this->findNamespace(substr($name, 0, $pos)); } @@ -473,7 +580,9 @@ class Console if (count($commands) > 1 && !$exact) { $suggestions = $this->getAbbreviationSuggestions(array_values($commands)); - throw new \InvalidArgumentException(sprintf('Command "%s" is ambiguous (%s).', $name, $suggestions)); + throw new \InvalidArgumentException( + sprintf('Command "%s" is ambiguous (%s).', $name, $suggestions) + ); } return $this->get($exact ? $name : reset($commands)); @@ -481,21 +590,20 @@ class Console /** * 获取所有的指令 - * @param string $namespace 命名空间 + * @access public + * @param string $namespace 命名空间 * @return Command[] - * @api */ public function all($namespace = null) { - if (null === $namespace) { - return $this->commands; - } + if (null === $namespace) return $this->commands; $commands = []; + foreach ($this->commands as $name => $command) { - if ($this->extractNamespace($name, substr_count($namespace, ':') + 1) === $namespace) { - $commands[$name] = $command; - } + $ext = $this->extractNamespace($name, substr_count($namespace, ':') + 1); + + if ($ext === $namespace) $commands[$name] = $command; } return $commands; @@ -503,7 +611,8 @@ class Console /** * 获取可能的指令名 - * @param array $names + * @access public + * @param array $names 指令名 * @return array */ public static function getAbbreviations($names) @@ -520,9 +629,11 @@ class Console } /** - * 配置基于用户的参数和选项的输入和输出实例。 - * @param Input $input 输入实例 - * @param Output $output 输出实例 + * 配置基于用户的参数和选项的输入和输出实例 + * @access protected + * @param Input $input 输入实例 + * @param Output $output 输出实例 + * @return void */ protected function configureIO(Input $input, Output $output) { @@ -551,9 +662,10 @@ class Console /** * 执行指令 - * @param Command $command 指令实例 - * @param Input $input 输入实例 - * @param Output $output 输出实例 + * @access protected + * @param Command $command 指令实例 + * @param Input $input 输入实例 + * @param Output $output 输出实例 * @return int * @throws \Exception */ @@ -563,8 +675,9 @@ class Console } /** - * 获取指令的基础名称 - * @param Input $input + * 获取指令的名称 + * @access protected + * @param Input $input 输入实例 * @return string */ protected function getCommandName(Input $input) @@ -574,6 +687,7 @@ class Console /** * 获取默认输入定义 + * @access protected * @return InputDefinition */ protected function getDefaultInputDefinition() @@ -591,41 +705,55 @@ class Console } /** - * 设置默认命令 - * @return Command[] An array of default Command instances + * 获取默认命令 + * @access protected + * @return Command[] */ protected function getDefaultCommands() { $defaultCommands = []; - foreach (self::$defaultCommands as $classname) { - if (class_exists($classname) && is_subclass_of($classname, "think\\console\\Command")) { - $defaultCommands[] = new $classname(); + foreach (self::$defaultCommands as $class) { + if (class_exists($class) && is_subclass_of($class, "think\\console\\Command")) { + $defaultCommands[] = new $class(); } } return $defaultCommands; } - public static function addDefaultCommands(array $classnames) + /** + * 添加默认指令 + * @access public + * @param array $classes 指令 + * @return void + */ + public static function addDefaultCommands(array $classes) { - self::$defaultCommands = array_merge(self::$defaultCommands, $classnames); + self::$defaultCommands = array_merge(self::$defaultCommands, $classes); } /** * 获取可能的建议 - * @param array $abbrevs + * @access private + * @param array $abbrevs * @return string */ private function getAbbreviationSuggestions($abbrevs) { - return sprintf('%s, %s%s', $abbrevs[0], $abbrevs[1], count($abbrevs) > 2 ? sprintf(' and %d more', count($abbrevs) - 2) : ''); + return sprintf( + '%s, %s%s', + $abbrevs[0], + $abbrevs[1], + count($abbrevs) > 2 ? sprintf(' and %d more', count($abbrevs) - 2) : '' + ); } /** - * 返回命名空间部分 - * @param string $name 指令 - * @param string $limit 部分的命名空间的最大数量 + * 返回指令的命名空间部分 + * @access public + * @param string $name 指令名称 + * @param string $limit 部分的命名空间的最大数量 * @return string */ public function extractNamespace($name, $limit = null) @@ -638,16 +766,17 @@ class Console /** * 查找可替代的建议 - * @param string $name - * @param array|\Traversable $collection + * @access private + * @param string $name 指令名称 + * @param array|\Traversable $collection 建议集合 * @return array */ private function findAlternatives($name, $collection) { - $threshold = 1e3; - $alternatives = []; - + $threshold = 1e3; + $alternatives = []; $collectionParts = []; + foreach ($collection as $item) { $collectionParts[$item] = explode(':', $item); } @@ -655,6 +784,7 @@ class Console foreach (explode(':', $name) as $i => $subname) { foreach ($collectionParts as $collectionName => $parts) { $exists = isset($alternatives[$collectionName]); + if (!isset($parts[$i]) && $exists) { $alternatives[$collectionName] += $threshold; continue; @@ -663,8 +793,14 @@ class Console } $lev = levenshtein($subname, $parts[$i]); - if ($lev <= strlen($subname) / 3 || '' !== $subname && false !== strpos($parts[$i], $subname)) { - $alternatives[$collectionName] = $exists ? $alternatives[$collectionName] + $lev : $lev; + + if ($lev <= strlen($subname) / 3 || + '' !== $subname && + false !== strpos($parts[$i], $subname) + ) { + $alternatives[$collectionName] = $exists ? + $alternatives[$collectionName] + $lev : + $lev; } elseif ($exists) { $alternatives[$collectionName] += $threshold; } @@ -673,14 +809,18 @@ class Console foreach ($collection as $item) { $lev = levenshtein($name, $item); + if ($lev <= strlen($name) / 3 || false !== strpos($item, $name)) { - $alternatives[$item] = isset($alternatives[$item]) ? $alternatives[$item] - $lev : $lev; + $alternatives[$item] = isset($alternatives[$item]) ? + $alternatives[$item] - $lev : + $lev; } } $alternatives = array_filter($alternatives, function ($lev) use ($threshold) { return $lev < 2 * $threshold; }); + asort($alternatives); return array_keys($alternatives); @@ -688,24 +828,28 @@ class Console /** * 设置默认的指令 - * @param string $commandName The Command name + * @access public + * @param string $commandName 指令名称 + * @return $this */ public function setDefaultCommand($commandName) { $this->defaultCommand = $commandName; + + return $this; } /** * 返回所有的命名空间 - * @param string $name + * @access private + * @param string $name 指令名称 * @return array */ private function extractAllNamespaces($name) { - $parts = explode(':', $name, -1); $namespaces = []; - foreach ($parts as $part) { + foreach (explode(':', $name, -1) as $part) { if (count($namespaces)) { $namespaces[] = end($namespaces) . ':' . $part; } else { diff --git a/thinkphp/library/think/Controller.php b/thinkphp/library/think/Controller.php index 7aba39cd..77225b73 100644 --- a/thinkphp/library/think/Controller.php +++ b/thinkphp/library/think/Controller.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -11,46 +11,49 @@ namespace think; -\think\Loader::import('controller/Jump', TRAIT_PATH, EXT); - use think\exception\ValidateException; +use traits\controller\Jump; + +Loader::import('controller/Jump', TRAIT_PATH, EXT); class Controller { - use \traits\controller\Jump; + use Jump; /** * @var \think\View 视图类实例 */ protected $view; + /** - * @var \think\Request Request实例 + * @var \think\Request Request 实例 */ protected $request; - // 验证失败是否抛出异常 + + /** + * @var bool 验证失败是否抛出异常 + */ protected $failException = false; - // 是否批量验证 + + /** + * @var bool 是否批量验证 + */ protected $batchValidate = false; /** - * 前置操作方法列表 - * @var array $beforeActionList - * @access protected + * @var array 前置操作方法列表 */ protected $beforeActionList = []; /** * 构造方法 - * @param Request $request Request对象 * @access public + * @param Request $request Request 对象 */ public function __construct(Request $request = null) { - if (is_null($request)) { - $request = Request::instance(); - } $this->view = View::instance(Config::get('template'), Config::get('view_replace_str')); - $this->request = $request; + $this->request = is_null($request) ? Request::instance() : $request; // 控制器初始化 $this->_initialize(); @@ -65,7 +68,10 @@ class Controller } } - // 初始化 + /** + * 初始化操作 + * @access protected + */ protected function _initialize() { } @@ -73,8 +79,9 @@ class Controller /** * 前置操作 * @access protected - * @param string $method 前置操作方法名 - * @param array $options 调用参数 ['only'=>[...]] 或者['except'=>[...]] + * @param string $method 前置操作方法名 + * @param array $options 调用参数 ['only'=>[...]] 或者 ['except'=>[...]] + * @return void */ protected function beforeAction($method, $options = []) { @@ -82,6 +89,7 @@ class Controller if (is_string($options['only'])) { $options['only'] = explode(',', $options['only']); } + if (!in_array($this->request->action(), $options['only'])) { return; } @@ -89,6 +97,7 @@ class Controller if (is_string($options['except'])) { $options['except'] = explode(',', $options['except']); } + if (in_array($this->request->action(), $options['except'])) { return; } @@ -100,10 +109,10 @@ class Controller /** * 加载模板输出 * @access protected - * @param string $template 模板文件名 - * @param array $vars 模板输出变量 - * @param array $replace 模板替换 - * @param array $config 模板参数 + * @param string $template 模板文件名 + * @param array $vars 模板输出变量 + * @param array $replace 模板替换 + * @param array $config 模板参数 * @return mixed */ protected function fetch($template = '', $vars = [], $replace = [], $config = []) @@ -114,10 +123,10 @@ class Controller /** * 渲染内容输出 * @access protected - * @param string $content 模板内容 - * @param array $vars 模板输出变量 - * @param array $replace 替换内容 - * @param array $config 模板参数 + * @param string $content 模板内容 + * @param array $vars 模板输出变量 + * @param array $replace 替换内容 + * @param array $config 模板参数 * @return mixed */ protected function display($content = '', $vars = [], $replace = [], $config = []) @@ -128,24 +137,28 @@ class Controller /** * 模板变量赋值 * @access protected - * @param mixed $name 要显示的模板变量 - * @param mixed $value 变量的值 - * @return void + * @param mixed $name 要显示的模板变量 + * @param mixed $value 变量的值 + * @return $this */ protected function assign($name, $value = '') { $this->view->assign($name, $value); + + return $this; } /** * 初始化模板引擎 * @access protected * @param array|string $engine 引擎参数 - * @return void + * @return $this */ protected function engine($engine) { $this->view->engine($engine); + + return $this; } /** @@ -157,17 +170,18 @@ class Controller protected function validateFailException($fail = true) { $this->failException = $fail; + return $this; } /** * 验证数据 * @access protected - * @param array $data 数据 - * @param string|array $validate 验证器名或者验证规则数组 - * @param array $message 提示信息 - * @param bool $batch 是否批量验证 - * @param mixed $callback 回调方法(闭包) + * @param array $data 数据 + * @param string|array $validate 验证器名或者验证规则数组 + * @param array $message 提示信息 + * @param bool $batch 是否批量验证 + * @param mixed $callback 回调方法(闭包) * @return array|string|true * @throws ValidateException */ @@ -177,24 +191,27 @@ class Controller $v = Loader::validate(); $v->rule($validate); } else { + // 支持场景 if (strpos($validate, '.')) { - // 支持场景 list($validate, $scene) = explode('.', $validate); } + $v = Loader::validate($validate); - if (!empty($scene)) { - $v->scene($scene); - } + + !empty($scene) && $v->scene($scene); } - // 是否批量验证 + + // 批量验证 if ($batch || $this->batchValidate) { $v->batch(true); } + // 设置错误信息 if (is_array($message)) { $v->message($message); } + // 使用回调验证 if ($callback && is_callable($callback)) { call_user_func_array($callback, [$v, &$data]); } @@ -202,11 +219,11 @@ class Controller if (!$v->check($data)) { if ($this->failException) { throw new ValidateException($v->getError()); - } else { - return $v->getError(); } - } else { - return true; + + return $v->getError(); } + + return true; } } diff --git a/thinkphp/library/think/Cookie.php b/thinkphp/library/think/Cookie.php index 3205fcd9..61b47cce 100644 --- a/thinkphp/library/think/Cookie.php +++ b/thinkphp/library/think/Cookie.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -13,28 +13,28 @@ namespace think; class Cookie { + /** + * @var array cookie 设置参数 + */ protected static $config = [ - // cookie 名称前缀 - 'prefix' => '', - // cookie 保存时间 - 'expire' => 0, - // cookie 保存路径 - 'path' => '/', - // cookie 有效域名 - 'domain' => '', - // cookie 启用安全传输 - 'secure' => false, - // httponly设置 - 'httponly' => '', - // 是否使用 setcookie - 'setcookie' => true, + 'prefix' => '', // cookie 名称前缀 + 'expire' => 0, // cookie 保存时间 + 'path' => '/', // cookie 保存路径 + 'domain' => '', // cookie 有效域名 + 'secure' => false, // cookie 启用安全传输 + 'httponly' => false, // httponly 设置 + 'setcookie' => true, // 是否使用 setcookie ]; + /** + * @var bool 是否完成初始化了 + */ protected static $init; /** * Cookie初始化 - * @param array $config + * @access public + * @param array $config 配置参数 * @return void */ public static function init(array $config = []) @@ -42,39 +42,43 @@ class Cookie if (empty($config)) { $config = Config::get('cookie'); } + self::$config = array_merge(self::$config, array_change_key_case($config)); + if (!empty(self::$config['httponly'])) { ini_set('session.cookie_httponly', 1); } + self::$init = true; } /** - * 设置或者获取cookie作用域(前缀) - * @param string $prefix - * @return string|void + * 设置或者获取 cookie 作用域(前缀) + * @access public + * @param string $prefix 前缀 + * @return string| */ public static function prefix($prefix = '') { if (empty($prefix)) { return self::$config['prefix']; } - self::$config['prefix'] = $prefix; + + return self::$config['prefix'] = $prefix; } /** * Cookie 设置、获取、删除 - * - * @param string $name cookie名称 - * @param mixed $value cookie值 - * @param mixed $option 可选参数 可能会是 null|integer|string - * - * @return mixed - * @internal param mixed $options cookie参数 + * @access public + * @param string $name cookie 名称 + * @param mixed $value cookie 值 + * @param mixed $option 可选参数 可能会是 null|integer|string + * @return void */ public static function set($name, $value = '', $option = null) { !isset(self::$init) && self::init(); + // 参数设置(会覆盖黙认设置) if (!is_null($option)) { if (is_numeric($option)) { @@ -82,28 +86,40 @@ class Cookie } elseif (is_string($option)) { parse_str($option, $option); } + $config = array_merge(self::$config, array_change_key_case($option)); } else { $config = self::$config; } + $name = $config['prefix'] . $name; - // 设置cookie + + // 设置 cookie if (is_array($value)) { array_walk_recursive($value, 'self::jsonFormatProtect', 'encode'); $value = 'think:' . json_encode($value); } - $expire = !empty($config['expire']) ? $_SERVER['REQUEST_TIME'] + intval($config['expire']) : 0; + + $expire = !empty($config['expire']) ? + $_SERVER['REQUEST_TIME'] + intval($config['expire']) : + 0; + if ($config['setcookie']) { - setcookie($name, $value, $expire, $config['path'], $config['domain'], $config['secure'], $config['httponly']); + setcookie( + $name, $value, $expire, $config['path'], $config['domain'], + $config['secure'], $config['httponly'] + ); } + $_COOKIE[$name] = $value; } /** - * 永久保存Cookie数据 - * @param string $name cookie名称 - * @param mixed $value cookie值 - * @param mixed $option 可选参数 可能会是 null|integer|string + * 永久保存 Cookie 数据 + * @access public + * @param string $name cookie 名称 + * @param mixed $value cookie 值 + * @param mixed $option 可选参数 可能会是 null|integer|string * @return void */ public static function forever($name, $value = '', $option = null) @@ -111,33 +127,39 @@ class Cookie if (is_null($option) || is_numeric($option)) { $option = []; } + $option['expire'] = 315360000; + self::set($name, $value, $option); } /** - * 判断Cookie数据 - * @param string $name cookie名称 - * @param string|null $prefix cookie前缀 + * 判断是否有 Cookie 数据 + * @access public + * @param string $name cookie 名称 + * @param string|null $prefix cookie 前缀 * @return bool */ public static function has($name, $prefix = null) { !isset(self::$init) && self::init(); + $prefix = !is_null($prefix) ? $prefix : self::$config['prefix']; - $name = $prefix . $name; - return isset($_COOKIE[$name]); + + return isset($_COOKIE[$prefix . $name]); } /** - * Cookie获取 - * @param string $name cookie名称 - * @param string|null $prefix cookie前缀 + * 获取 Cookie 的值 + * @access public + * @param string $name cookie 名称 + * @param string|null $prefix cookie 前缀 * @return mixed */ public static function get($name = '', $prefix = null) { !isset(self::$init) && self::init(); + $prefix = !is_null($prefix) ? $prefix : self::$config['prefix']; $key = $prefix . $name; @@ -145,80 +167,102 @@ class Cookie // 获取全部 if ($prefix) { $value = []; + foreach ($_COOKIE as $k => $val) { if (0 === strpos($k, $prefix)) { $value[$k] = $val; } + } } else { $value = $_COOKIE; } } elseif (isset($_COOKIE[$key])) { $value = $_COOKIE[$key]; + if (0 === strpos($value, 'think:')) { - $value = substr($value, 6); - $value = json_decode($value, true); + $value = json_decode(substr($value, 6), true); array_walk_recursive($value, 'self::jsonFormatProtect', 'decode'); } } else { $value = null; } + return $value; } /** - * Cookie删除 - * @param string $name cookie名称 - * @param string|null $prefix cookie前缀 - * @return mixed + * 删除 Cookie + * @access public + * @param string $name cookie 名称 + * @param string|null $prefix cookie 前缀 + * @return void */ public static function delete($name, $prefix = null) { !isset(self::$init) && self::init(); + $config = self::$config; $prefix = !is_null($prefix) ? $prefix : $config['prefix']; $name = $prefix . $name; + if ($config['setcookie']) { - setcookie($name, '', $_SERVER['REQUEST_TIME'] - 3600, $config['path'], $config['domain'], $config['secure'], $config['httponly']); + setcookie( + $name, '', $_SERVER['REQUEST_TIME'] - 3600, $config['path'], + $config['domain'], $config['secure'], $config['httponly'] + ); } - // 删除指定cookie + + // 删除指定 cookie unset($_COOKIE[$name]); } /** - * Cookie清空 - * @param string|null $prefix cookie前缀 - * @return mixed + * 清除指定前缀的所有 cookie + * @access public + * @param string|null $prefix cookie 前缀 + * @return void */ public static function clear($prefix = null) { - // 清除指定前缀的所有cookie if (empty($_COOKIE)) { return; } + !isset(self::$init) && self::init(); - // 要删除的cookie前缀,不指定则删除config设置的指定前缀 + + // 要删除的 cookie 前缀,不指定则删除 config 设置的指定前缀 $config = self::$config; $prefix = !is_null($prefix) ? $prefix : $config['prefix']; + if ($prefix) { - // 如果前缀为空字符串将不作处理直接返回 foreach ($_COOKIE as $key => $val) { if (0 === strpos($key, $prefix)) { if ($config['setcookie']) { - setcookie($key, '', $_SERVER['REQUEST_TIME'] - 3600, $config['path'], $config['domain'], $config['secure'], $config['httponly']); + setcookie( + $key, '', $_SERVER['REQUEST_TIME'] - 3600, $config['path'], + $config['domain'], $config['secure'], $config['httponly'] + ); } + unset($_COOKIE[$key]); } } } - return; } - private static function jsonFormatProtect(&$val, $key, $type = 'encode') + /** + * json 转换时的格式保护 + * @access protected + * @param mixed $val 要转换的值 + * @param string $key 键名 + * @param string $type 转换类别 + * @return void + */ + protected static function jsonFormatProtect(&$val, $key, $type = 'encode') { if (!empty($val) && true !== $val) { $val = 'decode' == $type ? urldecode($val) : urlencode($val); } } - } diff --git a/thinkphp/library/think/Db.php b/thinkphp/library/think/Db.php index 3e613f7a..80f08d24 100644 --- a/thinkphp/library/think/Db.php +++ b/thinkphp/library/think/Db.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -49,19 +49,26 @@ use think\db\Query; */ class Db { - // 数据库连接实例 + /** + * @var Connection[] 数据库连接实例 + */ private static $instance = []; - // 查询次数 + + /** + * @var int 查询次数 + */ public static $queryTimes = 0; - // 执行次数 + + /** + * @var int 执行次数 + */ public static $executeTimes = 0; /** - * 数据库初始化 并取得数据库类实例 - * @static + * 数据库初始化,并取得数据库类实例 * @access public - * @param mixed $config 连接配置 - * @param bool|string $name 连接标识 true 强制重新连接 + * @param mixed $config 连接配置 + * @param bool|string $name 连接标识 true 强制重新连接 * @return Connection * @throws Exception */ @@ -70,31 +77,48 @@ class Db if (false === $name) { $name = md5(serialize($config)); } + if (true === $name || !isset(self::$instance[$name])) { // 解析连接参数 支持数组和字符串 $options = self::parseConfig($config); + if (empty($options['type'])) { - throw new \InvalidArgumentException('Underfined db type'); + throw new \InvalidArgumentException('Undefined db type'); } - $class = false !== strpos($options['type'], '\\') ? $options['type'] : '\\think\\db\\connector\\' . ucwords($options['type']); + + $class = false !== strpos($options['type'], '\\') ? + $options['type'] : + '\\think\\db\\connector\\' . ucwords($options['type']); + // 记录初始化信息 if (App::$debug) { Log::record('[ DB ] INIT ' . $options['type'], 'info'); } + if (true === $name) { - return new $class($options); - } else { - self::$instance[$name] = new $class($options); + $name = md5(serialize($config)); } + + self::$instance[$name] = new $class($options); } + return self::$instance[$name]; } + /** + * 清除连接实例 + * @access public + * @return void + */ + public static function clear() + { + self::$instance = []; + } + /** * 数据库连接参数解析 - * @static * @access private - * @param mixed $config + * @param mixed $config 连接参数 * @return array */ private static function parseConfig($config) @@ -102,30 +126,27 @@ class Db if (empty($config)) { $config = Config::get('database'); } elseif (is_string($config) && false === strpos($config, '/')) { - // 支持读取配置参数 - $config = Config::get($config); - } - if (is_string($config)) { - return self::parseDsn($config); - } else { - return $config; + $config = Config::get($config); // 支持读取配置参数 } + + return is_string($config) ? self::parseDsn($config) : $config; } /** - * DSN解析 + * DSN 解析 * 格式: mysql://username:passwd@localhost:3306/DbName?param1=val1¶m2=val2#utf8 - * @static * @access private - * @param string $dsnStr + * @param string $dsnStr 数据库 DSN 字符串解析 * @return array */ private static function parseDsn($dsnStr) { $info = parse_url($dsnStr); + if (!$info) { return []; } + $dsn = [ 'type' => $info['scheme'], 'username' => isset($info['user']) ? $info['user'] : '', @@ -141,13 +162,19 @@ class Db } else { $dsn['params'] = []; } + return $dsn; } - // 调用驱动类的方法 + /** + * 调用驱动类的方法 + * @access public + * @param string $method 方法名 + * @param array $params 参数 + * @return mixed + */ public static function __callStatic($method, $params) { - // 自动初始化数据库 return call_user_func_array([self::connect(), $method], $params); } } diff --git a/thinkphp/library/think/Debug.php b/thinkphp/library/think/Debug.php index 9994e20c..df487485 100644 --- a/thinkphp/library/think/Debug.php +++ b/thinkphp/library/think/Debug.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -16,21 +16,27 @@ use think\response\Redirect; class Debug { - // 区间时间信息 + /** + * @var array 区间时间信息 + */ protected static $info = []; - // 区间内存信息 + + /** + * @var array 区间内存信息 + */ protected static $mem = []; /** * 记录时间(微秒)和内存使用情况 - * @param string $name 标记位置 - * @param mixed $value 标记值 留空则取当前 time 表示仅记录时间 否则同时记录时间和内存 - * @return mixed + * @access public + * @param string $name 标记位置 + * @param mixed $value 标记值(留空则取当前 time 表示仅记录时间 否则同时记录时间和内存) + * @return void */ public static function remark($name, $value = '') { - // 记录时间和内存使用 self::$info[$name] = is_float($value) ? $value : microtime(true); + if ('time' != $value) { self::$mem['mem'][$name] = is_float($value) ? $value : memory_get_usage(); self::$mem['peak'][$name] = memory_get_peak_usage(); @@ -39,23 +45,26 @@ class Debug /** * 统计某个区间的时间(微秒)使用情况 返回值以秒为单位 - * @param string $start 开始标签 - * @param string $end 结束标签 - * @param integer|string $dec 小数位 - * @return integer + * @access public + * @param string $start 开始标签 + * @param string $end 结束标签 + * @param integer $dec 小数位 + * @return string */ public static function getRangeTime($start, $end, $dec = 6) { if (!isset(self::$info[$end])) { self::$info[$end] = microtime(true); } + return number_format((self::$info[$end] - self::$info[$start]), $dec); } /** * 统计从开始到统计时的时间(微秒)使用情况 返回值以秒为单位 - * @param integer|string $dec 小数位 - * @return integer + * @access public + * @param integer $dec 小数位 + * @return string */ public static function getUseTime($dec = 6) { @@ -64,6 +73,7 @@ class Debug /** * 获取当前访问的吞吐率情况 + * @access public * @return string */ public static function getThroughputRate() @@ -73,9 +83,10 @@ class Debug /** * 记录区间的内存使用情况 - * @param string $start 开始标签 - * @param string $end 结束标签 - * @param integer|string $dec 小数位 + * @access public + * @param string $start 开始标签 + * @param string $end 结束标签 + * @param integer $dec 小数位 * @return string */ public static function getRangeMem($start, $end, $dec = 2) @@ -83,19 +94,23 @@ class Debug if (!isset(self::$mem['mem'][$end])) { self::$mem['mem'][$end] = memory_get_usage(); } + $size = self::$mem['mem'][$end] - self::$mem['mem'][$start]; $a = ['B', 'KB', 'MB', 'GB', 'TB']; $pos = 0; + while ($size >= 1024) { $size /= 1024; $pos++; } + return round($size, $dec) . " " . $a[$pos]; } /** * 统计从开始到统计时的内存使用情况 - * @param integer|string $dec 小数位 + * @access public + * @param integer $dec 小数位 * @return string */ public static function getUseMem($dec = 2) @@ -103,103 +118,128 @@ class Debug $size = memory_get_usage() - THINK_START_MEM; $a = ['B', 'KB', 'MB', 'GB', 'TB']; $pos = 0; + while ($size >= 1024) { $size /= 1024; $pos++; } + return round($size, $dec) . " " . $a[$pos]; } /** * 统计区间的内存峰值情况 - * @param string $start 开始标签 - * @param string $end 结束标签 - * @param integer|string $dec 小数位 - * @return mixed + * @access public + * @param string $start 开始标签 + * @param string $end 结束标签 + * @param integer $dec 小数位 + * @return string */ public static function getMemPeak($start, $end, $dec = 2) { if (!isset(self::$mem['peak'][$end])) { self::$mem['peak'][$end] = memory_get_peak_usage(); } + $size = self::$mem['peak'][$end] - self::$mem['peak'][$start]; $a = ['B', 'KB', 'MB', 'GB', 'TB']; $pos = 0; + while ($size >= 1024) { $size /= 1024; $pos++; } + return round($size, $dec) . " " . $a[$pos]; } /** * 获取文件加载信息 - * @param bool $detail 是否显示详细 + * @access public + * @param bool $detail 是否显示详细 * @return integer|array */ public static function getFile($detail = false) { + $files = get_included_files(); + if ($detail) { - $files = get_included_files(); - $info = []; - foreach ($files as $key => $file) { + $info = []; + + foreach ($files as $file) { $info[] = $file . ' ( ' . number_format(filesize($file) / 1024, 2) . ' KB )'; } + return $info; } - return count(get_included_files()); + + return count($files); } /** * 浏览器友好的变量输出 - * @param mixed $var 变量 - * @param boolean $echo 是否输出 默认为true 如果为false 则返回输出字符串 - * @param string $label 标签 默认为空 - * @param integer $flags htmlspecialchars flags - * @return void|string + * @access public + * @param mixed $var 变量 + * @param boolean $echo 是否输出(默认为 true,为 false 则返回输出字符串) + * @param string|null $label 标签(默认为空) + * @param integer $flags htmlspecialchars 的标志 + * @return null|string */ public static function dump($var, $echo = true, $label = null, $flags = ENT_SUBSTITUTE) { $label = (null === $label) ? '' : rtrim($label) . ':'; + ob_start(); var_dump($var); - $output = ob_get_clean(); - $output = preg_replace('/\]\=\>\n(\s+)/m', '] => ', $output); + $output = preg_replace('/\]\=\>\n(\s+)/m', '] => ', ob_get_clean()); + if (IS_CLI) { $output = PHP_EOL . $label . $output . PHP_EOL; } else { if (!extension_loaded('xdebug')) { $output = htmlspecialchars($output, $flags); } + $output = '
' . $label . $output . '
'; } + if ($echo) { echo($output); return; - } else { - return $output; } + + return $output; } + /** + * 调试信息注入到响应中 + * @access public + * @param Response $response 响应实例 + * @param string $content 返回的字符串 + * @return void + */ public static function inject(Response $response, &$content) { - $config = Config::get('trace'); - $type = isset($config['type']) ? $config['type'] : 'Html'; - $request = Request::instance(); - $class = false !== strpos($type, '\\') ? $type : '\\think\\debug\\' . ucwords($type); + $config = Config::get('trace'); + $type = isset($config['type']) ? $config['type'] : 'Html'; + $class = false !== strpos($type, '\\') ? $type : '\\think\\debug\\' . ucwords($type); + unset($config['type']); - if (class_exists($class)) { - $trace = new $class($config); - } else { + + if (!class_exists($class)) { throw new ClassNotFoundException('class not exists:' . $class, $class); } + /** @var \think\debug\Console|\think\debug\Html $trace */ + $trace = new $class($config); + if ($response instanceof Redirect) { - //TODO 记录 + // TODO 记录 } else { $output = $trace->output($response, Log::getLog()); + if (is_string($output)) { - // trace调试信息注入 + // trace 调试信息注入 $pos = strripos($content, ''); if (false !== $pos) { $content = substr($content, 0, $pos) . $output . substr($content, $pos); diff --git a/thinkphp/library/think/Env.php b/thinkphp/library/think/Env.php index fa87897c..0a8b2509 100644 --- a/thinkphp/library/think/Env.php +++ b/thinkphp/library/think/Env.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -15,22 +15,25 @@ class Env { /** * 获取环境变量值 - * @param string $name 环境变量名(支持二级 .号分割) - * @param string $default 默认值 + * @access public + * @param string $name 环境变量名(支持二级 . 号分割) + * @param string $default 默认值 * @return mixed */ public static function get($name, $default = null) { $result = getenv(ENV_PREFIX . strtoupper(str_replace('.', '_', $name))); + if (false !== $result) { if ('false' === $result) { $result = false; } elseif ('true' === $result) { $result = true; } + return $result; - } else { - return $default; } + + return $default; } } diff --git a/thinkphp/library/think/Error.php b/thinkphp/library/think/Error.php index c17292bf..5f361d58 100644 --- a/thinkphp/library/think/Error.php +++ b/thinkphp/library/think/Error.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -20,6 +20,7 @@ class Error { /** * 注册异常处理 + * @access public * @return void */ public static function register() @@ -31,8 +32,10 @@ class Error } /** - * Exception Handler - * @param \Exception|\Throwable $e + * 异常处理 + * @access public + * @param \Exception|\Throwable $e 异常 + * @return void */ public static function appException($e) { @@ -40,44 +43,50 @@ class Error $e = new ThrowableError($e); } - self::getExceptionHandler()->report($e); + $handler = self::getExceptionHandler(); + $handler->report($e); + if (IS_CLI) { - self::getExceptionHandler()->renderForConsole(new ConsoleOutput, $e); + $handler->renderForConsole(new ConsoleOutput, $e); } else { - self::getExceptionHandler()->render($e)->send(); + $handler->render($e)->send(); } } /** - * Error Handler - * @param integer $errno 错误编号 - * @param integer $errstr 详细错误信息 - * @param string $errfile 出错的文件 - * @param integer $errline 出错行号 - * @param array $errcontext + * 错误处理 + * @access public + * @param integer $errno 错误编号 + * @param integer $errstr 详细错误信息 + * @param string $errfile 出错的文件 + * @param integer $errline 出错行号 + * @return void * @throws ErrorException */ - public static function appError($errno, $errstr, $errfile = '', $errline = 0, $errcontext = []) + public static function appError($errno, $errstr, $errfile = '', $errline = 0) { - $exception = new ErrorException($errno, $errstr, $errfile, $errline, $errcontext); + $exception = new ErrorException($errno, $errstr, $errfile, $errline); + + // 符合异常处理的则将错误信息托管至 think\exception\ErrorException if (error_reporting() & $errno) { - // 将错误信息托管至 think\exception\ErrorException throw $exception; - } else { - self::getExceptionHandler()->report($exception); } + + self::getExceptionHandler()->report($exception); } /** - * Shutdown Handler + * 异常中止处理 + * @access public + * @return void */ public static function appShutdown() { + // 将错误信息托管至 think\ErrorException if (!is_null($error = error_get_last()) && self::isFatal($error['type'])) { - // 将错误信息托管至think\ErrorException - $exception = new ErrorException($error['type'], $error['message'], $error['file'], $error['line']); - - self::appException($exception); + self::appException(new ErrorException( + $error['type'], $error['message'], $error['file'], $error['line'] + )); } // 写入日志 @@ -86,8 +95,8 @@ class Error /** * 确定错误类型是否致命 - * - * @param int $type + * @access protected + * @param int $type 错误类型 * @return bool */ protected static function isFatal($type) @@ -96,22 +105,32 @@ class Error } /** - * Get an instance of the exception handler. - * + * 获取异常处理的实例 + * @access public * @return Handle */ public static function getExceptionHandler() { static $handle; + if (!$handle) { - // 异常处理handle + // 异常处理 handle $class = Config::get('exception_handle'); - if ($class && class_exists($class) && is_subclass_of($class, "\\think\\exception\\Handle")) { + + if ($class && is_string($class) && class_exists($class) && + is_subclass_of($class, "\\think\\exception\\Handle") + ) { $handle = new $class; } else { $handle = new Handle; + + if ($class instanceof \Closure) { + $handle->setRender($class); + } + } } + return $handle; } } diff --git a/thinkphp/library/think/Exception.php b/thinkphp/library/think/Exception.php index 034c85b6..1ef06bdb 100644 --- a/thinkphp/library/think/Exception.php +++ b/thinkphp/library/think/Exception.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -13,15 +13,13 @@ namespace think; class Exception extends \Exception { - /** - * 保存异常页面显示的额外Debug数据 - * @var array + * @var array 保存异常页面显示的额外 Debug 数据 */ protected $data = []; /** - * 设置异常额外的Debug数据 + * 设置异常额外的 Debug 数据 * 数据将会显示为下面的格式 * * Exception Data @@ -33,8 +31,10 @@ class Exception extends \Exception * key1 value1 * key2 value2 * - * @param string $label 数据分类,用于异常页面显示 - * @param array $data 需要显示的数据,必须为关联数组 + * @access protected + * @param string $label 数据分类,用于异常页面显示 + * @param array $data 需要显示的数据,必须为关联数组 + * @return void */ final protected function setData($label, array $data) { @@ -42,13 +42,14 @@ class Exception extends \Exception } /** - * 获取异常额外Debug数据 + * 获取异常额外 Debug 数据 * 主要用于输出到异常页面便于调试 - * @return array 由setData设置的Debug数据 + * @access public + * @return array */ final public function getData() { return $this->data; } - + } diff --git a/thinkphp/library/think/File.php b/thinkphp/library/think/File.php index 90eac4e2..d2ed2208 100644 --- a/thinkphp/library/think/File.php +++ b/thinkphp/library/think/File.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -16,25 +16,51 @@ use SplFileObject; class File extends SplFileObject { /** - * 错误信息 - * @var string + * @var string 错误信息 */ private $error = ''; - // 当前完整文件名 + + /** + * @var string 当前完整文件名 + */ protected $filename; - // 上传文件名 + + /** + * @var string 上传文件名 + */ protected $saveName; - // 文件上传命名规则 + + /** + * @var string 文件上传命名规则 + */ protected $rule = 'date'; - // 文件上传验证规则 + + /** + * @var array 文件上传验证规则 + */ protected $validate = []; - // 单元测试 + + /** + * @var bool 单元测试 + */ protected $isTest; - // 上传文件信息 + + /** + * @var array 上传文件信息 + */ protected $info; - // 文件hash信息 + + /** + * @var array 文件 hash 信息 + */ protected $hash = []; + /** + * File constructor. + * @access public + * @param string $filename 文件名称 + * @param string $mode 访问模式 + */ public function __construct($filename, $mode = 'r') { parent::__construct($filename, $mode); @@ -42,30 +68,35 @@ class File extends SplFileObject } /** - * 是否测试 - * @param bool $test 是否测试 + * 设置是否是单元测试 + * @access public + * @param bool $test 是否是测试 * @return $this */ public function isTest($test = false) { $this->isTest = $test; + return $this; } /** * 设置上传信息 - * @param array $info 上传文件信息 + * @access public + * @param array $info 上传文件信息 * @return $this */ public function setUploadInfo($info) { $this->info = $info; + return $this; } /** * 获取上传文件的信息 - * @param string $name + * @access public + * @param string $name 信息名称 * @return array|string */ public function getInfo($name = '') @@ -75,106 +106,111 @@ class File extends SplFileObject /** * 获取上传文件的文件名 + * @access public * @return string */ public function getSaveName() { return $this->saveName; } - public function getFileName() - { - return $this->filename; - } /** * 设置上传文件的保存文件名 - * @param string $saveName + * @access public + * @param string $saveName 保存名称 * @return $this */ public function setSaveName($saveName) { $this->saveName = $saveName; + return $this; } /** * 获取文件的哈希散列值 - * @return $string + * @access public + * @param string $type 类型 + * @return string */ public function hash($type = 'sha1') { if (!isset($this->hash[$type])) { $this->hash[$type] = hash_file($type, $this->filename); } + return $this->hash[$type]; } /** * 检查目录是否可写 - * @param string $path 目录 + * @access protected + * @param string $path 目录 * @return boolean */ protected function checkPath($path) { - if (is_dir($path)) { + if (is_dir($path) || mkdir($path, 0755, true)) { return true; } - if (mkdir($path, 0755, true)) { - return true; - } else { - $this->error = "目录 {$path} 创建失败!"; - return false; - } + $this->error = ['directory {:path} creation failed', ['path' => $path]]; + + return false; } /** * 获取文件类型信息 + * @access public * @return string */ public function getMime() { $finfo = finfo_open(FILEINFO_MIME_TYPE); + return finfo_file($finfo, $this->filename); } /** * 设置文件的命名规则 - * @param string $rule 文件命名规则 + * @access public + * @param string $rule 文件命名规则 * @return $this */ public function rule($rule) { $this->rule = $rule; + return $this; } /** * 设置上传文件的验证规则 - * @param array $rule 验证规则 + * @access public + * @param array $rule 验证规则 * @return $this */ - public function validate($rule = []) + public function validate(array $rule = []) { $this->validate = $rule; + return $this; } /** * 检测是否合法的上传文件 + * @access public * @return bool */ public function isValid() { - if ($this->isTest) { - return is_file($this->filename); - } - return is_uploaded_file($this->filename); + return $this->isTest ? is_file($this->filename) : is_uploaded_file($this->filename); } /** * 检测上传文件 - * @param array $rule 验证规则 + * @access public + * @param array $rule 验证规则 * @return bool */ public function check($rule = []) @@ -183,25 +219,25 @@ class File extends SplFileObject /* 检查文件大小 */ if (isset($rule['size']) && !$this->checkSize($rule['size'])) { - $this->error = '上传文件大小不符!'; + $this->error = 'filesize not match'; return false; } - /* 检查文件Mime类型 */ + /* 检查文件 Mime 类型 */ if (isset($rule['type']) && !$this->checkMime($rule['type'])) { - $this->error = '上传文件MIME类型不允许!'; + $this->error = 'mimetype to upload is not allowed'; return false; } /* 检查文件后缀 */ if (isset($rule['ext']) && !$this->checkExt($rule['ext'])) { - $this->error = '上传文件后缀不允许'; + $this->error = 'extensions to upload is not allowed'; return false; } /* 检查图像文件 */ if (!$this->checkImg()) { - $this->error = '非法图像文件!'; + $this->error = 'illegal image files'; return false; } @@ -210,7 +246,8 @@ class File extends SplFileObject /** * 检测上传文件后缀 - * @param array|string $ext 允许后缀 + * @access public + * @param array|string $ext 允许后缀 * @return bool */ public function checkExt($ext) @@ -218,73 +255,76 @@ class File extends SplFileObject if (is_string($ext)) { $ext = explode(',', $ext); } + $extension = strtolower(pathinfo($this->getInfo('name'), PATHINFO_EXTENSION)); - if (!in_array($extension, $ext)) { - return false; - } - return true; + + return in_array($extension, $ext); } /** * 检测图像文件 + * @access public * @return bool */ public function checkImg() { $extension = strtolower(pathinfo($this->getInfo('name'), PATHINFO_EXTENSION)); - /* 对图像文件进行严格检测 */ - if (in_array($extension, ['gif', 'jpg', 'jpeg', 'bmp', 'png', 'swf']) && !in_array($this->getImageType($this->filename), [1, 2, 3, 4, 6])) { - return false; - } - return true; + + // 如果上传的不是图片,或者是图片而且后缀确实符合图片类型则返回 true + return !in_array($extension, ['gif', 'jpg', 'jpeg', 'bmp', 'png', 'swf']) || in_array($this->getImageType($this->filename), [1, 2, 3, 4, 6, 13]); } - // 判断图像类型 + /** + * 判断图像类型 + * @access protected + * @param string $image 图片名称 + * @return bool|int + */ protected function getImageType($image) { if (function_exists('exif_imagetype')) { return exif_imagetype($image); - } else { + } + + try { $info = getimagesize($image); - return $info[2]; + return $info ? $info[2] : false; + } catch (\Exception $e) { + return false; } } /** * 检测上传文件大小 - * @param integer $size 最大大小 + * @access public + * @param integer $size 最大大小 * @return bool */ public function checkSize($size) { - if ($this->getSize() > $size) { - return false; - } - return true; + return $this->getSize() <= $size; } /** * 检测上传文件类型 - * @param array|string $mime 允许类型 + * @access public + * @param array|string $mime 允许类型 * @return bool */ public function checkMime($mime) { - if (is_string($mime)) { - $mime = explode(',', $mime); - } - if (!in_array(strtolower($this->getMime()), $mime)) { - return false; - } - return true; + $mime = is_string($mime) ? explode(',', $mime) : $mime; + + return in_array(strtolower($this->getMime()), $mime); } /** * 移动文件 - * @param string $path 保存路径 - * @param string|bool $savename 保存的文件名 默认自动生成 - * @param boolean $replace 同名文件是否覆盖 - * @return false|File false-失败 否则返回File实例 + * @access public + * @param string $path 保存路径 + * @param string|bool $savename 保存的文件名 默认自动生成 + * @param boolean $replace 同名文件是否覆盖 + * @return false|File */ public function move($path, $savename = true, $replace = true) { @@ -296,7 +336,7 @@ class File extends SplFileObject // 检测合法性 if (!$this->isValid()) { - $this->error = '非法上传文件'; + $this->error = 'upload illegal files'; return false; } @@ -304,6 +344,7 @@ class File extends SplFileObject if (!$this->check()) { return false; } + $path = rtrim($path, DS) . DS; // 文件保存命名规则 $saveName = $this->buildSaveName($savename); @@ -314,9 +355,9 @@ class File extends SplFileObject return false; } - /* 不覆盖同名文件 */ + // 不覆盖同名文件 if (!$replace && is_file($filename)) { - $this->error = '存在同名文件'; + $this->error = ['has the same filename: {:filename}', ['filename' => $filename]]; return false; } @@ -324,25 +365,27 @@ class File extends SplFileObject if ($this->isTest) { rename($this->filename, $filename); } elseif (!move_uploaded_file($this->filename, $filename)) { - $this->error = '文件上传保存错误!'; + $this->error = 'upload write error'; return false; } - // 返回 File对象实例 + + // 返回 File 对象实例 $file = new self($filename); - $file->setSaveName($saveName); - $file->setUploadInfo($this->info); + $file->setSaveName($saveName)->setUploadInfo($this->info); + return $file; } /** * 获取保存文件名 - * @param string|bool $savename 保存的文件名 默认自动生成 + * @access protected + * @param string|bool $savename 保存的文件名 默认自动生成 * @return string */ protected function buildSaveName($savename) { + // 自动生成文件名 if (true === $savename) { - // 自动生成文件名 if ($this->rule instanceof \Closure) { $savename = call_user_func_array($this->rule, [$this]); } else { @@ -361,52 +404,73 @@ class File extends SplFileObject } } } - } elseif ('' === $savename) { + } elseif ('' === $savename || false === $savename) { $savename = $this->getInfo('name'); } + if (!strpos($savename, '.')) { $savename .= '.' . pathinfo($this->getInfo('name'), PATHINFO_EXTENSION); } + return $savename; } /** * 获取错误代码信息 - * @param int $errorNo 错误号 + * @access private + * @param int $errorNo 错误号 + * @return $this */ private function error($errorNo) { switch ($errorNo) { case 1: case 2: - $this->error = '上传文件大小超过了最大值!'; + $this->error = 'upload File size exceeds the maximum value'; break; case 3: - $this->error = '文件只有部分被上传!'; + $this->error = 'only the portion of file is uploaded'; break; case 4: - $this->error = '没有文件被上传!'; + $this->error = 'no file to uploaded'; break; case 6: - $this->error = '找不到临时文件夹!'; + $this->error = 'upload temp dir not found'; break; case 7: - $this->error = '文件写入失败!'; + $this->error = 'file write error'; break; default: - $this->error = '未知上传错误!'; + $this->error = 'unknown upload error'; } + + return $this; } /** - * 获取错误信息 - * @return mixed + * 获取错误信息(支持多语言) + * @access public + * @return string */ public function getError() { - return $this->error; + if (is_array($this->error)) { + list($msg, $vars) = $this->error; + } else { + $msg = $this->error; + $vars = []; + } + + return Lang::has($msg) ? Lang::get($msg, $vars) : $msg; } + /** + * 魔法方法,获取文件的 hash 值 + * @access public + * @param string $method 方法名 + * @param mixed $args 调用参数 + * @return string + */ public function __call($method, $args) { return $this->hash($method); diff --git a/thinkphp/library/think/Hook.php b/thinkphp/library/think/Hook.php index f06196e4..a69ce546 100644 --- a/thinkphp/library/think/Hook.php +++ b/thinkphp/library/think/Hook.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -13,19 +13,23 @@ namespace think; class Hook { - + /** + * @var array 标签 + */ private static $tags = []; /** * 动态添加行为扩展到某个标签 - * @param string $tag 标签名称 - * @param mixed $behavior 行为名称 - * @param bool $first 是否放到开头执行 + * @access public + * @param string $tag 标签名称 + * @param mixed $behavior 行为名称 + * @param bool $first 是否放到开头执行 * @return void */ public static function add($tag, $behavior, $first = false) { isset(self::$tags[$tag]) || self::$tags[$tag] = []; + if (is_array($behavior) && !is_callable($behavior)) { if (!array_key_exists('_overlay', $behavior) || !$behavior['_overlay']) { unset($behavior['_overlay']); @@ -43,8 +47,10 @@ class Hook /** * 批量导入插件 - * @param array $tags 插件信息 - * @param boolean $recursive 是否递归合并 + * @access public + * @param array $tags 插件信息 + * @param boolean $recursive 是否递归合并 + * @return void */ public static function import(array $tags, $recursive = true) { @@ -59,55 +65,59 @@ class Hook /** * 获取插件信息 - * @param string $tag 插件位置 留空获取全部 + * @access public + * @param string $tag 插件位置(留空获取全部) * @return array */ public static function get($tag = '') { if (empty($tag)) { - //获取全部的插件信息 return self::$tags; - } else { - return array_key_exists($tag, self::$tags) ? self::$tags[$tag] : []; } + + return array_key_exists($tag, self::$tags) ? self::$tags[$tag] : []; } /** * 监听标签的行为 - * @param string $tag 标签名称 - * @param mixed $params 传入参数 - * @param mixed $extra 额外参数 - * @param bool $once 只获取一个有效返回值 + * @access public + * @param string $tag 标签名称 + * @param mixed $params 传入参数 + * @param mixed $extra 额外参数 + * @param bool $once 只获取一个有效返回值 * @return mixed */ public static function listen($tag, &$params = null, $extra = null, $once = false) { $results = []; - $tags = static::get($tag); - foreach ($tags as $key => $name) { + + foreach (static::get($tag) as $key => $name) { $results[$key] = self::exec($name, $tag, $params, $extra); - if (false === $results[$key]) { - // 如果返回false 则中断行为执行 - break; - } elseif (!is_null($results[$key]) && $once) { + + // 如果返回 false,或者仅获取一个有效返回则中断行为执行 + if (false === $results[$key] || (!is_null($results[$key]) && $once)) { break; } } + return $once ? end($results) : $results; } /** * 执行某个行为 - * @param mixed $class 要执行的行为 - * @param string $tag 方法名(标签名) - * @param Mixed $params 传人的参数 - * @param mixed $extra 额外参数 + * @access public + * @param mixed $class 要执行的行为 + * @param string $tag 方法名(标签名) + * @param mixed $params 传人的参数 + * @param mixed $extra 额外参数 * @return mixed */ public static function exec($class, $tag = '', &$params = null, $extra = null) { App::$debug && Debug::remark('behavior_start', 'time'); + $method = Loader::parseName($tag, 1, false); + if ($class instanceof \Closure) { $result = call_user_func_array($class, [ & $params, $extra]); $class = 'Closure'; @@ -126,10 +136,12 @@ class Hook $method = ($tag && is_callable([$obj, $method])) ? $method : 'run'; $result = $obj->$method($params, $extra); } + if (App::$debug) { Debug::remark('behavior_end', 'time'); Log::record('[ BEHAVIOR ] Run ' . $class . ' @' . $tag . ' [ RunTime:' . Debug::getRangeTime('behavior_start', 'behavior_end') . 's ]', 'info'); } + return $result; } diff --git a/thinkphp/library/think/Lang.php b/thinkphp/library/think/Lang.php index 2df3767c..a50d838d 100644 --- a/thinkphp/library/think/Lang.php +++ b/thinkphp/library/think/Lang.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -13,114 +13,148 @@ namespace think; class Lang { - // 语言数据 + /** + * @var array 语言数据 + */ private static $lang = []; - // 语言作用域 + + /** + * @var string 语言作用域 + */ private static $range = 'zh-cn'; - // 语言自动侦测的变量 + + /** + * @var string 语言自动侦测的变量 + */ protected static $langDetectVar = 'lang'; - // 语言Cookie变量 + + /** + * @var string 语言 Cookie 变量 + */ protected static $langCookieVar = 'think_var'; - // 语言Cookie的过期时间 + + /** + * @var int 语言 Cookie 的过期时间 + */ protected static $langCookieExpire = 3600; - // 允许语言列表 + + /** + * @var array 允许语言列表 + */ protected static $allowLangList = []; - // Accept-Language转义为对应语言包名称 系统默认配置 - protected static $acceptLanguage = [ - 'zh-hans-cn' => 'zh-cn', - ]; - // 设定当前的语言 + /** + * @var array Accept-Language 转义为对应语言包名称 系统默认配置 + */ + protected static $acceptLanguage = ['zh-hans-cn' => 'zh-cn']; + + /** + * 设定当前的语言 + * @access public + * @param string $range 语言作用域 + * @return string + */ public static function range($range = '') { - if ('' == $range) { - return self::$range; - } else { + if ($range) { self::$range = $range; } + return self::$range; } /** * 设置语言定义(不区分大小写) - * @param string|array $name 语言变量 - * @param string $value 语言值 - * @param string $range 语言作用域 + * @access public + * @param string|array $name 语言变量 + * @param string $value 语言值 + * @param string $range 语言作用域 * @return mixed */ public static function set($name, $value = null, $range = '') { $range = $range ?: self::$range; - // 批量定义 + if (!isset(self::$lang[$range])) { self::$lang[$range] = []; } + if (is_array($name)) { return self::$lang[$range] = array_change_key_case($name) + self::$lang[$range]; - } else { - return self::$lang[$range][strtolower($name)] = $value; } + + return self::$lang[$range][strtolower($name)] = $value; } /** * 加载语言定义(不区分大小写) - * @param string $file 语言文件 - * @param string $range 语言作用域 + * @access public + * @param array|string $file 语言文件 + * @param string $range 语言作用域 * @return mixed */ public static function load($file, $range = '') { $range = $range ?: self::$range; + $file = is_string($file) ? [$file] : $file; + if (!isset(self::$lang[$range])) { self::$lang[$range] = []; } - // 批量定义 - if (is_string($file)) { - $file = [$file]; - } + $lang = []; + foreach ($file as $_file) { if (is_file($_file)) { // 记录加载信息 App::$debug && Log::record('[ LANG ] ' . $_file, 'info'); + $_lang = include $_file; + if (is_array($_lang)) { $lang = array_change_key_case($_lang) + $lang; } } } + if (!empty($lang)) { self::$lang[$range] = $lang + self::$lang[$range]; } + return self::$lang[$range]; } /** * 获取语言定义(不区分大小写) - * @param string|null $name 语言变量 - * @param string $range 语言作用域 + * @access public + * @param string|null $name 语言变量 + * @param string $range 语言作用域 * @return mixed */ public static function has($name, $range = '') { $range = $range ?: self::$range; + return isset(self::$lang[$range][strtolower($name)]); } /** * 获取语言定义(不区分大小写) - * @param string|null $name 语言变量 - * @param array $vars 变量替换 - * @param string $range 语言作用域 + * @access public + * @param string|null $name 语言变量 + * @param array $vars 变量替换 + * @param string $range 语言作用域 * @return mixed */ public static function get($name = null, $vars = [], $range = '') { $range = $range ?: self::$range; + // 空参数返回所有定义 if (empty($name)) { return self::$lang[$range]; } + $key = strtolower($name); $value = isset(self::$lang[$range][$key]) ? self::$lang[$range][$key] : $name; @@ -145,42 +179,50 @@ class Lang } } + return $value; } /** * 自动侦测设置获取语言选择 + * @access public * @return string */ public static function detect() { - // 自动侦测设置获取语言选择 $langSet = ''; if (isset($_GET[self::$langDetectVar])) { - // url中设置了语言变量 + // url 中设置了语言变量 $langSet = strtolower($_GET[self::$langDetectVar]); + } elseif (isset($_COOKIE[self::$langCookieVar])) { + // Cookie 中设置了语言变量 + $langSet = strtolower($_COOKIE[self::$langCookieVar]); } elseif (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { // 自动侦测浏览器语言 preg_match('/^([a-z\d\-]+)/i', $_SERVER['HTTP_ACCEPT_LANGUAGE'], $matches); $langSet = strtolower($matches[1]); $acceptLangs = Config::get('header_accept_lang'); + if (isset($acceptLangs[$langSet])) { $langSet = $acceptLangs[$langSet]; } elseif (isset(self::$acceptLanguage[$langSet])) { $langSet = self::$acceptLanguage[$langSet]; } } + + // 合法的语言 if (empty(self::$allowLangList) || in_array($langSet, self::$allowLangList)) { - // 合法的语言 self::$range = $langSet ?: self::$range; } + return self::$range; } /** * 设置语言自动侦测的变量 - * @param string $var 变量名称 + * @access public + * @param string $var 变量名称 * @return void */ public static function setLangDetectVar($var) @@ -189,8 +231,9 @@ class Lang } /** - * 设置语言的cookie保存变量 - * @param string $var 变量名称 + * 设置语言的 cookie 保存变量 + * @access public + * @param string $var 变量名称 * @return void */ public static function setLangCookieVar($var) @@ -199,8 +242,9 @@ class Lang } /** - * 设置语言的cookie的过期时间 - * @param string $expire 过期时间 + * 设置语言的 cookie 的过期时间 + * @access public + * @param string $expire 过期时间 * @return void */ public static function setLangCookieExpire($expire) @@ -210,7 +254,8 @@ class Lang /** * 设置允许的语言列表 - * @param array $list 语言列表 + * @access public + * @param array $list 语言列表 * @return void */ public static function setAllowLangList($list) diff --git a/thinkphp/library/think/Loader.php b/thinkphp/library/think/Loader.php index a0727fef..d813a5d7 100644 --- a/thinkphp/library/think/Loader.php +++ b/thinkphp/library/think/Loader.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -15,26 +15,57 @@ use think\exception\ClassNotFoundException; class Loader { + /** + * @var array 实例数组 + */ protected static $instance = []; - // 类名映射 - protected static $map = []; - // 命名空间别名 + /** + * @var array 类名映射 + */ + protected static $classMap = []; + + /** + * @var array 命名空间别名 + */ protected static $namespaceAlias = []; - // PSR-4 + /** + * @var array PSR-4 命名空间前缀长度映射 + */ private static $prefixLengthsPsr4 = []; - private static $prefixDirsPsr4 = []; - private static $fallbackDirsPsr4 = []; - // PSR-0 - private static $prefixesPsr0 = []; + /** + * @var array PSR-4 的加载目录 + */ + private static $prefixDirsPsr4 = []; + + /** + * @var array PSR-4 加载失败的回退目录 + */ + private static $fallbackDirsPsr4 = []; + + /** + * @var array PSR-0 命名空间前缀映射 + */ + private static $prefixesPsr0 = []; + + /** + * @var array PSR-0 加载失败的回退目录 + */ private static $fallbackDirsPsr0 = []; - // 自动加载的文件 - private static $autoloadFiles = []; + /** + * @var array 需要加载的文件 + */ + private static $files = []; - // 自动加载 + /** + * 自动加载 + * @access public + * @param string $class 类名 + * @return bool + */ public static function autoload($class) { // 检测命名空间别名 @@ -49,33 +80,33 @@ class Loader } if ($file = self::findFile($class)) { - - // Win环境严格区分大小写 - if (IS_WIN && pathinfo($file, PATHINFO_FILENAME) != pathinfo(realpath($file), PATHINFO_FILENAME)) { - return false; + // 非 Win 环境不严格区分大小写 + if (!IS_WIN || pathinfo($file, PATHINFO_FILENAME) == pathinfo(realpath($file), PATHINFO_FILENAME)) { + __include_file($file); + return true; } - - __include_file($file); - return true; } + + return false; } /** * 查找文件 - * @param $class - * @return bool + * @access private + * @param string $class 类名 + * @return bool|string */ private static function findFile($class) { - if (!empty(self::$map[$class])) { - // 类库映射 - return self::$map[$class]; + // 类库映射 + if (!empty(self::$classMap[$class])) { + return self::$classMap[$class]; } // 查找 PSR-4 $logicalPathPsr4 = strtr($class, '\\', DS) . EXT; + $first = $class[0]; - $first = $class[0]; if (isset(self::$prefixLengthsPsr4[$first])) { foreach (self::$prefixLengthsPsr4[$first] as $prefix => $length) { if (0 === strpos($class, $prefix)) { @@ -97,7 +128,7 @@ class Loader // 查找 PSR-0 if (false !== $pos = strrpos($class, '\\')) { - // namespaced class name + // namespace class name $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) . strtr(substr($logicalPathPsr4, $pos + 1), '_', DS); } else { @@ -124,20 +155,33 @@ class Loader } } - return self::$map[$class] = false; + // 找不到则设置映射为 false 并返回 + return self::$classMap[$class] = false; } - // 注册classmap + /** + * 注册 classmap + * @access public + * @param string|array $class 类名 + * @param string $map 映射 + * @return void + */ public static function addClassMap($class, $map = '') { if (is_array($class)) { - self::$map = array_merge(self::$map, $class); + self::$classMap = array_merge(self::$classMap, $class); } else { - self::$map[$class] = $map; + self::$classMap[$class] = $map; } } - // 注册命名空间 + /** + * 注册命名空间 + * @access public + * @param string|array $namespace 命名空间 + * @param string $path 路径 + * @return void + */ public static function addNamespace($namespace, $path = '') { if (is_array($namespace)) { @@ -149,84 +193,77 @@ class Loader } } - // 添加Ps0空间 + /** + * 添加 PSR-0 命名空间 + * @access private + * @param array|string $prefix 空间前缀 + * @param array $paths 路径 + * @param bool $prepend 预先设置的优先级更高 + * @return void + */ private static function addPsr0($prefix, $paths, $prepend = false) { if (!$prefix) { - if ($prepend) { - self::$fallbackDirsPsr0 = array_merge( - (array) $paths, - self::$fallbackDirsPsr0 - ); + self::$fallbackDirsPsr0 = $prepend ? + array_merge((array) $paths, self::$fallbackDirsPsr0) : + array_merge(self::$fallbackDirsPsr0, (array) $paths); + } else { + $first = $prefix[0]; + + if (!isset(self::$prefixesPsr0[$first][$prefix])) { + self::$prefixesPsr0[$first][$prefix] = (array) $paths; } else { - self::$fallbackDirsPsr0 = array_merge( - self::$fallbackDirsPsr0, - (array) $paths - ); + self::$prefixesPsr0[$first][$prefix] = $prepend ? + array_merge((array) $paths, self::$prefixesPsr0[$first][$prefix]) : + array_merge(self::$prefixesPsr0[$first][$prefix], (array) $paths); } - - return; - } - - $first = $prefix[0]; - if (!isset(self::$prefixesPsr0[$first][$prefix])) { - self::$prefixesPsr0[$first][$prefix] = (array) $paths; - - return; - } - if ($prepend) { - self::$prefixesPsr0[$first][$prefix] = array_merge( - (array) $paths, - self::$prefixesPsr0[$first][$prefix] - ); - } else { - self::$prefixesPsr0[$first][$prefix] = array_merge( - self::$prefixesPsr0[$first][$prefix], - (array) $paths - ); } } - // 添加Psr4空间 + /** + * 添加 PSR-4 空间 + * @access private + * @param array|string $prefix 空间前缀 + * @param string $paths 路径 + * @param bool $prepend 预先设置的优先级更高 + * @return void + */ private static function addPsr4($prefix, $paths, $prepend = false) { if (!$prefix) { // Register directories for the root namespace. - if ($prepend) { - self::$fallbackDirsPsr4 = array_merge( - (array) $paths, - self::$fallbackDirsPsr4 - ); - } else { - self::$fallbackDirsPsr4 = array_merge( - self::$fallbackDirsPsr4, - (array) $paths - ); - } + self::$fallbackDirsPsr4 = $prepend ? + array_merge((array) $paths, self::$fallbackDirsPsr4) : + array_merge(self::$fallbackDirsPsr4, (array) $paths); + } elseif (!isset(self::$prefixDirsPsr4[$prefix])) { // Register directories for a new namespace. $length = strlen($prefix); if ('\\' !== $prefix[$length - 1]) { - throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + throw new \InvalidArgumentException( + "A non-empty PSR-4 prefix must end with a namespace separator." + ); } + self::$prefixLengthsPsr4[$prefix[0]][$prefix] = $length; self::$prefixDirsPsr4[$prefix] = (array) $paths; - } elseif ($prepend) { - // Prepend directories for an already registered namespace. - self::$prefixDirsPsr4[$prefix] = array_merge( - (array) $paths, - self::$prefixDirsPsr4[$prefix] - ); + } else { + self::$prefixDirsPsr4[$prefix] = $prepend ? + // Prepend directories for an already registered namespace. + array_merge((array) $paths, self::$prefixDirsPsr4[$prefix]) : // Append directories for an already registered namespace. - self::$prefixDirsPsr4[$prefix] = array_merge( - self::$prefixDirsPsr4[$prefix], - (array) $paths - ); + array_merge(self::$prefixDirsPsr4[$prefix], (array) $paths); } } - // 注册命名空间别名 + /** + * 注册命名空间别名 + * @access public + * @param array|string $namespace 命名空间 + * @param string $original 源文件 + * @return void + */ public static function addNamespaceAlias($namespace, $original = '') { if (is_array($namespace)) { @@ -236,32 +273,58 @@ class Loader } } - // 注册自动加载机制 - public static function register($autoload = '') + /** + * 注册自动加载机制 + * @access public + * @param callable $autoload 自动加载处理方法 + * @return void + */ + public static function register($autoload = null) { // 注册系统自动加载 spl_autoload_register($autoload ?: 'think\\Loader::autoload', true, true); + + // Composer 自动加载支持 + if (is_dir(VENDOR_PATH . 'composer')) { + if (PHP_VERSION_ID >= 50600 && is_file(VENDOR_PATH . 'composer' . DS . 'autoload_static.php')) { + require VENDOR_PATH . 'composer' . DS . 'autoload_static.php'; + + $declaredClass = get_declared_classes(); + $composerClass = array_pop($declaredClass); + + foreach (['prefixLengthsPsr4', 'prefixDirsPsr4', 'fallbackDirsPsr4', 'prefixesPsr0', 'fallbackDirsPsr0', 'classMap', 'files'] as $attr) { + if (property_exists($composerClass, $attr)) { + self::${$attr} = $composerClass::${$attr}; + } + } + } else { + self::registerComposerLoader(); + } + } + // 注册命名空间定义 self::addNamespace([ 'think' => LIB_PATH . 'think' . DS, 'behavior' => LIB_PATH . 'behavior' . DS, 'traits' => LIB_PATH . 'traits' . DS, ]); + // 加载类库映射文件 if (is_file(RUNTIME_PATH . 'classmap' . EXT)) { self::addClassMap(__include_file(RUNTIME_PATH . 'classmap' . EXT)); } - // Composer自动加载支持 - if (is_dir(VENDOR_PATH . 'composer')) { - self::registerComposerLoader(); - } + self::loadComposerAutoloadFiles(); - // 自动加载extend目录 + // 自动加载 extend 目录 self::$fallbackDirsPsr4[] = rtrim(EXTEND_PATH, DS); } - // 注册composer自动加载 + /** + * 注册 composer 自动加载 + * @access private + * @return void + */ private static function registerComposerLoader() { if (is_file(VENDOR_PATH . 'composer/autoload_namespaces.php')) { @@ -286,28 +349,36 @@ class Loader } if (is_file(VENDOR_PATH . 'composer/autoload_files.php')) { - $includeFiles = require VENDOR_PATH . 'composer/autoload_files.php'; - foreach ($includeFiles as $fileIdentifier => $file) { - if (empty(self::$autoloadFiles[$fileIdentifier])) { - __require_file($file); - self::$autoloadFiles[$fileIdentifier] = true; - } + self::$files = require VENDOR_PATH . 'composer/autoload_files.php'; + } + } + + // 加载composer autofile文件 + public static function loadComposerAutoloadFiles() + { + foreach (self::$files as $fileIdentifier => $file) { + if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { + __require_file($file); + + $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; } } } /** - * 导入所需的类库 同java的Import 本函数有缓存功能 - * @param string $class 类库命名空间字符串 - * @param string $baseUrl 起始路径 - * @param string $ext 导入的文件扩展名 - * @return boolean + * 导入所需的类库 同 Java 的 Import 本函数有缓存功能 + * @access public + * @param string $class 类库命名空间字符串 + * @param string $baseUrl 起始路径 + * @param string $ext 导入的文件扩展名 + * @return bool */ public static function import($class, $baseUrl = '', $ext = EXT) { static $_file = []; $key = $class . $baseUrl; $class = str_replace(['.', '#'], [DS, '.'], $class); + if (isset($_file[$key])) { return true; } @@ -319,7 +390,7 @@ class Loader // 注册的命名空间 $baseUrl = self::$prefixDirsPsr4[$name . '\\']; } elseif ('@' == $name) { - //加载当前模块应用类库 + // 加载当前模块应用类库 $baseUrl = App::$modulePath; } elseif (is_dir(EXTEND_PATH . $name)) { $baseUrl = EXTEND_PATH . $name . DS; @@ -330,11 +401,11 @@ class Loader } elseif (substr($baseUrl, -1) != DS) { $baseUrl .= DS; } - // 如果类存在 则导入类库文件 + + // 如果类存在则导入类库文件 if (is_array($baseUrl)) { foreach ($baseUrl as $path) { - $filename = $path . DS . $class . $ext; - if (is_file($filename)) { + if (is_file($filename = $path . DS . $class . $ext)) { break; } } @@ -342,135 +413,154 @@ class Loader $filename = $baseUrl . $class . $ext; } - if (!empty($filename) && is_file($filename)) { - // 开启调试模式Win环境严格区分大小写 - if (IS_WIN && pathinfo($filename, PATHINFO_FILENAME) != pathinfo(realpath($filename), PATHINFO_FILENAME)) { - return false; - } + if (!empty($filename) && + is_file($filename) && + (!IS_WIN || pathinfo($filename, PATHINFO_FILENAME) == pathinfo(realpath($filename), PATHINFO_FILENAME)) + ) { __include_file($filename); $_file[$key] = true; + return true; } + return false; } /** * 实例化(分层)模型 - * @param string $name Model名称 - * @param string $layer 业务层名称 - * @param bool $appendSuffix 是否添加类名后缀 - * @param string $common 公共模块名 - * @return Object + * @access public + * @param string $name Model名称 + * @param string $layer 业务层名称 + * @param bool $appendSuffix 是否添加类名后缀 + * @param string $common 公共模块名 + * @return object * @throws ClassNotFoundException */ public static function model($name = '', $layer = 'model', $appendSuffix = false, $common = 'common') { - $guid = $name . $layer; - if (isset(self::$instance[$guid])) { - return self::$instance[$guid]; - } - if (false !== strpos($name, '\\')) { - $class = $name; - $module = Request::instance()->module(); - } else { - if (strpos($name, '/')) { - list($module, $name) = explode('/', $name, 2); - } else { - $module = Request::instance()->module(); - } - $class = self::parseClass($module, $layer, $name, $appendSuffix); + $uid = $name . $layer; + + if (isset(self::$instance[$uid])) { + return self::$instance[$uid]; } + + list($module, $class) = self::getModuleAndClass($name, $layer, $appendSuffix); + if (class_exists($class)) { $model = new $class(); } else { $class = str_replace('\\' . $module . '\\', '\\' . $common . '\\', $class); + if (class_exists($class)) { $model = new $class(); } else { throw new ClassNotFoundException('class not exists:' . $class, $class); } } - self::$instance[$guid] = $model; - return $model; + + return self::$instance[$uid] = $model; } /** * 实例化(分层)控制器 格式:[模块名/]控制器名 - * @param string $name 资源地址 - * @param string $layer 控制层名称 - * @param bool $appendSuffix 是否添加类名后缀 - * @param string $empty 空控制器名称 - * @return Object|false + * @access public + * @param string $name 资源地址 + * @param string $layer 控制层名称 + * @param bool $appendSuffix 是否添加类名后缀 + * @param string $empty 空控制器名称 + * @return object * @throws ClassNotFoundException */ public static function controller($name, $layer = 'controller', $appendSuffix = false, $empty = '') { - if (false !== strpos($name, '\\')) { - $class = $name; - $module = Request::instance()->module(); - } else { - if (strpos($name, '/')) { - list($module, $name) = explode('/', $name); - } else { - $module = Request::instance()->module(); - } - $class = self::parseClass($module, $layer, $name, $appendSuffix); - } + list($module, $class) = self::getModuleAndClass($name, $layer, $appendSuffix); + if (class_exists($class)) { return App::invokeClass($class); - } elseif ($empty && class_exists($emptyClass = self::parseClass($module, $layer, $empty, $appendSuffix))) { - return new $emptyClass(Request::instance()); } + + if ($empty) { + $emptyClass = self::parseClass($module, $layer, $empty, $appendSuffix); + + if (class_exists($emptyClass)) { + return new $emptyClass(Request::instance()); + } + } + + throw new ClassNotFoundException('class not exists:' . $class, $class); } /** * 实例化验证类 格式:[模块名/]验证器名 - * @param string $name 资源地址 - * @param string $layer 验证层名称 - * @param bool $appendSuffix 是否添加类名后缀 - * @param string $common 公共模块名 - * @return Object|false + * @access public + * @param string $name 资源地址 + * @param string $layer 验证层名称 + * @param bool $appendSuffix 是否添加类名后缀 + * @param string $common 公共模块名 + * @return object|false * @throws ClassNotFoundException */ public static function validate($name = '', $layer = 'validate', $appendSuffix = false, $common = 'common') { $name = $name ?: Config::get('default_validate'); + if (empty($name)) { return new Validate; } - $guid = $name . $layer; - if (isset(self::$instance[$guid])) { - return self::$instance[$guid]; - } - if (false !== strpos($name, '\\')) { - $class = $name; - $module = Request::instance()->module(); - } else { - if (strpos($name, '/')) { - list($module, $name) = explode('/', $name); - } else { - $module = Request::instance()->module(); - } - $class = self::parseClass($module, $layer, $name, $appendSuffix); + + $uid = $name . $layer; + if (isset(self::$instance[$uid])) { + return self::$instance[$uid]; } + + list($module, $class) = self::getModuleAndClass($name, $layer, $appendSuffix); + if (class_exists($class)) { $validate = new $class; } else { $class = str_replace('\\' . $module . '\\', '\\' . $common . '\\', $class); + if (class_exists($class)) { $validate = new $class; } else { throw new ClassNotFoundException('class not exists:' . $class, $class); } } - self::$instance[$guid] = $validate; - return $validate; + + return self::$instance[$uid] = $validate; + } + + /** + * 解析模块和类名 + * @access protected + * @param string $name 资源地址 + * @param string $layer 验证层名称 + * @param bool $appendSuffix 是否添加类名后缀 + * @return array + */ + protected static function getModuleAndClass($name, $layer, $appendSuffix) + { + if (false !== strpos($name, '\\')) { + $module = Request::instance()->module(); + $class = $name; + } else { + if (strpos($name, '/')) { + list($module, $name) = explode('/', $name, 2); + } else { + $module = Request::instance()->module(); + } + + $class = self::parseClass($module, $layer, $name, $appendSuffix); + } + + return [$module, $class]; } /** * 数据库初始化 并取得数据库类实例 - * @param mixed $config 数据库配置 - * @param bool|string $name 连接标识 true 强制重新连接 + * @access public + * @param mixed $config 数据库配置 + * @param bool|string $name 连接标识 true 强制重新连接 * @return \think\db\Connection */ public static function db($config = [], $name = false) @@ -480,10 +570,11 @@ class Loader /** * 远程调用模块的操作方法 参数格式 [模块/控制器/]操作 - * @param string $url 调用地址 - * @param string|array $vars 调用参数 支持字符串和数组 - * @param string $layer 要调用的控制层名称 - * @param bool $appendSuffix 是否添加类名后缀 + * @access public + * @param string $url 调用地址 + * @param string|array $vars 调用参数 支持字符串和数组 + * @param string $layer 要调用的控制层名称 + * @param bool $appendSuffix 是否添加类名后缀 * @return mixed */ public static function action($url, $vars = [], $layer = 'controller', $appendSuffix = false) @@ -492,6 +583,7 @@ class Loader $action = $info['basename']; $module = '.' != $info['dirname'] ? $info['dirname'] : Request::instance()->controller(); $class = self::controller($module, $layer, $appendSuffix); + if ($class) { if (is_scalar($vars)) { if (strpos($vars, '=')) { @@ -500,16 +592,20 @@ class Loader $vars = [$vars]; } } + return App::invokeMethod([$class, $action . Config::get('action_suffix')], $vars); } + + return false; } /** * 字符串命名风格转换 - * type 0 将Java风格转换为C的风格 1 将C风格转换为Java的风格 - * @param string $name 字符串 - * @param integer $type 转换类型 - * @param bool $ucfirst 首字母是否大写(驼峰规则) + * type 0 将 Java 风格转换为 C 的风格 1 将 C 风格转换为 Java 的风格 + * @access public + * @param string $name 字符串 + * @param integer $type 转换类型 + * @param bool $ucfirst 首字母是否大写(驼峰规则) * @return string */ public static function parseName($name, $type = 0, $ucfirst = true) @@ -518,31 +614,38 @@ class Loader $name = preg_replace_callback('/_([a-zA-Z])/', function ($match) { return strtoupper($match[1]); }, $name); + return $ucfirst ? ucfirst($name) : lcfirst($name); - } else { - return strtolower(trim(preg_replace("/[A-Z]/", "_\\0", $name), "_")); } + + return strtolower(trim(preg_replace("/[A-Z]/", "_\\0", $name), "_")); } /** * 解析应用类的类名 - * @param string $module 模块名 - * @param string $layer 层名 controller model ... - * @param string $name 类名 - * @param bool $appendSuffix + * @access public + * @param string $module 模块名 + * @param string $layer 层名 controller model ... + * @param string $name 类名 + * @param bool $appendSuffix 是否添加类名后缀 * @return string */ public static function parseClass($module, $layer, $name, $appendSuffix = false) { - $name = str_replace(['/', '.'], '\\', $name); - $array = explode('\\', $name); - $class = self::parseName(array_pop($array), 1) . (App::$suffix || $appendSuffix ? ucfirst($layer) : ''); + + $array = explode('\\', str_replace(['/', '.'], '\\', $name)); + $class = self::parseName(array_pop($array), 1); + $class = $class . (App::$suffix || $appendSuffix ? ucfirst($layer) : ''); $path = $array ? implode('\\', $array) . '\\' : ''; - return App::$namespace . '\\' . ($module ? $module . '\\' : '') . $layer . '\\' . $path . $class; + + return App::$namespace . '\\' . + ($module ? $module . '\\' : '') . + $layer . '\\' . $path . $class; } /** * 初始化类的实例 + * @access public * @return void */ public static function clearInstance() @@ -551,10 +654,11 @@ class Loader } } +// 作用范围隔离 + /** - * 作用范围隔离 - * - * @param $file + * include + * @param string $file 文件路径 * @return mixed */ function __include_file($file) @@ -562,6 +666,11 @@ function __include_file($file) return include $file; } +/** + * require + * @param string $file 文件路径 + * @return mixed + */ function __require_file($file) { return require $file; diff --git a/thinkphp/library/think/Log.php b/thinkphp/library/think/Log.php index a20ab262..c064306c 100644 --- a/thinkphp/library/think/Log.php +++ b/thinkphp/library/think/Log.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -17,12 +17,12 @@ use think\exception\ClassNotFoundException; * Class Log * @package think * - * @method void log($msg) static - * @method void error($msg) static - * @method void info($msg) static - * @method void sql($msg) static - * @method void notice($msg) static - * @method void alert($msg) static + * @method void log($msg) static 记录一般日志 + * @method void error($msg) static 记录错误日志 + * @method void info($msg) static 记录一般信息日志 + * @method void sql($msg) static 记录 SQL 查询日志 + * @method void notice($msg) static 记录提示日志 + * @method void alert($msg) static 记录报警日志 */ class Log { @@ -34,41 +34,60 @@ class Log const ALERT = 'alert'; const DEBUG = 'debug'; - // 日志信息 + /** + * @var array 日志信息 + */ protected static $log = []; - // 配置参数 + + /** + * @var array 配置参数 + */ protected static $config = []; - // 日志类型 + + /** + * @var array 日志类型 + */ protected static $type = ['log', 'error', 'info', 'sql', 'notice', 'alert', 'debug']; - // 日志写入驱动 + + /** + * @var log\driver\File|log\driver\Test|log\driver\Socket 日志写入驱动 + */ protected static $driver; - // 当前日志授权key + /** + * @var string 当前日志授权 key + */ protected static $key; /** * 日志初始化 - * @param array $config + * @access public + * @param array $config 配置参数 + * @return void */ public static function init($config = []) { - $type = isset($config['type']) ? $config['type'] : 'File'; - $class = false !== strpos($type, '\\') ? $type : '\\think\\log\\driver\\' . ucwords($type); + $type = isset($config['type']) ? $config['type'] : 'File'; + $class = false !== strpos($type, '\\') ? $type : '\\think\\log\\driver\\' . ucwords($type); + self::$config = $config; unset($config['type']); + if (class_exists($class)) { self::$driver = new $class($config); } else { throw new ClassNotFoundException('class not exists:' . $class, $class); } + // 记录初始化信息 App::$debug && Log::record('[ LOG ] INIT ' . $type, 'info'); } /** * 获取日志信息 - * @param string $type 信息类型 - * @return array + * @access public + * @param string $type 信息类型 + * @return array|string */ public static function getLog($type = '') { @@ -77,21 +96,22 @@ class Log /** * 记录调试信息 - * @param mixed $msg 调试信息 - * @param string $type 信息类型 + * @access public + * @param mixed $msg 调试信息 + * @param string $type 信息类型 * @return void */ public static function record($msg, $type = 'log') { self::$log[$type][] = $msg; - if (IS_CLI) { - // 命令行下面日志写入改进 - self::save(); - } + + // 命令行下面日志写入改进 + IS_CLI && self::save(); } /** * 清空日志信息 + * @access public * @return void */ public static function clear() @@ -100,8 +120,9 @@ class Log } /** - * 当前日志记录的授权key - * @param string $key 授权key + * 设置当前日志记录的授权 key + * @access public + * @param string $key 授权 key * @return void */ public static function key($key) @@ -111,102 +132,105 @@ class Log /** * 检查日志写入权限 - * @param array $config 当前日志配置参数 + * @access public + * @param array $config 当前日志配置参数 * @return bool */ public static function check($config) { - if (self::$key && !empty($config['allow_key']) && !in_array(self::$key, $config['allow_key'])) { - return false; - } - return true; + return !self::$key || empty($config['allow_key']) || in_array(self::$key, $config['allow_key']); } /** * 保存调试信息 + * @access public * @return bool */ public static function save() { - if (!empty(self::$log)) { - if (is_null(self::$driver)) { - self::init(Config::get('log')); - } + // 没有需要保存的记录则直接返回 + if (empty(self::$log)) { + return true; + } - if (!self::check(self::$config)) { - // 检测日志写入权限 - return false; - } + is_null(self::$driver) && self::init(Config::get('log')); - if (empty(self::$config['level'])) { - // 获取全部日志 - $log = self::$log; - if (!App::$debug && isset($log['debug'])) { - unset($log['debug']); - } - } else { - // 记录允许级别 - $log = []; - foreach (self::$config['level'] as $level) { - if (isset(self::$log[$level])) { - $log[$level] = self::$log[$level]; - } + // 检测日志写入权限 + if (!self::check(self::$config)) { + return false; + } + + if (empty(self::$config['level'])) { + // 获取全部日志 + $log = self::$log; + if (!App::$debug && isset($log['debug'])) { + unset($log['debug']); + } + } else { + // 记录允许级别 + $log = []; + foreach (self::$config['level'] as $level) { + if (isset(self::$log[$level])) { + $log[$level] = self::$log[$level]; } } + } - $result = self::$driver->save($log); - if ($result) { - self::$log = []; - } - Hook::listen('log_write_done', $log); - return $result; + if ($result = self::$driver->save($log, true)) { + self::$log = []; } - return true; + + Hook::listen('log_write_done', $log); + + return $result; } /** * 实时写入日志信息 并支持行为 - * @param mixed $msg 调试信息 - * @param string $type 信息类型 - * @param bool $force 是否强制写入 + * @access public + * @param mixed $msg 调试信息 + * @param string $type 信息类型 + * @param bool $force 是否强制写入 * @return bool */ public static function write($msg, $type = 'log', $force = false) { $log = self::$log; - // 封装日志信息 - if (true === $force || empty(self::$config['level'])) { - $log[$type][] = $msg; - } elseif (in_array($type, self::$config['level'])) { - $log[$type][] = $msg; - } else { + + // 如果不是强制写入,而且信息类型不在可记录的类别中则直接返回 false 不做记录 + if (true !== $force && !empty(self::$config['level']) && !in_array($type, self::$config['level'])) { return false; } - // 监听log_write + // 封装日志信息 + $log[$type][] = $msg; + + // 监听 log_write Hook::listen('log_write', $log); - if (is_null(self::$driver)) { - self::init(Config::get('log')); - } + + is_null(self::$driver) && self::init(Config::get('log')); + // 写入日志 - $result = self::$driver->save($log); - if ($result) { + if ($result = self::$driver->save($log, false)) { self::$log = []; } + return $result; } /** - * 静态调用 - * @param $method - * @param $args - * @return mixed + * 静态方法调用 + * @access public + * @param string $method 调用方法 + * @param mixed $args 参数 + * @return void */ public static function __callStatic($method, $args) { if (in_array($method, self::$type)) { array_push($args, $method); - return call_user_func_array('\\think\\Log::record', $args); + + call_user_func_array('\\think\\Log::record', $args); } } diff --git a/thinkphp/library/think/Model.php b/thinkphp/library/think/Model.php index 6fc8cabe..2dc27b48 100644 --- a/thinkphp/library/think/Model.php +++ b/thinkphp/library/think/Model.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -11,6 +11,7 @@ namespace think; +use BadMethodCallException; use InvalidArgumentException; use think\db\Query; use think\exception\ValidateException; @@ -56,6 +57,10 @@ abstract class Model implements \JsonSerializable, \ArrayAccess protected $pk; // 数据表字段信息 留空则自动获取 protected $field = []; + // 数据排除字段 + protected $except = []; + // 数据废弃字段 + protected $disuse = []; // 只读字段 protected $readonly = []; // 显示属性 @@ -89,6 +94,10 @@ abstract class Model implements \JsonSerializable, \ArrayAccess protected $type = []; // 是否为更新数据 protected $isUpdate = false; + // 是否使用Replace + protected $replace = false; + // 是否强制更新所有数据 + protected $force = false; // 更新条件 protected $updateWhere; // 验证失败是否抛出异常 @@ -109,6 +118,12 @@ abstract class Model implements \JsonSerializable, \ArrayAccess */ protected static $initialized = []; + /** + * 是否从主库读取(主从分布式有效) + * @var array + */ + protected static $readMaster; + /** * 构造方法 * @access public @@ -121,6 +136,16 @@ abstract class Model implements \JsonSerializable, \ArrayAccess } else { $this->data = $data; } + + if ($this->disuse) { + // 废弃字段 + foreach ((array) $this->disuse as $key) { + if (array_key_exists($key, $this->data)) { + unset($this->data[$key]); + } + } + } + // 记录原始数据 $this->origin = $this->data; @@ -154,6 +179,20 @@ abstract class Model implements \JsonSerializable, \ArrayAccess $this->initialize(); } + /** + * 是否从主库读取数据(主从分布有效) + * @access public + * @param bool $all 是否所有模型生效 + * @return $this + */ + public function readMaster($all = false) + { + $model = $all ? '*' : $this->class; + + static::$readMaster[$model] = true; + return $this; + } + /** * 创建模型的查询对象 * @access protected @@ -175,7 +214,11 @@ abstract class Model implements \JsonSerializable, \ArrayAccess $con = Db::connect($connection); // 设置当前模型 确保查询返回模型对象 $queryClass = $this->query ?: $con->getConfig('query'); - $query = new $queryClass($con, $this->class); + $query = new $queryClass($con, $this); + + if (isset(static::$readMaster['*']) || isset(static::$readMaster[$this->class])) { + $query->master(true); + } // 设置当前数据表和模型名 if (!empty($this->table)) { @@ -191,6 +234,19 @@ abstract class Model implements \JsonSerializable, \ArrayAccess return $query; } + /** + * 创建新的模型实例 + * @access public + * @param array|object $data 数据 + * @param bool $isUpdate 是否为更新 + * @param mixed $where 更新条件 + * @return Model + */ + public function newInstance($data = [], $isUpdate = false, $where = null) + { + return (new static($data))->isUpdate($isUpdate, $where); + } + /** * 获取当前模型的查询对象 * @access public @@ -261,7 +317,6 @@ abstract class Model implements \JsonSerializable, \ArrayAccess public function setParent($model) { $this->parent = $model; - return $this; } @@ -336,6 +391,18 @@ abstract class Model implements \JsonSerializable, \ArrayAccess return $this; } + /** + * 更新是否强制写入数据 而不做比较 + * @access public + * @param bool $force + * @return $this + */ + public function force($force = true) + { + $this->force = $force; + return $this; + } + /** * 修改器 设置数据对象值 * @access public @@ -353,7 +420,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess // 检测修改器 $method = 'set' . Loader::parseName($name, 1) . 'Attr'; if (method_exists($this, $method)) { - $value = $this->$method($value, array_merge($this->data, $data)); + $value = $this->$method($value, array_merge($this->data, $data), $this->relation); } elseif (isset($this->type[$name])) { // 类型转换 $value = $this->writeTransform($value, $this->type[$name]); @@ -532,7 +599,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess // 检测属性获取器 $method = 'get' . Loader::parseName($name, 1) . 'Attr'; if (method_exists($this, $method)) { - $value = $this->$method($value, $this->data); + $value = $this->$method($value, $this->data, $this->relation); } elseif (isset($this->type[$name])) { // 类型转换 $value = $this->readTransform($value, $this->type[$name]); @@ -567,14 +634,19 @@ abstract class Model implements \JsonSerializable, \ArrayAccess * @access public * @param Relation $modelRelation 模型关联对象 * @return mixed + * @throws BadMethodCallException */ protected function getRelationData(Relation $modelRelation) { - if ($this->parent && get_class($this->parent) == $modelRelation->getModel()) { + if ($this->parent && !$modelRelation->isSelfRelation() && get_class($modelRelation->getModel()) == get_class($this->parent)) { $value = $this->parent; } else { // 首先获取关联数据 - $value = $modelRelation->getRelation(); + if (method_exists($modelRelation, 'getRelation')) { + $value = $modelRelation->getRelation(); + } else { + throw new BadMethodCallException('method not exists:' . get_class($modelRelation) . '-> getRelation'); + } } return $value; } @@ -633,7 +705,11 @@ abstract class Model implements \JsonSerializable, \ArrayAccess $value = empty($value) ? new \stdClass() : json_decode($value); break; case 'serialize': - $value = unserialize($value); + try { + $value = unserialize($value); + } catch (\Exception $e) { + $value = null; + } break; default: if (false !== strpos($type, '\\')) { @@ -686,7 +762,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess if (isset($this->data[$key])) { throw new Exception('bind attr has exists:' . $key); } else { - $this->data[$key] = $model->$attr; + $this->data[$key] = $model->getAttr($attr); } } } @@ -820,7 +896,29 @@ abstract class Model implements \JsonSerializable, \ArrayAccess $relation = $this->getAttr($key); $item[$key] = $relation->append([$attr])->toArray(); } else { - $item[$name] = $this->getAttr($name); + $relation = Loader::parseName($name, 1, false); + if (method_exists($this, $relation)) { + $modelRelation = $this->$relation(); + $value = $this->getRelationData($modelRelation); + + if (method_exists($modelRelation, 'getBindAttr')) { + $bindAttr = $modelRelation->getBindAttr(); + if ($bindAttr) { + foreach ($bindAttr as $key => $attr) { + $key = is_numeric($key) ? $attr : $key; + if (isset($this->data[$key])) { + throw new Exception('bind attr has exists:' . $key); + } else { + $item[$key] = $value ? $value->getAttr($attr) : null; + } + } + continue; + } + } + $item[$name] = $value; + } else { + $item[$name] = $this->getAttr($name); + } } } } @@ -838,6 +936,17 @@ abstract class Model implements \JsonSerializable, \ArrayAccess return json_encode($this->toArray(), $options); } + /** + * 移除当前模型的关联属性 + * @access public + * @return $this + */ + public function removeRelation() + { + $this->relation = []; + return $this; + } + /** * 转换当前模型数据集为数据集对象 * @access public @@ -906,6 +1015,18 @@ abstract class Model implements \JsonSerializable, \ArrayAccess return false; } + /** + * 新增数据是否使用Replace + * @access public + * @param bool $replace + * @return $this + */ + public function replace($replace = true) + { + $this->replace = $replace; + return $this; + } + /** * 保存当前数据对象 * @access public @@ -916,18 +1037,26 @@ abstract class Model implements \JsonSerializable, \ArrayAccess */ public function save($data = [], $where = [], $sequence = null) { + if (is_string($data)) { + $sequence = $data; + $data = []; + } + + // 数据自动验证 if (!empty($data)) { - // 数据自动验证 if (!$this->validateData($data)) { return false; } + // 数据对象赋值 foreach ($data as $key => $value) { $this->setAttr($key, $value, $data); } - if (!empty($where)) { - $this->isUpdate = true; - } + } + + if (!empty($where)) { + $this->isUpdate = true; + $this->updateWhere = $where; } // 自动关联写入 @@ -964,9 +1093,6 @@ abstract class Model implements \JsonSerializable, \ArrayAccess } $pk = $this->getPk(); if ($this->isUpdate) { - // 检测字段 - $this->checkAllowField($this->data, array_merge($this->auto, $this->update)); - // 自动更新 $this->autoCompleteData($this->update); @@ -986,7 +1112,8 @@ abstract class Model implements \JsonSerializable, \ArrayAccess return 0; } elseif ($this->autoWriteTimestamp && $this->updateTime && !isset($data[$this->updateTime])) { // 自动写入更新时间 - $data[$this->updateTime] = $this->autoWriteTimestamp($this->updateTime); + $data[$this->updateTime] = $this->autoWriteTimestamp($this->updateTime); + $this->data[$this->updateTime] = $data[$this->updateTime]; } if (empty($where) && !empty($this->updateWhere)) { @@ -1000,16 +1127,28 @@ abstract class Model implements \JsonSerializable, \ArrayAccess } } - if (is_string($pk) && isset($data[$pk])) { - if (!isset($where[$pk])) { - unset($where); - $where[$pk] = $data[$pk]; + $array = []; + + foreach ((array) $pk as $key) { + if (isset($data[$key])) { + $array[$key] = $data[$key]; + unset($data[$key]); } - unset($data[$pk]); } + if (!empty($array)) { + $where = $array; + } + + // 检测字段 + $allowFields = $this->checkAllowField(array_merge($this->auto, $this->update)); + // 模型更新 - $result = $this->getQuery()->where($where)->update($data); + if (!empty($allowFields)) { + $result = $this->getQuery()->where($where)->strict(false)->field($allowFields)->update($data); + } else { + $result = $this->getQuery()->where($where)->update($data); + } // 关联更新 if (isset($relation)) { @@ -1020,9 +1159,6 @@ abstract class Model implements \JsonSerializable, \ArrayAccess $this->trigger('after_update', $this); } else { - // 检测字段 - $this->checkAllowField($this->data, array_merge($this->auto, $this->insert)); - // 自动写入 $this->autoCompleteData($this->insert); @@ -1040,13 +1176,20 @@ abstract class Model implements \JsonSerializable, \ArrayAccess return false; } - $result = $this->getQuery()->insert($this->data); + // 检测字段 + $allowFields = $this->checkAllowField(array_merge($this->auto, $this->insert)); + if (!empty($allowFields)) { + $result = $this->getQuery()->strict(false)->field($allowFields)->insert($this->data, $this->replace, false, $sequence); + } else { + $result = $this->getQuery()->insert($this->data, $this->replace, false, $sequence); + } // 获取自动增长主键 - if ($result && is_string($pk) && (!isset($this->data[$pk]) || '' == $this->data[$pk])) { - $insertId = $this->getQuery()->getLastInsID($sequence); - if ($insertId) { - $this->data[$pk] = $insertId; + if ($result && $insertId = $this->getQuery()->getLastInsID($sequence)) { + foreach ((array) $pk as $key) { + if (!isset($this->data[$key]) || '' == $this->data[$key]) { + $this->data[$key] = $insertId; + } } } @@ -1073,22 +1216,29 @@ abstract class Model implements \JsonSerializable, \ArrayAccess return $result; } - protected function checkAllowField(&$data, $auto = []) + protected function checkAllowField($auto = []) { - if (!empty($this->field)) { - if (true === $this->field) { - $this->field = $this->getQuery()->getTableInfo('', 'fields'); - $field = $this->field; - } else { - $field = array_merge($this->field, $auto); + if (true === $this->field) { + $this->field = $this->getQuery()->getTableInfo('', 'fields'); + $field = $this->field; + } elseif (!empty($this->field)) { + $field = array_merge($this->field, $auto); + if ($this->autoWriteTimestamp) { + array_push($field, $this->createTime, $this->updateTime); } + } elseif (!empty($this->except)) { + $fields = $this->getQuery()->getTableInfo('', 'fields'); + $field = array_diff($fields, (array) $this->except); + $this->field = $field; + } else { + $field = []; + } - foreach ($data as $key => $val) { - if (!in_array($key, $field)) { - unset($data[$key]); - } - } + if ($this->disuse) { + // 废弃字段 + $field = array_diff($field, (array) $this->disuse); } + return $field; } protected function autoRelationUpdate($relation) @@ -1113,12 +1263,16 @@ abstract class Model implements \JsonSerializable, \ArrayAccess */ public function getChangedData() { - $data = array_udiff_assoc($this->data, $this->origin, function ($a, $b) { - if ((empty($b) || empty($b)) && $a !== $b) { - return 1; - } - return is_object($a) || $a != $b ? 1 : 0; - }); + if ($this->force) { + $data = $this->data; + } else { + $data = array_udiff_assoc($this->data, $this->origin, function ($a, $b) { + if ((empty($a) || empty($b)) && $a !== $b) { + return 1; + } + return is_object($a) || $a != $b ? 1 : 0; + }); + } if (!empty($this->readonly)) { // 只读字段不允许更新 @@ -1143,16 +1297,8 @@ abstract class Model implements \JsonSerializable, \ArrayAccess */ public function setInc($field, $step = 1, $lazyTime = 0) { - // 删除条件 - $pk = $this->getPk(); - - if (is_string($pk) && isset($this->data[$pk])) { - $where = [$pk => $this->data[$pk]]; - } elseif (!empty($this->updateWhere)) { - $where = $this->updateWhere; - } else { - $where = null; - } + // 更新条件 + $where = $this->getWhere(); $result = $this->getQuery()->where($where)->setInc($field, $step, $lazyTime); if (true !== $result) { @@ -1172,6 +1318,23 @@ abstract class Model implements \JsonSerializable, \ArrayAccess * @throws Exception */ public function setDec($field, $step = 1, $lazyTime = 0) + { + // 更新条件 + $where = $this->getWhere(); + $result = $this->getQuery()->where($where)->setDec($field, $step, $lazyTime); + if (true !== $result) { + $this->data[$field] -= $step; + } + + return $result; + } + + /** + * 获取更新条件 + * @access protected + * @return mixed + */ + protected function getWhere() { // 删除条件 $pk = $this->getPk(); @@ -1183,13 +1346,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess } else { $where = null; } - - $result = $this->getQuery()->where($where)->setDec($field, $step, $lazyTime); - if (true !== $result) { - $this->data[$field] -= $step; - } - - return $result; + return $where; } /** @@ -1221,14 +1378,14 @@ abstract class Model implements \JsonSerializable, \ArrayAccess $auto = true; } foreach ($dataSet as $key => $data) { - if (!empty($auto) && isset($data[$pk])) { + if ($this->isUpdate || (!empty($auto) && isset($data[$pk]))) { $result[$key] = self::update($data, [], $this->field); } else { $result[$key] = self::create($data, $this->field); } } $db->commit(); - return $result; + return $this->toCollection($result); } catch (\Exception $e) { $db->rollback(); throw $e; @@ -1238,7 +1395,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess /** * 设置允许写入的字段 * @access public - * @param mixed $field 允许写入的字段 如果为true只允许写入数据表字段 + * @param string|array $field 允许写入的字段 如果为true只允许写入数据表字段 * @return $this */ public function allowField($field) @@ -1250,6 +1407,21 @@ abstract class Model implements \JsonSerializable, \ArrayAccess return $this; } + /** + * 设置排除写入的字段 + * @access public + * @param string|array $field 排除允许写入的字段 + * @return $this + */ + public function except($field) + { + if (is_string($field)) { + $field = explode(',', $field); + } + $this->except = $field; + return $this; + } + /** * 设置只读字段 * @access public @@ -1317,14 +1489,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess } // 删除条件 - $pk = $this->getPk(); - if (is_string($pk) && isset($this->data[$pk])) { - $where = [$pk => $this->data[$pk]]; - } elseif (!empty($this->updateWhere)) { - $where = $this->updateWhere; - } else { - $where = null; - } + $where = $this->getWhere(); // 删除当前模型数据 $result = $this->getQuery()->where($where)->delete(); @@ -1595,14 +1760,14 @@ abstract class Model implements \JsonSerializable, \ArrayAccess { $model = new static(); $query = $model->db(); - if (is_array($data) && key($data) !== 0) { + if (empty($data) && 0 !== $data) { + return 0; + } elseif (is_array($data) && key($data) !== 0) { $query->where($data); $data = null; } elseif ($data instanceof \Closure) { call_user_func_array($data, [ & $query]); $data = null; - } elseif (empty($data) && 0 !== $data) { - return 0; } $resultSet = $query->select($data); $count = 0; @@ -1627,6 +1792,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess $model = new static(); $query = $model->db(); $params = func_get_args(); + array_shift($params); array_unshift($params, $query); if ($name instanceof \Closure) { call_user_func_array($name, $params); @@ -1648,7 +1814,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess * 设置是否使用全局查询范围 * @param bool $use 是否启用全局查询范围 * @access public - * @return Model + * @return Query */ public static function useGlobalScope($use) { @@ -1677,13 +1843,14 @@ abstract class Model implements \JsonSerializable, \ArrayAccess /** * 根据关联条件查询当前模型 * @access public - * @param string $relation 关联方法名 - * @param mixed $where 查询条件(数组或者闭包) + * @param string $relation 关联方法名 + * @param mixed $where 查询条件(数组或者闭包) + * @param mixed $fields 字段 * @return Relation|Query */ - public static function hasWhere($relation, $where = []) + public static function hasWhere($relation, $where = [], $fields = null) { - return (new static())->$relation()->hasWhere($where); + return (new static())->$relation()->hasWhere($where, $fields); } /** @@ -1840,7 +2007,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess * @access public * @param string $model 模型名 * @param string $foreignKey 关联外键 - * @param string $localKey 关联主键 + * @param string $localKey 当前模型主键 * @param array $alias 别名定义(已经废弃) * @param string $joinType JOIN类型 * @return HasOne @@ -1880,7 +2047,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess * @access public * @param string $model 模型名 * @param string $foreignKey 关联外键 - * @param string $localKey 关联主键 + * @param string $localKey 当前模型主键 * @return HasMany */ public function hasMany($model, $foreignKey = '', $localKey = '') @@ -1899,7 +2066,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess * @param string $through 中间模型名 * @param string $foreignKey 关联外键 * @param string $throughKey 关联外键 - * @param string $localKey 关联主键 + * @param string $localKey 当前模型主键 * @return HasManyThrough */ public function hasManyThrough($model, $through, $foreignKey = '', $throughKey = '', $localKey = '') @@ -1927,7 +2094,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess // 记录当前关联信息 $model = $this->parseModel($model); $name = Loader::parseName(basename(str_replace('\\', '/', $model))); - $table = $table ?: $this->getQuery()->getTable(Loader::parseName($this->name) . '_' . $name); + $table = $table ?: Loader::parseName($this->name) . '_' . $name; $foreignKey = $foreignKey ?: $name . '_id'; $localKey = $localKey ?: $this->getForeignKey($this->name); return new BelongsToMany($this, $model, $table, $foreignKey, $localKey); @@ -1949,7 +2116,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess $trace = debug_backtrace(false, 2); $morph = Loader::parseName($trace[1]['function']); } - $type = $type ?: Loader::parseName($this->name); + $type = $type ?: get_class($this); if (is_array($morph)) { list($morphType, $foreignKey) = $morph; } else { @@ -1975,7 +2142,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess $trace = debug_backtrace(false, 2); $morph = Loader::parseName($trace[1]['function']); } - $type = $type ?: Loader::parseName($this->name); + $type = $type ?: get_class($this); if (is_array($morph)) { list($morphType, $foreignKey) = $morph; } else { @@ -2013,7 +2180,6 @@ abstract class Model implements \JsonSerializable, \ArrayAccess public function __call($method, $args) { $query = $this->db(true, false); - if (method_exists($this, 'scope' . $method)) { // 动态调用命名范围 $method = 'scope' . $method; @@ -2029,7 +2195,6 @@ abstract class Model implements \JsonSerializable, \ArrayAccess { $model = new static(); $query = $model->db(); - if (method_exists($model, 'scope' . $method)) { // 动态调用命名范围 $method = 'scope' . $method; diff --git a/thinkphp/library/think/Paginator.php b/thinkphp/library/think/Paginator.php index 5a8fa20e..36555678 100644 --- a/thinkphp/library/think/Paginator.php +++ b/thinkphp/library/think/Paginator.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -49,6 +49,9 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J 'fragment' => '', ]; + /** @var mixed simple模式下的下个元素 */ + protected $nextItem; + public function __construct($items, $listRows, $currentPage = null, $total = null, $simple = false, $options = []) { $this->options = array_merge($this->options, $options); @@ -65,7 +68,10 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J if ($simple) { $this->currentPage = $this->setCurrentPage($currentPage); $this->hasMore = count($items) > ($this->listRows); - $items = $items->slice(0, $this->listRows); + if ($this->hasMore) { + $this->nextItem = $items->slice($this->listRows, 1); + } + $items = $items->slice(0, $this->listRows); } else { $this->total = $total; $this->lastPage = (int) ceil($total / $listRows); @@ -122,7 +128,7 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J } $url = $path; if (!empty($parameters)) { - $url .= '?' . urldecode(http_build_query($parameters, null, '&')); + $url .= '?' . http_build_query($parameters, null, '&'); } return $url . $this->buildFragment(); } @@ -135,9 +141,9 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J */ public static function getCurrentPage($varPage = 'page', $default = 1) { - $page = Request::instance()->request($varPage); + $page = (int) Request::instance()->param($varPage); - if (filter_var($page, FILTER_VALIDATE_INT) !== false && (int) $page >= 1) { + if (filter_var($page, FILTER_VALIDATE_INT) !== false && $page >= 1) { return $page; } @@ -282,8 +288,11 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J public function each(callable $callback) { foreach ($this->items as $key => $item) { - if ($callback($item, $key) === false) { + $result = $callback($item, $key); + if (false === $result) { break; + } elseif (!is_object($item)) { + $this->items[$key] = $result; } } @@ -356,19 +365,24 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J public function toArray() { - try { - $total = $this->total(); - } catch (\DomainException $e) { - $total = null; + if ($this->simple) { + return [ + 'per_page' => $this->listRows, + 'current_page' => $this->currentPage, + 'has_more' => $this->hasMore, + 'next_item' => $this->nextItem, + 'data' => $this->items->toArray(), + ]; + } else { + return [ + 'total' => $this->total, + 'per_page' => $this->listRows, + 'current_page' => $this->currentPage, + 'last_page' => $this->lastPage, + 'data' => $this->items->toArray(), + ]; } - return [ - 'total' => $total, - 'per_page' => $this->listRows(), - 'current_page' => $this->currentPage(), - 'last_page' => $this->lastPage, - 'data' => $this->items->toArray(), - ]; } /** @@ -381,7 +395,15 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J public function __call($name, $arguments) { - return call_user_func_array([$this->getCollection(), $name], $arguments); + $collection = $this->getCollection(); + + $result = call_user_func_array([$collection, $name], $arguments); + + if ($result === $collection) { + return $this; + } + + return $result; } } diff --git a/thinkphp/library/think/Request.php b/thinkphp/library/think/Request.php index e3fa3a4f..5997a763 100644 --- a/thinkphp/library/think/Request.php +++ b/thinkphp/library/think/Request.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -59,6 +59,11 @@ class Request */ protected $routeInfo = []; + /** + * @var array 环境变量 + */ + protected $env; + /** * @var array 当前调度信息 */ @@ -116,6 +121,11 @@ class Request protected $cache; // 缓存是否检查 protected $isCheckCache; + /** + * 是否合并Param + * @var bool + */ + protected $mergeParam = false; /** * 构造函数 @@ -150,8 +160,8 @@ class Request /** * Hook 方法注入 * @access public - * @param string|array $method 方法名 - * @param mixed $callback callable + * @param string|array $method 方法名 + * @param mixed $callback callable * @return void */ public static function hook($method, $callback = null) @@ -177,16 +187,28 @@ class Request return self::$instance; } + /** + * 销毁当前请求对象 + * @access public + * @return void + */ + public static function destroy() + { + if (!is_null(self::$instance)) { + self::$instance = null; + } + } + /** * 创建一个URL请求 * @access public - * @param string $uri URL地址 - * @param string $method 请求类型 - * @param array $params 请求参数 - * @param array $cookie - * @param array $files - * @param array $server - * @param string $content + * @param string $uri URL地址 + * @param string $method 请求类型 + * @param array $params 请求参数 + * @param array $cookie + * @param array $files + * @param array $server + * @param string $content * @return \think\Request */ public static function create($uri, $method = 'GET', $params = [], $cookie = [], $files = [], $server = [], $content = null) @@ -227,7 +249,7 @@ class Request parse_str(html_entity_decode($info['query']), $query); if (!empty($params)) { $params = array_replace($query, $params); - $queryString = http_build_query($query, '', '&'); + $queryString = http_build_query($params, '', '&'); } else { $params = $query; $queryString = $info['query']; @@ -474,8 +496,8 @@ class Request /** * 设置资源类型 * @access public - * @param string|array $type 资源类型名 - * @param string $val 资源类型 + * @param string|array $type 资源类型名 + * @param string $val 资源类型 * @return void */ public function mimeType($type, $val = '') @@ -490,22 +512,28 @@ class Request /** * 当前的请求类型 * @access public - * @param bool $method true 获取原始请求类型 + * @param bool $method true 获取原始请求类型 * @return string */ public function method($method = false) { if (true === $method) { // 获取原始请求类型 - return IS_CLI ? 'GET' : (isset($this->server['REQUEST_METHOD']) ? $this->server['REQUEST_METHOD'] : $_SERVER['REQUEST_METHOD']); + return $this->server('REQUEST_METHOD') ?: 'GET'; } elseif (!$this->method) { if (isset($_POST[Config::get('var_method')])) { - $this->method = strtoupper($_POST[Config::get('var_method')]); - $this->{$this->method}($_POST); + $method = strtoupper($_POST[Config::get('var_method')]); + if (in_array($method, ['GET', 'POST', 'DELETE', 'PUT', 'PATCH'])) { + $this->method = $method; + $this->{$this->method}($_POST); + } else { + $this->method = 'POST'; + } + unset($_POST[Config::get('var_method')]); } elseif (isset($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'])) { $this->method = strtoupper($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE']); } else { - $this->method = IS_CLI ? 'GET' : (isset($this->server['REQUEST_METHOD']) ? $this->server['REQUEST_METHOD'] : $_SERVER['REQUEST_METHOD']); + $this->method = $this->server('REQUEST_METHOD') ?: 'GET'; } } return $this->method; @@ -604,14 +632,14 @@ class Request /** * 获取当前请求的参数 * @access public - * @param string|array $name 变量名 - * @param mixed $default 默认值 - * @param string|array $filter 过滤方法 + * @param string|array $name 变量名 + * @param mixed $default 默认值 + * @param string|array $filter 过滤方法 * @return mixed */ public function param($name = '', $default = null, $filter = '') { - if (empty($this->param)) { + if (empty($this->mergeParam)) { $method = $this->method(true); // 自动获取请求变量 switch ($method) { @@ -627,7 +655,8 @@ class Request $vars = []; } // 当前请求参数和URL地址中的参数合并 - $this->param = array_merge($this->get(false), $vars, $this->route(false)); + $this->param = array_merge($this->param, $this->get(false), $vars, $this->route(false)); + $this->mergeParam = true; } if (true === $name) { // 获取包含文件上传信息的数组 @@ -641,15 +670,16 @@ class Request /** * 设置获取路由参数 * @access public - * @param string|array $name 变量名 - * @param mixed $default 默认值 - * @param string|array $filter 过滤方法 + * @param string|array $name 变量名 + * @param mixed $default 默认值 + * @param string|array $filter 过滤方法 * @return mixed */ public function route($name = '', $default = null, $filter = '') { if (is_array($name)) { $this->param = []; + $this->mergeParam = false; return $this->route = array_merge($this->route, $name); } return $this->input($this->route, $name, $default, $filter); @@ -658,9 +688,9 @@ class Request /** * 设置获取GET参数 * @access public - * @param string|array $name 变量名 - * @param mixed $default 默认值 - * @param string|array $filter 过滤方法 + * @param string|array $name 变量名 + * @param mixed $default 默认值 + * @param string|array $filter 过滤方法 * @return mixed */ public function get($name = '', $default = null, $filter = '') @@ -670,6 +700,7 @@ class Request } if (is_array($name)) { $this->param = []; + $this->mergeParam = false; return $this->get = array_merge($this->get, $name); } return $this->input($this->get, $name, $default, $filter); @@ -678,9 +709,9 @@ class Request /** * 设置获取POST参数 * @access public - * @param string $name 变量名 - * @param mixed $default 默认值 - * @param string|array $filter 过滤方法 + * @param string $name 变量名 + * @param mixed $default 默认值 + * @param string|array $filter 过滤方法 * @return mixed */ public function post($name = '', $default = null, $filter = '') @@ -695,6 +726,7 @@ class Request } if (is_array($name)) { $this->param = []; + $this->mergeParam = false; return $this->post = array_merge($this->post, $name); } return $this->input($this->post, $name, $default, $filter); @@ -703,9 +735,9 @@ class Request /** * 设置获取PUT参数 * @access public - * @param string|array $name 变量名 - * @param mixed $default 默认值 - * @param string|array $filter 过滤方法 + * @param string|array $name 变量名 + * @param mixed $default 默认值 + * @param string|array $filter 过滤方法 * @return mixed */ public function put($name = '', $default = null, $filter = '') @@ -720,6 +752,7 @@ class Request } if (is_array($name)) { $this->param = []; + $this->mergeParam = false; return $this->put = is_null($this->put) ? $name : array_merge($this->put, $name); } @@ -729,9 +762,9 @@ class Request /** * 设置获取DELETE参数 * @access public - * @param string|array $name 变量名 - * @param mixed $default 默认值 - * @param string|array $filter 过滤方法 + * @param string|array $name 变量名 + * @param mixed $default 默认值 + * @param string|array $filter 过滤方法 * @return mixed */ public function delete($name = '', $default = null, $filter = '') @@ -742,9 +775,9 @@ class Request /** * 设置获取PATCH参数 * @access public - * @param string|array $name 变量名 - * @param mixed $default 默认值 - * @param string|array $filter 过滤方法 + * @param string|array $name 变量名 + * @param mixed $default 默认值 + * @param string|array $filter 过滤方法 * @return mixed */ public function patch($name = '', $default = null, $filter = '') @@ -754,9 +787,9 @@ class Request /** * 获取request变量 - * @param string $name 数据名称 - * @param string $default 默认值 - * @param string|array $filter 过滤方法 + * @param string $name 数据名称 + * @param string $default 默认值 + * @param string|array $filter 过滤方法 * @return mixed */ public function request($name = '', $default = null, $filter = '') @@ -766,6 +799,7 @@ class Request } if (is_array($name)) { $this->param = []; + $this->mergeParam = false; return $this->request = array_merge($this->request, $name); } return $this->input($this->request, $name, $default, $filter); @@ -774,9 +808,9 @@ class Request /** * 获取session数据 * @access public - * @param string|array $name 数据名称 - * @param string $default 默认值 - * @param string|array $filter 过滤方法 + * @param string|array $name 数据名称 + * @param string $default 默认值 + * @param string|array $filter 过滤方法 * @return mixed */ public function session($name = '', $default = null, $filter = '') @@ -793,9 +827,9 @@ class Request /** * 获取cookie参数 * @access public - * @param string|array $name 数据名称 - * @param string $default 默认值 - * @param string|array $filter 过滤方法 + * @param string|array $name 数据名称 + * @param string $default 默认值 + * @param string|array $filter 过滤方法 * @return mixed */ public function cookie($name = '', $default = null, $filter = '') @@ -826,9 +860,9 @@ class Request /** * 获取server参数 * @access public - * @param string|array $name 数据名称 - * @param string $default 默认值 - * @param string|array $filter 过滤方法 + * @param string|array $name 数据名称 + * @param string $default 默认值 + * @param string|array $filter 过滤方法 * @return mixed */ public function server($name = '', $default = null, $filter = '') @@ -904,9 +938,9 @@ class Request /** * 获取环境变量 - * @param string|array $name 数据名称 - * @param string $default 默认值 - * @param string|array $filter 过滤方法 + * @param string|array $name 数据名称 + * @param string $default 默认值 + * @param string|array $filter 过滤方法 * @return mixed */ public function env($name = '', $default = null, $filter = '') @@ -923,8 +957,8 @@ class Request /** * 设置或者获取当前的Header * @access public - * @param string|array $name header名称 - * @param string $default 默认值 + * @param string|array $name header名称 + * @param string $default 默认值 * @return string */ public function header($name = '', $default = null) @@ -962,10 +996,10 @@ class Request /** * 获取变量 支持过滤和默认值 - * @param array $data 数据源 - * @param string|false $name 字段名 - * @param mixed $default 默认值 - * @param string|array $filter 过滤函数 + * @param array $data 数据源 + * @param string|false $name 字段名 + * @param mixed $default 默认值 + * @param string|array $filter 过滤函数 * @return mixed */ public function input($data = [], $name = '', $default = null, $filter = '') @@ -1046,9 +1080,9 @@ class Request /** * 递归过滤给定的值 - * @param mixed $value 键值 - * @param mixed $key 键名 - * @param array $filters 过滤方法+默认值 + * @param mixed $value 键值 + * @param mixed $key 键名 + * @param array $filters 过滤方法+默认值 * @return mixed */ private function filterValue(&$value, $key, $filters) @@ -1088,7 +1122,7 @@ class Request public function filterExp(&$value) { // 过滤查询特殊字符 - if (is_string($value) && preg_match('/^(EXP|NEQ|GT|EGT|LT|ELT|OR|XOR|LIKE|NOTLIKE|NOT BETWEEN|NOTBETWEEN|BETWEEN|NOTIN|NOT IN|IN)$/i', $value)) { + if (is_string($value) && preg_match('/^(EXP|NEQ|GT|EGT|LT|ELT|OR|XOR|LIKE|NOTLIKE|NOT LIKE|NOT BETWEEN|NOTBETWEEN|BETWEEN|NOT EXISTS|NOTEXISTS|EXISTS|NOT NULL|NOTNULL|NULL|BETWEEN TIME|NOT BETWEEN TIME|NOTBETWEEN TIME|NOTIN|NOT IN|IN)$/i', $value)) { $value .= ' '; } // TODO 其他安全过滤 @@ -1133,9 +1167,9 @@ class Request /** * 是否存在某个请求参数 * @access public - * @param string $name 变量名 - * @param string $type 变量类型 - * @param bool $checkEmpty 是否检测空值 + * @param string $name 变量名 + * @param string $type 变量类型 + * @param bool $checkEmpty 是否检测空值 * @return mixed */ public function has($name, $type = 'param', $checkEmpty = false) @@ -1159,8 +1193,8 @@ class Request /** * 获取指定的参数 * @access public - * @param string|array $name 变量名 - * @param string $type 变量类型 + * @param string|array $name 变量名 + * @param string $type 变量类型 * @return mixed */ public function only($name, $type = 'param') @@ -1181,8 +1215,8 @@ class Request /** * 排除指定参数获取 * @access public - * @param string|array $name 变量名 - * @param string $type 变量类型 + * @param string|array $name 变量名 + * @param string $type 变量类型 * @return mixed */ public function except($name, $type = 'param') @@ -1215,6 +1249,8 @@ class Request return true; } elseif (isset($server['HTTP_X_FORWARDED_PROTO']) && 'https' == $server['HTTP_X_FORWARDED_PROTO']) { return true; + } elseif (Config::get('https_agent_name') && isset($server[Config::get('https_agent_name')])) { + return true; } return false; } @@ -1222,7 +1258,7 @@ class Request /** * 当前是否Ajax请求 * @access public - * @param bool $ajax true 获取原始ajax请求 + * @param bool $ajax true 获取原始ajax请求 * @return bool */ public function isAjax($ajax = false) @@ -1232,14 +1268,16 @@ class Request if (true === $ajax) { return $result; } else { - return $this->param(Config::get('var_ajax')) ? true : $result; + $result = $this->param(Config::get('var_ajax')) ? true : $result; + $this->mergeParam = false; + return $result; } } /** * 当前是否Pjax请求 * @access public - * @param bool $pjax true 获取原始pjax请求 + * @param bool $pjax true 获取原始pjax请求 * @return bool */ public function isPjax($pjax = false) @@ -1248,17 +1286,19 @@ class Request if (true === $pjax) { return $result; } else { - return $this->param(Config::get('var_pjax')) ? true : $result; + $result = $this->param(Config::get('var_pjax')) ? true : $result; + $this->mergeParam = false; + return $result; } } /** * 获取客户端IP地址 - * @param integer $type 返回类型 0 返回IP地址 1 返回IPV4地址数字 - * @param boolean $adv 是否进行高级模式获取(有可能被伪装) + * @param integer $type 返回类型 0 返回IP地址 1 返回IPV4地址数字 + * @param boolean $adv 是否进行高级模式获取(有可能被伪装) * @return mixed */ - public function ip($type = 0, $adv = false) + public function ip($type = 0, $adv = true) { $type = $type ? 1 : 0; static $ip = null; @@ -1266,7 +1306,11 @@ class Request return $ip[$type]; } - if ($adv) { + $httpAgentIp = Config::get('http_agent_ip'); + + if ($httpAgentIp && isset($_SERVER[$httpAgentIp])) { + $ip = $_SERVER[$httpAgentIp]; + } elseif ($adv) { if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) { $arr = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']); $pos = array_search('unknown', $arr); @@ -1331,11 +1375,18 @@ class Request /** * 当前请求的host * @access public + * @param bool $strict true 仅仅获取HOST * @return string */ - public function host() + public function host($strict = false) { - return $this->server('HTTP_HOST'); + if (isset($_SERVER['HTTP_X_REAL_HOST'])) { + $host = $_SERVER['HTTP_X_REAL_HOST']; + } else { + $host = $this->server('HTTP_HOST'); + } + + return true === $strict && strpos($host, ':') ? strstr($host, ':', true) : $host; } /** @@ -1405,7 +1456,7 @@ class Request /** * 设置或者获取当前请求的调度信息 * @access public - * @param array $dispatch 调度信息 + * @param array $dispatch 调度信息 * @return array */ public function dispatch($dispatch = null) @@ -1456,11 +1507,12 @@ class Request */ public function action($action = null) { - if (!is_null($action)) { + if (!is_null($action) && !is_bool($action)) { $this->action = $action; return $this; } else { - return $this->action ?: ''; + $name = $this->action ?: ''; + return true === $action ? $name : strtolower($name); } } @@ -1524,13 +1576,19 @@ class Request /** * 设置当前地址的请求缓存 * @access public - * @param string $key 缓存标识,支持变量规则 ,例如 item/:name/:id + * @param string $key 缓存标识,支持变量规则 ,例如 item/:name/:id * @param mixed $expire 缓存有效期 * @param array $except 缓存排除 + * @param string $tag 缓存标签 * @return void */ - public function cache($key, $expire = null, $except = []) + public function cache($key, $expire = null, $except = [], $tag = null) { + if (!is_array($except)) { + $tag = $except; + $except = []; + } + if (false !== $key && $this->isGet() && !$this->isCheckCache) { // 标记请求缓存检查 $this->isCheckCache = true; @@ -1542,7 +1600,7 @@ class Request $key = call_user_func_array($key, [$this]); } elseif (true === $key) { foreach ($except as $rule) { - if (0 === strpos($this->url(), $rule)) { + if (0 === stripos($this->url(), $rule)) { return; } } @@ -1584,7 +1642,7 @@ class Request $response = Response::create($content)->header($header); throw new \think\exception\HttpResponseException($response); } else { - $this->cache = [$key, $expire]; + $this->cache = [$key, $expire, $tag]; } } } @@ -1602,8 +1660,8 @@ class Request /** * 设置当前请求绑定的对象实例 * @access public - * @param string $name 绑定的对象标识 - * @param mixed $obj 绑定的对象实例 + * @param string|array $name 绑定的对象标识 + * @param mixed $obj 绑定的对象实例 * @return mixed */ public function bind($name, $obj = null) diff --git a/thinkphp/library/think/Response.php b/thinkphp/library/think/Response.php index 96737dcd..c5c15209 100644 --- a/thinkphp/library/think/Response.php +++ b/thinkphp/library/think/Response.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -69,9 +69,7 @@ class Response */ public static function create($data = '', $type = '', $code = 200, array $header = [], $options = []) { - $type = empty($type) ? 'null' : strtolower($type); - - $class = false !== strpos($type, '\\') ? $type : '\\think\\response\\' . ucfirst($type); + $class = false !== strpos($type, '\\') ? $type : '\\think\\response\\' . ucfirst(strtolower($type)); if (class_exists($class)) { $response = new $class($data, $code, $header, $options); } else { @@ -89,6 +87,9 @@ class Response */ public function send() { + // 监听response_send + Hook::listen('response_send', $this); + // 处理输出数据 $data = $this->getContent(); @@ -103,7 +104,7 @@ class Response $this->header['Cache-Control'] = 'max-age=' . $cache[1] . ',must-revalidate'; $this->header['Last-Modified'] = gmdate('D, d M Y H:i:s') . ' GMT'; $this->header['Expires'] = gmdate('D, d M Y H:i:s', $_SERVER['REQUEST_TIME'] + $cache[1]) . ' GMT'; - Cache::set($cache[0], [$data, $this->header], $cache[1]); + Cache::tag($cache[2])->set($cache[0], [$data, $this->header], $cache[1]); } } diff --git a/thinkphp/library/think/Route.php b/thinkphp/library/think/Route.php index a5b19327..ab53aa20 100644 --- a/thinkphp/library/think/Route.php +++ b/thinkphp/library/think/Route.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -68,8 +68,8 @@ class Route /** * 注册变量规则 * @access public - * @param string|array $name 变量名 - * @param string $rule 变量规则 + * @param string|array $name 变量名 + * @param string $rule 变量规则 * @return void */ public static function pattern($name = null, $rule = '') @@ -84,10 +84,10 @@ class Route /** * 注册子域名部署规则 * @access public - * @param string|array $domain 子域名 - * @param mixed $rule 路由规则 - * @param array $option 路由参数 - * @param array $pattern 变量规则 + * @param string|array $domain 子域名 + * @param mixed $rule 路由规则 + * @param array $option 路由参数 + * @param array $pattern 变量规则 * @return void */ public static function domain($domain, $rule = '', $option = [], $pattern = []) @@ -121,8 +121,8 @@ class Route /** * 设置路由绑定 * @access public - * @param mixed $bind 绑定信息 - * @param string $type 绑定类型 默认为module 支持 namespace class controller + * @param mixed $bind 绑定信息 + * @param string $type 绑定类型 默认为module 支持 namespace class controller * @return mixed */ public static function bind($bind, $type = 'module') @@ -133,8 +133,8 @@ class Route /** * 设置或者获取路由标识 * @access public - * @param string|array $name 路由命名标识 数组表示批量设置 - * @param array $value 路由地址及变量信息 + * @param string|array $name 路由命名标识 数组表示批量设置 + * @param array $value 路由地址及变量信息 * @return array */ public static function name($name = '', $value = null) @@ -154,7 +154,7 @@ class Route /** * 读取路由绑定 * @access public - * @param string $type 绑定类型 + * @param string $type 绑定类型 * @return mixed */ public static function getBind($type) @@ -165,8 +165,8 @@ class Route /** * 导入配置文件的路由规则 * @access public - * @param array $rule 路由规则 - * @param string $type 请求类型 + * @param array $rule 路由规则 + * @param string $type 请求类型 * @return void */ public static function import(array $rule, $type = '*') @@ -222,11 +222,11 @@ class Route /** * 注册路由规则 * @access public - * @param string $rule 路由规则 - * @param string $route 路由地址 - * @param string $type 请求类型 - * @param array $option 路由参数 - * @param array $pattern 变量规则 + * @param string|array $rule 路由规则 + * @param string $route 路由地址 + * @param string $type 请求类型 + * @param array $option 路由参数 + * @param array $pattern 变量规则 * @return void */ public static function rule($rule, $route = '', $type = '*', $option = [], $pattern = []) @@ -255,9 +255,11 @@ class Route $option1 = array_merge($option, $val[1]); $pattern1 = array_merge($pattern, isset($val[2]) ? $val[2] : []); } else { - $route = $val; + $option1 = null; + $pattern1 = null; + $route = $val; } - self::setRule($key, $route, $type, isset($option1) ? $option1 : $option, isset($pattern1) ? $pattern1 : $pattern, $group); + self::setRule($key, $route, $type, !is_null($option1) ? $option1 : $option, !is_null($pattern1) ? $pattern1 : $pattern, $group); } } else { self::setRule($rule, $route, $type, $option, $pattern, $group); @@ -268,12 +270,12 @@ class Route /** * 设置路由规则 * @access public - * @param string $rule 路由规则 - * @param string $route 路由地址 - * @param string $type 请求类型 - * @param array $option 路由参数 - * @param array $pattern 变量规则 - * @param string $group 所属分组 + * @param string|array $rule 路由规则 + * @param string $route 路由地址 + * @param string $type 请求类型 + * @param array $option 路由参数 + * @param array $pattern 变量规则 + * @param string $group 所属分组 * @return void */ protected static function setRule($rule, $route, $type = '*', $option = [], $pattern = [], $group = '') @@ -333,9 +335,9 @@ class Route if ('*' == $type) { // 注册路由快捷方式 foreach (['get', 'post', 'put', 'delete', 'patch', 'head', 'options'] as $method) { - if (self::$domain) { + if (self::$domain && !isset(self::$rules['domain'][self::$domain][$method][$rule])) { self::$rules['domain'][self::$domain][$method][$rule] = true; - } else { + } elseif (!self::$domain && !isset(self::$rules[$method][$rule])) { self::$rules[$method][$rule] = true; } } @@ -346,7 +348,7 @@ class Route /** * 设置当前执行的参数信息 * @access public - * @param array $options 参数信息 + * @param array $options 参数信息 * @return mixed */ protected static function setOption($options = []) @@ -367,7 +369,7 @@ class Route /** * 获取当前的分组信息 * @access public - * @param string $type 分组信息名称 name option pattern + * @param string $type 分组信息名称 name option pattern * @return mixed */ public static function getGroup($type) @@ -382,9 +384,9 @@ class Route /** * 设置当前的路由分组 * @access public - * @param string $name 分组名称 - * @param array $option 分组路由参数 - * @param array $pattern 分组变量规则 + * @param string $name 分组名称 + * @param array $option 分组路由参数 + * @param array $pattern 分组变量规则 * @return void */ public static function setGroup($name, $option = [], $pattern = []) @@ -397,10 +399,10 @@ class Route /** * 注册路由分组 * @access public - * @param string|array $name 分组名称或者参数 - * @param array|\Closure $routes 路由地址 - * @param array $option 路由参数 - * @param array $pattern 变量规则 + * @param string|array $name 分组名称或者参数 + * @param array|\Closure $routes 路由地址 + * @param array $option 路由参数 + * @param array $pattern 变量规则 * @return void */ public static function group($name, $routes, $option = [], $pattern = []) @@ -428,7 +430,8 @@ class Route self::$rules['*'][$name]['pattern'] = $pattern; } } else { - $item = []; + $item = []; + $completeMatch = Config::get('route_complete_match'); foreach ($routes as $key => $val) { if (is_numeric($key)) { $key = array_shift($val); @@ -447,6 +450,8 @@ class Route // 是否完整匹配 $options['complete_match'] = true; $key = substr($key, 0, -1); + } elseif ($completeMatch) { + $options['complete_match'] = true; } $key = trim($key, '/'); $vars = self::parseVar($key); @@ -482,10 +487,10 @@ class Route /** * 注册路由 * @access public - * @param string $rule 路由规则 - * @param string $route 路由地址 - * @param array $option 路由参数 - * @param array $pattern 变量规则 + * @param string|array $rule 路由规则 + * @param string $route 路由地址 + * @param array $option 路由参数 + * @param array $pattern 变量规则 * @return void */ public static function any($rule, $route = '', $option = [], $pattern = []) @@ -496,10 +501,10 @@ class Route /** * 注册GET路由 * @access public - * @param string $rule 路由规则 - * @param string $route 路由地址 - * @param array $option 路由参数 - * @param array $pattern 变量规则 + * @param string|array $rule 路由规则 + * @param string $route 路由地址 + * @param array $option 路由参数 + * @param array $pattern 变量规则 * @return void */ public static function get($rule, $route = '', $option = [], $pattern = []) @@ -510,10 +515,10 @@ class Route /** * 注册POST路由 * @access public - * @param string $rule 路由规则 - * @param string $route 路由地址 - * @param array $option 路由参数 - * @param array $pattern 变量规则 + * @param string|array $rule 路由规则 + * @param string $route 路由地址 + * @param array $option 路由参数 + * @param array $pattern 变量规则 * @return void */ public static function post($rule, $route = '', $option = [], $pattern = []) @@ -524,10 +529,10 @@ class Route /** * 注册PUT路由 * @access public - * @param string $rule 路由规则 - * @param string $route 路由地址 - * @param array $option 路由参数 - * @param array $pattern 变量规则 + * @param string|array $rule 路由规则 + * @param string $route 路由地址 + * @param array $option 路由参数 + * @param array $pattern 变量规则 * @return void */ public static function put($rule, $route = '', $option = [], $pattern = []) @@ -538,10 +543,10 @@ class Route /** * 注册DELETE路由 * @access public - * @param string $rule 路由规则 - * @param string $route 路由地址 - * @param array $option 路由参数 - * @param array $pattern 变量规则 + * @param string|array $rule 路由规则 + * @param string $route 路由地址 + * @param array $option 路由参数 + * @param array $pattern 变量规则 * @return void */ public static function delete($rule, $route = '', $option = [], $pattern = []) @@ -552,10 +557,10 @@ class Route /** * 注册PATCH路由 * @access public - * @param string $rule 路由规则 - * @param string $route 路由地址 - * @param array $option 路由参数 - * @param array $pattern 变量规则 + * @param string|array $rule 路由规则 + * @param string $route 路由地址 + * @param array $option 路由参数 + * @param array $pattern 变量规则 * @return void */ public static function patch($rule, $route = '', $option = [], $pattern = []) @@ -566,10 +571,10 @@ class Route /** * 注册资源路由 * @access public - * @param string $rule 路由规则 - * @param string $route 路由地址 - * @param array $option 路由参数 - * @param array $pattern 变量规则 + * @param string|array $rule 路由规则 + * @param string $route 路由地址 + * @param array $option 路由参数 + * @param array $pattern 变量规则 * @return void */ public static function resource($rule, $route = '', $option = [], $pattern = []) @@ -613,10 +618,10 @@ class Route /** * 注册控制器路由 操作方法对应不同的请求后缀 * @access public - * @param string $rule 路由规则 - * @param string $route 路由地址 - * @param array $option 路由参数 - * @param array $pattern 变量规则 + * @param string $rule 路由规则 + * @param string $route 路由地址 + * @param array $option 路由参数 + * @param array $pattern 变量规则 * @return void */ public static function controller($rule, $route = '', $option = [], $pattern = []) @@ -629,9 +634,9 @@ class Route /** * 注册别名路由 * @access public - * @param string|array $rule 路由别名 - * @param string $route 路由地址 - * @param array $option 路由参数 + * @param string|array $rule 路由别名 + * @param string $route 路由地址 + * @param array $option 路由参数 * @return void */ public static function alias($rule = null, $route = '', $option = []) @@ -646,8 +651,8 @@ class Route /** * 设置不同请求类型下面的方法前缀 * @access public - * @param string $method 请求类型 - * @param string $prefix 类型前缀 + * @param string $method 请求类型 + * @param string $prefix 类型前缀 * @return void */ public static function setMethodPrefix($method, $prefix = '') @@ -662,8 +667,8 @@ class Route /** * rest方法定义和修改 * @access public - * @param string $name 方法名称 - * @param array|bool $resource 资源 + * @param string|array $name 方法名称 + * @param array|bool $resource 资源 * @return void */ public static function rest($name, $resource = []) @@ -678,9 +683,9 @@ class Route /** * 注册未匹配路由规则后的处理 * @access public - * @param string $route 路由地址 - * @param string $method 请求类型 - * @param array $option 路由参数 + * @param string $route 路由地址 + * @param string $method 请求类型 + * @param array $option 路由参数 * @return void */ public static function miss($route, $method = '*', $option = []) @@ -691,7 +696,7 @@ class Route /** * 注册一个自动解析的URL路由 * @access public - * @param string $route 路由地址 + * @param string $route 路由地址 * @return void */ public static function auto($route) @@ -721,9 +726,9 @@ class Route /** * 检测子域名部署 * @access public - * @param Request $request Request请求对象 - * @param array $currentRules 当前路由规则 - * @param string $method 请求类型 + * @param Request $request Request请求对象 + * @param array $currentRules 当前路由规则 + * @param string $method 请求类型 * @return void */ public static function checkDomain($request, &$currentRules, $method = 'get') @@ -732,7 +737,7 @@ class Route $rules = self::$rules['domain']; // 开启子域名部署 支持二级和三级域名 if (!empty($rules)) { - $host = $request->host(); + $host = $request->host(true); if (isset($rules[$host])) { // 完整域名或者IP配置 $item = $rules[$host]; @@ -822,14 +827,23 @@ class Route /** * 检测URL路由 * @access public - * @param Request $request Request请求对象 - * @param string $url URL地址 - * @param string $depr URL分隔符 - * @param bool $checkDomain 是否检测域名规则 + * @param Request $request Request请求对象 + * @param string $url URL地址 + * @param string $depr URL分隔符 + * @param bool $checkDomain 是否检测域名规则 * @return false|array */ public static function check($request, $url, $depr = '/', $checkDomain = false) { + //检查解析缓存 + if (!App::$debug && Config::get('route_check_cache')) { + $key = self::getCheckCacheKey($request); + if (Cache::has($key)) { + list($rule, $route, $pathinfo, $option, $matches) = Cache::get($key); + return self::parseRule($rule, $route, $pathinfo, $option, $matches, true); + } + } + // 分隔符替换 确保路由定义使用统一的分隔符 $url = str_replace($depr, '|', $url); @@ -883,12 +897,12 @@ class Route /** * 检测路由规则 * @access private - * @param Request $request - * @param array $rules 路由规则 - * @param string $url URL地址 - * @param string $depr URL分割符 - * @param string $group 路由分组名 - * @param array $options 路由参数(分组) + * @param Request $request + * @param array $rules 路由规则 + * @param string $url URL地址 + * @param string $depr URL分割符 + * @param string $group 路由分组名 + * @param array $options 路由参数(分组) * @return mixed */ private static function checkRoute($request, $rules, $url, $depr = '/', $group = '', $options = []) @@ -966,9 +980,9 @@ class Route /** * 检测路由别名 * @access private - * @param Request $request - * @param string $url URL地址 - * @param string $depr URL分隔符 + * @param Request $request + * @param string $url URL地址 + * @param string $depr URL分隔符 * @return mixed */ private static function checkRouteAlias($request, $url, $depr) @@ -1013,9 +1027,9 @@ class Route /** * 检测URL绑定 * @access private - * @param string $url URL地址 - * @param array $rules 路由规则 - * @param string $depr URL分隔符 + * @param string $url URL地址 + * @param array $rules 路由规则 + * @param string $depr URL分隔符 * @return mixed */ private static function checkUrlBind(&$url, &$rules, $depr = '/') @@ -1044,9 +1058,9 @@ class Route /** * 绑定到类 * @access public - * @param string $url URL地址 - * @param string $class 类名(带命名空间) - * @param string $depr URL分隔符 + * @param string $url URL地址 + * @param string $class 类名(带命名空间) + * @param string $depr URL分隔符 * @return array */ public static function bindToClass($url, $class, $depr = '/') @@ -1063,9 +1077,9 @@ class Route /** * 绑定到命名空间 * @access public - * @param string $url URL地址 - * @param string $namespace 命名空间 - * @param string $depr URL分隔符 + * @param string $url URL地址 + * @param string $namespace 命名空间 + * @param string $depr URL分隔符 * @return array */ public static function bindToNamespace($url, $namespace, $depr = '/') @@ -1083,9 +1097,9 @@ class Route /** * 绑定到控制器类 * @access public - * @param string $url URL地址 - * @param string $controller 控制器名 (支持带模块名 index/user ) - * @param string $depr URL分隔符 + * @param string $url URL地址 + * @param string $controller 控制器名 (支持带模块名 index/user ) + * @param string $depr URL分隔符 * @return array */ public static function bindToController($url, $controller, $depr = '/') @@ -1102,9 +1116,9 @@ class Route /** * 绑定到模块/控制器 * @access public - * @param string $url URL地址 - * @param string $controller 控制器类名(带命名空间) - * @param string $depr URL分隔符 + * @param string $url URL地址 + * @param string $controller 控制器类名(带命名空间) + * @param string $depr URL分隔符 * @return array */ public static function bindToModule($url, $controller, $depr = '/') @@ -1121,8 +1135,8 @@ class Route /** * 路由参数有效性检查 * @access private - * @param array $option 路由参数 - * @param Request $request Request对象 + * @param array $option 路由参数 + * @param Request $request Request对象 * @return bool */ private static function checkOption($option, $request) @@ -1148,18 +1162,18 @@ class Route /** * 检测路由规则 * @access private - * @param string $rule 路由规则 - * @param string $route 路由地址 - * @param string $url URL地址 - * @param array $pattern 变量规则 - * @param array $option 路由参数 - * @param string $depr URL分隔符(全局) + * @param string $rule 路由规则 + * @param string $route 路由地址 + * @param string $url URL地址 + * @param array $pattern 变量规则 + * @param array $option 路由参数 + * @param string $depr URL分隔符(全局) * @return array|false */ private static function checkRule($rule, $route, $url, $pattern, $option, $depr) { // 检查完整规则定义 - if (isset($pattern['__url__']) && !preg_match('/^' . $pattern['__url__'] . '/', str_replace('|', $depr, $url))) { + if (isset($pattern['__url__']) && !preg_match(0 === strpos($pattern['__url__'], '/') ? $pattern['__url__'] : '/^' . $pattern['__url__'] . '/', str_replace('|', $depr, $url))) { return false; } // 检查路由的参数分隔符 @@ -1195,9 +1209,9 @@ class Route /** * 解析模块的URL地址 [模块/控制器/操作?]参数1=值1&参数2=值2... * @access public - * @param string $url URL地址 - * @param string $depr URL分隔符 - * @param bool $autoSearch 是否自动深度搜索控制器 + * @param string $url URL地址 + * @param string $depr URL分隔符 + * @param bool $autoSearch 是否自动深度搜索控制器 * @return array */ public static function parseUrl($url, $depr = '/', $autoSearch = false) @@ -1264,7 +1278,7 @@ class Route /** * 解析URL的pathinfo参数和变量 * @access private - * @param string $url URL地址 + * @param string $url URL地址 * @return array */ private static function parseUrlPath($url) @@ -1290,9 +1304,9 @@ class Route /** * 检测URL和规则路由是否匹配 * @access private - * @param string $url URL地址 - * @param string $rule 路由规则 - * @param array $pattern 变量规则 + * @param string $url URL地址 + * @param string $rule 路由规则 + * @param array $pattern 变量规则 * @return array|false */ private static function match($url, $rule, $pattern) @@ -1349,7 +1363,7 @@ class Route if (false === $result) { return false; } - } elseif (!preg_match('/^' . $pattern[$name] . '$/', $m1[$key])) { + } elseif (!preg_match(0 === strpos($pattern[$name], '/') ? $pattern[$name] : '/^' . $pattern[$name] . '$/', $m1[$key])) { return false; } } @@ -1365,16 +1379,28 @@ class Route /** * 解析规则路由 * @access private - * @param string $rule 路由规则 - * @param string $route 路由地址 - * @param string $pathinfo URL地址 - * @param array $option 路由参数 - * @param array $matches 匹配的变量 + * @param string $rule 路由规则 + * @param string $route 路由地址 + * @param string $pathinfo URL地址 + * @param array $option 路由参数 + * @param array $matches 匹配的变量 + * @param bool $fromCache 通过缓存解析 * @return array */ - private static function parseRule($rule, $route, $pathinfo, $option = [], $matches = []) + private static function parseRule($rule, $route, $pathinfo, $option = [], $matches = [], $fromCache = false) { $request = Request::instance(); + + //保存解析缓存 + if (Config::get('route_check_cache') && !$fromCache) { + try { + $key = self::getCheckCacheKey($request); + Cache::tag('route_check')->set($key, [$rule, $route, $pathinfo, $option, $matches]); + } catch (\Exception $e) { + + } + } + // 解析路由规则 if ($rule) { $rule = explode('/', $rule); @@ -1449,6 +1475,10 @@ class Route $request->bind($bind); } + if (!empty($option['response'])) { + Hook::add('response_send', $option['response']); + } + // 解析额外参数 self::parseUrlParams(empty($paths) ? '' : implode('|', $paths), $matches); // 记录匹配的路由信息 @@ -1497,18 +1527,19 @@ class Route App::$modulePath = APP_PATH . (Config::get('app_multi_module') ? $request->module() . DS : ''); } else { // 路由到模块/控制器/操作 - $result = self::parseModule($route); + $result = self::parseModule($route, isset($option['convert']) ? $option['convert'] : false); } // 开启请求缓存 if ($request->isGet() && isset($option['cache'])) { $cache = $option['cache']; if (is_array($cache)) { - list($key, $expire) = $cache; + list($key, $expire, $tag) = array_pad($cache, 3, null); } else { $key = str_replace('|', '/', $pathinfo); $expire = $cache; + $tag = null; } - $request->cache($key, $expire); + $request->cache($key, $expire, $tag); } return $result; } @@ -1516,10 +1547,11 @@ class Route /** * 解析URL地址为 模块/控制器/操作 * @access private - * @param string $url URL地址 + * @param string $url URL地址 + * @param bool $convert 是否自动转换URL地址 * @return array */ - private static function parseModule($url) + private static function parseModule($url, $convert = false) { list($path, $var) = self::parseUrlPath($url); $action = array_pop($path); @@ -1533,14 +1565,14 @@ class Route // 设置当前请求的路由变量 Request::instance()->route($var); // 路由到模块/控制器/操作 - return ['type' => 'module', 'module' => [$module, $controller, $action], 'convert' => false]; + return ['type' => 'module', 'module' => [$module, $controller, $action], 'convert' => $convert]; } /** * 解析URL地址中的参数Request对象 * @access private - * @param string $rule 路由规则 - * @param array $var 变量 + * @param string $url 路由规则 + * @param array $var 变量 * @return void */ private static function parseUrlParams($url, &$var = []) @@ -1590,4 +1622,24 @@ class Route } return $var; } + + /** + * 获取路由解析缓存的key + * @param Request $request + * @return string + */ + private static function getCheckCacheKey(Request $request) + { + static $key; + + if (empty($key)) { + if ($callback = Config::get('route_check_cache_key')) { + $key = call_user_func($callback, $request); + } else { + $key = "{$request->host(true)}|{$request->method()}|{$request->path()}"; + } + } + + return $key; + } } diff --git a/thinkphp/library/think/Session.php b/thinkphp/library/think/Session.php index d5a6a5a5..61150bca 100644 --- a/thinkphp/library/think/Session.php +++ b/thinkphp/library/think/Session.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -25,6 +25,7 @@ class Session */ public static function prefix($prefix = '') { + empty(self::$init) && self::boot(); if (empty($prefix) && null !== $prefix) { return self::$prefix; } else { @@ -56,7 +57,7 @@ class Session $isDoStart = true; } - if (isset($config['prefix']) && (self::$prefix === '' || self::$prefix === null)) { + if (isset($config['prefix']) && ('' === self::$prefix || null === self::$prefix)) { self::$prefix = $config['prefix']; } if (isset($config['var_session_id']) && isset($_REQUEST[$config['var_session_id']])) { @@ -347,7 +348,7 @@ class Session * @param bool $delete 是否删除关联会话文件 * @return void */ - private static function regenerate($delete = false) + public static function regenerate($delete = false) { session_regenerate_id($delete); } diff --git a/thinkphp/library/think/Template.php b/thinkphp/library/think/Template.php index 4abf21ce..9ba0ff35 100644 --- a/thinkphp/library/think/Template.php +++ b/thinkphp/library/think/Template.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -12,6 +12,7 @@ namespace think; use think\exception\TemplateNotFoundException; +use think\template\TagLib; /** * ThinkPHP分离出来的模板引擎 @@ -59,15 +60,20 @@ class Template /** * 构造函数 * @access public + * @param array $config */ public function __construct(array $config = []) { - $this->config['cache_path'] = TEMP_PATH; - $this->config = array_merge($this->config, $config); - $this->config['taglib_begin'] = $this->stripPreg($this->config['taglib_begin']); - $this->config['taglib_end'] = $this->stripPreg($this->config['taglib_end']); - $this->config['tpl_begin'] = $this->stripPreg($this->config['tpl_begin']); - $this->config['tpl_end'] = $this->stripPreg($this->config['tpl_end']); + $this->config['cache_path'] = TEMP_PATH; + $this->config = array_merge($this->config, $config); + + $this->config['taglib_begin_origin'] = $this->config['taglib_begin']; + $this->config['taglib_end_origin'] = $this->config['taglib_end']; + + $this->config['taglib_begin'] = preg_quote($this->config['taglib_begin'], '/'); + $this->config['taglib_end'] = preg_quote($this->config['taglib_end'], '/'); + $this->config['tpl_begin'] = preg_quote($this->config['tpl_begin'], '/'); + $this->config['tpl_end'] = preg_quote($this->config['tpl_end'], '/'); // 初始化模板编译存储器 $type = $this->config['compile_type'] ? $this->config['compile_type'] : 'File'; @@ -75,20 +81,6 @@ class Template $this->storage = new $class(); } - /** - * 字符串替换 避免正则混淆 - * @access private - * @param string $str - * @return string - */ - private function stripPreg($str) - { - return str_replace( - ['{', '}', '(', ')', '|', '[', ']', '-', '+', '*', '.', '^', '?'], - ['\{', '\}', '\(', '\)', '\|', '\[', '\]', '\-', '\+', '\*', '\.', '\^', '\?'], - $str); - } - /** * 模板变量赋值 * @access public @@ -120,7 +112,7 @@ class Template * 模板引擎配置项 * @access public * @param array|string $config - * @return void|array + * @return string|void|array */ public function config($config) { @@ -183,7 +175,7 @@ class Template } $template = $this->parseTemplateFile($template); if ($template) { - $cacheFile = $this->config['cache_path'] . $this->config['cache_prefix'] . md5($template) . '.' . ltrim($this->config['cache_suffix'], '.'); + $cacheFile = $this->config['cache_path'] . $this->config['cache_prefix'] . md5($this->config['layout_name'] . $template) . '.' . ltrim($this->config['cache_suffix'], '.'); if (!$this->checkCache($cacheFile)) { // 缓存无效 重新模板编译 $content = file_get_contents($template); @@ -234,7 +226,7 @@ class Template * @access public * @param mixed $name 布局模板名称 false 则关闭布局 * @param string $replace 布局模板内容替换标识 - * @return object + * @return Template */ public function layout($name, $replace = '') { @@ -688,6 +680,7 @@ class Template } else { $className = '\\think\\template\\taglib\\' . ucwords($tagLib); } + /** @var Taglib $tLib */ $tLib = new $className($this); $tLib->parseTag($content, $hide ? '' : $tagLib); return; @@ -763,31 +756,26 @@ class Template } else { if (isset($array[1])) { $this->parseVar($array[2]); - $_name = ' && ' . $name . $array[1] . $array[2]; + $express = $name . $array[1] . $array[2]; } else { - $_name = ''; + $express = false; } // $name为数组 switch ($first) { case '?': // {$varname??'xxx'} $varname有定义则输出$varname,否则输出xxx - $str = ''; + $str = ''; break; case '=': // {$varname?='xxx'} $varname为真时才输出xxx - $str = ''; + $str = ''; break; case ':': // {$varname?:'xxx'} $varname为真时输出$varname,否则输出xxx - $str = ''; + $str = ''; break; default: - if (strpos($str, ':')) { - // {$varname ? 'a' : 'b'} $varname为真时输出a,否则输出b - $str = ''; - } else { - $str = ''; - } + $str = ''; } } } else { @@ -1075,7 +1063,7 @@ class Template } else { $path = isset($module) ? APP_PATH . $module . DS . basename($this->config['view_path']) . DS : $this->config['view_path']; } - $template = $path . $template . '.' . ltrim($this->config['view_suffix'], '.'); + $template = realpath($path . $template . '.' . ltrim($this->config['view_suffix'], '.')); } if (is_file($template)) { diff --git a/thinkphp/library/think/Url.php b/thinkphp/library/think/Url.php index 9f725e2c..53a545f9 100644 --- a/thinkphp/library/think/Url.php +++ b/thinkphp/library/think/Url.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -118,7 +118,7 @@ class Url $type = Route::getBind('type'); if ($type) { $bind = Route::getBind($type); - if (0 === strpos($url, $bind)) { + if ($bind && 0 === strpos($url, $bind)) { $url = substr($url, strlen($bind) + 1); } } @@ -135,7 +135,7 @@ class Url if (!empty($vars)) { // 添加参数 if (Config::get('url_common_param')) { - $vars = urldecode(http_build_query($vars)); + $vars = http_build_query($vars); $url .= $suffix . '?' . $vars . $anchor; } else { $paramType = Config::get('url_param_type'); @@ -210,17 +210,21 @@ class Url } $module = $module ? $module . '/' : ''; - $controller = Loader::parseName($request->controller()); + $controller = $request->controller(); if ('' == $url) { // 空字符串输出当前的 模块/控制器/操作 - $url = $module . $controller . '/' . $request->action(); + $action = $request->action(); } else { $path = explode('/', $url); - $action = Config::get('url_convert') ? strtolower(array_pop($path)) : array_pop($path); - $controller = empty($path) ? $controller : (Config::get('url_convert') ? Loader::parseName(array_pop($path)) : array_pop($path)); + $action = array_pop($path); + $controller = empty($path) ? $controller : array_pop($path); $module = empty($path) ? $module : array_pop($path) . '/'; - $url = $module . $controller . '/' . $action; } + if (Config::get('url_convert')) { + $action = strtolower($action); + $controller = Loader::parseName($controller); + } + $url = $module . $controller . '/' . $action; } return $url; } @@ -272,7 +276,7 @@ class Url $domain .= '.' . $rootDomain; } } - if (false !== strpos($domain, ':')) { + if (false !== strpos($domain, '://')) { $scheme = ''; } else { $scheme = $request->isSsl() || Config::get('is_https') ? 'https://' : 'http://'; @@ -298,11 +302,12 @@ class Url foreach ($rule as $item) { list($url, $pattern, $domain, $suffix) = $item; if (empty($pattern)) { - return [$url, $domain, $suffix]; + return [rtrim($url, '$'), $domain, $suffix]; } + $type = Config::get('url_common_param'); foreach ($pattern as $key => $val) { if (isset($vars[$key])) { - $url = str_replace(['[:' . $key . ']', '<' . $key . '?>', ':' . $key . '', '<' . $key . '>'], urlencode($vars[$key]), $url); + $url = str_replace(['[:' . $key . ']', '<' . $key . '?>', ':' . $key . '', '<' . $key . '>'], $type ? $vars[$key] : urlencode($vars[$key]), $url); unset($vars[$key]); $result = [$url, $domain, $suffix]; } elseif (2 == $val) { diff --git a/thinkphp/library/think/Validate.php b/thinkphp/library/think/Validate.php index 8d1cb3b5..608e1e4a 100644 --- a/thinkphp/library/think/Validate.php +++ b/thinkphp/library/think/Validate.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -36,54 +36,56 @@ class Validate // 验证规则默认提示信息 protected static $typeMsg = [ - 'require' => ':attribute不能为空', - 'number' => ':attribute必须是数字', - 'float' => ':attribute必须是浮点数', - 'boolean' => ':attribute必须是布尔值', - 'email' => ':attribute格式不符', - 'array' => ':attribute必须是数组', - 'accepted' => ':attribute必须是yes、on或者1', - 'date' => ':attribute格式不符合', - 'file' => ':attribute不是有效的上传文件', - 'image' => ':attribute不是有效的图像文件', - 'alpha' => ':attribute只能是字母', - 'alphaNum' => ':attribute只能是字母和数字', - 'alphaDash' => ':attribute只能是字母、数字和下划线_及破折号-', - 'activeUrl' => ':attribute不是有效的域名或者IP', - 'chs' => ':attribute只能是汉字', - 'chsAlpha' => ':attribute只能是汉字、字母', - 'chsAlphaNum' => ':attribute只能是汉字、字母和数字', - 'chsDash' => ':attribute只能是汉字、字母、数字和下划线_及破折号-', - 'url' => ':attribute不是有效的URL地址', - 'ip' => ':attribute不是有效的IP地址', - 'dateFormat' => ':attribute必须使用日期格式 :rule', - 'in' => ':attribute必须在 :rule 范围内', - 'notIn' => ':attribute不能在 :rule 范围内', - 'between' => ':attribute只能在 :1 - :2 之间', - 'notBetween' => ':attribute不能在 :1 - :2 之间', - 'length' => ':attribute长度不符合要求 :rule', - 'max' => ':attribute长度不能超过 :rule', - 'min' => ':attribute长度不能小于 :rule', - 'after' => ':attribute日期不能小于 :rule', - 'before' => ':attribute日期不能超过 :rule', - 'expire' => '不在有效期内 :rule', - 'allowIp' => '不允许的IP访问', - 'denyIp' => '禁止的IP访问', - 'confirm' => ':attribute和确认字段:2不一致', - 'different' => ':attribute和比较字段:2不能相同', - 'egt' => ':attribute必须大于等于 :rule', - 'gt' => ':attribute必须大于 :rule', - 'elt' => ':attribute必须小于等于 :rule', - 'lt' => ':attribute必须小于 :rule', - 'eq' => ':attribute必须等于 :rule', - 'unique' => ':attribute已存在', - 'regex' => ':attribute不符合指定规则', - 'method' => '无效的请求类型', - 'token' => '令牌数据无效', - 'fileSize' => '上传文件大小不符', - 'fileExt' => '上传文件后缀不符', - 'fileMime' => '上传文件类型不符', - + 'require' => ':attribute require', + 'number' => ':attribute must be numeric', + 'integer' => ':attribute must be integer', + 'float' => ':attribute must be float', + 'boolean' => ':attribute must be bool', + 'email' => ':attribute not a valid email address', + 'array' => ':attribute must be a array', + 'accepted' => ':attribute must be yes,on or 1', + 'date' => ':attribute not a valid datetime', + 'file' => ':attribute not a valid file', + 'image' => ':attribute not a valid image', + 'alpha' => ':attribute must be alpha', + 'alphaNum' => ':attribute must be alpha-numeric', + 'alphaDash' => ':attribute must be alpha-numeric, dash, underscore', + 'activeUrl' => ':attribute not a valid domain or ip', + 'chs' => ':attribute must be chinese', + 'chsAlpha' => ':attribute must be chinese or alpha', + 'chsAlphaNum' => ':attribute must be chinese,alpha-numeric', + 'chsDash' => ':attribute must be chinese,alpha-numeric,underscore, dash', + 'url' => ':attribute not a valid url', + 'ip' => ':attribute not a valid ip', + 'dateFormat' => ':attribute must be dateFormat of :rule', + 'in' => ':attribute must be in :rule', + 'notIn' => ':attribute be notin :rule', + 'between' => ':attribute must between :1 - :2', + 'notBetween' => ':attribute not between :1 - :2', + 'length' => 'size of :attribute must be :rule', + 'max' => 'max size of :attribute must be :rule', + 'min' => 'min size of :attribute must be :rule', + 'after' => ':attribute cannot be less than :rule', + 'before' => ':attribute cannot exceed :rule', + 'afterWith' => ':attribute cannot be less than :rule', + 'beforeWith' => ':attribute cannot exceed :rule', + 'expire' => ':attribute not within :rule', + 'allowIp' => 'access IP is not allowed', + 'denyIp' => 'access IP denied', + 'confirm' => ':attribute out of accord with :2', + 'different' => ':attribute cannot be same with :2', + 'egt' => ':attribute must greater than or equal :rule', + 'gt' => ':attribute must greater than :rule', + 'elt' => ':attribute must less than or equal :rule', + 'lt' => ':attribute must less than :rule', + 'eq' => ':attribute must equal :rule', + 'unique' => ':attribute has exists', + 'regex' => ':attribute not conform to the rules', + 'method' => 'invalid Request method', + 'token' => 'invalid token', + 'fileSize' => 'filesize not match', + 'fileExt' => 'extensions to upload is not allowed', + 'fileMime' => 'mimetype to upload is not allowed', ]; // 当前验证场景 @@ -339,6 +341,41 @@ class Validate return !empty($this->error) ? false : true; } + /** + * 根据验证规则验证数据 + * @access protected + * @param mixed $value 字段值 + * @param mixed $rules 验证规则 + * @return bool + */ + protected function checkRule($value, $rules) + { + if ($rules instanceof \Closure) { + return call_user_func_array($rules, [$value]); + } elseif (is_string($rules)) { + $rules = explode('|', $rules); + } + + foreach ($rules as $key => $rule) { + if ($rule instanceof \Closure) { + $result = call_user_func_array($rule, [$value]); + } else { + // 判断验证类型 + list($type, $rule) = $this->getValidateType($key, $rule); + + $callback = isset(self::$type[$type]) ? self::$type[$type] : [$this, $type]; + + $result = call_user_func_array($callback, [$value, $rule]); + } + + if (true !== $result) { + return $result; + } + } + + return true; + } + /** * 验证单个字段规则 * @access protected @@ -363,25 +400,7 @@ class Validate $info = is_numeric($key) ? '' : $key; } else { // 判断验证类型 - if (is_numeric($key)) { - if (strpos($rule, ':')) { - list($type, $rule) = explode(':', $rule, 2); - if (isset($this->alias[$type])) { - // 判断别名 - $type = $this->alias[$type]; - } - $info = $type; - } elseif (method_exists($this, $rule)) { - $type = $rule; - $info = $rule; - $rule = ''; - } else { - $type = 'is'; - $info = $rule; - } - } else { - $info = $type = $key; - } + list($type, $rule, $info) = $this->getValidateType($key, $rule); // 如果不是require 有数据才会行验证 if (0 === strpos($info, 'require') || (!is_null($value) && '' !== $value)) { @@ -417,6 +436,39 @@ class Validate return $result; } + /** + * 获取当前验证类型及规则 + * @access public + * @param mixed $key + * @param mixed $rule + * @return array + */ + protected function getValidateType($key, $rule) + { + // 判断验证类型 + if (!is_numeric($key)) { + return [$key, $rule, $key]; + } + + if (strpos($rule, ':')) { + list($type, $rule) = explode(':', $rule, 2); + if (isset($this->alias[$type])) { + // 判断别名 + $type = $this->alias[$type]; + } + $info = $type; + } elseif (method_exists($this, $rule)) { + $type = $rule; + $info = $rule; + $rule = ''; + } else { + $type = 'is'; + $info = $rule; + } + + return [$type, $rule, $info]; + } + /** * 验证是否和某个字段的值一致 * @access protected @@ -568,7 +620,7 @@ class Validate break; case 'chsDash': // 只允许汉字、字母、数字和下划线_及破折号- - $result = $this->regex($value, '/^[\x{4e00}-\x{9fa5}a-zA-Z0-9\_\-\.]+$/u'); + $result = $this->regex($value, '/^[\x{4e00}-\x{9fa5}a-zA-Z0-9\_\-]+$/u'); break; case 'activeUrl': // 是否为有效的网址 @@ -632,8 +684,12 @@ class Validate if (function_exists('exif_imagetype')) { return exif_imagetype($image); } else { - $info = getimagesize($image); - return $info[2]; + try { + $info = getimagesize($image); + return $info ? $info[2] : false; + } catch (\Exception $e) { + return false; + } } } @@ -676,21 +732,17 @@ class Validate */ protected function fileExt($file, $rule) { - if (!($file instanceof File)) { - return false; - } - if (is_string($rule)) { - $rule = explode(',', $rule); - } if (is_array($file)) { foreach ($file as $item) { - if (!$item->checkExt($rule)) { + if (!($item instanceof File) || !$item->checkExt($rule)) { return false; } } return true; - } else { + } elseif ($file instanceof File) { return $file->checkExt($rule); + } else { + return false; } } @@ -703,21 +755,17 @@ class Validate */ protected function fileMime($file, $rule) { - if (!($file instanceof File)) { - return false; - } - if (is_string($rule)) { - $rule = explode(',', $rule); - } if (is_array($file)) { foreach ($file as $item) { - if (!$item->checkMime($rule)) { + if (!($item instanceof File) || !$item->checkMime($rule)) { return false; } } return true; - } else { + } elseif ($file instanceof File) { return $file->checkMime($rule); + } else { + return false; } } @@ -730,18 +778,17 @@ class Validate */ protected function fileSize($file, $rule) { - if (!($file instanceof File)) { - return false; - } if (is_array($file)) { foreach ($file as $item) { - if (!$item->checkSize($rule)) { + if (!($item instanceof File) || !$item->checkSize($rule)) { return false; } } return true; - } else { + } elseif ($file instanceof File) { return $file->checkSize($rule); + } else { + return false; } } @@ -833,21 +880,26 @@ class Validate // 支持多个字段验证 $fields = explode('^', $key); foreach ($fields as $key) { - $map[$key] = $data[$key]; + if (isset($data[$key])) { + $map[$key] = $data[$key]; + } } } elseif (strpos($key, '=')) { parse_str($key, $map); - } else { + } elseif (isset($data[$field])) { $map[$key] = $data[$field]; + } else { + $map = []; } - $pk = strval(isset($rule[3]) ? $rule[3] : $db->getPk()); - if (isset($rule[2])) { - $map[$pk] = ['neq', $rule[2]]; - } elseif (isset($data[$pk])) { - $map[$pk] = ['neq', $data[$pk]]; + $pk = isset($rule[3]) ? $rule[3] : $db->getPk(); + if (is_string($pk)) { + if (isset($rule[2])) { + $map[$pk] = ['neq', $rule[2]]; + } elseif (isset($data[$pk])) { + $map[$pk] = ['neq', $data[$pk]]; + } } - if ($db->where($map)->field($pk)->find()) { return false; } @@ -899,7 +951,7 @@ class Validate { list($field, $val) = explode(',', $rule); if ($this->getDataValue($data, $field) == $val) { - return !empty($value); + return !empty($value) || '0' == $value; } else { return true; } @@ -917,7 +969,7 @@ class Validate { $result = call_user_func_array($rule, [$value, $data]); if ($result) { - return !empty($value); + return !empty($value) || '0' == $value; } else { return true; } @@ -935,7 +987,7 @@ class Validate { $val = $this->getDataValue($data, $rule); if (!empty($val)) { - return !empty($value); + return !empty($value) || '0' == $value; } else { return true; } @@ -1067,9 +1119,10 @@ class Validate * @access protected * @param mixed $value 字段值 * @param mixed $rule 验证规则 + * @param array $data 数据 * @return bool */ - protected function after($value, $rule) + protected function after($value, $rule, $data) { return strtotime($value) >= strtotime($rule); } @@ -1079,13 +1132,42 @@ class Validate * @access protected * @param mixed $value 字段值 * @param mixed $rule 验证规则 + * @param array $data 数据 * @return bool */ - protected function before($value, $rule) + protected function before($value, $rule, $data) { return strtotime($value) <= strtotime($rule); } + /** + * 验证日期字段 + * @access protected + * @param mixed $value 字段值 + * @param mixed $rule 验证规则 + * @param array $data 数据 + * @return bool + */ + protected function afterWith($value, $rule, $data) + { + $rule = $this->getDataValue($data, $rule); + return !is_null($rule) && strtotime($value) >= strtotime($rule); + } + + /** + * 验证日期字段 + * @access protected + * @param mixed $value 字段值 + * @param mixed $rule 验证规则 + * @param array $data 数据 + * @return bool + */ + protected function beforeWith($value, $rule, $data) + { + $rule = $this->getDataValue($data, $rule); + return !is_null($rule) && strtotime($value) <= strtotime($rule); + } + /** * 验证有效期 * @access protected @@ -1149,7 +1231,7 @@ class Validate // 不是正则表达式则两端补上/ $rule = '/^' . $rule . '$/'; } - return 1 === preg_match($rule, (string) $value); + return is_scalar($value) && 1 === preg_match($rule, (string) $value); } /** @@ -1225,12 +1307,16 @@ class Validate $msg = $this->message[$attribute]; } elseif (isset(self::$typeMsg[$type])) { $msg = self::$typeMsg[$type]; + } elseif (0 === strpos($type, 'require')) { + $msg = self::$typeMsg['require']; } else { - $msg = $title . '规则错误'; + $msg = $title . Lang::get('not conform to the rules'); } if (is_string($msg) && 0 === strpos($msg, '{%')) { $msg = Lang::get(substr($msg, 2, -1)); + } elseif (Lang::has($msg)) { + $msg = Lang::get($msg); } if (is_string($msg) && is_scalar($rule) && false !== strpos($msg, ':')) { diff --git a/thinkphp/library/think/View.php b/thinkphp/library/think/View.php index 96ae56c9..ca2dadbb 100644 --- a/thinkphp/library/think/View.php +++ b/thinkphp/library/think/View.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -33,7 +33,7 @@ class View public function __construct($engine = [], $replace = []) { // 初始化模板引擎 - $this->engine((array) $engine); + $this->engine($engine); // 基础替换字符串 $request = Request::instance(); $base = $request->root(); @@ -127,7 +127,7 @@ class View * @access private * @param string|array $name 参数名 * @param mixed $value 参数值 - * @return void + * @return $this */ public function config($name, $value = null) { @@ -155,18 +155,21 @@ class View ob_implicit_flush(0); // 渲染输出 - $method = $renderContent ? 'display' : 'fetch'; - $this->engine->$method($template, $vars, $config); + try { + $method = $renderContent ? 'display' : 'fetch'; + // 允许用户自定义模板的字符串替换 + $replace = array_merge($this->replace, $replace, (array) $this->engine->config('tpl_replace_string')); + $this->engine->config('tpl_replace_string', $replace); + $this->engine->$method($template, $vars, $config); + } catch (\Exception $e) { + ob_end_clean(); + throw $e; + } // 获取并清空缓存 $content = ob_get_clean(); // 内容过滤标签 Hook::listen('view_filter', $content); - // 允许用户自定义模板的字符串替换 - $replace = array_merge($this->replace, $replace); - if (!empty($replace)) { - $content = strtr($content, $replace); - } return $content; } diff --git a/thinkphp/library/think/cache/Driver.php b/thinkphp/library/think/cache/Driver.php index 688507a8..07805e48 100644 --- a/thinkphp/library/think/cache/Driver.php +++ b/thinkphp/library/think/cache/Driver.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -120,10 +120,29 @@ abstract class Driver public function remember($name, $value, $expire = null) { if (!$this->has($name)) { - if ($value instanceof \Closure) { - $value = call_user_func($value); + $time = time(); + while ($time + 5 > time() && $this->has($name . '_lock')) { + // 存在锁定则等待 + usleep(200000); + } + + try { + // 锁定 + $this->set($name . '_lock', true); + if ($value instanceof \Closure) { + $value = call_user_func($value); + } + $this->set($name, $value, $expire); + // 解锁 + $this->rm($name . '_lock'); + } catch (\Exception $e) { + // 解锁 + $this->rm($name . '_lock'); + throw $e; + } catch (\throwable $e) { + $this->rm($name . '_lock'); + throw $e; } - $this->set($name, $value, $expire); } else { $value = $this->get($name); } @@ -140,7 +159,9 @@ abstract class Driver */ public function tag($name, $keys = null, $overlay = false) { - if (is_null($keys)) { + if (is_null($name)) { + + } elseif (is_null($keys)) { $this->tag = $name; } else { $key = 'tag_' . md5($name); @@ -153,7 +174,7 @@ abstract class Driver } else { $value = array_unique(array_merge($this->getTagItem($name), $keys)); } - $this->set($key, implode(',', $value)); + $this->set($key, implode(',', $value), 0); } return $this; } @@ -170,12 +191,13 @@ abstract class Driver $key = 'tag_' . md5($this->tag); $this->tag = null; if ($this->has($key)) { - $value = $this->get($key); - $value .= ',' . $name; + $value = explode(',', $this->get($key)); + $value[] = $name; + $value = implode(',', array_unique($value)); } else { $value = $name; } - $this->set($key, $value); + $this->set($key, $value, 0); } } @@ -190,7 +212,7 @@ abstract class Driver $key = 'tag_' . md5($tag); $value = $this->get($key); if ($value) { - return explode(',', $value); + return array_filter(explode(',', $value)); } else { return []; } diff --git a/thinkphp/library/think/cache/driver/File.php b/thinkphp/library/think/cache/driver/File.php index 5aadb2b1..fee64894 100644 --- a/thinkphp/library/think/cache/driver/File.php +++ b/thinkphp/library/think/cache/driver/File.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -27,6 +27,8 @@ class File extends Driver 'data_compress' => false, ]; + protected $expire; + /** * 构造函数 * @param array $options @@ -61,10 +63,11 @@ class File extends Driver /** * 取得变量的存储文件名 * @access protected - * @param string $name 缓存变量名 + * @param string $name 缓存变量名 + * @param bool $auto 是否自动创建目录 * @return string */ - protected function getCacheKey($name) + protected function getCacheKey($name, $auto = false) { $name = md5($name); if ($this->options['cache_subdir']) { @@ -76,7 +79,8 @@ class File extends Driver } $filename = $this->options['path'] . $name . '.php'; $dir = dirname($filename); - if (!is_dir($dir)) { + + if ($auto && !is_dir($dir)) { mkdir($dir, 0755, true); } return $filename; @@ -106,15 +110,15 @@ class File extends Driver if (!is_file($filename)) { return $default; } - $content = file_get_contents($filename); + $content = file_get_contents($filename); + $this->expire = null; if (false !== $content) { $expire = (int) substr($content, 8, 12); - if (0 != $expire && $_SERVER['REQUEST_TIME'] > filemtime($filename) + $expire) { - //缓存过期删除缓存文件 - $this->unlink($filename); + if (0 != $expire && time() > filemtime($filename) + $expire) { return $default; } - $content = substr($content, 20, -3); + $this->expire = $expire; + $content = substr($content, 32); if ($this->options['data_compress'] && function_exists('gzcompress')) { //启用数据压缩 $content = gzuncompress($content); @@ -129,9 +133,9 @@ class File extends Driver /** * 写入缓存 * @access public - * @param string $name 缓存变量名 - * @param mixed $value 存储数据 - * @param int $expire 有效时间 0为永久 + * @param string $name 缓存变量名 + * @param mixed $value 存储数据 + * @param integer|\DateTime $expire 有效时间(秒) * @return boolean */ public function set($name, $value, $expire = null) @@ -139,7 +143,10 @@ class File extends Driver if (is_null($expire)) { $expire = $this->options['expire']; } - $filename = $this->getCacheKey($name); + if ($expire instanceof \DateTime) { + $expire = $expire->getTimestamp() - time(); + } + $filename = $this->getCacheKey($name, true); if ($this->tag && !is_file($filename)) { $first = true; } @@ -148,7 +155,7 @@ class File extends Driver //数据压缩 $data = gzcompress($data, 3); } - $data = ""; + $data = "\n" . $data; $result = file_put_contents($filename, $data); if ($result) { isset($first) && $this->setTagItem($filename); @@ -169,11 +176,14 @@ class File extends Driver public function inc($name, $step = 1) { if ($this->has($name)) { - $value = $this->get($name) + $step; + $value = $this->get($name) + $step; + $expire = $this->expire; } else { - $value = $step; + $value = $step; + $expire = 0; } - return $this->set($name, $value, 0) ? $value : false; + + return $this->set($name, $value, $expire) ? $value : false; } /** @@ -186,11 +196,14 @@ class File extends Driver public function dec($name, $step = 1) { if ($this->has($name)) { - $value = $this->get($name) - $step; + $value = $this->get($name) - $step; + $expire = $this->expire; } else { - $value = $step; + $value = -$step; + $expire = 0; } - return $this->set($name, $value, 0) ? $value : false; + + return $this->set($name, $value, $expire) ? $value : false; } /** @@ -201,7 +214,11 @@ class File extends Driver */ public function rm($name) { - return $this->unlink($this->getCacheKey($name)); + $filename = $this->getCacheKey($name); + try { + return $this->unlink($filename); + } catch (\Exception $e) { + } } /** @@ -224,7 +241,10 @@ class File extends Driver $files = (array) glob($this->options['path'] . ($this->options['prefix'] ? $this->options['prefix'] . DS : '') . '*'); foreach ($files as $path) { if (is_dir($path)) { - array_map('unlink', glob($path . '/*.php')); + $matches = glob($path . '/*.php'); + if (is_array($matches)) { + array_map('unlink', $matches); + } rmdir($path); } else { unlink($path); diff --git a/thinkphp/library/think/cache/driver/Lite.php b/thinkphp/library/think/cache/driver/Lite.php index eeb96a19..8cbf08f9 100644 --- a/thinkphp/library/think/cache/driver/Lite.php +++ b/thinkphp/library/think/cache/driver/Lite.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -77,7 +77,7 @@ class Lite extends Driver if (is_file($filename)) { // 判断是否过期 $mtime = filemtime($filename); - if ($mtime < $_SERVER['REQUEST_TIME']) { + if ($mtime < time()) { // 清除已经过期的文件 unlink($filename); return $default; @@ -91,9 +91,9 @@ class Lite extends Driver /** * 写入缓存 * @access public - * @param string $name 缓存变量名 - * @param mixed $value 存储数据 - * @param int $expire 有效时间 0为永久 + * @param string $name 缓存变量名 + * @param mixed $value 存储数据 + * @param integer|\DateTime $expire 有效时间(秒) * @return bool */ public function set($name, $value, $expire = null) @@ -101,9 +101,11 @@ class Lite extends Driver if (is_null($expire)) { $expire = $this->options['expire']; } - // 模拟永久 - if (0 === $expire) { - $expire = 10 * 365 * 24 * 3600; + if ($expire instanceof \DateTime) { + $expire = $expire->getTimestamp(); + } else { + $expire = 0 === $expire ? 10 * 365 * 24 * 3600 : $expire; + $expire = time() + $expire; } $filename = $this->getCacheKey($name); if ($this->tag && !is_file($filename)) { @@ -113,7 +115,7 @@ class Lite extends Driver // 通过设置修改时间实现有效期 if ($ret) { isset($first) && $this->setTagItem($filename); - touch($filename, $_SERVER['REQUEST_TIME'] + $expire); + touch($filename, $expire); } return $ret; } @@ -147,7 +149,7 @@ class Lite extends Driver if ($this->has($name)) { $value = $this->get($name) - $step; } else { - $value = $step; + $value = -$step; } return $this->set($name, $value, 0) ? $value : false; } diff --git a/thinkphp/library/think/cache/driver/Memcache.php b/thinkphp/library/think/cache/driver/Memcache.php index e464f38c..58703ea3 100644 --- a/thinkphp/library/think/cache/driver/Memcache.php +++ b/thinkphp/library/think/cache/driver/Memcache.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -63,7 +63,7 @@ class Memcache extends Driver public function has($name) { $key = $this->getCacheKey($name); - return $this->handler->get($key) ? true : false; + return false !== $this->handler->get($key); } /** @@ -82,9 +82,9 @@ class Memcache extends Driver /** * 写入缓存 * @access public - * @param string $name 缓存变量名 - * @param mixed $value 存储数据 - * @param integer $expire 有效时间(秒) + * @param string $name 缓存变量名 + * @param mixed $value 存储数据 + * @param integer|\DateTime $expire 有效时间(秒) * @return bool */ public function set($name, $value, $expire = null) @@ -92,6 +92,9 @@ class Memcache extends Driver if (is_null($expire)) { $expire = $this->options['expire']; } + if ($expire instanceof \DateTime) { + $expire = $expire->getTimestamp() - time(); + } if ($this->tag && !$this->has($name)) { $first = true; } diff --git a/thinkphp/library/think/cache/driver/Memcached.php b/thinkphp/library/think/cache/driver/Memcached.php index 4a9d898c..5aab5a30 100644 --- a/thinkphp/library/think/cache/driver/Memcached.php +++ b/thinkphp/library/think/cache/driver/Memcached.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -93,9 +93,9 @@ class Memcached extends Driver /** * 写入缓存 * @access public - * @param string $name 缓存变量名 - * @param mixed $value 存储数据 - * @param integer $expire 有效时间(秒) + * @param string $name 缓存变量名 + * @param mixed $value 存储数据 + * @param integer|\DateTime $expire 有效时间(秒) * @return bool */ public function set($name, $value, $expire = null) @@ -103,6 +103,9 @@ class Memcached extends Driver if (is_null($expire)) { $expire = $this->options['expire']; } + if ($expire instanceof \DateTime) { + $expire = $expire->getTimestamp() - time(); + } if ($this->tag && !$this->has($name)) { $first = true; } diff --git a/thinkphp/library/think/cache/driver/Redis.php b/thinkphp/library/think/cache/driver/Redis.php index 4f618785..027b3ea2 100644 --- a/thinkphp/library/think/cache/driver/Redis.php +++ b/thinkphp/library/think/cache/driver/Redis.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -46,9 +46,12 @@ class Redis extends Driver if (!empty($options)) { $this->options = array_merge($this->options, $options); } - $func = $this->options['persistent'] ? 'pconnect' : 'connect'; $this->handler = new \Redis; - $this->handler->$func($this->options['host'], $this->options['port'], $this->options['timeout']); + if ($this->options['persistent']) { + $this->handler->pconnect($this->options['host'], $this->options['port'], $this->options['timeout'], 'persistent_id_' . $this->options['select']); + } else { + $this->handler->connect($this->options['host'], $this->options['port'], $this->options['timeout']); + } if ('' != $this->options['password']) { $this->handler->auth($this->options['password']); @@ -67,7 +70,7 @@ class Redis extends Driver */ public function has($name) { - return $this->handler->get($this->getCacheKey($name)) ? true : false; + return $this->handler->exists($this->getCacheKey($name)); } /** @@ -80,20 +83,25 @@ class Redis extends Driver public function get($name, $default = false) { $value = $this->handler->get($this->getCacheKey($name)); - if (is_null($value)) { + if (is_null($value) || false === $value) { return $default; } - $jsonData = json_decode($value, true); - // 检测是否为JSON数据 true 返回JSON解析数组, false返回源数据 byron sampson - return (null === $jsonData) ? $value : $jsonData; + + try { + $result = 0 === strpos($value, 'think_serialize:') ? unserialize(substr($value, 16)) : $value; + } catch (\Exception $e) { + $result = $default; + } + + return $result; } /** * 写入缓存 * @access public - * @param string $name 缓存变量名 - * @param mixed $value 存储数据 - * @param integer $expire 有效时间(秒) + * @param string $name 缓存变量名 + * @param mixed $value 存储数据 + * @param integer|\DateTime $expire 有效时间(秒) * @return boolean */ public function set($name, $value, $expire = null) @@ -101,13 +109,15 @@ class Redis extends Driver if (is_null($expire)) { $expire = $this->options['expire']; } + if ($expire instanceof \DateTime) { + $expire = $expire->getTimestamp() - time(); + } if ($this->tag && !$this->has($name)) { $first = true; } - $key = $this->getCacheKey($name); - //对数组/对象数据进行缓存处理,保证数据完整性 byron sampson - $value = (is_object($value) || is_array($value)) ? json_encode($value) : $value; - if (is_int($expire) && $expire) { + $key = $this->getCacheKey($name); + $value = is_scalar($value) ? $value : 'think_serialize:' . serialize($value); + if ($expire) { $result = $this->handler->setex($key, $expire, $value); } else { $result = $this->handler->set($key, $value); @@ -119,26 +129,28 @@ class Redis extends Driver /** * 自增缓存(针对数值缓存) * @access public - * @param string $name 缓存变量名 - * @param int $step 步长 + * @param string $name 缓存变量名 + * @param int $step 步长 * @return false|int */ public function inc($name, $step = 1) { $key = $this->getCacheKey($name); + return $this->handler->incrby($key, $step); } /** * 自减缓存(针对数值缓存) * @access public - * @param string $name 缓存变量名 - * @param int $step 步长 + * @param string $name 缓存变量名 + * @param int $step 步长 * @return false|int */ public function dec($name, $step = 1) { $key = $this->getCacheKey($name); + return $this->handler->decrby($key, $step); } diff --git a/thinkphp/library/think/cache/driver/Sqlite.php b/thinkphp/library/think/cache/driver/Sqlite.php index 305fd9e8..dc2ee055 100644 --- a/thinkphp/library/think/cache/driver/Sqlite.php +++ b/thinkphp/library/think/cache/driver/Sqlite.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -96,9 +96,9 @@ class Sqlite extends Driver /** * 写入缓存 * @access public - * @param string $name 缓存变量名 - * @param mixed $value 存储数据 - * @param integer $expire 有效时间(秒) + * @param string $name 缓存变量名 + * @param mixed $value 存储数据 + * @param integer|\DateTime $expire 有效时间(秒) * @return boolean */ public function set($name, $value, $expire = null) @@ -108,7 +108,11 @@ class Sqlite extends Driver if (is_null($expire)) { $expire = $this->options['expire']; } - $expire = (0 == $expire) ? 0 : ($_SERVER['REQUEST_TIME'] + $expire); //缓存有效期为0表示永久缓存 + if ($expire instanceof \DateTime) { + $expire = $expire->getTimestamp(); + } else { + $expire = (0 == $expire) ? 0 : (time() + $expire); //缓存有效期为0表示永久缓存 + } if (function_exists('gzcompress')) { //数据压缩 $value = gzcompress($value, 3); @@ -155,7 +159,7 @@ class Sqlite extends Driver if ($this->has($name)) { $value = $this->get($name) - $step; } else { - $value = $step; + $value = -$step; } return $this->set($name, $value, 0) ? $value : false; } diff --git a/thinkphp/library/think/cache/driver/Wincache.php b/thinkphp/library/think/cache/driver/Wincache.php index 3076fc14..03f8d357 100644 --- a/thinkphp/library/think/cache/driver/Wincache.php +++ b/thinkphp/library/think/cache/driver/Wincache.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -68,9 +68,9 @@ class Wincache extends Driver /** * 写入缓存 * @access public - * @param string $name 缓存变量名 - * @param mixed $value 存储数据 - * @param integer $expire 有效时间(秒) + * @param string $name 缓存变量名 + * @param mixed $value 存储数据 + * @param integer|\DateTime $expire 有效时间(秒) * @return boolean */ public function set($name, $value, $expire = null) @@ -78,6 +78,9 @@ class Wincache extends Driver if (is_null($expire)) { $expire = $this->options['expire']; } + if ($expire instanceof \DateTime) { + $expire = $expire->getTimestamp() - time(); + } $key = $this->getCacheKey($name); if ($this->tag && !$this->has($name)) { $first = true; diff --git a/thinkphp/library/think/cache/driver/Xcache.php b/thinkphp/library/think/cache/driver/Xcache.php index 2a0e07ad..4d94c033 100644 --- a/thinkphp/library/think/cache/driver/Xcache.php +++ b/thinkphp/library/think/cache/driver/Xcache.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -68,9 +68,9 @@ class Xcache extends Driver /** * 写入缓存 * @access public - * @param string $name 缓存变量名 - * @param mixed $value 存储数据 - * @param integer $expire 有效时间(秒) + * @param string $name 缓存变量名 + * @param mixed $value 存储数据 + * @param integer|\DateTime $expire 有效时间(秒) * @return boolean */ public function set($name, $value, $expire = null) @@ -78,6 +78,9 @@ class Xcache extends Driver if (is_null($expire)) { $expire = $this->options['expire']; } + if ($expire instanceof \DateTime) { + $expire = $expire->getTimestamp() - time(); + } if ($this->tag && !$this->has($name)) { $first = true; } diff --git a/thinkphp/library/think/config/driver/Ini.php b/thinkphp/library/think/config/driver/Ini.php index a223a578..bcd12b69 100644 --- a/thinkphp/library/think/config/driver/Ini.php +++ b/thinkphp/library/think/config/driver/Ini.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- diff --git a/thinkphp/library/think/config/driver/Json.php b/thinkphp/library/think/config/driver/Json.php index 557f75fe..479dcc89 100644 --- a/thinkphp/library/think/config/driver/Json.php +++ b/thinkphp/library/think/config/driver/Json.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- diff --git a/thinkphp/library/think/config/driver/Xml.php b/thinkphp/library/think/config/driver/Xml.php index b573a562..1158519f 100644 --- a/thinkphp/library/think/config/driver/Xml.php +++ b/thinkphp/library/think/config/driver/Xml.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- diff --git a/thinkphp/library/think/console/command/Clear.php b/thinkphp/library/think/console/command/Clear.php index 41019cea..1b5102ec 100644 --- a/thinkphp/library/think/console/command/Clear.php +++ b/thinkphp/library/think/console/command/Clear.php @@ -10,8 +10,10 @@ // +---------------------------------------------------------------------- namespace think\console\command; +use think\Cache; use think\console\Command; use think\console\Input; +use think\console\input\Argument; use think\console\input\Option; use think\console\Output; @@ -22,6 +24,7 @@ class Clear extends Command // 指令配置 $this ->setName('clear') + ->addArgument('type', Argument::OPTIONAL, 'type to clear', null) ->addOption('path', 'd', Option::VALUE_OPTIONAL, 'path to clear', null) ->setDescription('Clear runtime file'); } @@ -30,8 +33,14 @@ class Clear extends Command { $path = $input->getOption('path') ?: RUNTIME_PATH; - if (is_dir($path)) { - $this->clearPath($path); + $type = $input->getArgument('type'); + + if ($type == 'route') { + Cache::clear('route_check'); + } else { + if (is_dir($path)) { + $this->clearPath($path); + } } $output->writeln("Clear Successed"); diff --git a/thinkphp/library/think/console/command/optimize/Config.php b/thinkphp/library/think/console/command/optimize/Config.php index cadfe5ee..59c69a8e 100644 --- a/thinkphp/library/think/console/command/optimize/Config.php +++ b/thinkphp/library/think/console/command/optimize/Config.php @@ -30,7 +30,7 @@ class Config extends Command protected function execute(Input $input, Output $output) { - if ($input->hasArgument('module')) { + if ($input->getArgument('module')) { $module = $input->getArgument('module') . DS; } else { $module = ''; diff --git a/thinkphp/library/think/console/command/optimize/Route.php b/thinkphp/library/think/console/command/optimize/Route.php index 911e4c14..6da1d9a6 100644 --- a/thinkphp/library/think/console/command/optimize/Route.php +++ b/thinkphp/library/think/console/command/optimize/Route.php @@ -27,6 +27,11 @@ class Route extends Command protected function execute(Input $input, Output $output) { + + if (!is_dir(RUNTIME_PATH)) { + @mkdir(RUNTIME_PATH, 0755, true); + } + file_put_contents(RUNTIME_PATH . 'route.php', $this->buildRouteCache()); $output->writeln('Succeed!'); } diff --git a/thinkphp/library/think/console/command/optimize/Schema.php b/thinkphp/library/think/console/command/optimize/Schema.php index 27eb9dbb..33534240 100644 --- a/thinkphp/library/think/console/command/optimize/Schema.php +++ b/thinkphp/library/think/console/command/optimize/Schema.php @@ -44,7 +44,8 @@ class Schema extends Command if ($input->hasOption('module')) { $module = $input->getOption('module'); // 读取模型 - $list = scandir(APP_PATH . $module . DS . 'model'); + $path = APP_PATH . $module . DS . 'model'; + $list = is_dir($path) ? scandir($path) : []; $app = App::$namespace; foreach ($list as $file) { if (0 === strpos($file, '.')) { @@ -66,7 +67,8 @@ class Schema extends Command $tables = Db::connect($config)->getTables($dbName); } elseif (!\think\Config::get('app_multi_module')) { $app = App::$namespace; - $list = scandir(APP_PATH . 'model'); + $path = APP_PATH . 'model'; + $list = is_dir($path) ? scandir($path) : []; foreach ($list as $file) { if (0 === strpos($file, '.')) { continue; diff --git a/thinkphp/library/think/console/output/Descriptor.php b/thinkphp/library/think/console/output/Descriptor.php index 6d98d53c..23dc6481 100644 --- a/thinkphp/library/think/console/output/Descriptor.php +++ b/thinkphp/library/think/console/output/Descriptor.php @@ -69,7 +69,7 @@ class Descriptor * 描述参数 * @param InputArgument $argument * @param array $options - * @return string|mixed + * @return void */ protected function describeInputArgument(InputArgument $argument, array $options = []) { @@ -93,7 +93,7 @@ class Descriptor * 描述选项 * @param InputOption $option * @param array $options - * @return string|mixed + * @return void */ protected function describeInputOption(InputOption $option, array $options = []) { @@ -128,7 +128,7 @@ class Descriptor * 描述输入 * @param InputDefinition $definition * @param array $options - * @return string|mixed + * @return void */ protected function describeInputDefinition(InputDefinition $definition, array $options = []) { @@ -173,7 +173,7 @@ class Descriptor * 描述指令 * @param Command $command * @param array $options - * @return string|mixed + * @return void */ protected function describeCommand(Command $command, array $options = []) { @@ -208,7 +208,7 @@ class Descriptor * 描述控制台 * @param Console $console * @param array $options - * @return string|mixed + * @return void */ protected function describeConsole(Console $console, array $options = []) { diff --git a/thinkphp/library/think/controller/Rest.php b/thinkphp/library/think/controller/Rest.php index 8c5911df..43ab2f62 100644 --- a/thinkphp/library/think/controller/Rest.php +++ b/thinkphp/library/think/controller/Rest.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -43,7 +43,7 @@ abstract class Rest if ('' == $ext) { // 自动检测资源类型 $this->type = $request->type(); - } elseif (!preg_match('/\(' . $this->restTypeList . '\)$/i', $ext)) { + } elseif (!preg_match('/(' . $this->restTypeList . ')$/i', $ext)) { // 资源类型非法 则用默认资源类型访问 $this->type = $this->restDefaultType; } else { @@ -51,7 +51,7 @@ abstract class Rest } // 请求方式检测 $method = strtolower($request->method()); - if (false === stripos($this->restMethodList, $method)) { + if (!preg_match('/(' . $this->restMethodList . ')$/i', $method)) { // 请求方式非法 则用默认请求方法 $method = $this->restDefaultMethod; } diff --git a/thinkphp/library/think/db/Builder.php b/thinkphp/library/think/db/Builder.php index 23f88836..58b45aa8 100644 --- a/thinkphp/library/think/db/Builder.php +++ b/thinkphp/library/think/db/Builder.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -22,10 +22,10 @@ abstract class Builder protected $query; // 数据库表达式 - protected $exp = ['eq' => '=', 'neq' => '<>', 'gt' => '>', 'egt' => '>=', 'lt' => '<', 'elt' => '<=', 'notlike' => 'NOT LIKE', 'like' => 'LIKE', 'in' => 'IN', 'exp' => 'EXP', 'notin' => 'NOT IN', 'not in' => 'NOT IN', 'between' => 'BETWEEN', 'not between' => 'NOT BETWEEN', 'notbetween' => 'NOT BETWEEN', 'exists' => 'EXISTS', 'notexists' => 'NOT EXISTS', 'not exists' => 'NOT EXISTS', 'null' => 'NULL', 'notnull' => 'NOT NULL', 'not null' => 'NOT NULL', '> time' => '> TIME', '< time' => '< TIME', '>= time' => '>= TIME', '<= time' => '<= TIME', 'between time' => 'BETWEEN TIME', 'not between time' => 'NOT BETWEEN TIME', 'notbetween time' => 'NOT BETWEEN TIME']; + protected $exp = ['eq' => '=', 'neq' => '<>', 'gt' => '>', 'egt' => '>=', 'lt' => '<', 'elt' => '<=', 'notlike' => 'NOT LIKE', 'not like' => 'NOT LIKE', 'like' => 'LIKE', 'in' => 'IN', 'exp' => 'EXP', 'notin' => 'NOT IN', 'not in' => 'NOT IN', 'between' => 'BETWEEN', 'not between' => 'NOT BETWEEN', 'notbetween' => 'NOT BETWEEN', 'exists' => 'EXISTS', 'notexists' => 'NOT EXISTS', 'not exists' => 'NOT EXISTS', 'null' => 'NULL', 'notnull' => 'NOT NULL', 'not null' => 'NOT NULL', '> time' => '> TIME', '< time' => '< TIME', '>= time' => '>= TIME', '<= time' => '<= TIME', 'between time' => 'BETWEEN TIME', 'not between time' => 'NOT BETWEEN TIME', 'notbetween time' => 'NOT BETWEEN TIME']; // SQL表达式 - protected $selectSql = 'SELECT%DISTINCT% %FIELD% FROM %TABLE%%FORCE%%JOIN%%WHERE%%GROUP%%HAVING%%ORDER%%LIMIT% %UNION%%LOCK%%COMMENT%'; + protected $selectSql = 'SELECT%DISTINCT% %FIELD% FROM %TABLE%%FORCE%%JOIN%%WHERE%%GROUP%%HAVING%%UNION%%ORDER%%LIMIT%%LOCK%%COMMENT%'; protected $insertSql = '%INSERT% INTO %TABLE% (%FIELD%) VALUES (%DATA%) %COMMENT%'; protected $insertAllSql = '%INSERT% INTO %TABLE% (%FIELD%) %DATA% %COMMENT%'; protected $updateSql = 'UPDATE %TABLE% SET %SET% %JOIN% %WHERE% %ORDER%%LIMIT% %LOCK%%COMMENT%'; @@ -46,7 +46,7 @@ abstract class Builder /** * 获取当前的连接对象实例 * @access public - * @return void + * @return Connection */ public function getConnection() { @@ -56,7 +56,7 @@ abstract class Builder /** * 获取当前的Query对象实例 * @access public - * @return void + * @return Query */ public function getQuery() { @@ -80,6 +80,7 @@ abstract class Builder * @param array $data 数据 * @param array $options 查询参数 * @return array + * @throws Exception */ protected function parseData($data, $options) { @@ -97,8 +98,15 @@ abstract class Builder $result = []; foreach ($data as $key => $val) { - $item = $this->parseKey($key, $options); - if (is_object($val) && method_exists($val, '__toString')) { + if ('*' != $options['field'] && !in_array($key, $fields, true)) { + continue; + } + + $item = $this->parseKey($key, $options, true); + if ($val instanceof Expression) { + $result[$item] = $val->getValue(); + continue; + } elseif (is_object($val) && method_exists($val, '__toString')) { // 对象数据写入 $val = $val->__toString(); } @@ -108,16 +116,25 @@ abstract class Builder } } elseif (is_null($val)) { $result[$item] = 'NULL'; - } elseif (isset($val[0]) && 'exp' == $val[0]) { - $result[$item] = $val[1]; + } elseif (is_array($val) && !empty($val)) { + switch (strtolower($val[0])) { + case 'inc': + $result[$item] = $item . '+' . floatval($val[1]); + break; + case 'dec': + $result[$item] = $item . '-' . floatval($val[1]); + break; + case 'exp': + throw new Exception('not support data:[' . $val[0] . ']'); + } } elseif (is_scalar($val)) { // 过滤非标量数据 if (0 === strpos($val, ':') && $this->query->isBind(substr($val, 1))) { $result[$item] = $val; } else { $key = str_replace('.', '_', $key); - $this->query->bind('__data__' . $key, $val, isset($bind[$key]) ? $bind[$key] : PDO::PARAM_STR); - $result[$item] = ':__data__' . $key; + $this->query->bind('data__' . $key, $val, isset($bind[$key]) ? $bind[$key] : PDO::PARAM_STR); + $result[$item] = ':data__' . $key; } } } @@ -131,7 +148,7 @@ abstract class Builder * @param array $options * @return string */ - protected function parseKey($key, $options = []) + protected function parseKey($key, $options = [], $strict = false) { return $key; } @@ -172,8 +189,10 @@ abstract class Builder // 支持 'field1'=>'field2' 这样的字段别名定义 $array = []; foreach ($fields as $key => $field) { - if (!is_numeric($key)) { - $array[] = $this->parseKey($key, $options) . ' AS ' . $this->parseKey($field, $options); + if ($field instanceof Expression) { + $array[] = $field->getValue(); + } elseif (!is_numeric($key)) { + $array[] = $this->parseKey($key, $options) . ' AS ' . $this->parseKey($field, $options, true); } else { $array[] = $this->parseKey($field, $options); } @@ -195,11 +214,8 @@ abstract class Builder $item = []; foreach ((array) $tables as $key => $table) { if (!is_numeric($key)) { - if (strpos($key, '@think')) { - $key = strstr($key, '@think', true); - } $key = $this->parseSqlTable($key); - $item[] = $this->parseKey($key) . ' ' . $this->parseKey($table); + $item[] = $this->parseKey($key) . ' ' . (isset($options['alias'][$table]) ? $this->parseKey($options['alias'][$table]) : $this->parseKey($table)); } else { $table = $this->parseSqlTable($table); if (isset($options['alias'][$table])) { @@ -255,7 +271,9 @@ abstract class Builder foreach ($where as $key => $val) { $str = []; foreach ($val as $field => $value) { - if ($value instanceof \Closure) { + if ($value instanceof Expression) { + $str[] = ' ' . $key . ' ( ' . $value->getValue() . ' )'; + } elseif ($value instanceof \Closure) { // 使用闭包查询 $query = new Query($this->connection); call_user_func_array($value, [ & $query]); @@ -296,11 +314,11 @@ abstract class Builder protected function parseWhereItem($field, $val, $rule = '', $options = [], $binds = [], $bindName = null) { // 字段分析 - $key = $field ? $this->parseKey($field, $options) : ''; + $key = $field ? $this->parseKey($field, $options, true) : ''; // 查询规则和条件 if (!is_array($val)) { - $val = ['=', $val]; + $val = is_null($val) ? ['null', ''] : ['=', $val]; } list($exp, $value) = $val; @@ -329,12 +347,19 @@ abstract class Builder throw new Exception('where express error:' . $exp); } } - $bindName = $bindName ?: 'where_' . str_replace(['.', '-'], '_', $field); + $bindName = $bindName ?: 'where_' . $rule . '_' . str_replace(['.', '-'], '_', $field); if (preg_match('/\W/', $bindName)) { // 处理带非单词字符的字段名 $bindName = md5($bindName); } + if ($value instanceof Expression) { + + } elseif (is_object($value) && method_exists($value, '__toString')) { + // 对象数据写入 + $value = $value->__toString(); + } + $bindType = isset($binds[$field]) ? $binds[$field] : PDO::PARAM_STR; if (is_scalar($value) && array_key_exists($field, $binds) && !in_array($exp, ['EXP', 'NOT NULL', 'NULL', 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN']) && strpos($exp, 'TIME') === false) { if (strpos($value, ':') !== 0 || !$this->query->isBind(substr($value, 1))) { @@ -367,7 +392,11 @@ abstract class Builder } } elseif ('EXP' == $exp) { // 表达式查询 - $whereStr .= '( ' . $key . ' ' . $value . ' )'; + if ($value instanceof Expression) { + $whereStr .= '( ' . $key . ' ' . $value->getValue() . ' )'; + } else { + throw new Exception('where express error:' . $exp); + } } elseif (in_array($exp, ['NOT NULL', 'NULL'])) { // NULL 查询 $whereStr .= $key . ' IS ' . $exp; @@ -380,11 +409,13 @@ abstract class Builder if (array_key_exists($field, $binds)) { $bind = []; $array = []; - foreach ($value as $k => $v) { - if ($this->query->isBind($bindName . '_in_' . $k)) { - $bindKey = $bindName . '_in_' . uniqid() . '_' . $k; + $i = 0; + foreach ($value as $v) { + $i++; + if ($this->query->isBind($bindName . '_in_' . $i)) { + $bindKey = $bindName . '_in_' . uniqid() . '_' . $i; } else { - $bindKey = $bindName . '_in_' . $k; + $bindKey = $bindName . '_in_' . $i; } $bind[$bindKey] = [$v, $bindType]; $array[] = ':' . $bindKey; @@ -483,6 +514,11 @@ abstract class Builder } } $bindName = $bindName ?: $key; + + if ($this->query->isBind($bindName)) { + $bindName .= '_' . str_replace('.', '_', uniqid('', true)); + } + $this->query->bind($bindName, $value, $bindType); return ':' . $bindName; } @@ -490,7 +526,7 @@ abstract class Builder /** * limit分析 * @access protected - * @param mixed $lmit + * @param mixed $limit * @return string */ protected function parseLimit($limit) @@ -513,7 +549,9 @@ abstract class Builder list($table, $type, $on) = $item; $condition = []; foreach ((array) $on as $val) { - if (strpos($val, '=')) { + if ($val instanceof Expression) { + $condition[] = $val->getValue(); + } elseif (strpos($val, '=')) { list($val1, $val2) = explode('=', $val, 2); $condition[] = $this->parseKey($val1, $options) . '=' . $this->parseKey($val2, $options); } else { @@ -537,24 +575,29 @@ abstract class Builder */ protected function parseOrder($order, $options = []) { - if (is_array($order)) { - $array = []; - foreach ($order as $key => $val) { + if (empty($order)) { + return ''; + } + + $array = []; + foreach ($order as $key => $val) { + if ($val instanceof Expression) { + $array[] = $val->getValue(); + } elseif ('[rand]' == $val) { + $array[] = $this->parseRand(); + } else { if (is_numeric($key)) { - if ('[rand]' == $val) { - $array[] = $this->parseRand(); - } elseif (false === strpos($val, '(')) { - $array[] = $this->parseKey($val, $options); - } else { - $array[] = $val; - } + list($key, $sort) = explode(' ', strpos($val, ' ') ? $val : $val . ' '); } else { - $sort = in_array(strtolower(trim($val)), ['asc', 'desc']) ? ' ' . $val : ''; - $array[] = $this->parseKey($key, $options) . ' ' . $sort; + $sort = $val; } + $sort = strtoupper($sort); + $sort = in_array($sort, ['ASC', 'DESC'], true) ? ' ' . $sort : ''; + $array[] = $this->parseKey($key, $options, true) . $sort; } - $order = implode(',', $array); } + $order = implode(',', $array); + return !empty($order) ? ' ORDER BY ' . $order : ''; } @@ -566,7 +609,7 @@ abstract class Builder */ protected function parseGroup($group) { - return !empty($group) ? ' GROUP BY ' . $group : ''; + return !empty($group) ? ' GROUP BY ' . $this->parseKey($group) : ''; } /** @@ -588,6 +631,9 @@ abstract class Builder */ protected function parseComment($comment) { + if (false !== strpos($comment, '*/')) { + $comment = strstr($comment, '*/', true); + } return !empty($comment) ? ' /* ' . $comment . ' */' : ''; } @@ -617,12 +663,12 @@ abstract class Builder unset($union['type']); foreach ($union as $u) { if ($u instanceof \Closure) { - $sql[] = $type . ' ' . $this->parseClosure($u, false); + $sql[] = $type . ' ' . $this->parseClosure($u); } elseif (is_string($u)) { - $sql[] = $type . ' ' . $this->parseSqlTable($u); + $sql[] = $type . ' ( ' . $this->parseSqlTable($u) . ' )'; } } - return implode(' ', $sql); + return ' ' . implode(' ', $sql); } /** @@ -637,22 +683,22 @@ abstract class Builder return ''; } - if (is_array($index)) { - $index = join(",", $index); - } - - return sprintf(" FORCE INDEX ( %s ) ", $index); + return sprintf(" FORCE INDEX ( %s ) ", is_array($index) ? implode(',', $index) : $index); } /** * 设置锁机制 * @access protected - * @param bool $locl + * @param bool|string $lock * @return string */ protected function parseLock($lock = false) { - return $lock ? ' FOR UPDATE ' : ''; + if (is_bool($lock)) { + return $lock ? ' FOR UPDATE ' : ''; + } elseif (is_string($lock)) { + return ' ' . trim($lock) . ' '; + } } /** @@ -721,8 +767,9 @@ abstract class Builder * @param array $options 表达式 * @param bool $replace 是否replace * @return string + * @throws Exception */ - public function insertAll($dataSet, $options, $replace = false) + public function insertAll($dataSet, $options = [], $replace = false) { // 获取合法的字段 if ('*' == $options['field']) { @@ -731,7 +778,7 @@ abstract class Builder $fields = $options['field']; } - foreach ($dataSet as &$data) { + foreach ($dataSet as $data) { foreach ($data as $key => $val) { if (!in_array($key, $fields, true)) { if ($options['strict']) { @@ -752,23 +799,29 @@ abstract class Builder } $value = array_values($data); $values[] = 'SELECT ' . implode(',', $value); + + if (!isset($insertFields)) { + $insertFields = array_keys($data); + } } - $fields = array_map([$this, 'parseKey'], array_keys(reset($dataSet))); - $sql = str_replace( + + foreach ($insertFields as $field) { + $fields[] = $this->parseKey($field, $options, true); + } + + return str_replace( ['%INSERT%', '%TABLE%', '%FIELD%', '%DATA%', '%COMMENT%'], [ $replace ? 'REPLACE' : 'INSERT', $this->parseTable($options['table'], $options), - implode(' , ', $fields), + implode(' , ', $insertFields), implode(' UNION ALL ', $values), $this->parseComment($options['comment']), ], $this->insertAllSql); - - return $sql; } /** - * 生成slectinsert SQL + * 生成select insert SQL * @access public * @param array $fields 数据 * @param string $table 数据表 @@ -789,7 +842,7 @@ abstract class Builder /** * 生成update SQL * @access public - * @param array $fields 数据 + * @param array $data 数据 * @param array $options 表达式 * @return string */ diff --git a/thinkphp/library/think/db/Connection.php b/thinkphp/library/think/db/Connection.php index fa773e51..578cc8f9 100644 --- a/thinkphp/library/think/db/Connection.php +++ b/thinkphp/library/think/db/Connection.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -90,6 +90,8 @@ abstract class Connection 'master_num' => 1, // 指定从服务器序号 'slave_no' => '', + // 模型写入后自动读取主服务器 + 'read_master' => false, // 是否严格检查字段是否存在 'fields_strict' => true, // 数据返回类型 @@ -338,8 +340,8 @@ abstract class Connection * @param bool $master 是否在主服务器读操作 * @param bool $pdo 是否返回PDO对象 * @return mixed - * @throws BindParamException * @throws PDOException + * @throws \Exception */ public function query($sql, $bind = [], $master = false, $pdo = false) { @@ -354,19 +356,14 @@ abstract class Connection $this->bind = $bind; } - // 释放前次的查询结果 - if (!empty($this->PDOStatement)) { - $this->free(); - } - Db::$queryTimes++; try { // 调试开始 $this->debug(true); + // 预处理 - if (empty($this->PDOStatement)) { - $this->PDOStatement = $this->linkID->prepare($sql); - } + $this->PDOStatement = $this->linkID->prepare($sql); + // 是否为存储过程调用 $procedure = in_array(strtolower(substr(trim($sql), 0, 4)), ['call', 'exec']); // 参数绑定 @@ -378,7 +375,7 @@ abstract class Connection // 执行查询 $this->PDOStatement->execute(); // 调试结束 - $this->debug(false); + $this->debug(false, '', $master); // 返回结果集 return $this->getResult($pdo, $procedure); } catch (\PDOException $e) { @@ -386,7 +383,12 @@ abstract class Connection return $this->close()->query($sql, $bind, $master, $pdo); } throw new PDOException($e, $this->config, $this->getLastsql()); - } catch (\ErrorException $e) { + } catch (\Throwable $e) { + if ($this->isBreak($e)) { + return $this->close()->query($sql, $bind, $master, $pdo); + } + throw $e; + } catch (\Exception $e) { if ($this->isBreak($e)) { return $this->close()->query($sql, $bind, $master, $pdo); } @@ -397,13 +399,14 @@ abstract class Connection /** * 执行语句 * @access public - * @param string $sql sql指令 - * @param array $bind 参数绑定 + * @param string $sql sql指令 + * @param array $bind 参数绑定 + * @param Query $query 查询对象 * @return int - * @throws BindParamException * @throws PDOException + * @throws \Exception */ - public function execute($sql, $bind = []) + public function execute($sql, $bind = [], Query $query = null) { $this->initConnect(true); if (!$this->linkID) { @@ -416,19 +419,14 @@ abstract class Connection $this->bind = $bind; } - //释放前次的查询结果 - if (!empty($this->PDOStatement) && $this->PDOStatement->queryString != $sql) { - $this->free(); - } - Db::$executeTimes++; try { // 调试开始 $this->debug(true); + // 预处理 - if (empty($this->PDOStatement)) { - $this->PDOStatement = $this->linkID->prepare($sql); - } + $this->PDOStatement = $this->linkID->prepare($sql); + // 是否为存储过程调用 $procedure = in_array(strtolower(substr(trim($sql), 0, 4)), ['call', 'exec']); // 参数绑定 @@ -440,18 +438,27 @@ abstract class Connection // 执行语句 $this->PDOStatement->execute(); // 调试结束 - $this->debug(false); + $this->debug(false, '', true); + + if ($query && !empty($this->config['deploy']) && !empty($this->config['read_master'])) { + $query->readMaster(); + } $this->numRows = $this->PDOStatement->rowCount(); return $this->numRows; } catch (\PDOException $e) { if ($this->isBreak($e)) { - return $this->close()->execute($sql, $bind); + return $this->close()->execute($sql, $bind, $query); } throw new PDOException($e, $this->config, $this->getLastsql()); - } catch (\ErrorException $e) { + } catch (\Throwable $e) { if ($this->isBreak($e)) { - return $this->close()->execute($sql, $bind); + return $this->close()->execute($sql, $bind, $query); + } + throw $e; + } catch (\Exception $e) { + if ($this->isBreak($e)) { + return $this->close()->execute($sql, $bind, $query); } throw $e; } @@ -466,6 +473,10 @@ abstract class Connection */ public function getRealSql($sql, array $bind = []) { + if (is_array($sql)) { + $sql = implode(';', $sql); + } + foreach ($bind as $key => $val) { $value = is_array($val) ? $val[0] : $val; $type = is_array($val) ? $val[1] : PDO::PARAM_STR; @@ -478,8 +489,8 @@ abstract class Connection $sql = is_numeric($key) ? substr_replace($sql, $value, strpos($sql, '?'), 1) : str_replace( - [':' . $key . ')', ':' . $key . ',', ':' . $key . ' '], - [$value . ')', $value . ',', $value . ' '], + [':' . $key . ')', ':' . $key . ',', ':' . $key . ' ', ':' . $key . PHP_EOL], + [$value . ')', $value . ',', $value . ' ', $value . PHP_EOL], $sql . ' '); } return rtrim($sql); @@ -552,7 +563,7 @@ abstract class Connection * @access protected * @param bool $pdo 是否返回PDOStatement * @param bool $procedure 是否存储过程 - * @return array + * @return PDOStatement|array */ protected function getResult($pdo = false, $procedure = false) { @@ -618,7 +629,8 @@ abstract class Connection /** * 启动事务 * @access public - * @return void + * @return bool|mixed + * @throws \Exception */ public function startTrans() { @@ -637,13 +649,15 @@ abstract class Connection ); } - } catch (\PDOException $e) { + } catch (\Exception $e) { if ($this->isBreak($e)) { + --$this->transTimes; return $this->close()->startTrans(); } throw $e; - } catch (\ErrorException $e) { + } catch (\Error $e) { if ($this->isBreak($e)) { + --$this->transTimes; return $this->close()->startTrans(); } throw $e; @@ -724,7 +738,7 @@ abstract class Connection * @param array $sqlArray SQL批处理指令 * @return boolean */ - public function batchQuery($sqlArray = []) + public function batchQuery($sqlArray = [], $bind = [], Query $query = null) { if (!is_array($sqlArray)) { return false; @@ -733,7 +747,7 @@ abstract class Connection $this->startTrans(); try { foreach ($sqlArray as $sql) { - $this->execute($sql); + $this->execute($sql, $bind, $query); } // 提交事务 $this->commit(); @@ -741,6 +755,7 @@ abstract class Connection $this->rollback(); throw $e; } + return true; } @@ -776,13 +791,15 @@ abstract class Connection $this->linkWrite = null; $this->linkRead = null; $this->links = []; + // 释放查询 + $this->free(); return $this; } /** * 是否断线 * @access protected - * @param \PDOException $e 异常对象 + * @param \PDOException|\Exception $e 异常对象 * @return bool */ protected function isBreak($e) @@ -802,6 +819,7 @@ abstract class Connection 'SSL connection has been closed unexpectedly', 'Error writing data to the connection', 'Resource deadlock avoided', + 'failed with errno', ]; $error = $e->getMessage(); @@ -882,9 +900,10 @@ abstract class Connection * @access protected * @param boolean $start 调试开始标记 true 开始 false 结束 * @param string $sql 执行的SQL语句 留空自动获取 + * @param boolean $master 主从标记 * @return void */ - protected function debug($start, $sql = '') + protected function debug($start, $sql = '', $master = false) { if (!empty($this->config['debug'])) { // 开启数据库调试模式 @@ -901,7 +920,7 @@ abstract class Connection $result = $this->getExplain($sql); } // SQL监听 - $this->trigger($sql, $runtime, $result); + $this->trigger($sql, $runtime, $result, $master); } } } @@ -923,19 +942,27 @@ abstract class Connection * @param string $sql SQL语句 * @param float $runtime SQL运行时间 * @param mixed $explain SQL分析 - * @return bool + * @param bool $master 主从标记 + * @return void */ - protected function trigger($sql, $runtime, $explain = []) + protected function trigger($sql, $runtime, $explain = [], $master = false) { if (!empty(self::$event)) { foreach (self::$event as $callback) { if (is_callable($callback)) { - call_user_func_array($callback, [$sql, $runtime, $explain]); + call_user_func_array($callback, [$sql, $runtime, $explain, $master]); } } } else { // 未注册监听则记录到日志中 - Log::record('[ SQL ] ' . $sql . ' [ RunTime:' . $runtime . 's ]', 'sql'); + if ($this->config['deploy']) { + // 分布式记录当前操作的主从 + $master = $master ? 'master|' : 'slave|'; + } else { + $master = ''; + } + + Log::record('[ SQL ] ' . $sql . ' [ ' . $master . 'RunTime:' . $runtime . 's ]', 'sql'); if (!empty($explain)) { Log::record('[ EXPLAIN : ' . var_export($explain, true) . ' ]', 'sql'); } diff --git a/thinkphp/library/think/db/Expression.php b/thinkphp/library/think/db/Expression.php new file mode 100644 index 00000000..f1b92abd --- /dev/null +++ b/thinkphp/library/think/db/Expression.php @@ -0,0 +1,48 @@ + +// +---------------------------------------------------------------------- + +namespace think\db; + +class Expression +{ + /** + * 查询表达式 + * + * @var string + */ + protected $value; + + /** + * 创建一个查询表达式 + * + * @param string $value + * @return void + */ + public function __construct($value) + { + $this->value = $value; + } + + /** + * 获取表达式 + * + * @return string + */ + public function getValue() + { + return $this->value; + } + + public function __toString() + { + return (string) $this->value; + } +} diff --git a/thinkphp/library/think/db/Query.php b/thinkphp/library/think/db/Query.php index a8722a1a..ac4adea1 100644 --- a/thinkphp/library/think/db/Query.php +++ b/thinkphp/library/think/db/Query.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -12,6 +12,7 @@ namespace think\db; use PDO; +use think\App; use think\Cache; use think\Collection; use think\Config; @@ -52,14 +53,16 @@ class Query protected static $info = []; // 回调事件 private static $event = []; + // 读取主库 + protected static $readMaster = []; /** * 构造函数 * @access public * @param Connection $connection 数据库对象实例 - * @param string $model 模型名 + * @param Model $model 模型对象 */ - public function __construct(Connection $connection = null, $model = '') + public function __construct(Connection $connection = null, $model = null) { $this->connection = $connection ?: Db::connect([], true); $this->prefix = $this->connection->getConfig('prefix'); @@ -89,6 +92,13 @@ class Query $name = Loader::parseName(substr($method, 10)); $where[$name] = $args[0]; return $this->where($where)->value($args[1]); + } elseif ($this->model && method_exists($this->model, 'scope' . $method)) { + // 动态调用命名范围 + $method = 'scope' . $method; + array_unshift($args, $this); + + call_user_func_array([$this->model, $method], $args); + return $this; } else { throw new Exception('method not exist:' . __CLASS__ . '->' . $method); } @@ -114,6 +124,7 @@ class Query { $this->connection = Db::connect($config); $this->setBuilder(); + $this->prefix = $this->connection->getConfig('prefix'); return $this; } @@ -129,15 +140,34 @@ class Query } /** - * 获取当前的模型对象名 + * 获取当前的模型对象实例 * @access public - * @return string + * @return Model|null */ public function getModel() { return $this->model; } + /** + * 设置后续从主库读取数据 + * @access public + * @param bool $allTable + * @return void + */ + public function readMaster($allTable = false) + { + if ($allTable) { + $table = '*'; + } else { + $table = isset($this->options['table']) ? $this->options['table'] : $this->getTable(); + } + + static::$readMaster[$table] = true; + + return $this; + } + /** * 获取当前的builder实例对象 * @access public @@ -236,7 +266,7 @@ class Query */ public function execute($sql, $bind = []) { - return $this->connection->execute($sql, $bind); + return $this->connection->execute($sql, $bind, $this); } /** @@ -310,9 +340,9 @@ class Query * @param array $sql SQL批处理指令 * @return boolean */ - public function batchQuery($sql = []) + public function batchQuery($sql = [], $bind = []) { - return $this->connection->batchQuery($sql); + return $this->connection->batchQuery($sql, $bind); } /** @@ -401,7 +431,7 @@ class Query if (empty($this->options['table'])) { $this->options['table'] = $this->getTable(); } - $key = is_string($cache['key']) ? $cache['key'] : md5($field . serialize($this->options) . serialize($this->bind)); + $key = is_string($cache['key']) ? $cache['key'] : md5($this->connection->getConfig('database') . '.' . $field . serialize($this->options) . serialize($this->bind)); $result = Cache::get($key); } if (false === $result) { @@ -413,11 +443,13 @@ class Query // 返回SQL语句 return $pdo; } + $result = $pdo->fetchColumn(); if ($force) { - $result = is_numeric($result) ? $result + 0 : $result; + $result = (float) $result; } - if (isset($cache)) { + + if (isset($cache) && false !== $result) { // 缓存数据 $this->cacheData($key, $result, $cache); } @@ -444,7 +476,7 @@ class Query if (empty($this->options['table'])) { $this->options['table'] = $this->getTable(); } - $guid = is_string($cache['key']) ? $cache['key'] : md5($field . serialize($this->options) . serialize($this->bind)); + $guid = is_string($cache['key']) ? $cache['key'] : md5($this->connection->getConfig('database') . '.' . $field . serialize($this->options) . serialize($this->bind)); $result = Cache::get($guid); } if (false === $result) { @@ -507,13 +539,43 @@ class Query public function count($field = '*') { if (isset($this->options['group'])) { + if (!preg_match('/^[\w\.\*]+$/', $field)) { + throw new Exception('not support data:' . $field); + } // 支持GROUP $options = $this->getOptions(); $subSql = $this->options($options)->field('count(' . $field . ')')->bind($this->bind)->buildSql(); - return $this->table([$subSql => '_group_count_'])->value('COUNT(*) AS tp_count', 0, true); + + $count = $this->table([$subSql => '_group_count_'])->value('COUNT(*) AS tp_count', 0, true); + } else { + $count = $this->aggregate('COUNT', $field, true); + } + + return is_string($count) ? $count : (int) $count; + + } + + /** + * 聚合查询 + * @access public + * @param string $aggregate 聚合方法 + * @param string $field 字段名 + * @param bool $force 强制转为数字类型 + * @return mixed + */ + public function aggregate($aggregate, $field, $force = false) + { + if (0 === stripos($field, 'DISTINCT ')) { + list($distinct, $field) = explode(' ', $field); + } + + if (!preg_match('/^[\w\.\+\-\*]+$/', $field)) { + throw new Exception('not support data:' . $field); } - return $this->value('COUNT(' . $field . ') AS tp_count', 0, true); + $result = $this->value($aggregate . '(' . (!empty($distinct) ? 'DISTINCT ' : '') . $field . ') AS tp_' . strtolower($aggregate), 0, $force); + + return $result; } /** @@ -524,29 +586,31 @@ class Query */ public function sum($field) { - return $this->value('SUM(' . $field . ') AS tp_sum', 0, true); + return $this->aggregate('SUM', $field, true); } /** * MIN查询 * @access public * @param string $field 字段名 + * @param bool $force 强制转为数字类型 * @return mixed */ - public function min($field) + public function min($field, $force = true) { - return $this->value('MIN(' . $field . ') AS tp_min', 0, true); + return $this->aggregate('MIN', $field, $force); } /** * MAX查询 * @access public * @param string $field 字段名 + * @param bool $force 强制转为数字类型 * @return mixed */ - public function max($field) + public function max($field, $force = true) { - return $this->value('MAX(' . $field . ') AS tp_max', 0, true); + return $this->aggregate('MAX', $field, $force); } /** @@ -557,7 +621,7 @@ class Query */ public function avg($field) { - return $this->value('AVG(' . $field . ') AS tp_avg', 0, true); + return $this->aggregate('AVG', $field, true); } /** @@ -604,7 +668,7 @@ class Query return true; } } - return $this->setField($field, ['exp', $field . '+' . $step]); + return $this->setField($field, ['inc', $step]); } /** @@ -632,8 +696,9 @@ class Query $this->options = []; return true; } + return $this->setField($field, ['inc', $step]); } - return $this->setField($field, ['exp', $field . '-' . $step]); + return $this->setField($field, ['dec', $step]); } /** @@ -701,7 +766,8 @@ class Query { // 传入的表名为数组 if (is_array($join)) { - list($table, $alias) = each($join); + $table = $join; + $alias = array_shift($join); } else { $join = trim($join); if (false !== strpos($join, '(')) { @@ -722,13 +788,9 @@ class Query $table = $this->getTable($table); } } - } - if (isset($alias)) { - if (isset($this->options['alias'][$table])) { - $table = $table . '@think' . uniqid(); + if (isset($alias) && $table != $alias) { + $table = [$table => $alias]; } - $table = [$table => $alias]; - $this->alias($table); } return $table; } @@ -766,8 +828,15 @@ class Query { if (empty($field)) { return $this; + } elseif ($field instanceof Expression) { + $this->options['field'][] = $field; + return $this; } + if (is_string($field)) { + if (preg_match('/[\<\'\"\(]/', $field)) { + return $this->fieldRaw($field); + } $field = array_map('trim', explode(',', $field)); } if (true === $field) { @@ -791,12 +860,30 @@ class Query } if (isset($this->options['field'])) { - $field = array_merge($this->options['field'], $field); + $field = array_merge((array) $this->options['field'], $field); } $this->options['field'] = array_unique($field); return $this; } + /** + * 表达式方式指定查询字段 + * @access public + * @param string $field 字段名 + * @param array $bind 参数绑定 + * @return $this + */ + public function fieldRaw($field, array $bind = []) + { + $this->options['field'][] = $this->raw($field); + + if ($bind) { + $this->bind($bind); + } + + return $this; + } + /** * 设置数据 * @access public @@ -825,7 +912,7 @@ class Query { $fields = is_string($field) ? explode(',', $field) : $field; foreach ($fields as $field) { - $this->data($field, ['exp', $field . '+' . $step]); + $this->data($field, ['inc', $step]); } return $this; } @@ -841,7 +928,7 @@ class Query { $fields = is_string($field) ? explode(',', $field) : $field; foreach ($fields as $field) { - $this->data($field, ['exp', $field . '-' . $step]); + $this->data($field, ['dec', $step]); } return $this; } @@ -855,25 +942,36 @@ class Query */ public function exp($field, $value) { - $this->data($field, ['exp', $value]); + $this->data($field, $this->raw($value)); return $this; } + /** + * 使用表达式设置数据 + * @access public + * @param mixed $value 表达式 + * @return Expression + */ + public function raw($value) + { + return new Expression($value); + } + /** * 指定JOIN查询字段 * @access public * @param string|array $table 数据表 * @param string|array $field 查询字段 - * @param string|array $on JOIN条件 + * @param mixed $on JOIN条件 * @param string $type JOIN类型 * @return $this */ public function view($join, $field = true, $on = null, $type = 'INNER') { $this->options['view'] = true; - if (is_array($join) && key($join) !== 0) { + if (is_array($join) && key($join) === 0) { foreach ($join as $key => $val) { - $this->view($key, $val[0], isset($val[1]) ? $val[1] : null, isset($val[2]) ? $val[2] : 'INNER'); + $this->view($val[0], $val[1], isset($val[2]) ? $val[2] : null, isset($val[3]) ? $val[3] : 'INNER'); } } else { $fields = []; @@ -972,6 +1070,37 @@ class Query return $this; } + /** + * 指定表达式查询条件 + * @access public + * @param string $where 查询条件 + * @param array $bind 参数绑定 + * @param string $logic 查询逻辑 and or xor + * @return $this + */ + public function whereRaw($where, $bind = [], $logic = 'AND') + { + $this->options['where'][$logic][] = $this->raw($where); + + if ($bind) { + $this->bind($bind); + } + + return $this; + } + + /** + * 指定表达式查询条件 OR + * @access public + * @param string $where 查询条件 + * @param array $bind 参数绑定 + * @return $this + */ + public function whereOrRaw($where, $bind = []) + { + return $this->whereRaw($where, $bind, 'OR'); + } + /** * 指定Null查询条件 * @access public @@ -981,7 +1110,7 @@ class Query */ public function whereNull($field, $logic = 'AND') { - $this->parseWhereExp($logic, $field, 'null', null); + $this->parseWhereExp($logic, $field, 'null', null, [], true); return $this; } @@ -994,7 +1123,7 @@ class Query */ public function whereNotNull($field, $logic = 'AND') { - $this->parseWhereExp($logic, $field, 'notnull', null); + $this->parseWhereExp($logic, $field, 'notnull', null, [], true); return $this; } @@ -1034,7 +1163,7 @@ class Query */ public function whereIn($field, $condition, $logic = 'AND') { - $this->parseWhereExp($logic, $field, 'in', $condition); + $this->parseWhereExp($logic, $field, 'in', $condition, [], true); return $this; } @@ -1048,7 +1177,7 @@ class Query */ public function whereNotIn($field, $condition, $logic = 'AND') { - $this->parseWhereExp($logic, $field, 'not in', $condition); + $this->parseWhereExp($logic, $field, 'not in', $condition, [], true); return $this; } @@ -1062,7 +1191,7 @@ class Query */ public function whereLike($field, $condition, $logic = 'AND') { - $this->parseWhereExp($logic, $field, 'like', $condition); + $this->parseWhereExp($logic, $field, 'like', $condition, [], true); return $this; } @@ -1076,7 +1205,7 @@ class Query */ public function whereNotLike($field, $condition, $logic = 'AND') { - $this->parseWhereExp($logic, $field, 'not like', $condition); + $this->parseWhereExp($logic, $field, 'not like', $condition, [], true); return $this; } @@ -1090,7 +1219,7 @@ class Query */ public function whereBetween($field, $condition, $logic = 'AND') { - $this->parseWhereExp($logic, $field, 'between', $condition); + $this->parseWhereExp($logic, $field, 'between', $condition, [], true); return $this; } @@ -1104,7 +1233,7 @@ class Query */ public function whereNotBetween($field, $condition, $logic = 'AND') { - $this->parseWhereExp($logic, $field, 'not between', $condition); + $this->parseWhereExp($logic, $field, 'not between', $condition, [], true); return $this; } @@ -1118,7 +1247,7 @@ class Query */ public function whereExp($field, $condition, $logic = 'AND') { - $this->parseWhereExp($logic, $field, 'exp', $condition); + $this->parseWhereExp($logic, $field, 'exp', $this->raw($condition), [], true); return $this; } @@ -1145,9 +1274,10 @@ class Query * @param mixed $op 查询表达式 * @param mixed $condition 查询条件 * @param array $param 查询参数 + * @param bool $strict 严格模式 * @return void */ - protected function parseWhereExp($logic, $field, $op, $condition, $param = []) + protected function parseWhereExp($logic, $field, $op, $condition, $param = [], $strict = false) { $logic = strtoupper($logic); if ($field instanceof \Closure) { @@ -1158,8 +1288,17 @@ class Query if (is_string($field) && !empty($this->options['via']) && !strpos($field, '.')) { $field = $this->options['via'] . '.' . $field; } - if (is_string($field) && preg_match('/[,=\>\<\'\"\(\s]/', $field)) { - $where[] = ['exp', $field]; + + if ($field instanceof Expression) { + return $this->whereRaw($field, is_array($op) ? $op : []); + } elseif ($strict) { + // 使用严格模式查询 + $where[$field] = [$op, $condition]; + + // 记录一个字段多次查询条件 + $this->options['multi'][$logic][$field][] = $where[$field]; + } elseif (is_string($field) && preg_match('/[,=\>\<\'\"\(\s]/', $field)) { + $where[] = ['exp', $this->raw($field)]; if (is_array($op)) { // 参数绑定 $this->bind($op); @@ -1180,23 +1319,28 @@ class Query $where[$field] = $param; } elseif (in_array(strtolower($op), ['null', 'notnull', 'not null'])) { // null查询 - $where[$field] = [$op, '']; + $where[$field] = [$op, '']; + $this->options['multi'][$logic][$field][] = $where[$field]; } elseif (is_null($condition)) { // 字段相等查询 $where[$field] = ['eq', $op]; - if ('AND' != $logic) { - $this->options['multi'][$logic][$field][] = $where[$field]; - } + + $this->options['multi'][$logic][$field][] = $where[$field]; } else { - $where[$field] = [$op, $condition, isset($param[2]) ? $param[2] : null]; - if ('exp' == strtolower($op) && isset($param[2]) && is_array($param[2])) { + if ('exp' == strtolower($op)) { + $where[$field] = ['exp', $this->raw($condition)]; // 参数绑定 - $this->bind($param[2]); + if (isset($param[2]) && is_array($param[2])) { + $this->bind($param[2]); + } + } else { + $where[$field] = [$op, $condition]; } // 记录一个字段多次查询条件 $this->options['multi'][$logic][$field][] = $where[$field]; } + if (!empty($where)) { if (!isset($this->options['where'][$logic])) { $this->options['where'][$logic] = []; @@ -1238,6 +1382,7 @@ class Query $logic = strtoupper($logic); if (isset($this->options['where'][$logic][$field])) { unset($this->options['where'][$logic][$field]); + unset($this->options['multi'][$logic][$field]); } return $this; } @@ -1413,49 +1558,78 @@ class Query */ public function order($field, $order = null) { - if (!empty($field)) { - if (is_string($field)) { - if (!empty($this->options['via'])) { - $field = $this->options['via'] . '.' . $field; - } - $field = empty($order) ? $field : [$field => $order]; - } elseif (!empty($this->options['via'])) { - foreach ($field as $key => $val) { - if (is_numeric($key)) { - $field[$key] = $this->options['via'] . '.' . $val; - } else { - $field[$this->options['via'] . '.' . $key] = $val; - unset($field[$key]); - } - } - } - if (!isset($this->options['order'])) { - $this->options['order'] = []; + if (empty($field)) { + return $this; + } elseif ($field instanceof Expression) { + $this->options['order'][] = $field; + return $this; + } + + if (is_string($field)) { + if (!empty($this->options['via'])) { + $field = $this->options['via'] . '.' . $field; } - if (is_array($field)) { - $this->options['order'] = array_merge($this->options['order'], $field); + if (strpos($field, ',')) { + $field = array_map('trim', explode(',', $field)); } else { - $this->options['order'][] = $field; + $field = empty($order) ? $field : [$field => $order]; } + } elseif (!empty($this->options['via'])) { + foreach ($field as $key => $val) { + if (is_numeric($key)) { + $field[$key] = $this->options['via'] . '.' . $val; + } else { + $field[$this->options['via'] . '.' . $key] = $val; + unset($field[$key]); + } + } + } + if (!isset($this->options['order'])) { + $this->options['order'] = []; + } + if (is_array($field)) { + $this->options['order'] = array_merge($this->options['order'], $field); + } else { + $this->options['order'][] = $field; } + + return $this; + } + + /** + * 表达式方式指定Field排序 + * @access public + * @param string $field 排序字段 + * @param array $bind 参数绑定 + * @return $this + */ + public function orderRaw($field, array $bind = []) + { + $this->options['order'][] = $this->raw($field); + + if ($bind) { + $this->bind($bind); + } + return $this; } /** * 查询缓存 * @access public - * @param mixed $key 缓存key - * @param integer $expire 缓存有效期 - * @param string $tag 缓存标签 + * @param mixed $key 缓存key + * @param integer|\DateTime $expire 缓存有效期 + * @param string $tag 缓存标签 * @return $this */ public function cache($key = true, $expire = null, $tag = null) { // 增加快捷调用方式 cache(10) 等同于 cache(true, 10) - if (is_numeric($key) && is_null($expire)) { + if ($key instanceof \DateTime || (is_numeric($key) && is_null($expire))) { $expire = $key; $key = true; } + if (false !== $key) { $this->options['cache'] = ['key' => $key, 'expire' => $expire, 'tag' => $tag]; } @@ -1489,7 +1663,7 @@ class Query /** * 指定查询lock * @access public - * @param boolean $lock 是否lock + * @param bool|string $lock 是否lock * @return $this */ public function lock($lock = false) @@ -1521,7 +1695,12 @@ class Query { if (is_array($alias)) { foreach ($alias as $key => $val) { - $this->options['alias'][$key] = $val; + if (false !== strpos($key, '__')) { + $table = $this->parseSqlTable($key); + } else { + $table = $key; + } + $this->options['alias'][$table] = $val; } } else { if (isset($this->options['table'])) { @@ -1649,46 +1828,49 @@ class Query * 查询日期或者时间 * @access public * @param string $field 日期字段名 - * @param string $op 比较运算符或者表达式 + * @param string|array $op 比较运算符或者表达式 * @param string|array $range 比较范围 * @return $this */ public function whereTime($field, $op, $range = null) { if (is_null($range)) { - // 使用日期表达式 - $date = getdate(); - switch (strtolower($op)) { - case 'today': - case 'd': - $range = ['today', 'tomorrow']; - break; - case 'week': - case 'w': - $range = 'this week 00:00:00'; - break; - case 'month': - case 'm': - $range = mktime(0, 0, 0, $date['mon'], 1, $date['year']); - break; - case 'year': - case 'y': - $range = mktime(0, 0, 0, 1, 1, $date['year']); - break; - case 'yesterday': - $range = ['yesterday', 'today']; - break; - case 'last week': - $range = ['last week 00:00:00', 'this week 00:00:00']; - break; - case 'last month': - $range = [date('y-m-01', strtotime('-1 month')), mktime(0, 0, 0, $date['mon'], 1, $date['year'])]; - break; - case 'last year': - $range = [mktime(0, 0, 0, 1, 1, $date['year'] - 1), mktime(0, 0, 0, 1, 1, $date['year'])]; - break; - default: - $range = $op; + if (is_array($op)) { + $range = $op; + } else { + // 使用日期表达式 + switch (strtolower($op)) { + case 'today': + case 'd': + $range = ['today', 'tomorrow']; + break; + case 'week': + case 'w': + $range = ['this week 00:00:00', 'next week 00:00:00']; + break; + case 'month': + case 'm': + $range = ['first Day of this month 00:00:00', 'first Day of next month 00:00:00']; + break; + case 'year': + case 'y': + $range = ['this year 1/1', 'next year 1/1']; + break; + case 'yesterday': + $range = ['yesterday', 'today']; + break; + case 'last week': + $range = ['last week 00:00:00', 'this week 00:00:00']; + break; + case 'last month': + $range = ['first Day of last month 00:00:00', 'first Day of this month 00:00:00']; + break; + case 'last year': + $range = ['last year 1/1', 'this year 1/1']; + break; + default: + $range = $op; + } } $op = is_array($range) ? 'between' : '>'; } @@ -1733,7 +1915,7 @@ class Query $schema = $guid; } // 读取缓存 - if (is_file(RUNTIME_PATH . 'schema/' . $schema . '.php')) { + if (!App::$debug && is_file(RUNTIME_PATH . 'schema/' . $schema . '.php')) { $info = include RUNTIME_PATH . 'schema/' . $schema . '.php'; } else { $info = $this->connection->getFields($guid); @@ -1808,7 +1990,9 @@ class Query */ protected function getFieldBindType($type) { - if (preg_match('/(int|double|float|decimal|real|numeric|serial|bit)/is', $type)) { + if (0 === strpos($type, 'set') || 0 === strpos($type, 'enum')) { + $bind = PDO::PARAM_STR; + } elseif (preg_match('/(int|double|float|decimal|real|numeric|serial|bit)/is', $type)) { $bind = PDO::PARAM_INT; } elseif (preg_match('/bool/is', $type)) { $bind = PDO::PARAM_BOOL; @@ -1890,11 +2074,10 @@ class Query $with = explode(',', $with); } - $first = true; - $currentModel = $this->model; + $first = true; /** @var Model $class */ - $class = new $currentModel; + $class = $this->model; foreach ($with as $key => $relation) { $subRelation = ''; $closure = false; @@ -1947,14 +2130,23 @@ class Query $this->field('*'); } foreach ($relations as $key => $relation) { - $closure = false; + $closure = $name = null; if ($relation instanceof \Closure) { $closure = $relation; $relation = $key; + } elseif (!is_int($key)) { + $name = $relation; + $relation = $key; } $relation = Loader::parseName($relation, 1, false); - $count = '(' . (new $this->model)->$relation()->getRelationCountQuery($closure) . ')'; - $this->field([$count => Loader::parseName($relation) . '_count']); + + $count = '(' . $this->model->$relation()->getRelationCountQuery($closure, $name) . ')'; + + if (empty($name)) { + $name = Loader::parseName($relation) . '_count'; + } + + $this->field([$count => $name]); } } return $this; @@ -2080,7 +2272,7 @@ class Query } // 执行操作 - $result = $this->execute($sql, $bind); + $result = 0 === $sql ? 0 : $this->execute($sql, $bind, $this); if ($result) { $sequence = $sequence ?: (isset($options['sequence']) ? $options['sequence'] : null); $lastInsId = $this->getLastInsID($sequence); @@ -2116,27 +2308,40 @@ class Query /** * 批量插入记录 * @access public - * @param mixed $dataSet 数据集 - * @param boolean $replace 是否replace + * @param mixed $dataSet 数据集 + * @param boolean $replace 是否replace + * @param integer $limit 每次写入数据限制 * @return integer|string */ - public function insertAll(array $dataSet, $replace = false) + public function insertAll(array $dataSet, $replace = false, $limit = null) { // 分析查询表达式 $options = $this->parseExpress(); if (!is_array(reset($dataSet))) { return false; } + // 生成SQL语句 - $sql = $this->builder->insertAll($dataSet, $options, $replace); + if (is_null($limit)) { + $sql = $this->builder->insertAll($dataSet, $options, $replace); + } else { + $array = array_chunk($dataSet, $limit, true); + foreach ($array as $item) { + $sql[] = $this->builder->insertAll($item, $options, $replace); + } + } + // 获取参数绑定 $bind = $this->getBind(); if ($options['fetch_sql']) { // 获取实际执行的SQL语句 return $this->connection->getRealSql($sql, $bind); + } elseif (is_array($sql)) { + // 执行操作 + return $this->batchQuery($sql, $bind, $this); } else { // 执行操作 - return $this->execute($sql, $bind); + return $this->execute($sql, $bind, $this); } } @@ -2162,7 +2367,7 @@ class Query return $this->connection->getRealSql($sql, $bind); } else { // 执行操作 - return $this->execute($sql, $bind); + return $this->execute($sql, $bind, $this); } } @@ -2229,7 +2434,7 @@ class Query Cache::clear($options['cache']['tag']); } // 执行操作 - $result = '' == $sql ? 0 : $this->execute($sql, $bind); + $result = '' == $sql ? 0 : $this->execute($sql, $bind, $this); if ($result) { if (is_string($pk) && isset($where[$pk])) { $data[$pk] = $where[$pk]; @@ -2298,10 +2503,10 @@ class Query // 判断查询缓存 $cache = $options['cache']; unset($options['cache']); - $key = is_string($cache['key']) ? $cache['key'] : md5(serialize($options) . serialize($this->bind)); + $key = is_string($cache['key']) ? $cache['key'] : md5($this->connection->getConfig('database') . '.' . serialize($options) . serialize($this->bind)); $resultSet = Cache::get($key); } - if (!$resultSet) { + if (false === $resultSet) { // 生成查询SQL $sql = $this->builder->select($options); // 获取参数绑定 @@ -2323,7 +2528,7 @@ class Query } } - if (isset($cache) && $resultSet) { + if (isset($cache) && false !== $resultSet) { // 缓存数据集 $this->cacheData($key, $resultSet, $cache); } @@ -2332,11 +2537,10 @@ class Query // 数据列表读取后的处理 if (!empty($this->model)) { // 生成模型对象 - $modelName = $this->model; if (count($resultSet) > 0) { foreach ($resultSet as $key => $result) { - /** @var Model $result */ - $model = new $modelName($result); + /** @var Model $model */ + $model = $this->model->newInstance($result); $model->isUpdate(true); // 关联查询 @@ -2356,7 +2560,7 @@ class Query // 模型数据集转换 $resultSet = $model->toCollection($resultSet); } else { - $resultSet = (new $modelName)->toCollection($resultSet); + $resultSet = $this->model->toCollection($resultSet); } } elseif ('collection' == $this->connection->getConfig('resultset_type')) { // 返回Collection对象 @@ -2391,18 +2595,25 @@ class Query * @param mixed $value 缓存数据 * @param array $options 缓存参数 * @param array $bind 绑定参数 + * @return string */ protected function getCacheKey($value, $options, $bind = []) { if (is_scalar($value)) { $data = $value; - } elseif (is_array($value) && 'eq' == strtolower($value[0])) { + } elseif (is_array($value) && is_string($value[0]) && 'eq' == strtolower($value[0])) { $data = $value[1]; } + $prefix = $this->connection->getConfig('database') . '.'; + if (isset($data)) { - return 'think:' . (is_array($options['table']) ? key($options['table']) : $options['table']) . '|' . $data; - } else { - return md5(serialize($options) . serialize($bind)); + return 'think:' . $prefix . (is_array($options['table']) ? key($options['table']) : $options['table']) . '|' . $data; + } + + try { + return md5($prefix . serialize($options) . serialize($bind)); + } catch (\Exception $e) { + throw new Exception('closure not support cache(true)'); } } @@ -2439,11 +2650,11 @@ class Query // 判断查询缓存 $cache = $options['cache']; if (true === $cache['key'] && !is_null($data) && !is_array($data)) { - $key = 'think:' . (is_array($options['table']) ? key($options['table']) : $options['table']) . '|' . $data; + $key = 'think:' . $this->connection->getConfig('database') . '.' . (is_array($options['table']) ? key($options['table']) : $options['table']) . '|' . $data; } elseif (is_string($cache['key'])) { $key = $cache['key']; } elseif (!isset($key)) { - $key = md5(serialize($options) . serialize($this->bind)); + $key = md5($this->connection->getConfig('database') . '.' . serialize($options) . serialize($this->bind)); } $result = Cache::get($key); } @@ -2491,8 +2702,7 @@ class Query if (!empty($result)) { if (!empty($this->model)) { // 返回模型对象 - $model = $this->model; - $result = new $model($result); + $result = $this->model->newInstance($result); $result->isUpdate(true, isset($options['where']['AND']) ? $options['where']['AND'] : null); // 关联查询 if (!empty($options['relation'])) { @@ -2523,7 +2733,8 @@ class Query protected function throwNotFound($options = []) { if (!empty($this->model)) { - throw new ModelNotFoundException('model data Not Found:' . $this->model, $this->model, $options); + $class = get_class($this->model); + throw new ModelNotFoundException('model data Not Found:' . $class, $class, $options); } else { $table = is_array($options['table']) ? key($options['table']) : $options['table']; throw new DataNotFoundException('table data not Found:' . $table, $table, $options); @@ -2564,44 +2775,61 @@ class Query * @param integer $count 每次处理的数据数量 * @param callable $callback 处理回调方法 * @param string $column 分批处理的字段名 + * @param string $order 排序规则 * @return boolean + * @throws \LogicException */ - public function chunk($count, $callback, $column = null) + public function chunk($count, $callback, $column = null, $order = 'asc') { $options = $this->getOptions(); - if (isset($options['table'])) { - $table = is_array($options['table']) ? key($options['table']) : $options['table']; - } else { - $table = ''; + if (empty($options['table'])) { + $options['table'] = $this->getTable(); } - $column = $column ?: $this->getPk($table); - $bind = $this->bind; - $resultSet = $this->limit($count)->order($column, 'asc')->select(); - if (strpos($column, '.')) { - list($alias, $key) = explode('.', $column); - } else { - $key = $column; + $column = $column ?: $this->getPk($options); + + if (isset($options['order'])) { + if (App::$debug) { + throw new \LogicException('chunk not support call order'); + } + unset($options['order']); } - if ($resultSet instanceof Collection) { - $resultSet = $resultSet->all(); + $bind = $this->bind; + if (is_array($column)) { + $times = 1; + $query = $this->options($options)->page($times, $count); + } else { + if (strpos($column, '.')) { + list($alias, $key) = explode('.', $column); + } else { + $key = $column; + } + $query = $this->options($options)->limit($count); } + $resultSet = $query->order($column, $order)->select(); + + while (count($resultSet) > 0) { + if ($resultSet instanceof Collection) { + $resultSet = $resultSet->all(); + } - while (!empty($resultSet)) { if (false === call_user_func($callback, $resultSet)) { return false; } - $end = end($resultSet); - $lastId = is_array($end) ? $end[$key] : $end->$key; - $resultSet = $this->options($options) - ->limit($count) - ->bind($bind) - ->where($column, '>', $lastId) - ->order($column, 'asc') - ->select(); - if ($resultSet instanceof Collection) { - $resultSet = $resultSet->all(); + + if (is_array($column)) { + $times++; + $query = $this->options($options)->page($times, $count); + } else { + $end = end($resultSet); + $lastId = is_array($end) ? $end[$key] : $end->getData($key); + $query = $this->options($options) + ->limit($count) + ->where($column, 'asc' == strtolower($order) ? '>' : '<', $lastId); } + + $resultSet = $query->bind($bind)->order($column, $order)->select(); } + return true; } @@ -2678,7 +2906,7 @@ class Query Cache::clear($options['cache']['tag']); } // 执行操作 - $result = $this->execute($sql, $bind); + $result = $this->execute($sql, $bind, $this); if ($result) { if (!is_array($data) && is_string($pk) && isset($key) && strpos($key, '|')) { list($a, $val) = explode('|', $key); @@ -2763,6 +2991,10 @@ class Query } } + if (isset(static::$readMaster['*']) || (is_string($options['table']) && isset(static::$readMaster[$options['table']]))) { + $options['master'] = true; + } + foreach (['join', 'union', 'group', 'having', 'limit', 'order', 'force', 'comment'] as $name) { if (!isset($options[$name])) { $options[$name] = ''; diff --git a/thinkphp/library/think/db/builder/Mysql.php b/thinkphp/library/think/db/builder/Mysql.php index 5bc9d03b..be2af714 100644 --- a/thinkphp/library/think/db/builder/Mysql.php +++ b/thinkphp/library/think/db/builder/Mysql.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -12,28 +12,93 @@ namespace think\db\builder; use think\db\Builder; +use think\Exception; /** * mysql数据库驱动 */ class Mysql extends Builder { - protected $updateSql = 'UPDATE %TABLE% %JOIN% SET %SET% %WHERE% %ORDER%%LIMIT% %LOCK%%COMMENT%'; + + protected $insertAllSql = '%INSERT% INTO %TABLE% (%FIELD%) VALUES %DATA% %COMMENT%'; + protected $updateSql = 'UPDATE %TABLE% %JOIN% SET %SET% %WHERE% %ORDER%%LIMIT% %LOCK%%COMMENT%'; + + /** + * 生成insertall SQL + * @access public + * @param array $dataSet 数据集 + * @param array $options 表达式 + * @param bool $replace 是否replace + * @return string + * @throws Exception + */ + public function insertAll($dataSet, $options = [], $replace = false) + { + // 获取合法的字段 + if ('*' == $options['field']) { + $fields = array_keys($this->query->getFieldsType($options['table'])); + } else { + $fields = $options['field']; + } + + foreach ($dataSet as $data) { + foreach ($data as $key => $val) { + if (!in_array($key, $fields, true)) { + if ($options['strict']) { + throw new Exception('fields not exists:[' . $key . ']'); + } + unset($data[$key]); + } elseif (is_null($val)) { + $data[$key] = 'NULL'; + } elseif (is_scalar($val)) { + $data[$key] = $this->parseValue($val, $key); + } elseif (is_object($val) && method_exists($val, '__toString')) { + // 对象数据写入 + $data[$key] = $val->__toString(); + } else { + // 过滤掉非标量数据 + unset($data[$key]); + } + } + $value = array_values($data); + $values[] = '( ' . implode(',', $value) . ' )'; + + if (!isset($insertFields)) { + $insertFields = array_map([$this, 'parseKey'], array_keys($data)); + } + } + + return str_replace( + ['%INSERT%', '%TABLE%', '%FIELD%', '%DATA%', '%COMMENT%'], + [ + $replace ? 'REPLACE' : 'INSERT', + $this->parseTable($options['table'], $options), + implode(' , ', $insertFields), + implode(' , ', $values), + $this->parseComment($options['comment']), + ], $this->insertAllSql); + } /** * 字段和表名处理 * @access protected - * @param string $key + * @param mixed $key * @param array $options * @return string */ - protected function parseKey($key, $options = []) + protected function parseKey($key, $options = [], $strict = false) { + if (is_numeric($key)) { + return $key; + } elseif ($key instanceof Expression) { + return $key->getValue(); + } + $key = trim($key); if (strpos($key, '$.') && false === strpos($key, '(')) { // JSON字段支持 list($field, $name) = explode('$.', $key); - $key = 'json_extract(' . $field . ', \'$.' . $name . '\')'; + return 'json_extract(' . $field . ', \'$.' . $name . '\')'; } elseif (strpos($key, '.') && !preg_match('/[,\'\"\(\)`\s]/', $key)) { list($table, $key) = explode('.', $key, 2); if ('__TABLE__' == $table) { @@ -43,7 +108,11 @@ class Mysql extends Builder $table = $options['alias'][$table]; } } - if (!preg_match('/[,\'\"\*\(\)`.\s]/', $key)) { + + if ($strict && !preg_match('/^[\w\.\*]+$/', $key)) { + throw new Exception('not support data:' . $key); + } + if ('*' != $key && ($strict || !preg_match('/[,\'\"\*\(\)`.\s]/', $key))) { $key = '`' . $key . '`'; } if (isset($table)) { diff --git a/thinkphp/library/think/db/builder/Pgsql.php b/thinkphp/library/think/db/builder/Pgsql.php index 5be0468a..acc22896 100644 --- a/thinkphp/library/think/db/builder/Pgsql.php +++ b/thinkphp/library/think/db/builder/Pgsql.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -18,6 +18,8 @@ use think\db\Builder; */ class Pgsql extends Builder { + protected $insertSql = 'INSERT INTO %TABLE% (%FIELD%) VALUES (%DATA%) %COMMENT%'; + protected $insertAllSql = 'INSERT INTO %TABLE% (%FIELD%) %DATA% %COMMENT%'; /** * limit分析 @@ -42,12 +44,18 @@ class Pgsql extends Builder /** * 字段和表名处理 * @access protected - * @param string $key + * @param mixed $key * @param array $options * @return string */ - protected function parseKey($key, $options = []) + protected function parseKey($key, $options = [], $strict = false) { + if (is_numeric($key)) { + return $key; + } elseif ($key instanceof Expression) { + return $key->getValue(); + } + $key = trim($key); if (strpos($key, '$.') && false === strpos($key, '(')) { // JSON字段支持 diff --git a/thinkphp/library/think/db/builder/Sqlite.php b/thinkphp/library/think/db/builder/Sqlite.php index 55d3abc4..c727f04b 100644 --- a/thinkphp/library/think/db/builder/Sqlite.php +++ b/thinkphp/library/think/db/builder/Sqlite.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -22,6 +22,7 @@ class Sqlite extends Builder /** * limit * @access public + * @param string $limit * @return string */ public function parseLimit($limit) @@ -51,12 +52,18 @@ class Sqlite extends Builder /** * 字段和表名处理 * @access protected - * @param string $key + * @param mixed $key * @param array $options * @return string */ - protected function parseKey($key, $options = []) + protected function parseKey($key, $options = [], $strict = false) { + if (is_numeric($key)) { + return $key; + } elseif ($key instanceof Expression) { + return $key->getValue(); + } + $key = trim($key); if (strpos($key, '.')) { list($table, $key) = explode('.', $key, 2); diff --git a/thinkphp/library/think/db/builder/Sqlsrv.php b/thinkphp/library/think/db/builder/Sqlsrv.php index 52629e73..dc425d9e 100644 --- a/thinkphp/library/think/db/builder/Sqlsrv.php +++ b/thinkphp/library/think/db/builder/Sqlsrv.php @@ -12,6 +12,7 @@ namespace think\db\builder; use think\db\Builder; +use think\db\Expression; /** * Sqlsrv数据库驱动 @@ -22,6 +23,8 @@ class Sqlsrv extends Builder protected $selectInsertSql = 'SELECT %DISTINCT% %FIELD% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%'; protected $updateSql = 'UPDATE %TABLE% SET %SET% FROM %TABLE% %JOIN% %WHERE% %LIMIT% %LOCK%%COMMENT%'; protected $deleteSql = 'DELETE FROM %TABLE% %USING% FROM %TABLE% %JOIN% %WHERE% %LIMIT% %LOCK%%COMMENT%'; + protected $insertSql = 'INSERT INTO %TABLE% (%FIELD%) VALUES (%DATA%) %COMMENT%'; + protected $insertAllSql = 'INSERT INTO %TABLE% (%FIELD%) %DATA% %COMMENT%'; /** * order分析 @@ -32,23 +35,29 @@ class Sqlsrv extends Builder */ protected function parseOrder($order, $options = []) { - if (is_array($order)) { - $array = []; - foreach ($order as $key => $val) { - if (is_numeric($key)) { - if (false === strpos($val, '(')) { - $array[] = $this->parseKey($val, $options); - } elseif ('[rand]' == $val) { - $array[] = $this->parseRand(); - } + if (empty($order)) { + return ' ORDER BY rand()'; + } + + $array = []; + foreach ($order as $key => $val) { + if ($val instanceof Expression) { + $array[] = $val->getValue(); + } elseif (is_numeric($key)) { + if (false === strpos($val, '(')) { + $array[] = $this->parseKey($val, $options); + } elseif ('[rand]' == $val) { + $array[] = $this->parseRand(); } else { - $sort = in_array(strtolower(trim($val)), ['asc', 'desc']) ? ' ' . $val : ''; - $array[] = $this->parseKey($key, $options) . ' ' . $sort; + $array[] = $val; } + } else { + $sort = in_array(strtolower(trim($val)), ['asc', 'desc'], true) ? ' ' . $val : ''; + $array[] = $this->parseKey($key, $options, true) . ' ' . $sort; } - $order = implode(',', $array); } - return !empty($order) ? ' ORDER BY ' . $order : ' ORDER BY rand()'; + + return ' ORDER BY ' . implode(',', $array); } /** @@ -64,12 +73,17 @@ class Sqlsrv extends Builder /** * 字段和表名处理 * @access protected - * @param string $key + * @param mixed $key * @param array $options * @return string */ - protected function parseKey($key, $options = []) + protected function parseKey($key, $options = [], $strict = false) { + if (is_numeric($key)) { + return $key; + } elseif ($key instanceof Expression) { + return $key->getValue(); + } $key = trim($key); if (strpos($key, '.') && !preg_match('/[,\'\"\(\)\[\s]/', $key)) { list($table, $key) = explode('.', $key, 2); @@ -80,7 +94,11 @@ class Sqlsrv extends Builder $table = $options['alias'][$table]; } } - if (!is_numeric($key) && !preg_match('/[,\'\"\*\(\)\[.\s]/', $key)) { + + if ($strict && !preg_match('/^[\w\.\*]+$/', $key)) { + throw new Exception('not support data:' . $key); + } + if ('*' != $key && ($strict || !preg_match('/[,\'\"\*\(\)\[.\s]/', $key))) { $key = '[' . $key . ']'; } if (isset($table)) { diff --git a/thinkphp/library/think/db/connector/Mysql.php b/thinkphp/library/think/db/connector/Mysql.php index 536125fd..be1a85ce 100644 --- a/thinkphp/library/think/db/connector/Mysql.php +++ b/thinkphp/library/think/db/connector/Mysql.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -31,12 +31,15 @@ class Mysql extends Connection */ protected function parseDsn($config) { - $dsn = 'mysql:dbname=' . $config['database'] . ';host=' . $config['hostname']; - if (!empty($config['hostport'])) { - $dsn .= ';port=' . $config['hostport']; - } elseif (!empty($config['socket'])) { - $dsn .= ';unix_socket=' . $config['socket']; + if (!empty($config['socket'])) { + $dsn = 'mysql:unix_socket=' . $config['socket']; + } elseif (!empty($config['hostport'])) { + $dsn = 'mysql:host=' . $config['hostname'] . ';port=' . $config['hostport']; + } else { + $dsn = 'mysql:host=' . $config['hostname']; } + $dsn .= ';dbname=' . $config['database']; + if (!empty($config['charset'])) { $dsn .= ';charset=' . $config['charset']; } diff --git a/thinkphp/library/think/db/connector/Pgsql.php b/thinkphp/library/think/db/connector/Pgsql.php index 761fbac4..bbcf5768 100644 --- a/thinkphp/library/think/db/connector/Pgsql.php +++ b/thinkphp/library/think/db/connector/Pgsql.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- diff --git a/thinkphp/library/think/db/connector/Sqlite.php b/thinkphp/library/think/db/connector/Sqlite.php index fd7f02b0..c4e3a724 100644 --- a/thinkphp/library/think/db/connector/Sqlite.php +++ b/thinkphp/library/think/db/connector/Sqlite.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- diff --git a/thinkphp/library/think/db/connector/Sqlsrv.php b/thinkphp/library/think/db/connector/Sqlsrv.php index 08ad45e2..35c66005 100644 --- a/thinkphp/library/think/db/connector/Sqlsrv.php +++ b/thinkphp/library/think/db/connector/Sqlsrv.php @@ -50,7 +50,10 @@ class Sqlsrv extends Connection public function getFields($tableName) { list($tableName) = explode(' ', $tableName); - $sql = "SELECT column_name, data_type, column_default, is_nullable + $tableNames = explode('.', $tableName); + $tableName = isset($tableNames[1]) ? $tableNames[1] : $tableNames[0]; + + $sql = "SELECT column_name, data_type, column_default, is_nullable FROM information_schema.tables AS t JOIN information_schema.columns AS c ON t.table_catalog = c.table_catalog diff --git a/thinkphp/library/think/db/exception/BindParamException.php b/thinkphp/library/think/db/exception/BindParamException.php index d0e2387b..4ed19546 100644 --- a/thinkphp/library/think/db/exception/BindParamException.php +++ b/thinkphp/library/think/db/exception/BindParamException.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- diff --git a/thinkphp/library/think/db/exception/DataNotFoundException.php b/thinkphp/library/think/db/exception/DataNotFoundException.php index e399b063..f2542ac6 100644 --- a/thinkphp/library/think/db/exception/DataNotFoundException.php +++ b/thinkphp/library/think/db/exception/DataNotFoundException.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- diff --git a/thinkphp/library/think/db/exception/ModelNotFoundException.php b/thinkphp/library/think/db/exception/ModelNotFoundException.php index 2180ab07..6e5f930c 100644 --- a/thinkphp/library/think/db/exception/ModelNotFoundException.php +++ b/thinkphp/library/think/db/exception/ModelNotFoundException.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- diff --git a/thinkphp/library/think/debug/Console.php b/thinkphp/library/think/debug/Console.php index 8a232c8c..c17911b2 100644 --- a/thinkphp/library/think/debug/Console.php +++ b/thinkphp/library/think/debug/Console.php @@ -137,7 +137,7 @@ JS; } break; case '错误': - $msg = str_replace("\n", '\n', $m); + $msg = str_replace("\n", '\n', json_encode($m)); $style = 'color:#F4006B;font-size:14px;'; $line[] = "console.error(\"%c{$msg}\", \"{$style}\");"; break; diff --git a/thinkphp/library/think/debug/Html.php b/thinkphp/library/think/debug/Html.php index f8651aa9..b6be7adb 100644 --- a/thinkphp/library/think/debug/Html.php +++ b/thinkphp/library/think/debug/Html.php @@ -53,7 +53,7 @@ class Html return false; } // 获取基本信息 - $runtime = number_format(microtime(true) - THINK_START_TIME, 10); + $runtime = number_format(microtime(true) - THINK_START_TIME, 10, '.', ''); $reqs = $runtime > 0 ? number_format(1 / $runtime, 2) : '∞'; $mem = number_format((memory_get_usage() - THINK_START_MEM) / 1024, 2); diff --git a/thinkphp/library/think/exception/DbException.php b/thinkphp/library/think/exception/DbException.php index 656d6913..0ae80ad1 100644 --- a/thinkphp/library/think/exception/DbException.php +++ b/thinkphp/library/think/exception/DbException.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -36,6 +36,7 @@ class DbException extends Exception 'Error SQL' => $sql, ]); + unset($config['username'], $config['password']); $this->setData('Database Config', $config); } diff --git a/thinkphp/library/think/exception/ErrorException.php b/thinkphp/library/think/exception/ErrorException.php index e3f18375..b3a9a30a 100644 --- a/thinkphp/library/think/exception/ErrorException.php +++ b/thinkphp/library/think/exception/ErrorException.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- diff --git a/thinkphp/library/think/exception/Handle.php b/thinkphp/library/think/exception/Handle.php index 8b6e6c40..f523db09 100644 --- a/thinkphp/library/think/exception/Handle.php +++ b/thinkphp/library/think/exception/Handle.php @@ -21,11 +21,16 @@ use think\Response; class Handle { - + protected $render; protected $ignoreReport = [ '\\think\\exception\\HttpException', ]; + public function setRender($render) + { + $this->render = $render; + } + /** * Report or log an exception. * @@ -52,6 +57,10 @@ class Handle $log = "[{$data['code']}]{$data['message']}"; } + if (Config::get('record_trace')) { + $log .= "\r\n" . $exception->getTraceAsString(); + } + Log::record($log, 'error'); } } @@ -74,6 +83,13 @@ class Handle */ public function render(Exception $e) { + if ($this->render && $this->render instanceof \Closure) { + $result = call_user_func_array($this->render, [$e]); + if ($result) { + return $result; + } + } + if ($e instanceof HttpException) { return $this->renderHttpException($e); } else { diff --git a/thinkphp/library/think/exception/PDOException.php b/thinkphp/library/think/exception/PDOException.php index ebd53dff..044f82a0 100644 --- a/thinkphp/library/think/exception/PDOException.php +++ b/thinkphp/library/think/exception/PDOException.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- diff --git a/thinkphp/library/think/exception/RouteNotFoundException.php b/thinkphp/library/think/exception/RouteNotFoundException.php index f85a3c4b..d22e3a63 100644 --- a/thinkphp/library/think/exception/RouteNotFoundException.php +++ b/thinkphp/library/think/exception/RouteNotFoundException.php @@ -16,7 +16,7 @@ class RouteNotFoundException extends HttpException public function __construct() { - parent::__construct(404); + parent::__construct(404, 'Route Not Found'); } } diff --git a/thinkphp/library/think/log/driver/File.php b/thinkphp/library/think/log/driver/File.php index d82a5243..f2296cfa 100644 --- a/thinkphp/library/think/log/driver/File.php +++ b/thinkphp/library/think/log/driver/File.php @@ -12,6 +12,7 @@ namespace think\log\driver; use think\App; +use think\Request; /** * 本地化调试输出到文件 @@ -20,13 +21,14 @@ class File { protected $config = [ 'time_format' => ' c ', + 'single' => false, 'file_size' => 2097152, 'path' => LOG_PATH, 'apart_level' => [], + 'max_files' => 0, + 'json' => false, ]; - protected $writed = []; - // 实例化并传入参数 public function __construct($config = []) { @@ -38,82 +40,231 @@ class File /** * 日志写入接口 * @access public - * @param array $log 日志信息 + * @param array $log 日志信息 + * @param bool $append 是否追加请求信息 * @return bool */ - public function save(array $log = []) + public function save(array $log = [], $append = false) { - $cli = IS_CLI ? '_cli' : ''; - $destination = $this->config['path'] . date('Ym') . DS . date('d') . $cli . '.log'; + $destination = $this->getMasterLogFile(); $path = dirname($destination); !is_dir($path) && mkdir($path, 0755, true); - $info = ''; + $info = []; foreach ($log as $type => $val) { - $level = ''; + foreach ($val as $msg) { if (!is_string($msg)) { $msg = var_export($msg, true); } - $level .= '[ ' . $type . ' ] ' . $msg . "\r\n"; + + $info[$type][] = $this->config['json'] ? $msg : '[ ' . $type . ' ] ' . $msg; } - if (in_array($type, $this->config['apart_level'])) { + + if (!$this->config['json'] && (true === $this->config['apart_level'] || in_array($type, $this->config['apart_level']))) { // 独立记录的日志级别 - $filename = $path . DS . date('d') . '_' . $type . $cli . '.log'; - $this->write($level, $filename, true); - } else { - $info .= $level; + $filename = $this->getApartLevelFile($path, $type); + + $this->write($info[$type], $filename, true, $append); + unset($info[$type]); } } + if ($info) { - return $this->write($info, $destination); + return $this->write($info, $destination, false, $append); } + return true; } - protected function write($message, $destination, $apart = false) + /** + * 获取主日志文件名 + * @access public + * @return string + */ + protected function getMasterLogFile() + { + if ($this->config['single']) { + $name = is_string($this->config['single']) ? $this->config['single'] : 'single'; + + $destination = $this->config['path'] . $name . '.log'; + } else { + $cli = PHP_SAPI == 'cli' ? '_cli' : ''; + + if ($this->config['max_files']) { + $filename = date('Ymd') . $cli . '.log'; + $files = glob($this->config['path'] . '*.log'); + + try { + if (count($files) > $this->config['max_files']) { + unlink($files[0]); + } + } catch (\Exception $e) { + } + } else { + $filename = date('Ym') . DIRECTORY_SEPARATOR . date('d') . $cli . '.log'; + } + + $destination = $this->config['path'] . $filename; + } + + return $destination; + } + + /** + * 获取独立日志文件名 + * @access public + * @param string $path 日志目录 + * @param string $type 日志类型 + * @return string + */ + protected function getApartLevelFile($path, $type) + { + $cli = PHP_SAPI == 'cli' ? '_cli' : ''; + + if ($this->config['single']) { + $name = is_string($this->config['single']) ? $this->config['single'] : 'single'; + + $name .= '_' . $type; + } elseif ($this->config['max_files']) { + $name = date('Ymd') . '_' . $type . $cli; + } else { + $name = date('d') . '_' . $type . $cli; + } + + return $path . DIRECTORY_SEPARATOR . $name . '.log'; + } + + /** + * 日志写入 + * @access protected + * @param array $message 日志信息 + * @param string $destination 日志文件 + * @param bool $apart 是否独立文件写入 + * @param bool $append 是否追加请求信息 + * @return bool + */ + protected function write($message, $destination, $apart = false, $append = false) + { + // 检测日志文件大小,超过配置大小则备份日志文件重新生成 + $this->checkLogSize($destination); + + // 日志信息封装 + $info['timestamp'] = date($this->config['time_format']); + + foreach ($message as $type => $msg) { + $info[$type] = is_array($msg) ? implode("\r\n", $msg) : $msg; + } + + if (PHP_SAPI == 'cli') { + $message = $this->parseCliLog($info); + } else { + // 添加调试日志 + $this->getDebugLog($info, $append, $apart); + + $message = $this->parseLog($info); + } + + return error_log($message, 3, $destination); + } + + /** + * 检查日志文件大小并自动生成备份文件 + * @access protected + * @param string $destination 日志文件 + * @return void + */ + protected function checkLogSize($destination) { - //检测日志文件大小,超过配置大小则备份日志文件重新生成 if (is_file($destination) && floor($this->config['file_size']) <= filesize($destination)) { - rename($destination, dirname($destination) . DS . time() . '-' . basename($destination)); - $this->writed[$destination] = false; + try { + rename($destination, dirname($destination) . DIRECTORY_SEPARATOR . time() . '-' . basename($destination)); + } catch (\Exception $e) { + } } + } - if (empty($this->writed[$destination]) && !IS_CLI) { - if (App::$debug && !$apart) { + /** + * CLI日志解析 + * @access protected + * @param array $info 日志信息 + * @return string + */ + protected function parseCliLog($info) + { + if ($this->config['json']) { + $message = json_encode($info, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . "\r\n"; + } else { + $now = $info['timestamp']; + unset($info['timestamp']); + + $message = implode("\r\n", $info); + + $message = "[{$now}]" . $message . "\r\n"; + } + + return $message; + } + + /** + * 解析日志 + * @access protected + * @param array $info 日志信息 + * @return string + */ + protected function parseLog($info) + { + $request = Request::instance(); + $requestInfo = [ + 'ip' => $request->ip(), + 'method' => $request->method(), + 'host' => $request->host(), + 'uri' => $request->url(), + ]; + + if ($this->config['json']) { + $info = $requestInfo + $info; + return json_encode($info, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . "\r\n"; + } + + array_unshift($info, "---------------------------------------------------------------\r\n[{$info['timestamp']}] {$requestInfo['ip']} {$requestInfo['method']} {$requestInfo['host']}{$requestInfo['uri']}"); + unset($info['timestamp']); + + return implode("\r\n", $info) . "\r\n"; + } + + protected function getDebugLog(&$info, $append, $apart) + { + if (App::$debug && $append) { + + if ($this->config['json']) { // 获取基本信息 - if (isset($_SERVER['HTTP_HOST'])) { - $current_uri = $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; - } else { - $current_uri = "cmd:" . implode(' ', $_SERVER['argv']); - } + $runtime = round(microtime(true) - THINK_START_TIME, 10); + $reqs = $runtime > 0 ? number_format(1 / $runtime, 2) : '∞'; - $runtime = round(microtime(true) - THINK_START_TIME, 10); - $reqs = $runtime > 0 ? number_format(1 / $runtime, 2) : '∞'; - $time_str = ' [运行时间:' . number_format($runtime, 6) . 's][吞吐率:' . $reqs . 'req/s]'; $memory_use = number_format((memory_get_usage() - THINK_START_MEM) / 1024, 2); + + $info = [ + 'runtime' => number_format($runtime, 6) . 's', + 'reqs' => $reqs . 'req/s', + 'memory' => $memory_use . 'kb', + 'file' => count(get_included_files()), + ] + $info; + + } elseif (!$apart) { + // 增加额外的调试信息 + $runtime = round(microtime(true) - THINK_START_TIME, 10); + $reqs = $runtime > 0 ? number_format(1 / $runtime, 2) : '∞'; + + $memory_use = number_format((memory_get_usage() - THINK_START_MEM) / 1024, 2); + + $time_str = '[运行时间:' . number_format($runtime, 6) . 's] [吞吐率:' . $reqs . 'req/s]'; $memory_str = ' [内存消耗:' . $memory_use . 'kb]'; $file_load = ' [文件加载:' . count(get_included_files()) . ']'; - $message = '[ info ] ' . $current_uri . $time_str . $memory_str . $file_load . "\r\n" . $message; + array_unshift($info, $time_str . $memory_str . $file_load); } - $now = date($this->config['time_format']); - $server = isset($_SERVER['SERVER_ADDR']) ? $_SERVER['SERVER_ADDR'] : '0.0.0.0'; - $remote = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '0.0.0.0'; - $method = isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : 'CLI'; - $uri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : ''; - $message = "---------------------------------------------------------------\r\n[{$now}] {$server} {$remote} {$method} {$uri}\r\n" . $message; - - $this->writed[$destination] = true; } - - if (IS_CLI) { - $now = date($this->config['time_format']); - $message = "[{$now}]" . $message; - } - - return error_log($message, 3, $destination); } - } diff --git a/thinkphp/library/think/log/driver/Socket.php b/thinkphp/library/think/log/driver/Socket.php index d30bba30..4f62915b 100644 --- a/thinkphp/library/think/log/driver/Socket.php +++ b/thinkphp/library/think/log/driver/Socket.php @@ -60,7 +60,7 @@ class Socket * @param array $log 日志信息 * @return bool */ - public function save(array $log = []) + public function save(array $log = [], $append = false) { if (!$this->check()) { return false; diff --git a/thinkphp/library/think/model/Collection.php b/thinkphp/library/think/model/Collection.php index 4e4bb4dc..0406533c 100644 --- a/thinkphp/library/think/model/Collection.php +++ b/thinkphp/library/think/model/Collection.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -16,20 +16,6 @@ use think\Model; class Collection extends BaseCollection { - /** - * 返回数组中指定的一列 - * @param string $column_key - * @param string|null $index_key - * @return array - */ - public function column($column_key, $index_key = null) - { - if (function_exists('array_column')) { - return array_column($this->toArray(), $column_key, $index_key); - } - return parent::column($column_key, $index_key); - } - /** * 延迟预载入关联查询 * @access public @@ -85,7 +71,7 @@ class Collection extends BaseCollection { $this->each(function ($model) use ($append, $override) { /** @var Model $model */ - $model->append($append, $override); + $model && $model->append($append, $override); }); return $this; } diff --git a/thinkphp/library/think/model/Merge.php b/thinkphp/library/think/model/Merge.php index d944979e..4a9da81e 100644 --- a/thinkphp/library/think/model/Merge.php +++ b/thinkphp/library/think/model/Merge.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- diff --git a/thinkphp/library/think/model/Pivot.php b/thinkphp/library/think/model/Pivot.php index 06c6b181..13525cdd 100644 --- a/thinkphp/library/think/model/Pivot.php +++ b/thinkphp/library/think/model/Pivot.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -24,11 +24,11 @@ class Pivot extends Model /** * 架构函数 * @access public - * @param Model $parent 上级模型 * @param array|object $data 数据 + * @param Model $parent 上级模型 * @param string $table 中间数据表名 */ - public function __construct(Model $parent, $data = [], $table = '') + public function __construct($data = [], Model $parent = null, $table = '') { $this->parent = $parent; @@ -37,8 +37,6 @@ class Pivot extends Model } parent::__construct($data); - - $this->class = $this->name; } } diff --git a/thinkphp/library/think/model/Relation.php b/thinkphp/library/think/model/Relation.php index 4869e526..25fe88db 100644 --- a/thinkphp/library/think/model/Relation.php +++ b/thinkphp/library/think/model/Relation.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -35,6 +35,8 @@ abstract class Relation protected $localKey; // 基础查询 protected $baseQuery; + // 是否为自关联 + protected $selfRelation; /** * 获取关联的所属模型 @@ -47,13 +49,13 @@ abstract class Relation } /** - * 获取当前的关联模型类 + * 获取当前的关联模型对象实例 * @access public - * @return string + * @return Model */ public function getModel() { - return $this->model; + return $this->query->getModel(); } /** @@ -66,6 +68,28 @@ abstract class Relation return $this->query; } + /** + * 设置当前关联为自关联 + * @access public + * @param bool $self 是否自关联 + * @return $this + */ + public function selfRelation($self = true) + { + $this->selfRelation = $self; + return $this; + } + + /** + * 当前关联是否为自关联 + * @access public + * @return bool + */ + public function isSelfRelation() + { + return $this->selfRelation; + } + /** * 封装关联数据集 * @access public @@ -108,7 +132,8 @@ abstract class Relation * @access protected * @return void */ - abstract protected function baseQuery(); + protected function baseQuery() + {} public function __call($method, $args) { diff --git a/thinkphp/library/think/model/relation/BelongsTo.php b/thinkphp/library/think/model/relation/BelongsTo.php index 905ea944..c1cbab97 100644 --- a/thinkphp/library/think/model/relation/BelongsTo.php +++ b/thinkphp/library/think/model/relation/BelongsTo.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -11,6 +11,7 @@ namespace think\model\relation; +use think\db\Query; use think\Loader; use think\Model; @@ -51,6 +52,7 @@ class BelongsTo extends OneToOne call_user_func_array($closure, [ & $this->query]); } $relationModel = $this->query + ->removeWhereField($this->localKey) ->where($this->localKey, $this->parent->$foreignKey) ->relation($subRelation) ->find(); @@ -68,7 +70,6 @@ class BelongsTo extends OneToOne * @param string $operator 比较操作符 * @param integer $count 个数 * @param string $id 关联表的统计字段 - * @param string $joinType JOIN类型 * @return Query */ public function has($operator = '>=', $count = 1, $id = '*') @@ -79,14 +80,16 @@ class BelongsTo extends OneToOne /** * 根据关联条件查询当前模型 * @access public - * @param mixed $where 查询条件(数组或者闭包) + * @param mixed $where 查询条件(数组或者闭包) + * @param mixed $fields 字段 * @return Query */ - public function hasWhere($where = []) + public function hasWhere($where = [], $fields = null) { $table = $this->query->getTable(); $model = basename(str_replace('\\', '/', get_class($this->parent))); $relation = basename(str_replace('\\', '/', $this->model)); + if (is_array($where)) { foreach ($where as $key => $val) { if (false === strpos($key, '.')) { @@ -95,9 +98,11 @@ class BelongsTo extends OneToOne } } } + $fields = $this->getRelationQueryFields($fields, $model); + return $this->parent->db()->alias($model) - ->field($model . '.*') - ->join($table . ' ' . $relation, $model . '.' . $this->foreignKey . '=' . $relation . '.' . $this->localKey, $this->joinType) + ->field($fields) + ->join([$table => $relation], $model . '.' . $this->foreignKey . '=' . $relation . '.' . $this->localKey, $this->joinType) ->where($where); } @@ -124,7 +129,8 @@ class BelongsTo extends OneToOne } if (!empty($range)) { - $data = $this->eagerlyWhere($this, [ + $this->query->removeWhereField($localKey); + $data = $this->eagerlyWhere($this->query, [ $localKey => [ 'in', $range, @@ -143,12 +149,13 @@ class BelongsTo extends OneToOne $relationModel->isUpdate(true); } - if ($relationModel && !empty($this->bindAttr)) { + if (!empty($this->bindAttr)) { // 绑定关联属性 $this->bindAttr($relationModel, $result, $this->bindAttr); + } else { + // 设置关联属性 + $result->setRelation($attr, $relationModel); } - // 设置关联属性 - $result->setRelation($attr, $relationModel); } } } @@ -166,7 +173,8 @@ class BelongsTo extends OneToOne { $localKey = $this->localKey; $foreignKey = $this->foreignKey; - $data = $this->eagerlyWhere($this, [$localKey => $result->$foreignKey], $localKey, $relation, $subRelation, $closure); + $this->query->removeWhereField($localKey); + $data = $this->eagerlyWhere($this->query, [$localKey => $result->$foreignKey], $localKey, $relation, $subRelation, $closure); // 关联模型 if (!isset($data[$result->$foreignKey])) { $relationModel = null; @@ -175,12 +183,13 @@ class BelongsTo extends OneToOne $relationModel->setParent(clone $result); $relationModel->isUpdate(true); } - if ($relationModel && !empty($this->bindAttr)) { + if (!empty($this->bindAttr)) { // 绑定关联属性 $this->bindAttr($relationModel, $result, $this->bindAttr); + } else { + // 设置关联属性 + $result->setRelation(Loader::parseName($relation), $relationModel); } - // 设置关联属性 - $result->setRelation(Loader::parseName($relation), $relationModel); } /** @@ -214,4 +223,21 @@ class BelongsTo extends OneToOne return $this->parent->setRelation($this->relation, null); } + + /** + * 执行基础查询(仅执行一次) + * @access protected + * @return void + */ + protected function baseQuery() + { + if (empty($this->baseQuery)) { + if (isset($this->parent->{$this->foreignKey})) { + // 关联查询带入关联条件 + $this->query->where($this->localKey, '=', $this->parent->{$this->foreignKey}); + } + + $this->baseQuery = true; + } + } } diff --git a/thinkphp/library/think/model/relation/BelongsToMany.php b/thinkphp/library/think/model/relation/BelongsToMany.php index 71ab4266..a41c45ce 100644 --- a/thinkphp/library/think/model/relation/BelongsToMany.php +++ b/thinkphp/library/think/model/relation/BelongsToMany.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -12,6 +12,7 @@ namespace think\model\relation; use think\Collection; +use think\Db; use think\db\Query; use think\Exception; use think\Loader; @@ -28,6 +29,8 @@ class BelongsToMany extends Relation protected $pivotName; // 中间表模型对象 protected $pivot; + // 中间表数据名称 + protected $pivotDataName = 'pivot'; /** * 构造函数 @@ -52,6 +55,10 @@ class BelongsToMany extends Relation } $this->query = (new $model)->db(); $this->pivot = $this->newPivot(); + + if ('think\model\Pivot' == get_class($this->pivot)) { + $this->pivot->name($this->middle); + } } /** @@ -66,14 +73,46 @@ class BelongsToMany extends Relation } /** - * 实例化中间表模型 + * 设置中间表数据名称 + * @access public + * @param string $name + * @return $this + */ + public function pivotDataName($name) + { + $this->pivotDataName = $name; + return $this; + } + + /** + * 获取中间表更新条件 * @param $data - * @return mixed + * @return array */ - protected function newPivot($data = []) + protected function getUpdateWhere($data) { - $pivot = $this->pivotName ?: '\\think\\model\\Pivot'; - return new $pivot($this->parent, $data, $this->middle); + return [ + $this->localKey => $data[$this->localKey], + $this->foreignKey => $data[$this->foreignKey], + ]; + } + + /** + * 实例化中间表模型 + * @param array $data + * @param bool $isUpdate + * @return Pivot + * @throws Exception + */ + protected function newPivot($data = [], $isUpdate = false) + { + $class = $this->pivotName ?: '\\think\\model\\Pivot'; + $pivot = new $class($data, $this->parent, $this->middle); + if ($pivot instanceof Pivot) { + return $isUpdate ? $pivot->isUpdate(true, $this->getUpdateWhere($data)) : $pivot; + } else { + throw new Exception('pivot model must extends: \think\model\Pivot'); + } } /** @@ -93,7 +132,7 @@ class BelongsToMany extends Relation } } } - $model->setRelation('pivot', $this->newPivot($pivot)); + $model->setRelation($this->pivotDataName, $this->newPivot($pivot, true)); } } @@ -105,9 +144,8 @@ class BelongsToMany extends Relation { $foreignKey = $this->foreignKey; $localKey = $this->localKey; - $middle = $this->middle; + $pk = $this->parent->getPk(); // 关联查询 - $pk = $this->parent->getPk(); $condition['pivot.' . $localKey] = $this->parent->$pk; return $this->belongsToManyQuery($foreignKey, $localKey, $condition); } @@ -207,11 +245,12 @@ class BelongsToMany extends Relation /** * 根据关联条件查询当前模型 * @access public - * @param mixed $where 查询条件(数组或者闭包) + * @param mixed $where 查询条件(数组或者闭包) + * @param mixed $fields 字段 * @return Query * @throws Exception */ - public function hasWhere($where = []) + public function hasWhere($where = [], $fields = null) { throw new Exception('relation not support: hasWhere'); } @@ -321,14 +360,22 @@ class BelongsToMany extends Relation * 获取关联统计子查询 * @access public * @param \Closure $closure 闭包 + * @param string $name 统计数据别名 * @return string */ - public function getRelationCountQuery($closure) + public function getRelationCountQuery($closure, &$name = null) { + if ($closure) { + $return = call_user_func_array($closure, [ & $this->query]); + if ($return && is_string($return)) { + $name = $return; + } + } + return $this->belongsToManyQuery($this->foreignKey, $this->localKey, [ 'pivot.' . $this->localKey => [ 'exp', - '=' . $this->parent->getTable() . '.' . $this->parent->getPk(), + Db::raw('=' . $this->parent->getTable() . '.' . $this->parent->getPk()), ], ])->fetchSql()->count(); } @@ -359,7 +406,7 @@ class BelongsToMany extends Relation } } } - $set->setRelation('pivot', $this->newPivot($pivot)); + $set->setRelation($this->pivotDataName, $this->newPivot($pivot, true)); $data[$pivot[$this->localKey]][] = $set; } return $data; @@ -385,7 +432,7 @@ class BelongsToMany extends Relation if (empty($this->baseQuery)) { $relationFk = $this->query->getPk(); - $query->join($table . ' pivot', 'pivot.' . $foreignKey . '=' . $tableName . '.' . $relationFk) + $query->join([$table => 'pivot'], 'pivot.' . $foreignKey . '=' . $tableName . '.' . $relationFk) ->where($condition); } return $query; @@ -462,7 +509,7 @@ class BelongsToMany extends Relation foreach ($ids as $id) { $pivot[$this->foreignKey] = $id; $this->pivot->insert($pivot, true); - $result[] = $this->newPivot($pivot); + $result[] = $this->newPivot($pivot, true); } if (count($result) == 1) { // 返回中间表模型对象 @@ -474,6 +521,29 @@ class BelongsToMany extends Relation } } + /** + * 判断是否存在关联数据 + * @access public + * @param mixed $data 数据 可以使用关联模型对象 或者 关联对象的主键 + * @return Pivot + * @throws Exception + */ + public function attached($data) + { + if ($data instanceof Model) { + $relationFk = $data->getPk(); + $id = $data->$relationFk; + } else { + $id = $data; + } + + $pk = $this->parent->getPk(); + + $pivot = $this->pivot->where($this->localKey, $this->parent->$pk)->where($this->foreignKey, $id)->find(); + + return $pivot ?: false; + } + /** * 解除关联的一个中间表数据 * @access public @@ -566,7 +636,7 @@ class BelongsToMany extends Relation if (empty($this->baseQuery) && $this->parent->getData()) { $pk = $this->parent->getPk(); $table = $this->pivot->getTable(); - $this->query->join($table . ' pivot', 'pivot.' . $this->foreignKey . '=' . $this->query->getTable() . '.' . $this->query->getPk())->where('pivot.' . $this->localKey, $this->parent->$pk); + $this->query->join([$table => 'pivot'], 'pivot.' . $this->foreignKey . '=' . $this->query->getTable() . '.' . $this->query->getPk())->where('pivot.' . $this->localKey, $this->parent->$pk); $this->baseQuery = true; } } diff --git a/thinkphp/library/think/model/relation/HasMany.php b/thinkphp/library/think/model/relation/HasMany.php index 9624fc67..ebab051a 100644 --- a/thinkphp/library/think/model/relation/HasMany.php +++ b/thinkphp/library/think/model/relation/HasMany.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -24,7 +24,7 @@ class HasMany extends Relation * @param Model $parent 上级模型对象 * @param string $model 模型名 * @param string $foreignKey 关联外键 - * @param string $localKey 关联主键 + * @param string $localKey 当前模型主键 */ public function __construct(Model $parent, $model, $foreignKey, $localKey) { @@ -77,7 +77,7 @@ class HasMany extends Relation } if (!empty($range)) { - $data = $this->eagerlyOneToMany($this, [ + $data = $this->eagerlyOneToMany($this->query, [ $this->foreignKey => [ 'in', $range, @@ -114,7 +114,7 @@ class HasMany extends Relation $localKey = $this->localKey; if (isset($result->$localKey)) { - $data = $this->eagerlyOneToMany($this, [$this->foreignKey => $result->$localKey], $relation, $subRelation, $closure); + $data = $this->eagerlyOneToMany($this->query, [$this->foreignKey => $result->$localKey], $relation, $subRelation, $closure); // 关联数据封装 if (!isset($data[$result->$localKey])) { $data[$result->$localKey] = []; @@ -143,7 +143,7 @@ class HasMany extends Relation if ($closure) { call_user_func_array($closure, [ & $this->query]); } - $count = $this->query->where([$this->foreignKey => $result->$localKey])->count(); + $count = $this->query->where($this->foreignKey, $result->$localKey)->count(); } return $count; } @@ -152,20 +152,19 @@ class HasMany extends Relation * 创建关联统计子查询 * @access public * @param \Closure $closure 闭包 + * @param string $name 统计数据别名 * @return string */ - public function getRelationCountQuery($closure) + public function getRelationCountQuery($closure, &$name = null) { if ($closure) { - call_user_func_array($closure, [ & $this->query]); + $return = call_user_func_array($closure, [ & $this->query]); + if ($return && is_string($return)) { + $name = $return; + } } - - return $this->query->where([ - $this->foreignKey => [ - 'exp', - '=' . $this->parent->getTable() . '.' . $this->parent->getPk(), - ], - ])->fetchSql()->count(); + $localKey = $this->localKey ?: $this->parent->getPk(); + return $this->query->whereExp($this->foreignKey, '=' . $this->parent->getTable() . '.' . $localKey)->fetchSql()->count(); } /** @@ -185,7 +184,7 @@ class HasMany extends Relation if ($closure) { call_user_func_array($closure, [ & $model]); } - $list = $model->where($where)->with($subRelation)->select(); + $list = $model->removeWhereField($foreignKey)->where($where)->with($subRelation)->select(); // 组装模型数据 $data = []; @@ -206,12 +205,31 @@ class HasMany extends Relation if ($data instanceof Model) { $data = $data->getData(); } + // 保存关联表数据 - $model = new $this->model; $data[$this->foreignKey] = $this->parent->{$this->localKey}; + + $model = new $this->model(); return $model->save($data) ? $model : false; } + /** + * 创建关联对象实例 + * @param array $data + * @return Model + */ + public function make($data = []) + { + if ($data instanceof Model) { + $data = $data->getData(); + } + + // 保存关联表数据 + $data[$this->foreignKey] = $this->parent->{$this->localKey}; + + return new $this->model($data); + } + /** * 批量保存当前关联数据对象 * @access public @@ -238,24 +256,31 @@ class HasMany extends Relation */ public function has($operator = '>=', $count = 1, $id = '*', $joinType = 'INNER') { - $table = $this->query->getTable(); - return $this->parent->db()->alias('a') - ->join($table . ' b', 'a.' . $this->localKey . '=b.' . $this->foreignKey, $joinType) - ->group('b.' . $this->foreignKey) + $table = $this->query->getTable(); + $model = basename(str_replace('\\', '/', get_class($this->parent))); + $relation = basename(str_replace('\\', '/', $this->model)); + + return $this->parent->db() + ->alias($model) + ->field($model . '.*') + ->join([$table => $relation], $model . '.' . $this->localKey . '=' . $relation . '.' . $this->foreignKey, $joinType) + ->group($relation . '.' . $this->foreignKey) ->having('count(' . $id . ')' . $operator . $count); } /** * 根据关联条件查询当前模型 * @access public - * @param mixed $where 查询条件(数组或者闭包) + * @param mixed $where 查询条件(数组或者闭包) + * @param mixed $fields 字段 * @return Query */ - public function hasWhere($where = []) + public function hasWhere($where = [], $fields = null) { $table = $this->query->getTable(); $model = basename(str_replace('\\', '/', get_class($this->parent))); $relation = basename(str_replace('\\', '/', $this->model)); + if (is_array($where)) { foreach ($where as $key => $val) { if (false === strpos($key, '.')) { @@ -264,9 +289,13 @@ class HasMany extends Relation } } } + + $fields = $this->getRelationQueryFields($fields, $model); + return $this->parent->db()->alias($model) - ->field($model . '.*') - ->join($table . ' ' . $relation, $model . '.' . $this->localKey . '=' . $relation . '.' . $this->foreignKey) + ->field($fields) + ->group($model . '.' . $this->localKey) + ->join([$table => $relation], $model . '.' . $this->localKey . '=' . $relation . '.' . $this->foreignKey) ->where($where); } diff --git a/thinkphp/library/think/model/relation/HasManyThrough.php b/thinkphp/library/think/model/relation/HasManyThrough.php index 1573fc65..3a9a5482 100644 --- a/thinkphp/library/think/model/relation/HasManyThrough.php +++ b/thinkphp/library/think/model/relation/HasManyThrough.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -77,10 +77,11 @@ class HasManyThrough extends Relation /** * 根据关联条件查询当前模型 * @access public - * @param mixed $where 查询条件(数组或者闭包) + * @param mixed $where 查询条件(数组或者闭包) + * @param mixed $fields 字段 * @return Query */ - public function hasWhere($where = []) + public function hasWhere($where = [], $fields = null) { throw new Exception('relation not support: hasWhere'); } @@ -92,10 +93,9 @@ class HasManyThrough extends Relation * @param string $relation 当前关联名 * @param string $subRelation 子关联名 * @param \Closure $closure 闭包 - * @param string $class 数据集对象名 为空表示数组 * @return void */ - public function eagerlyResultSet(&$resultSet, $relation, $subRelation, $closure, $class) + public function eagerlyResultSet(&$resultSet, $relation, $subRelation, $closure) {} /** @@ -105,10 +105,9 @@ class HasManyThrough extends Relation * @param string $relation 当前关联名 * @param string $subRelation 子关联名 * @param \Closure $closure 闭包 - * @param string $class 数据集对象名 为空表示数组 * @return void */ - public function eagerlyResult(&$result, $relation, $subRelation, $closure, $class) + public function eagerlyResult(&$result, $relation, $subRelation, $closure) {} /** @@ -121,6 +120,18 @@ class HasManyThrough extends Relation public function relationCount($result, $closure) {} + /** + * 创建关联统计子查询 + * @access public + * @param \Closure $closure 闭包 + * @param string $name 统计数据别名 + * @return string + */ + public function getRelationCountQuery($closure, &$name = null) + { + throw new Exception('relation not support: withCount'); + } + /** * 执行基础查询(进执行一次) * @access protected diff --git a/thinkphp/library/think/model/relation/HasOne.php b/thinkphp/library/think/model/relation/HasOne.php index c500c02a..db74e4a6 100644 --- a/thinkphp/library/think/model/relation/HasOne.php +++ b/thinkphp/library/think/model/relation/HasOne.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -23,7 +23,7 @@ class HasOne extends OneToOne * @param Model $parent 上级模型对象 * @param string $model 模型名 * @param string $foreignKey 关联外键 - * @param string $localKey 关联主键 + * @param string $localKey 当前模型主键 * @param string $joinType JOIN类型 */ public function __construct(Model $parent, $model, $foreignKey, $localKey, $joinType = 'INNER') @@ -50,7 +50,11 @@ class HasOne extends OneToOne call_user_func_array($closure, [ & $this->query]); } // 判断关联类型执行查询 - $relationModel = $this->query->where($this->foreignKey, $this->parent->$localKey)->relation($subRelation)->find(); + $relationModel = $this->query + ->removeWhereField($this->foreignKey) + ->where($this->foreignKey, $this->parent->$localKey) + ->relation($subRelation) + ->find(); if ($relationModel) { $relationModel->setParent(clone $this->parent); @@ -67,25 +71,30 @@ class HasOne extends OneToOne public function has() { $table = $this->query->getTable(); + $model = basename(str_replace('\\', '/', get_class($this->parent))); + $relation = basename(str_replace('\\', '/', $this->model)); $localKey = $this->localKey; $foreignKey = $this->foreignKey; - return $this->parent->db()->alias('a') - ->whereExists(function ($query) use ($table, $localKey, $foreignKey) { - $query->table([$table => 'b'])->field('b.' . $foreignKey)->whereExp('a.' . $localKey, '=b.' . $foreignKey); + return $this->parent->db() + ->alias($model) + ->whereExists(function ($query) use ($table, $model, $relation, $localKey, $foreignKey) { + $query->table([$table => $relation])->field($relation . '.' . $foreignKey)->whereExp($model . '.' . $localKey, '=' . $relation . '.' . $foreignKey); }); } /** * 根据关联条件查询当前模型 * @access public - * @param mixed $where 查询条件(数组或者闭包) + * @param mixed $where 查询条件(数组或者闭包) + * @param mixed $fields 字段 * @return Query */ - public function hasWhere($where = []) + public function hasWhere($where = [], $fields = null) { $table = $this->query->getTable(); $model = basename(str_replace('\\', '/', get_class($this->parent))); $relation = basename(str_replace('\\', '/', $this->model)); + if (is_array($where)) { foreach ($where as $key => $val) { if (false === strpos($key, '.')) { @@ -94,9 +103,11 @@ class HasOne extends OneToOne } } } + $fields = $this->getRelationQueryFields($fields, $model); + return $this->parent->db()->alias($model) - ->field($model . '.*') - ->join($table . ' ' . $relation, $model . '.' . $this->localKey . '=' . $relation . '.' . $this->foreignKey, $this->joinType) + ->field($fields) + ->join([$table => $relation], $model . '.' . $this->localKey . '=' . $relation . '.' . $this->foreignKey, $this->joinType) ->where($where); } @@ -123,7 +134,8 @@ class HasOne extends OneToOne } if (!empty($range)) { - $data = $this->eagerlyWhere($this, [ + $this->query->removeWhereField($foreignKey); + $data = $this->eagerlyWhere($this->query, [ $foreignKey => [ 'in', $range, @@ -140,13 +152,14 @@ class HasOne extends OneToOne $relationModel = $data[$result->$localKey]; $relationModel->setParent(clone $result); $relationModel->isUpdate(true); - if (!empty($this->bindAttr)) { - // 绑定关联属性 - $this->bindAttr($relationModel, $result, $this->bindAttr); - } } - // 设置关联属性 - $result->setRelation($attr, $relationModel); + if (!empty($this->bindAttr)) { + // 绑定关联属性 + $this->bindAttr($relationModel, $result, $this->bindAttr); + } else { + // 设置关联属性 + $result->setRelation($attr, $relationModel); + } } } } @@ -164,7 +177,8 @@ class HasOne extends OneToOne { $localKey = $this->localKey; $foreignKey = $this->foreignKey; - $data = $this->eagerlyWhere($this, [$foreignKey => $result->$localKey], $foreignKey, $relation, $subRelation, $closure); + $this->query->removeWhereField($foreignKey); + $data = $this->eagerlyWhere($this->query, [$foreignKey => $result->$localKey], $foreignKey, $relation, $subRelation, $closure); // 关联模型 if (!isset($data[$result->$localKey])) { @@ -173,13 +187,29 @@ class HasOne extends OneToOne $relationModel = $data[$result->$localKey]; $relationModel->setParent(clone $result); $relationModel->isUpdate(true); - if (!empty($this->bindAttr)) { - // 绑定关联属性 - $this->bindAttr($relationModel, $result, $this->bindAttr); - } } - - $result->setRelation(Loader::parseName($relation), $relationModel); + if (!empty($this->bindAttr)) { + // 绑定关联属性 + $this->bindAttr($relationModel, $result, $this->bindAttr); + } else { + $result->setRelation(Loader::parseName($relation), $relationModel); + } } + /** + * 执行基础查询(仅执行一次) + * @access protected + * @return void + */ + protected function baseQuery() + { + if (empty($this->baseQuery)) { + if (isset($this->parent->{$this->localKey})) { + // 关联查询带入关联条件 + $this->query->where($this->foreignKey, '=', $this->parent->{$this->localKey}); + } + + $this->baseQuery = true; + } + } } diff --git a/thinkphp/library/think/model/relation/MorphMany.php b/thinkphp/library/think/model/relation/MorphMany.php index 87c2d66c..2755d575 100644 --- a/thinkphp/library/think/model/relation/MorphMany.php +++ b/thinkphp/library/think/model/relation/MorphMany.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -11,6 +11,7 @@ namespace think\model\relation; +use think\Db; use think\db\Query; use think\Exception; use think\Loader; @@ -82,10 +83,11 @@ class MorphMany extends Relation /** * 根据关联条件查询当前模型 * @access public - * @param mixed $where 查询条件(数组或者闭包) + * @param mixed $where 查询条件(数组或者闭包) + * @param mixed $fields 字段 * @return Query */ - public function hasWhere($where = []) + public function hasWhere($where = [], $fields = null) { throw new Exception('relation not support: hasWhere'); } @@ -186,21 +188,25 @@ class MorphMany extends Relation } /** - * 获取关联统计子查询 + * 创建关联统计子查询 * @access public * @param \Closure $closure 闭包 + * @param string $name 统计数据别名 * @return string */ - public function getRelationCountQuery($closure) + public function getRelationCountQuery($closure, &$name = null) { if ($closure) { - call_user_func_array($closure, [ & $this->query]); + $return = call_user_func_array($closure, [ & $this->query]); + if ($return && is_string($return)) { + $name = $return; + } } return $this->query->where([ $this->morphKey => [ 'exp', - '=' . $this->parent->getTable() . '.' . $this->parent->getPk(), + Db::raw('=' . $this->parent->getTable() . '.' . $this->parent->getPk()), ], $this->morphType => $this->type, ])->fetchSql()->count(); @@ -242,13 +248,36 @@ class MorphMany extends Relation if ($data instanceof Model) { $data = $data->getData(); } + + // 保存关联表数据 + $pk = $this->parent->getPk(); + + $data[$this->morphKey] = $this->parent->$pk; + $data[$this->morphType] = $this->type; + + $model = new $this->model(); + + return $model->save() ? $model : false; + } + + /** + * 创建关联对象实例 + * @param array $data + * @return Model + */ + public function make($data = []) + { + if ($data instanceof Model) { + $data = $data->getData(); + } + // 保存关联表数据 $pk = $this->parent->getPk(); - $model = new $this->model; $data[$this->morphKey] = $this->parent->$pk; $data[$this->morphType] = $this->type; - return $model->save($data) ? $model : false; + + return new $this->model($data); } /** diff --git a/thinkphp/library/think/model/relation/MorphOne.php b/thinkphp/library/think/model/relation/MorphOne.php index 4dfd1c0f..5ec71724 100644 --- a/thinkphp/library/think/model/relation/MorphOne.php +++ b/thinkphp/library/think/model/relation/MorphOne.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -81,10 +81,11 @@ class MorphOne extends Relation /** * 根据关联条件查询当前模型 * @access public - * @param mixed $where 查询条件(数组或者闭包) + * @param mixed $where 查询条件(数组或者闭包) + * @param mixed $fields 字段 * @return Query */ - public function hasWhere($where = []) + public function hasWhere($where = [], $fields = null) { throw new Exception('relation not support: hasWhere'); } @@ -197,6 +198,28 @@ class MorphOne extends Relation * @return Model|false */ public function save($data) + { + if ($data instanceof Model) { + $data = $data->getData(); + } + + // 保存关联表数据 + $pk = $this->parent->getPk(); + + $data[$this->morphKey] = $this->parent->$pk; + $data[$this->morphType] = $this->type; + + $model = new $this->model(); + + return $model->save() ? $model : false; + } + + /** + * 创建关联对象实例 + * @param array $data + * @return Model + */ + public function make($data = []) { if ($data instanceof Model) { $data = $data->getData(); @@ -204,10 +227,10 @@ class MorphOne extends Relation // 保存关联表数据 $pk = $this->parent->getPk(); - $model = new $this->model; $data[$this->morphKey] = $this->parent->$pk; $data[$this->morphType] = $this->type; - return $model->save($data) ? $model : false; + + return new $this->model($data); } /** @@ -226,4 +249,15 @@ class MorphOne extends Relation } } + /** + * 创建关联统计子查询 + * @access public + * @param \Closure $closure 闭包 + * @param string $name 统计数据别名 + * @return string + */ + public function getRelationCountQuery($closure, &$name = null) + { + throw new Exception('relation not support: withCount'); + } } diff --git a/thinkphp/library/think/model/relation/MorphTo.php b/thinkphp/library/think/model/relation/MorphTo.php index df104a90..7d452651 100644 --- a/thinkphp/library/think/model/relation/MorphTo.php +++ b/thinkphp/library/think/model/relation/MorphTo.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -43,6 +43,18 @@ class MorphTo extends Relation $this->relation = $relation; } + /** + * 获取当前的关联模型类的实例 + * @access public + * @return Model + */ + public function getModel() + { + $morphType = $this->morphType; + $model = $this->parseModel($this->parent->$morphType); + return (new $model); + } + /** * 延迟获取关联数据 * @param string $subRelation 子关联名 @@ -82,17 +94,18 @@ class MorphTo extends Relation /** * 根据关联条件查询当前模型 * @access public - * @param mixed $where 查询条件(数组或者闭包) + * @param mixed $where 查询条件(数组或者闭包) + * @param mixed $fields 字段 * @return Query */ - public function hasWhere($where = []) + public function hasWhere($where = [], $fields = null) { throw new Exception('relation not support: hasWhere'); } /** * 解析模型的完整命名空间 - * @access public + * @access protected * @param string $model 模型名(或者完整类名) * @return string */ @@ -238,17 +251,18 @@ class MorphTo extends Relation /** * 添加关联数据 * @access public - * @param Model $model 关联模型对象 + * @param Model $model 关联模型对象 + * @param string $type 多态类型 * @return Model */ - public function associate($model) + public function associate($model, $type = '') { $morphKey = $this->morphKey; $morphType = $this->morphType; $pk = $model->getPk(); $this->parent->setAttr($morphKey, $model->$pk); - $this->parent->setAttr($morphType, get_class($model)); + $this->parent->setAttr($morphType, $type ?: get_class($model)); $this->parent->save(); return $this->parent->setRelation($this->relation, $model); @@ -272,10 +286,14 @@ class MorphTo extends Relation } /** - * 执行基础查询(进执行一次) - * @access protected - * @return void + * 创建关联统计子查询 + * @access public + * @param \Closure $closure 闭包 + * @param string $name 统计数据别名 + * @return string */ - protected function baseQuery() - {} + public function getRelationCountQuery($closure, &$name = null) + { + throw new Exception('relation not support: withCount'); + } } diff --git a/thinkphp/library/think/model/relation/OneToOne.php b/thinkphp/library/think/model/relation/OneToOne.php index ff066ed3..353ce21b 100644 --- a/thinkphp/library/think/model/relation/OneToOne.php +++ b/thinkphp/library/think/model/relation/OneToOne.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -57,18 +57,18 @@ abstract class OneToOne extends Relation */ public function eagerly(Query $query, $relation, $subRelation, $closure, $first) { - $name = Loader::parseName(basename(str_replace('\\', '/', $query->getModel()))); - $alias = $name; + $name = Loader::parseName(basename(str_replace('\\', '/', get_class($query->getModel())))); + if ($first) { $table = $query->getTable(); - $query->table([$table => $alias]); + $query->table([$table => $name]); if ($query->getOptions('field')) { $field = $query->getOptions('field'); $query->removeOption('field'); } else { $field = true; } - $query->field($field, false, $table, $alias); + $query->field($field, false, $table, $name); $field = null; } @@ -78,9 +78,9 @@ abstract class OneToOne extends Relation $query->via($joinAlias); if ($this instanceof BelongsTo) { - $query->join($joinTable . ' ' . $joinAlias, $alias . '.' . $this->foreignKey . '=' . $joinAlias . '.' . $this->localKey, $this->joinType); + $query->join([$joinTable => $joinAlias], $name . '.' . $this->foreignKey . '=' . $joinAlias . '.' . $this->localKey, $this->joinType); } else { - $query->join($joinTable . ' ' . $joinAlias, $alias . '.' . $this->localKey . '=' . $joinAlias . '.' . $this->foreignKey, $this->joinType); + $query->join([$joinTable => $joinAlias], $name . '.' . $this->localKey . '=' . $joinAlias . '.' . $this->foreignKey, $this->joinType); } if ($closure) { @@ -214,6 +214,16 @@ abstract class OneToOne extends Relation return $this; } + /** + * 获取绑定属性 + * @access public + * @return array + */ + public function getBindAttr() + { + return $this->bindAttr; + } + /** * 关联统计 * @access public @@ -276,7 +286,7 @@ abstract class OneToOne extends Relation if (isset($result->$key)) { throw new Exception('bind attr has exists:' . $key); } else { - $result->setAttr($key, $model->$attr); + $result->setAttr($key, $model ? $model->$attr : null); } } } @@ -294,6 +304,8 @@ abstract class OneToOne extends Relation */ protected function eagerlyWhere($model, $where, $key, $relation, $subRelation = '', $closure = false) { + $this->baseQuery = true; + // 预载入关联查询 支持嵌套预载入 if ($closure) { call_user_func_array($closure, [ & $model]); @@ -312,10 +324,14 @@ abstract class OneToOne extends Relation } /** - * 执行基础查询(进执行一次) - * @access protected - * @return void + * 创建关联统计子查询 + * @access public + * @param \Closure $closure 闭包 + * @param string $name 统计数据别名 + * @return string */ - protected function baseQuery() - {} + public function getRelationCountQuery($closure, &$name = null) + { + throw new Exception('relation not support: withCount'); + } } diff --git a/thinkphp/library/think/paginator/driver/Bootstrap.php b/thinkphp/library/think/paginator/driver/Bootstrap.php index 58fa9436..c5ac60db 100644 --- a/thinkphp/library/think/paginator/driver/Bootstrap.php +++ b/thinkphp/library/think/paginator/driver/Bootstrap.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- diff --git a/thinkphp/library/think/response/Json.php b/thinkphp/library/think/response/Json.php index 538fc5a0..c906bfc1 100644 --- a/thinkphp/library/think/response/Json.php +++ b/thinkphp/library/think/response/Json.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- diff --git a/thinkphp/library/think/response/Jsonp.php b/thinkphp/library/think/response/Jsonp.php index de8fb304..404bacbe 100644 --- a/thinkphp/library/think/response/Jsonp.php +++ b/thinkphp/library/think/response/Jsonp.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- diff --git a/thinkphp/library/think/response/Redirect.php b/thinkphp/library/think/response/Redirect.php index f45b0e1c..91694cb2 100644 --- a/thinkphp/library/think/response/Redirect.php +++ b/thinkphp/library/think/response/Redirect.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -67,7 +67,11 @@ class Redirect extends Response */ public function getTargetUrl() { - return strpos($this->data, '://') ? $this->data : Url::build($this->data, $this->params); + if (strpos($this->data, '://') || (0 === strpos($this->data, '/') && empty($this->params))) { + return $this->data; + } else { + return Url::build($this->data, $this->params); + } } public function params($params = []) diff --git a/thinkphp/library/think/response/View.php b/thinkphp/library/think/response/View.php index de75515a..48f944a7 100644 --- a/thinkphp/library/think/response/View.php +++ b/thinkphp/library/think/response/View.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- diff --git a/thinkphp/library/think/response/Xml.php b/thinkphp/library/think/response/Xml.php index ca12e295..3bdc052a 100644 --- a/thinkphp/library/think/response/Xml.php +++ b/thinkphp/library/think/response/Xml.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -11,6 +11,8 @@ namespace think\response; +use think\Collection; +use think\Model; use think\Response; class Xml extends Response @@ -81,6 +83,11 @@ class Xml extends Response protected function dataToXml($data, $item, $id) { $xml = $attr = ''; + + if ($data instanceof Collection || $data instanceof Model) { + $data = $data->toArray(); + } + foreach ($data as $key => $val) { if (is_numeric($key)) { $id && $attr = " {$id}=\"{$key}\""; diff --git a/thinkphp/library/think/session/driver/Memcache.php b/thinkphp/library/think/session/driver/Memcache.php index 0c02e23e..877d7bd7 100644 --- a/thinkphp/library/think/session/driver/Memcache.php +++ b/thinkphp/library/think/session/driver/Memcache.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- diff --git a/thinkphp/library/think/session/driver/Memcached.php b/thinkphp/library/think/session/driver/Memcached.php index bcaf8a1b..2994a07c 100644 --- a/thinkphp/library/think/session/driver/Memcached.php +++ b/thinkphp/library/think/session/driver/Memcached.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- diff --git a/thinkphp/library/think/session/driver/Redis.php b/thinkphp/library/think/session/driver/Redis.php index a4c2b54a..8d05126b 100644 --- a/thinkphp/library/think/session/driver/Redis.php +++ b/thinkphp/library/think/session/driver/Redis.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- diff --git a/thinkphp/library/think/template/TagLib.php b/thinkphp/library/think/template/TagLib.php index d343bed0..c5b72f91 100644 --- a/thinkphp/library/think/template/TagLib.php +++ b/thinkphp/library/think/template/TagLib.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -264,8 +264,8 @@ class TagLib if (!empty($this->tags[$name]['expression'])) { static $_taglibs; if (!isset($_taglibs[$name])) { - $_taglibs[$name][0] = strlen(ltrim($this->tpl->config('taglib_begin'), '\\') . $name); - $_taglibs[$name][1] = strlen(ltrim($this->tpl->config('taglib_end'), '\\')); + $_taglibs[$name][0] = strlen($this->tpl->config('taglib_begin_origin') . $name); + $_taglibs[$name][1] = strlen($this->tpl->config('taglib_end_origin')); } $result['expression'] = substr($str, $_taglibs[$name][0], -$_taglibs[$name][1]); // 清除自闭合标签尾部/ diff --git a/thinkphp/library/think/template/driver/File.php b/thinkphp/library/think/template/driver/File.php index b27e7265..a9a86bf2 100644 --- a/thinkphp/library/think/template/driver/File.php +++ b/thinkphp/library/think/template/driver/File.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -15,6 +15,8 @@ use think\Exception; class File { + protected $cacheFile; + /** * 写入编译缓存 * @param string $cacheFile 缓存的文件名 @@ -42,12 +44,13 @@ class File */ public function read($cacheFile, $vars = []) { + $this->cacheFile = $cacheFile; if (!empty($vars) && is_array($vars)) { // 模板阵列变量分解成为独立变量 extract($vars, EXTR_OVERWRITE); } //载入模版缓存文件 - include $cacheFile; + include $this->cacheFile; } /** diff --git a/thinkphp/library/think/template/taglib/Cx.php b/thinkphp/library/think/template/taglib/Cx.php index af7a54c8..31e0698d 100644 --- a/thinkphp/library/think/template/taglib/Cx.php +++ b/thinkphp/library/think/template/taglib/Cx.php @@ -278,7 +278,7 @@ class Cx extends Taglib */ public function tagCase($tag, $content) { - $value = !empty($tag['expression']) ? $tag['expression'] : $tag['value']; + $value = isset($tag['expression']) ? $tag['expression'] : $tag['value']; $flag = substr($value, 0, 1); if ('$' == $flag || ':' == $flag) { $value = $this->autoBuildVar($value); diff --git a/thinkphp/library/think/view/driver/Php.php b/thinkphp/library/think/view/driver/Php.php index 468d3611..f594a438 100644 --- a/thinkphp/library/think/view/driver/Php.php +++ b/thinkphp/library/think/view/driver/Php.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -29,7 +29,11 @@ class Php 'view_suffix' => 'php', // 模板文件名分隔符 'view_depr' => DS, + // 默认模板渲染规则 1 解析为小写+下划线 2 全部转换小写 + 'auto_rule' => 1, ]; + protected $template; + protected $content; public function __construct($config = []) { @@ -68,16 +72,12 @@ class Php if (!is_file($template)) { throw new TemplateNotFoundException('template not exists:' . $template, $template); } + $this->template = $template; // 记录视图信息 App::$debug && Log::record('[ VIEW ] ' . $template . ' [ ' . var_export(array_keys($data), true) . ' ]', 'info'); - if (isset($data['template'])) { - $__template__ = $template; - extract($data, EXTR_OVERWRITE); - include $__template__; - } else { - extract($data, EXTR_OVERWRITE); - include $template; - } + + extract($data, EXTR_OVERWRITE); + include $this->template; } /** @@ -89,14 +89,10 @@ class Php */ public function display($content, $data = []) { - if (isset($data['content'])) { - $__content__ = $content; - extract($data, EXTR_OVERWRITE); - eval('?>' . $__content__); - } else { - extract($data, EXTR_OVERWRITE); - eval('?>' . $content); - } + $this->content = $content; + + extract($data, EXTR_OVERWRITE); + eval('?>' . $this->content); } /** @@ -132,7 +128,7 @@ class Php if ($controller) { if ('' == $template) { // 如果模板文件名为空 按照默认规则定位 - $template = str_replace('.', DS, $controller) . $depr . $request->action(); + $template = str_replace('.', DS, $controller) . $depr . (1 == $this->config['auto_rule'] ? Loader::parseName($request->action(true)) : $request->action()); } elseif (false === strpos($template, $depr)) { $template = str_replace('.', DS, $controller) . $depr . $template; } diff --git a/thinkphp/library/think/view/driver/Think.php b/thinkphp/library/think/view/driver/Think.php index 39a14ca3..a314ad60 100644 --- a/thinkphp/library/think/view/driver/Think.php +++ b/thinkphp/library/think/view/driver/Think.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -34,6 +34,8 @@ class Think 'view_depr' => DS, // 是否开启模板编译缓存,设为false则每次都会重新编译 'tpl_cache' => true, + // 默认模板渲染规则 1 解析为小写+下划线 2 全部转换小写 + 'auto_rule' => 1, ]; public function __construct($config = []) @@ -127,7 +129,7 @@ class Think if ($controller) { if ('' == $template) { // 如果模板文件名为空 按照默认规则定位 - $template = str_replace('.', DS, $controller) . $depr . $request->action(); + $template = str_replace('.', DS, $controller) . $depr . (1 == $this->config['auto_rule'] ? Loader::parseName($request->action(true)) : $request->action()); } elseif (false === strpos($template, $depr)) { $template = str_replace('.', DS, $controller) . $depr . $template; } diff --git a/thinkphp/library/traits/controller/Jump.php b/thinkphp/library/traits/controller/Jump.php index 36f2f94d..6a572246 100644 --- a/thinkphp/library/traits/controller/Jump.php +++ b/thinkphp/library/traits/controller/Jump.php @@ -1,5 +1,4 @@ server('HTTP_REFERER'))) { + $url = Request::instance()->server('HTTP_REFERER'); + } elseif ('' !== $url && !strpos($url, '://') && 0 !== strpos($url, '/')) { + $url = Url::build($url); } + + $type = $this->getResponseType(); $result = [ - 'code' => $code, + 'code' => 1, 'msg' => $msg, 'data' => $data, 'url' => $url, 'wait' => $wait, ]; - $type = $this->getResponseType(); if ('html' == strtolower($type)) { - $result = ViewTemplate::instance(Config::get('template'), Config::get('view_replace_str')) + $template = Config::get('template'); + $view = Config::get('view_replace_str'); + + $result = ViewTemplate::instance($template, $view) ->fetch(Config::get('dispatch_success_tmpl'), $result); } + $response = Response::create($result, $type)->header($header); + throw new HttpResponseException($response); } /** * 操作错误跳转的快捷方法 * @access protected - * @param mixed $msg 提示信息 - * @param string $url 跳转的URL地址 - * @param mixed $data 返回的数据 - * @param integer $wait 跳转等待时间 - * @param array $header 发送的Header信息 + * @param mixed $msg 提示信息 + * @param string $url 跳转的 URL 地址 + * @param mixed $data 返回的数据 + * @param int $wait 跳转等待时间 + * @param array $header 发送的 Header 信息 * @return void + * @throws HttpResponseException */ - protected function error($msg = '',$code=404, $options=[],$url = null, $data = '', $wait = 3, array $header = []) + protected function error($msg = '', $url = null, $data = '', $wait = 3, array $header = []) { - $code = 0; - if (is_numeric($msg)) { - $code = $msg; - $msg = ''; - } if (is_null($url)) { $url = Request::instance()->isAjax() ? '' : 'javascript:history.back(-1);'; - } elseif ('' !== $url) { - $url = (strpos($url, '://') || 0 === strpos($url, '/')) ? $url : Url::build($url); + } elseif ('' !== $url && !strpos($url, '://') && 0 !== strpos($url, '/')) { + $url = Url::build($url); } + + $type = $this->getResponseType(); $result = [ - 'code' => $code, + 'code' => 0, 'msg' => $msg, 'data' => $data, 'url' => $url, 'wait' => $wait, - 'options' => $options, ]; - $type = $this->getResponseType(); if ('html' == strtolower($type)) { - $result = ViewTemplate::instance(Config::get('template'), Config::get('view_replace_str')) + $template = Config::get('template'); + $view = Config::get('view_replace_str'); + + $result = ViewTemplate::instance($template, $view) ->fetch(Config::get('dispatch_error_tmpl'), $result); } + $response = Response::create($result, $type)->header($header); + throw new HttpResponseException($response); } /** - * 返回封装后的API数据到客户端 + * 返回封装后的 API 数据到客户端 * @access protected - * @param mixed $data 要返回的数据 - * @param integer $code 返回的code - * @param mixed $msg 提示信息 - * @param string $type 返回数据格式 - * @param array $header 发送的Header信息 + * @param mixed $data 要返回的数据 + * @param int $code 返回的 code + * @param mixed $msg 提示信息 + * @param string $type 返回数据格式 + * @param array $header 发送的 Header 信息 * @return void + * @throws HttpResponseException */ protected function result($data, $code = 0, $msg = '', $type = '', array $header = []) { $result = [ 'code' => $code, 'msg' => $msg, - 'time' => $_SERVER['REQUEST_TIME'], + 'time' => Request::instance()->server('REQUEST_TIME'), 'data' => $data, ]; $type = $type ?: $this->getResponseType(); $response = Response::create($result, $type)->header($header); + throw new HttpResponseException($response); } /** - * URL重定向 + * URL 重定向 * @access protected - * @param string $url 跳转的URL表达式 - * @param array|integer $params 其它URL参数 - * @param integer $code http code - * @param array $with 隐式传参 + * @param string $url 跳转的 URL 表达式 + * @param array|int $params 其它 URL 参数 + * @param int $code http code + * @param array $with 隐式传参 * @return void + * @throws HttpResponseException */ protected function redirect($url, $params = [], $code = 302, $with = []) { - $response = new Redirect($url); if (is_integer($params)) { $code = $params; $params = []; } + + $response = new Redirect($url); $response->code($code)->params($params)->with($with); + throw new HttpResponseException($response); } /** - * 获取当前的response 输出类型 + * 获取当前的 response 输出类型 * @access protected * @return string */ protected function getResponseType() { - $isAjax = Request::instance()->isAjax(); - return $isAjax ? Config::get('default_ajax_return') : Config::get('default_return_type'); + return Request::instance()->isAjax() + ? Config::get('default_ajax_return') + : Config::get('default_return_type'); } } diff --git a/thinkphp/library/traits/model/SoftDelete.php b/thinkphp/library/traits/model/SoftDelete.php index be586342..70f31ba2 100644 --- a/thinkphp/library/traits/model/SoftDelete.php +++ b/thinkphp/library/traits/model/SoftDelete.php @@ -2,11 +2,15 @@ namespace traits\model; +use think\Collection; use think\db\Query; +use think\Model; +/** + * @mixin \Think\Model + */ trait SoftDelete { - /** * 判断当前实例是否被软删除 * @access public @@ -15,22 +19,21 @@ trait SoftDelete public function trashed() { $field = $this->getDeleteTimeField(); - if (!empty($this->data[$field])) { + + if ($field && !empty($this->data[$field])) { return true; } return false; } /** - * 查询软删除数据 + * 查询包含软删除的数据 * @access public * @return Query */ public static function withTrashed() { - $model = new static(); - $field = $model->getDeleteTimeField(true); - return $model->getQuery(); + return (new static )->getQuery(); } /** @@ -42,14 +45,18 @@ trait SoftDelete { $model = new static(); $field = $model->getDeleteTimeField(true); - return $model->getQuery() - ->useSoftDelete($field, ['not null', '']); + + if ($field) { + return $model->getQuery()->useSoftDelete($field, ['not null', '']); + } else { + return $model->getQuery(); + } } /** * 删除当前的记录 * @access public - * @param bool $force 是否强制删除 + * @param bool $force 是否强制删除 * @return integer */ public function delete($force = false) @@ -57,48 +64,71 @@ trait SoftDelete if (false === $this->trigger('before_delete', $this)) { return false; } + $name = $this->getDeleteTimeField(); - if (!$force) { + if ($name && !$force) { // 软删除 $this->data[$name] = $this->autoWriteTimestamp($name); $result = $this->isUpdate()->save(); } else { - $result = $this->getQuery()->delete($this->data); + // 强制删除当前模型数据 + $result = $this->getQuery()->where($this->getWhere())->delete(); + } + + // 关联删除 + if (!empty($this->relationWrite)) { + foreach ($this->relationWrite as $key => $name) { + $name = is_numeric($key) ? $name : $key; + $result = $this->getRelation($name); + if ($result instanceof Model) { + $result->delete(); + } elseif ($result instanceof Collection || is_array($result)) { + foreach ($result as $model) { + $model->delete(); + } + } + } } $this->trigger('after_delete', $this); + + // 清空原始数据 + $this->origin = []; + return $result; } /** * 删除记录 * @access public - * @param mixed $data 主键列表 支持闭包查询条件 + * @param mixed $data 主键列表(支持闭包查询条件) * @param bool $force 是否强制删除 * @return integer 成功删除的记录数 */ public static function destroy($data, $force = false) { + if (is_null($data)) { + return 0; + } + // 包含软删除数据 - $query = self::withTrashed(); + $query = (new static())->db(false); if (is_array($data) && key($data) !== 0) { $query->where($data); $data = null; } elseif ($data instanceof \Closure) { call_user_func_array($data, [ & $query]); $data = null; - } elseif (is_null($data)) { - return 0; } - $resultSet = $query->select($data); - $count = 0; - if ($resultSet) { + $count = 0; + if ($resultSet = $query->select($data)) { foreach ($resultSet as $data) { $result = $data->delete($force); $count += $result; } } + return $count; } @@ -110,46 +140,61 @@ trait SoftDelete */ public function restore($where = []) { - $name = $this->getDeleteTimeField(); if (empty($where)) { $pk = $this->getPk(); $where[$pk] = $this->getData($pk); } - // 恢复删除 - return $this->getQuery() - ->useSoftDelete($name, ['not null', '']) - ->where($where) - ->update([$name => null]); + + $name = $this->getDeleteTimeField(); + + if ($name) { + // 恢复删除 + return $this->getQuery() + ->useSoftDelete($name, ['not null', '']) + ->where($where) + ->update([$name => null]); + } else { + return 0; + } } /** * 查询默认不包含软删除数据 * @access protected * @param Query $query 查询对象 - * @return void + * @return Query */ protected function base($query) { $field = $this->getDeleteTimeField(true); - $query->useSoftDelete($field); + return $field ? $query->useSoftDelete($field) : $query; } /** * 获取软删除字段 * @access public - * @param bool $read 是否查询操作 写操作的时候会自动去掉表别名 + * @param bool $read 是否查询操作(写操作的时候会自动去掉表别名) * @return string */ protected function getDeleteTimeField($read = false) { - $field = property_exists($this, 'deleteTime') && isset($this->deleteTime) ? $this->deleteTime : 'delete_time'; + $field = property_exists($this, 'deleteTime') && isset($this->deleteTime) ? + $this->deleteTime : + 'delete_time'; + + if (false === $field) { + return false; + } + if (!strpos($field, '.')) { $field = '__TABLE__.' . $field; } + if (!$read && strpos($field, '.')) { $array = explode('.', $field); $field = array_pop($array); } + return $field; } } diff --git a/thinkphp/library/traits/think/Instance.php b/thinkphp/library/traits/think/Instance.php index ba45ddd8..428c8fde 100644 --- a/thinkphp/library/traits/think/Instance.php +++ b/thinkphp/library/traits/think/Instance.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -15,31 +15,40 @@ use think\Exception; trait Instance { + /** + * @var null|static 实例对象 + */ protected static $instance = null; /** - * @param array $options + * 获取示例 + * @param array $options 实例配置 * @return static */ public static function instance($options = []) { - if (is_null(self::$instance)) { - self::$instance = new self($options); - } + if (is_null(self::$instance)) self::$instance = new self($options); + return self::$instance; } - // 静态调用 - public static function __callStatic($method, $params) + /** + * 静态调用 + * @param string $method 调用方法 + * @param array $params 调用参数 + * @return mixed + * @throws Exception + */ + public static function __callStatic($method, array $params) { - if (is_null(self::$instance)) { - self::$instance = new self(); - } + if (is_null(self::$instance)) self::$instance = new self(); + $call = substr($method, 1); - if (0 === strpos($method, '_') && is_callable([self::$instance, $call])) { - return call_user_func_array([self::$instance, $call], $params); - } else { + + if (0 !== strpos($method, '_') || !is_callable([self::$instance, $call])) { throw new Exception("method not exists:" . $method); } + + return call_user_func_array([self::$instance, $call], $params); } } diff --git a/thinkphp/start.php b/thinkphp/start.php index 8af62ef3..adb1bc65 100644 --- a/thinkphp/start.php +++ b/thinkphp/start.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -12,7 +12,8 @@ namespace think; // ThinkPHP 引导文件 -// 加载基础文件 +// 1. 加载基础文件 require __DIR__ . '/base.php'; -// 执行应用 + +// 2. 执行应用 App::run()->send(); diff --git a/thinkphp/tests/.gitignore b/thinkphp/tests/.gitignore deleted file mode 100644 index a0306ecc..00000000 --- a/thinkphp/tests/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -/runtime/ -/application/common.php -/application/demo/ -/application/runtime/ \ No newline at end of file diff --git a/thinkphp/tests/README.md b/thinkphp/tests/README.md deleted file mode 100644 index 0c1d0869..00000000 --- a/thinkphp/tests/README.md +++ /dev/null @@ -1,132 +0,0 @@ -## 测试目录结构 - -测试文件主要在 tests 文件下面,主要有以下几个文件夹 - -- conf 测试环境配置文件。 -- script 测试环境配置脚本。 -- thinkphp 测试用例和相关文件,与项目文件夹结构一致。 -- mock.php 测试入口文件。 - -## 主要测试流程 - -thinkphp5 的测试的主要流程是跟 thinkphp 的系统流程是相似的,大体的流程为: - -1. 引用 mock.php 文件加载框架 - -2. 根据文件目录,添加测试文件 - -3. 执行单元测试,输出结果 - -## 测试举例 - -例如测试 thinkphp 里的 apc 缓存,将分为以下几个过程: - -1. 创建 apcTest.php 文件 - -该文件应与 apc.php 目录路径 `thinkphp/library/think/cache/driver` 一致,命名空间与目录所在一致,并引用 `PHPUnit_Framework_TestCase`。 - - ```php - markTestSkipped('apc扩展不可用!'); - }; - ``` - - - 编写测试用例 - - *具体写法参照 [PHPUnit 官方文档](https://phpunit.de/manual/4.8/zh_cn/index.html)* - - ```php - public function testGet() - { - App::run(); - $this->assertInstanceOf( - '\think\cache\driver\Apc', - Cache::connect(['type' => 'apc', 'expire' => 1]) - ); - $this->assertTrue(Cache::set('key', 'value')); - $this->assertEquals('value', Cache::get('key')); - $this->assertTrue(Cache::rm('key')); - $this->assertFalse(Cache::get('key')); - $this->assertTrue(Cache::clear('key')); - Config::reset(); - } - ``` - -3. 执行单元测试命令 - - 在项目根目录执行 - - ```bash - $ phpunit - ``` - - 若想看到所有结果,请添加-v参数 - - ```bash - $ phpunit -v - ``` - -4. 输出结果 - -## 相关文档 - -[各个部分单元测试说明](http://www.kancloud.cn/brother_simon/tp5_test/96971 "各部分单元测试说明") - -## 大家一起来 - -单元测试的内容会跟框架同步,测试内容方方面面,是一个相对复杂的模块,同时也是一个值得重视的部分。希望大家能够多多提出意见,多多参与。如果你有任何问题或想法,可以随时提 issue,我们期待着收到听大家的质疑和讨论。 - -## 任务进度 - -单元测试任务进度,请大家认领模块 - -|模块|认领人|进度| -|---|---|---| -|Base||| -|App|Haotong Lin|√| -|Build|刘志淳|| -|Config|Haotong Lin|√| -|Cache||| -|Controller|Haotong Lin|√| -|Cookie|Haotong Lin|√| -|Db||| -|Debug|大漠|√| -|Error|大漠|| -|Exception|Haotong Lin|√| -|Hook|流年|√| -|Input|Haotong Lin|√| -|Lang|流年|√| -|Loader|流年|| -|Log||| -|Model||| -|Response|大漠|√| -|Route|流年|| -|Session|大漠|√| -|Template|oldrind|| -|Url|流年|| -|View|mahuan|| diff --git a/thinkphp/tests/application/config.php b/thinkphp/tests/application/config.php deleted file mode 100644 index d94a8641..00000000 --- a/thinkphp/tests/application/config.php +++ /dev/null @@ -1,33 +0,0 @@ - -// +---------------------------------------------------------------------- -// $Id$ - -return [ - 'url_route_on' => true, - 'log' => [ - 'type' => 'file', // 支持 socket trace file - ], - 'view' => [ - // 模板引擎 - 'engine_type' => 'think', - // 模板引擎配置 - 'engine_config' => [ - // 模板路径 - 'view_path' => '', - // 模板后缀 - 'view_suffix' => '.html', - // 模板文件名分隔符 - 'view_depr' => DS, - ], - // 输出字符串替换 - 'parse_str' => [], - ], -]; diff --git a/thinkphp/tests/application/database.php b/thinkphp/tests/application/database.php deleted file mode 100644 index 24434efb..00000000 --- a/thinkphp/tests/application/database.php +++ /dev/null @@ -1,44 +0,0 @@ - -// +---------------------------------------------------------------------- -// $Id$ - -return [ - // 数据库类型 - 'type' => 'mysql', - // 数据库连接DSN配置 - 'dsn' => '', - // 服务器地址 - 'hostname' => '127.0.0.1', - // 数据库名 - 'database' => '', - // 数据库用户名 - 'username' => 'root', - // 数据库密码 - 'password' => '', - // 数据库连接端口 - 'hostport' => '', - // 数据库连接参数 - 'params' => [], - // 数据库编码默认采用utf8 - 'charset' => 'utf8', - // 数据库表前缀 - 'prefix' => '', - // 数据库调试模式 - 'debug' => true, - // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器) - 'deploy' => 0, - // 数据库读写是否分离 主从式有效 - 'rw_separate' => false, - // 读写分离后 主服务器数量 - 'master_num' => 1, - // 指定从服务器序号 - 'slave_no' => '', -]; diff --git a/thinkphp/tests/application/index/controller/Index.php b/thinkphp/tests/application/index/controller/Index.php deleted file mode 100644 index 803fe952..00000000 --- a/thinkphp/tests/application/index/controller/Index.php +++ /dev/null @@ -1,10 +0,0 @@ -*{ padding: 0; margin: 0; } div{ padding: 4px 48px;} a{color:#2E5CD5;cursor: pointer;text-decoration: none} a:hover{text-decoration:underline; } body{ background: #fff; font-family: "Century Gothic","Microsoft yahei"; color: #333;font-size:18px} h1{ font-size: 100px; font-weight: normal; margin-bottom: 12px; } p{ line-height: 1.6em; font-size: 42px }
'; - } -} diff --git a/thinkphp/tests/application/route.php b/thinkphp/tests/application/route.php deleted file mode 100644 index 45bcf79d..00000000 --- a/thinkphp/tests/application/route.php +++ /dev/null @@ -1,22 +0,0 @@ - -// +---------------------------------------------------------------------- -// $Id$ - -return [ - '__pattern__' => [ - 'name' => '\w+', - ], - '[hello]' => [ - ':id' => ['index/hello', ['method' => 'get'], ['id' => '\d+']], - ':name' => ['index/hello', ['method' => 'post']], - ], - -]; diff --git a/thinkphp/tests/conf/apcu.ini b/thinkphp/tests/conf/apcu.ini deleted file mode 100644 index 9c2abed2..00000000 --- a/thinkphp/tests/conf/apcu.ini +++ /dev/null @@ -1,3 +0,0 @@ -extension=apcu.so - -apc.enable_cli=1 diff --git a/thinkphp/tests/conf/apcu_bc.ini b/thinkphp/tests/conf/apcu_bc.ini deleted file mode 100644 index a7f6182d..00000000 --- a/thinkphp/tests/conf/apcu_bc.ini +++ /dev/null @@ -1,4 +0,0 @@ -extension=apcu.so -extension=apc.so - -apc.enable_cli=1 diff --git a/thinkphp/tests/conf/memcached.ini b/thinkphp/tests/conf/memcached.ini deleted file mode 100644 index 7d09664e..00000000 --- a/thinkphp/tests/conf/memcached.ini +++ /dev/null @@ -1 +0,0 @@ -extension=memcached.so diff --git a/thinkphp/tests/conf/redis.ini b/thinkphp/tests/conf/redis.ini deleted file mode 100644 index 6aecae48..00000000 --- a/thinkphp/tests/conf/redis.ini +++ /dev/null @@ -1 +0,0 @@ -extension=redis.so diff --git a/thinkphp/tests/conf/timezone.ini b/thinkphp/tests/conf/timezone.ini deleted file mode 100644 index ced3e0d7..00000000 --- a/thinkphp/tests/conf/timezone.ini +++ /dev/null @@ -1 +0,0 @@ -date.timezone = UTC \ No newline at end of file diff --git a/thinkphp/tests/extensions/5.4/apcu.so b/thinkphp/tests/extensions/5.4/apcu.so deleted file mode 100644 index 42a24a660e00f2fc2f57494bc4f62172da7cddf9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 404136 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 z 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 z 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�jPt<4cw1~GcZ$l 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 diff --git a/thinkphp/tests/extensions/5.6/apcu.so b/thinkphp/tests/extensions/5.6/apcu.so deleted file mode 100644 index fe952969ee5e3b7dae3305c44929714a4780e7c0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 404405 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ⓈU(dm{;I@5ln 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

xj!FZKB|x6BnyYl(I<911{N`C}q(P zcz!jr#r?eLFA0j74R(g13jR3oLiW4E4inv6qE4{!WIC_ajVe z{GE&gKL$QT_Wyo}X4jjB0r?OaX#5z>fyOZ6HJy>bsc5zVR}&Y%{Ym0KOI-Z+CmBb6 zNL*C>Nyd?~BG_AZ@$4@bTl=dsu!7qOYr_$=alkxShWO)vHqW7UhFt5-Kh zzlUn&T)k`gkP{)$S42ZSYc1$Qv7xT979b4S76A38XlnihaVg@P#X#)_02c$@BH9ch zE(W?q478NE80Z!;&=%nNC*XZjvDZekVz(R!9;w(GUkW@w7%g?vQfo!-YY4*+-_AvC z>aDJU-PMF>6*g@94MMik2Vq%pcG$oZ#K3%2UHiZU5!GZclG~CB0h7cB#sSafyL755 z`h189iLo@yQLp57vgCF-qe^b4h^TvsOKzt~ZVwQb+)k0)egoVZbPKE4cTp z*JceIHcvhCKTk})4DC8@2T<-f=rAf;71V0pGV{bX#gh#-9VHHMAEIan7$qWJp@=am zwG||kMyqlYb9|$OUm7HoiiB?(B$SE--w2WLB-ZpYPN~Fq*21c1_}K{!j%mY`iX>flrU&KhJtEWl&UrnZ@d?w`0WO@ zW^P!AUE*7h!2z@myQFOXA}+qQOMGkQNR*9iY(FRT_ke3(+HHIZz9E~i&o}ypv`l-1 z|9^}xzVf2@%8*gO#TWJp{Xyd53wy;EekLxyuvdJc^JokQy<2n!GEGLLov4puJ5dX| zZYMPEx&ZA&Rk)p~mo(B4hTj+}(un9oX=SIr!=D8FS%6zD5YAj?9V?rHG0=2LQ&avg! z<5^0Pr4(06Q58(8f(hd{n&;dKOr+iB*#Y7vTnVMpK|BVeBo}~h98xO)Fp5A4fJFqx z0N6-i8i2P5%m#10LXAJ_%{s6FpfE%sNI|Tdy{sb_BqR%rT z!=iB*uK3?!r4(99iKUcQN=c=ZQo&>^s020T*|u^cuH81R>41rtfl<@3AYL;Gsm}qh zi@-7fstUk#06hT|UvDBOn8;-}fpQsH)&kfDAm4&#mu&%dkXR@MDLD=xFdf!C319+%${zt>VX^ctJj6us5y@iCK!!3nrGrg z7#A&q!ucTH1f*mbfOi0tT>v0^27svmW)Qd>KrMixViS9edDbKEWlKPHVp@&G0zfwy zQmqGhDMyonXDLONQd}uTRWPXvCQR*kl(E)CYWkprSsfv61+*J`H;8J~*lm1_u6%-z z^Go;OQF(}P`3T0gOssHhoMSBhcUURoO3YHmtf0gSO2=&D5O37bJ-U`a9 zpkyY`W0G|y(s>U_m}SjEs!To$#CbqU`T^Jnplk?$R+j=81>k%FlL6cUU>GF@jf5&D zALq%hVe*VqO8!#vR!~+2B{TWU@GLNqK7Uvz{{y7`%H)@TSbiCRwE#8(D60kV2Z2Wb z47?mgu?qkzY}v~Isu5CF58!D69|HJ}z}Eme%!cqW>XsBJwmeFmGHLzKJkiOXcU8C< zSuS1Vors~Ek>%1wKC2~M%7OglQObHmYwI;nNLbV$;c}7iQ-g%dMMB^TL`hrjg@6-Y zeJ1jEM9Ii6kPx16%#fo|C%iMjsZTPU@HU>0JmF>glg%$8s?TM&Jv+Y#;4i)1z@LqM z6;xqa{LcP~YW`P;U%|HPTQ5hu)@Yv5OfWjf?LY{AB~Xk<2TB%z_!y9qYXMx0@m$F& z00#&>03Z(Ikg^>B4iR_(Kpp$_*8n7-zo>i%fOGYUWtE=^P_um8uQ2_3liFT7#VX%} zOCYTa817^j(+0rL1eyXEiIs_K;!CEkk0U&Z?caR> zuvKG~+y#KGLdh)vx}pl_*HhMRVD|tkdlf(rI9AzP0LBpb1VBgpm3@nUH{%cKl^|*7 z;{@TFwCKaWF-)%#;Xi<7INx;$GgN~idSJ;c1O<>UbZCrzx{e?QM^EUds_{wmUSK(& z(f|1ugAp-FL|CJFQZ~Vq&C#c{jB7wETn0VPf_M^0N#gl9+X&6d+5)(hKsNv%66gh> z379Jf0N{+OYy^Nw44EJy+n1MJ4B#<@lwAp+)pC%o7Si*}%WefQ3n68919*zSHUQre zcmhECYN#|uo!=40xhP828x21;Pt=5KAy-c(E|QwC8!>cUx=3om$6CVklrSkuoiH)K zZIp1JLBb@F(Cq54gh?Wy7jSFz3()42iFCzt2*K|PQ1(~DK8Hcve+__>01~c+@}~e) z0;v2OfOB=t(n`-rvCq=7Ab>UG=?WnJIsiQZ93c<_;JF?^Ie-TMRE`JWT>Z$>vKatA zC21aj%{PElEu^}oWh()^jgYc+0CH~xuob{e0(AiH1u*`30KYyfT3clSAiY<>Y4^gX z$_@bA1gxwcK;caY=CPBqkAU3=Y#hBP!9<-6ifZfr6y+nH7=1HDPT&Ufc*F6udE%O* zB{U7Ul*_>-n>L#X@L0uu0LA}~(ztIErqm)ivu`6&xo^X$`SsM0Co8@LCi^xkO}cB% zQ}5e|@_S8?6$|Cl+?%Ktt5M1=P<{ln*V+_lg?XwbZsDjP2YzEz*ZzpR%cZIf$8F{b z4|LOCu0^v5I+uB`L?rEjyX0K(Itm%1wibh<&ZTNh%zGLo3~G>2Clcx#B-Dw7)08lp z=dWu`q?h+mEu14+iN>3b_XmheZw25Vg?dCF1;GCRl%)e0bQ>Hd7XVywd07E~hZ#~L zA*Ys=jR6q93L(=Z1a)>cfVl`MTLPe04M;15ggUzxz($0W)dCp08o(m}`ri&<7l0cH zybRzi0ORWcBs{OREq?0-4OlPgXW1E0m#+c8bF^hW1AvygCJ&aH=~ne7lb@R>Y<> zs%l8>Ra;tI^v#L?T?gj}(BH_LU z2}L5|6)l0EUsk={DjaieqlB{!5_*e-|20VHEfU(^DY>|+HzZ`cRkev(((a`%!aD%=;Q8T-_kyeyKS-8zkH>HRoL|VN4<j^}3dgK(l;B3ItaEXPNSN6m;SP~-tCp}h9TIMJ zsc_7X8YK*BkZ`L=IM5*BR*~>EC8T|eHcvfa-f%gFD0&3#L^ z(66lUeN44ehYxo{+EYF_sg?ak3&2nNxOtV6&5yaL*L?VIWuHb!7?#DW*X4vg8Y3RS zKVfo^@j7_%3$DWpI_NP<_JMc}kdh++UMKJ#fSd0I@CAVF>rvs)0=VfO0QLnK7;ONM z2*9@y#{n~AE$b!pXQjmm8Ajur+OJcn1_j69ORhlJ&tNUN5Ww(F04f1I2_XLjSjv_H z%i9d#CIC^j0PX;=oWK?UIa|>CB)qI;&N0uj$3Qs(O4%y_P5~%=4gh}x_*L`k(T!H# z1C20=Up9g7*S>FJ{%D?RN~{k|B`<^4^j-kZ0vJ!=F#y{DSVdhAh(xR0JiD-${uolv z2)W~{nw)Q*LrJa&xy5~q{mMa2K4G30ll%zCvV>OrKNFmONVAo_08$lWS_5j4gkV(Md6un&#DyeTMd7eh zhW7XhPRc+p8-;)OfJu&}h1ot1CtDmV1BDmBAOnTZ2yhJH-i8$a&E7a-2vhi>S~Fr0 z85}WCM!pq~v^io(haed->@#T|GEZ~TV;tW{`Nf1~B9>Yl>!Me$K=?#NE?ENL1cBKA zrrZx;8i11k@@tvO9l(}80ALG%-vB`Ky|3^AzcSCVESTZC?O;j;up0okZbsxGx#2FA z`8sh-K#%C>$DmKcNJlp_!=;hPd??&d4VOk@DexhE*hZAQW+2)t#BXg1e1xkT@SzU_ zmpNaB(2o+Ax5UmDdh#P!Taw+6kuIK6!nW!XeQGI;*DV?HR}k_>$tzaVz&}*pRvYbd zJJ8!RzMMtAz{OARIak*&2}z?dMqa~mu0Fg(FGp2seIG^ovK&<@uU+jRF3VAs^6J&M zz-8HJ-Vtqt6D*6_E(xnOVSMFWUGIYFo?=%Qz|n=T-xdl6x} zp9zR6zQ>WYn68uS?DK$YtywbrVE>@rI@N1lQV6q z6fxBgz_qDb{mWFX|7EH+qTeG=B0arwC#L$0xL&yvQ?=NEyr%up9u|m>lXoRlx0UE0 zx;rI=X9ClwPsP4vbR5G0V;kQSmqQ*YF*|O4Z#4H}0&g6>CtI@bi|a;MvL36$CEIa2 zT)ZVdj^3i*b4n06Q@p|-N3X~};D!!OG>>>s(>V4^^1^T+E}!BhXNhrZOMtjN!@Ki8 zzXmku#=(fY-l=L$S!Nsu2Y#E8-v@3Bm+5*ZN8LZ|443J8`AWi;r+~`_&Uz<1w)cRC zj&T&fLFib?S)w;^HafZ6?OeTgNvOsP`X=Fbu6|?5kb3fOcG3v`r(tv1(5aR9vx&dl z3G^+_(-Ie2b|n%cdkBYD$jOFeITYZ+9S5hw+)sM7mwKP7xzhsHwW zxAgO+Tj7R0GqTUgEu+QHA&zV0SUq0Dl9(PnwX}u!=}l{p7?LuQOULwZ^G3jhpp0Ps|#=Y4El+;%&iwVQ*U_b}9xA z37zP$w>VXSi8-iILYGxxf4xN{OmC2Ii%7VM5(dre0Re~cN|1@T@Du85S&x9K)`TS- zmRExQ_flAg!}4y=u>HWr;}1LN@z(;^9)DEmI8nP;d;A;n#vS_p#oEK`<$bu_;MX4h zrtr6T8Msva|HwOaJBds6e@pl`ppVow;FyCo;5u||x(2-MU=0}cDsZ%P_-2a4KTTYk zm3Jlny$6B+6$Jgbyj67bp>Qkto_t^G58$E4nu7km(SO%sU86n_`q9@wmnP^#`IHEz zwu?jWpsuQq9Oolh)ab>mQ6D>4qn>&lsSSbKt53u_Rfof_d%|H{cd@QF(h@ek@Epzhp*X@Gy^w%;c zPk%ipI8J{pbFwx66sR?k-?&-vk;u1hHcv1}!dnb}e`C0=hDjgj2zAWYa;H?yJQH?; zVb?kb1Or%JZ^%+_$&%+ylj7?iYXL{hQ}xyN`d!G^W0M2o8-FsrF^V5*QhOY##>Bj$jkv5`H}*ct+kw)?XUf zC2v7z^HvvpYlZUlh~T+c86DiuQNV5ucP9M2hULV>9xd~!)(GFD!=+hxQQoGOk;2|s z)=525*cZ!@g8q=fOFCQzG5h5u>%5g~Ft?(_3>5F2J^}$cZ5Y8j1+M&Ld3xc5eFMZ91M%- z01?m&Iv$c(R$irqP?gss3mM91-boM5M!wkq(uNJmYiZtwza-ghD*y%Q1XoyJJ-=tw#Gt4i<1auk!3 z-M=$R>f=~`G6Fw2u{st~65C`F%8avy*L1nvS5K#!PT zg-B&@0h=OWg1E~BKfOGY!1(jz6II*zOxmH3JR>liZy{N1u0CrQAX%bSis4NG- zM+hm)2XF~m@zS9H%0}bg7GPyl0Ness8*l=t{(uaX%|*yQgp@4@KwU8gXoh9^yAiY+ zK}}Dvw?|0XL%{NYl|2n$If0h|+(%#&fL8$^ay3}{Gx9NneaEl?^$429pu#(_xBMx9 zQUF5X_CU=^J;@>_nz)NmcndXP_m-0dWQ z?*LQ~I0#??fnxv;0k8&CA)PXEC*Fw@uW*Mlt{smia28C<2-paDm7XFag!v|o8pKp* zV)N@Mp*vV?C?On+zorftHzk4NhuHioJS+QvLsbsrNuZsEUPJnc*b1Hk(m#2_k~Px2 z>Lw>`>KpMf>Rq-<*=Tl5bMugSqC0PLPq@{|mR6?{`j{ncar-4S(ipYB6(n?as5%q# znMMgC8zgiV37Z=vbQTFOQNkqkUVljVuiWdl*F-+pD5S6YEeiB9CH;N9A*B3Q=kN=N zIKyOIZH0-0i!4}FzqeQ>A4?kvd?4So7%3tgt7nA%3WD2QU%z@*h!>2h(W)C{I#yTd zgR>XNS%Z}8|4FiuF~I?`UDa(_%|LWSX zJ8V!~rI>+|(C)B71n&T@8|6)czXM#4ayH9{3w48BtJoVZgZz+WWQ!<*4rD>7dl3@9 z*WlY14C(IzexGD+;kS^zJrnp=p&tjXJCJQkcOdmwhQvtsE8T(A&L6NB)nVW!{LR9f zwsjbcAbR;YzWh4}(fLbAM$it`6io8Ud){{dxXgMPfcyebWtsJ5V6x15vx#@Rd2*R` z7{3rxZvtjh;8Uuk#TdM!@I6|IcmVme6x0z=F@o?LC*A^~{M9qc&+04ca4pJeI(SMJ z0N6y}5&%U%0GI^e76ADPFn!r7V8?(}-U9&Z2Ma165TIs3(Fh}Vo_W3o!DY{Ydg+e< z_5)Z0z$%{klO%85Yo29qg0zbyvrqnu5m1f<)vwCl3@zlu#;GvJmC%5{YH~DnbP01z zAjg0@gnDX?`5lgDz0|aR{l9;p9N#eJN`$XL%#vyVpAeV_APef1%mA>M zzytvM0pw@4L}u0j^T9)h@nfHN7?HCKTfMk zd2_&YYph&Po?z5ZGEcPPRmznHhBcZYXb9*zjpo_s7u51C_~W%U zV9H0{_9Lvg>R*flXHP{n+Z4+e+Ew|Gcinhwma+05U}qcpC+l~a{t!^DiT$=ik!Yp- ziVpN%BqJXJDw7WZ9YvV_5Rk@y0zQz5jPS2RkANdnR}I(;3k4A`+ZTfHaegj;%I6eP z#9WZf-f5hF^48&aPUd+HTRshtUk*a!o=cd$7NL%fldpq^C}|0L{{}xfg-~e;<^YqH zV1yB0X`W`oWk5k|eHL8nGow+T_r(aPD_~GFBK2va_1OzTqdsAF3q|vP>QjKwbMq5EL1rOXGy0d}W?+n}R?4VbC@ISJ*bH1`Y9) zeBkO;magrrT82IdzbT;r0uSlH8R5Xc>F}?Ahe)=wIvjYIefWo(bG8YLc|8MK-DgH8 zO|8(gO~KS$%|npwJaLguBx*R&kOHFC$c6yYU#>}^99EEU=)$nr=IyXn6&CBTLfhJd z>z26JMQqgtM(j4AF=RavW<@gToxxfY_nWXmbaDvT%3hRh4tIG;mSzz4|cag9L#~9rTfrdKJWcS5gBc$3eiBdw} zC4%%|+(sc;m65TI!KSJ%ZkLd%!z77yx(i58$Gs(_6Je616=J^k#Qh+og2>E;E=vGu zZ=AhNO8y+u$xM*;$92%8u|^F^YYJQTLvi^++8ZWGT9>s4sXlJ3kP60`SS*fEC%Vqt zaaRhdHcS$Mf3p$(Ag)G87Tk zxKD+2VnU?yfmD!wjQd+i1rrTPlPU|68k2|s&}d*h!JQtde!KHe9kZShBh zwD%m+_9&3H$A2v(t52kP3zI;4INte?IKVliYAXL&d}|?{h!hyJ3+0uAaPhF-R%j4g z_?_|Xg|&KqTPeR7uCrB!xg1vZA*s*_7a}NX2>wkygeHE_gY#U7tfp>-j6n}+q>apg z)`CZFzP6^GfS)>2wjcm^E_tqF3?;=px3dSj_6U~*SE7pUCIy@wF>RFQ+aNXN7M>F9PVqu?x;@# zd}}G#9N9?Ud7FUU;AhS|2u6F{9tv?}Ajnm+ncz5hhWh|>3w>g!fy;FvWqMo>z||aM zL66FX@hwLWv^Y^csk&$EV0_af+OPJ)7WSV(h;AaI764^3T_tZjkYH` z$)E|g7yV*%vO$yVqq#s^7&K^K0NY2mG-$e=i*k%kF=(d!U!tuH+SBd@(?qv6Xo04&Cy|o~ni5xEkgqiYruWg&+6Kc2>ZLDmW_manUS4K@mO7;I+!`Nxa11xN0_^c&Wj0 z*X%&z!)2LAE}MM>MIT)*+B@6tRrY)gKcXvCP||-{Sur`x-qYSQDBh&#=V=n(i|EIq z_h{=_zC+Bx3)(my-wHplm*_G2mbOJeJPIe8tg87)t+;(9CdXQ!8FnaeEk) zkk}cX=t;W@Er4Gx7Wd1=;{F{m5bw9BqhBr-_shlNez{oO-?JA~@XN*G{%=EYLBCuq z?w^gUd;L$MF8KU%vAEv>M~(AuZ-;ioFBgmZ zKSjoy`Q>79e@9T0{9E&|J?od8`2&5h-07E##r<-zxL+<7_shlN{w*FfLH@0%D{cL9 zvABOq8@v(WkBP=QuzxDtBGq3HN9*X9i^cuVw#SB@-wCsK@^3`*)!9D`wYH02E*AIy z1v7W^%f;e;xmesU7mNGlVsU@O#p0fcePO1Ai?d-#yVHJJQZ5$vKZ_zz{=slBhd&yV zJEz}9JLdAs#p3?|1W}v)5f_WwJ#Ii;xmY}=@I8P{^u^-d^b};kcM)o;H>=RcVz+#M zA+~qGZGtHuFBbO>V$!%T(8r6#y@Ok@1lxOjyja{j?15NfJ$<}b+*|SyG{gN(zGyW6 z-qOW!#0q?MXo$VTH8$AyEXvGVwnsS2eY{xQTduK@K3**D9igR+@l8W{dn+_H-nSJk zw)cFERrz?axOb$+rulfWxObGsX84wO05)1STT-pe-$dfeqZNHu1^DCh~7j~9!3ulP~WuU$TVYR)@nrAR*I@@;@0 zd*?Pm+45p>A1@a7&bwWxE8M=F$g20sv4YmPeFsosyjLX)y3Xz6S9ZM1sszR7Y~(8I zm{1zB)I?up?Mr_Nh>urU`#Le_^d??q?d$xcU>+YozUS-GO|S$Xud?=arO9w@kB3#c{O-{)CUf53Kf1>m@vG5mFALpI z)8P+M30$Hj_aHZ!crA#yPYeGO6+Mn(n>Ff8Zp-^J(nx4pNU^?E$VJm4D#Fz1xJ`@6 z1;@3LRMUZ9f|AU8ked!7cHiDPktT^a?@cE3~mpdI!VQyM?V#MT+c>&@)POs z;a)nx+=I+cCQ13SSuG`kFXvwoe7O-3WFWx?PlgwNT3)#aIgoxBK|bDt9Oy(BW3G4) za-j2WD8%X*M57ewLeIvC#g~lXPM~WO;Y^bJ2fFF}2Q81>fSfo59sD`7!K-X5D!#Od8i_83d^q&DKmZMRU77 zOeaZsyRs)u<_*Z+ZV@JEQAE#aG(j?NK=x+n0Ny;CoX(~@QwPY+vq=tb4m;cAW?ez) z5h1K)8Upengz*Ms?|Biz9%j>S%8bI2zl7U+O_}iq?uG%u@2x3$jPJFJ%)4u^iWok%R7X9sV_iQzBEJitfZiK zN-UanA8$bRPGtlH`*;Jgcbaa&UB0yl^JXd#CH(D#6Daki8c*g$Uk&+;k}1 z0~1t=OiJ?3XFuuV4anXFI=bcSN24wbixzDb?GbG}z8%cyVn)(qYxb3Jk0l%wNe%HX z)mbt(ARh(2sks5U8a!^#CkSzS4&r}`3JilTiHc3)zvrS@{Qdy^t>m-EiBpjL_TTVY zrB7l&LF;v(RvWI5C(r*9oKc)F1UX-C{vc-pN(DJzZ~l-$IR8#E^Ka`DFgUCZP{K@! zb0L>gVoY4|4<`}uq8@*rbO58Ca60sa)2XM!F3(_)9eTFw(34`fo;yz_LC>8XdeRI! zoDAGDDR$^dGvab??9g*#x1Jl9fz7Sw#ss505X4Duv`lDSeznX2o&OACnA}9cA?OPp zPH0`t6^aI^$HNJ&E6Jb<9!_Xo$p%gGa6;>9VbGw56IxeGgQj~pp>?GgG}FTgt*ezm zdwMvbb+tBVfrk@XSJ0q?J)F?G+8VUn!wIdcok7QVIH7fQP|rhuNBb%dC$zY@=OsaB zcsQYTrJEeh_HaV$>T1w=9!_Xo-PP@q!G#`9XkFQADNs&mJ)F?Ga@2K#U!y#n(7JNf zLCEHW*24*{t0xWx6JMb`oY1-o)kfj3Q65fcT|?D&!PhAdC$z3%2Cr2fPH0^v2H&nc zoY1;T4PK{k10(R^YP7`Pr97O_y2?d+PG~)x(7GycY?$d|LThtE>v}pyCbX{SX%a6d zw5~ncI+m9cTGtEOI36!2w62$QX(wPddOaezJWn7wADxi-ik%FAq4W<4{UIFM)QVH% z;ND7?)W1Fa2h^ios1ET{z)=JlKb!%AuSW;rC|30!oVi)5EmOab2);@wNRvN-;JbG1 z7-u#Re>xLsPsWVDK*JTCg4_nA$>j|+$Ld)LQ!*{pf$=*2O(9|Is9@My6k5NtXgazx z-lU)l7UnO&`W`iZKlDwcIh(P*yC0;XlxoKM?tVxkRy-=V!y1N;&Q$Sgh^jHwdVdow z@K8rE{m3-RncMKHm8qZ?mw-@#!VE8dx#lutt5WfZ?&LqWT%Na8H6tuLhTcjso*ii@YA?iWLa%e%lve(<{zKE-97c*)xREVYmR2UJS# zeil&2e}GEi-OsWc4>W;gww*<`4Vb^Dln>EAm9qR&iVqPTgJskN7UaV$N8C_kHJL}7 zKFSnbtB?P4m47Gk#|8u6443wQPV{kBgzt#TS5%)MS`9yKI>H6&GG#?U8h(N5Hqb>1 zzMjdgM!3I%%Dl-a9uHC%S2#v=B~bs@l>aW7r@{bNj^1P-H z(P-og6VEYn92_XZ$P=2w$fIJkN-a@2J zc@6#ZC&beJc@6zDEh%iuYv`X7fLbk7khxkZ63dOGRi=qs1CFOK+t4CcQe;kxu*j7Z zxdv!UDV>!RsYb+0gC(>>p!r{;zN^Uk573m6$i&qqmCPVWw=2kRbu)r{v{Y8BWdOzy zm;+!Zf$0F=1rVqXVhndDuy`~>t+xR9oWP?1@{xAyT>x%u4d7*x2-E|(2p$-y4A>Cqz13I%KNA=Z zAQ7YQRz(1M0tnQ$g`hdWW&>-z6hKl305<{XLtrg{31~c9*8->}@Cbm90R&F9Mbu}3 zE$N8h0|4$#1Mnt*8 zo|)&~T-5e$-_P&;eE$E>|IhN=IWuR@oH=vm%$enxXCJlcAhJjr-EL=SUkcxl7`#Av zy=SbFKC(pjo(qU0z@F`&Zv@%+RFM29+d=D*WUr_6|86_Te)B@0$?YKfEiy>kLH4~A zr0t-3N~P_feg*eZkhX)k+zv7(4MOmFLgZV;(2MvL@6W(vI0b3y)ISvg4K;dUeb8VFjCYWKA2h@QlO5#W2Mx8r zR0sL@LBlLC+d=+)P_zZ+ILN;bim||X4)X7VMp&T7LH>QvNW5)IvR~mK{~m8y9FkzA zgZ%p---eZg{QDr^hLwZ-`yjWz6M`^eH#o?@4;rVJ0wn+5LH>Qvc>Nj)x9Se^?}H}j zkApV(_YU&!gHrXMO87e6LH>QvG<~1MZ`U29{6Tp-NuM^X94Q3nTkw9}kxFoZ1wWuW zrV?Ce!AEq*EQ0$stQ_Ru2lZ`OImo{cTA=sH@}GmjB>z6>X{Yq>gN~C(1o`(t&noF? zg8ciS6G}K-kbfWKw_#O-3^slTN|gr418p`i zHV1i)s|=6W!#nRiXZ>3+?)aum|%jzqk(7QuHNSJPY8 z;%5+~V+-jgx|2AI9FDE)(d%e=>85x<*UXoYL(~rd)VfhZk>Xa^568AA!HN+ZE!Kg6 zWBYKZ8de3xpNYzjPi0!N_(Kw)Yx8AVs@Q@4>A0>=LfK&zI9Bbr{y7Qdgw+#t!vP7+ z6Q>h^c_XQ>5$h4hplpttW=0aULM#UBj+>(-R4JTP!Y$Pjsufc(UvTVfme2Kh+WU7Jb-(immoGh&k{p>Bhbp& z?a;+Z^g_q2BP56|&uU`nN4H7JM|H7-%DrulOvQ%h2Tp*uZ)<><+v!Dp*;pVJvZD%> z$Fhy6L^lt)RyAv+_$nIEb(y3wu|ou(1?UEq7A-2W0o|yeks=vohTIe?X~v5w4nQ|6 zC|OJ+=oST~3JuB;vhzn+mN8U}A>3&HkRK`VIz!wGTNiSh0^1F-s6W8l6?mH= z22TRGPl5Xlu@ikJ~RT@q|(;uGTPzHSNL#>CYSZpi(wOK?9E3rYMB z4M6XJ8Zj}Sz=vr;60%}q<1~PWsj0AW&cur`03T7{aV9oX>Z64c`4kf`Q|e<1>|x?} z=yxHHFO;cgm`Ffh4|$?Qg6Ei+1m;6dobJbjy&L{Q$GBw!|g6`vd$|9BOAkjLX)<2e7o9!q~19(*b2o*PCa~ug&pJP@*^EBhv zSTzVAm;fU5xWJ!)ZinH&@frzV_ss7TJW*=W$9duz;Ezz z)!he(JMDm;rK@bnFodAW!6#H&r1*&o&`AXi5iwB3;8O~U7VV<}{X{_{#ZZ`#;Gfcn zL>7KMx)4;z1-6Q@2=j+(uNDIJQqlVuU_dvKi^fM3V+b>X{OZcBH~A1rO4TC5UY&`aDW-@n5LGKO-24xkeh8 zkp&LDw7_BVs0V2rDR%I13mh^hD#~>`f{x&L{XTE5F}_@-^$l9E3kMlVV90f4Jn%1n42aHJ1RbIK zNS2~^B1Z2!X28zUV0X^_mTST5s80`(l2{*r z&NO6GlNMYT)(teagnE zGuSvOoQ;zf*f_PDjgx<4<1}y@TS@hrss215_-g9cax4wrOjeF$%}A9jNEcgR@4S#9 zKJtT@HZ&mkDzXJbz-?Vz~9r>JvWD}yFAyBvoHQ*#Di zFJotrGT$JBJ76+{Z3*1P_$9 zWDve19vp0$6>N6aKt&z8-RhP$PAN=ciLYcbb>M zRG5SAM}nZ1Hlrv=Ds>*6*&M7OE`C%9XoxcD4pLFV3PWads0@CBb~cC8bkdoNf>O=6 zap>IQ8YqN0ih@M)3s^97w1T*x(wR| zG2_K7sGgais3e1x!-SQGLe0dVQSc+OLO+t4wA+o~Z4~TJRj&dczUoVI7vY|U4c&xz z=cfpI!ls-=IIO+_+tz8+F^O%edswu^E4+-9*{!~IJa>sS`89ZmN#vdj3r}5WqMMj*m@4)snA%O;mn$zYn2fhJZUIcz#5U~mvOQPpNB$RR$S2Iw*cMT#U6_e=#v zi)Tr8vlJ9B-lK}nRuDBSd3MHcNZ2|1h@r7)){xb4C?(p3pl-OxYb_(UFnSDvy3?2m zT@I%S3}hP0Lu&58FB$QWT4}^3 z?v;eAInRtkM+{l_9Ff;C+=r~EASuWmxMU%9FG`3`BoGHSzM0@x$04bns5%G3LyHV) zbYhrQ`J24?MC7}ROie3;=AUi4i%S{dST126Ogs6sLj+nF8D*4yYk%+nb zB@`)WRv9r*aU3mPfGv!euPPcZf-o72Sa3>WCX3&~szfYQP^!2bDipCuLD@p1(ibZz zNBkXii&%0_=9?$XY(Ps@2_8`enM8P$-C7}%u^1Oo{9B1xDQN7DxPpwL5nC&=se}>* zZ4jTLCr7OKBQWK}{x8tih|;O3JnjF=kuqW>)tANIqziIABUT-eU^|X0V|a*It&lO# zUx@gKGGd6%JVM&NPL!P49^x)^S(YnWmB5Lp)@Dp;9R0v2kJs+-zFnqM(KJ6)=~mWzWfFB@n$V~u*>iA)*_Z2UN+LTnP=+*2 zat7M*0BN$$HcpbX@hDKS@wa^0CJ~;@MuiQOAYl%irt)Us$4=t1@v$~m1R*eIIs+PIwmfWxXUFjEn9sDS2JG90os(!60HqS z#R9Ej`Jwu_*Nk?mZRTN#{{)^vI<0^8;cCYERA5YhMPj^;r=mzJVg6XRLG>MZUr4NP zBo-AyYhry^QtPDDG~*Qrz)={7bhI&^s?BIc?K}9Iu@3#!F>jtkU4mzjPK#@PXi7ly zU^pBLsV2rj7lKP#Wsd9c94>t^Hv=FDr7J_%INz4G&6{jWE zD-w(9L`wz(N!bQcZyP8<*__xrK#zp4h+HM#%3L-qq7B!n6AedbpnS-zaR5ZNHil4G+c*N7*)s zcLScvG|*b2C4p@)SdOZDCBnlJf%rN`2=qYtKf#Y(I!(7E0C(-HfNlH@JXKrK0%2bx zXvTvWHXYTp1a0I0@L|ycWgnJR_}ke)t)<2{o|}wdLn5$jd_10tc8)I>g^(nt`upH2 zI+}_kZix?fiw~EUo(4*g1dUwM{aAun$A+CU*It>6=JAjEa>P4Z}b%Y?^b64_ zB35^t8VPW|wf+#`=*9YmbAh};gH{JF12yMD-+IJ{;Mlpyw;n~KvvaYPH`7bF^xm5o`78LKG#aCys{*45a9lwTXoXaibRL2K!KAcxrV20xzRM1(X>(VL6c6>Dn zV5zl8kuzwK=3Hr^7C7E4K-wyOEyQcY&T|}qA#s*js2&GJJIgI_xnmTSTA}xobXPb6 z;5j-g^&kmWI>I4#=UQtbRO=vz$hppv#Rdm?M9%fHT)8_#K9RG=g16}o@`{|b5}ig{ z$G24Ul~y`-V+!CIIO`=VEOw8smf#wsRhPRn{fSgKIP-|)kfzc)&6zKQ>l@c;&H@S!eu5-WD1*NwWu8w#%}53f z=Mt*hP=|BbAMiT_r%jy8`-omnR!ejKc{qGwr)LQAiWK6iNb#YGSRzrZARY60=M|@w zM6haxOwJOb>bwC8%$@6}Q~n*Yb=A@yc({>tyLL2j^?R71cxU~Kg!KrusdwQ>B*L6K z8_^Vyb%3})?cbyzF5aQaH!Em>xQ`TXgMu8w0mJOvs324P8J@Cp6IC7SoZ^fN&{fuw zpJu#|!kt$a5+84&oE&G%g5lt!o!Hw-jFU(Gm;vY-5(7=0j!|D~BeP1IQcEy?JGXs; zI9jrdp?upFG)Byd26U||D_N9)1Lt)LN)>-h19ZKDvNhvvlJ^a-6CWSaVBvi50P%5@ z`p847CYtz&>P%;sQC2|M%DT0h^N@ltp(D$3SV34n{s=^zk6b<+&q?En-c!8@3nLd1 zPb*ny;#IOJKUPqHI8EB?o1y$1j+oOsL&3-jBF^r^pb@+T!ANIXniw z%|SCUr`rO#V*}L4nPizthhq+MIFl_f#L-Gcr07aoPRB1U131nCL$zT`smSsAKd4MM zIE{2p(tqPCbFyVetTI!5CRUa?<w)qw1$WqBoEL=2h9YXH|uIDnCze#r1KVCO(9d2{o5(+A2!!e z4{FdLiG7Lp^A>6}>@2G1Y}Z2(9+B+)k=$=l)x7P}YTkZnHTPXw%{wlw=AD;T^DgO9 z(aww<2|F*XX4j?F-0vL;!TH`1@M)+?oRds^VKFlHRYZvAra@`OEYzvHXyRoUg-92w z0VrEcL0u!qYBDWHGhTq+My9-tT>baq@iG2eOHjsJSk@Rc=&y(ge-pv@{!z2y<3Rl} zs7loAH({cP`l}NG<&B^s6th8yr{r{8a4NEm?7+H$PLb@`Cg;& zQZUjMSVlo44g|DFZFlB~1Lz)6ODIiFMN2_1%0qoePDNLv-cdygyj~Z7o&>O1fj8*l zIPtSwfj8=+6S<&f1tAVXXU zsYcb(Ta93Yi5p`9)+x%^-@G9PVErE?SJ>Z7=?}0`QQjXa_EPnmm&?58LdCh!05?F; zAoXsj_zT)CYNO)$!%%UG3fiQ=k3z*$P>iUn6!^!`Fxoqa+Dr?PEcRlk*qMRUEsCqJ zLdD(iYooSOtD_Z6xmz98My@7Y4pTfZ6RF#%rBOjsGiHGFps4XEFMK+J+#YrPUSt(N z?+3ga)LJDV$TsRm1vy0VI6$}jRq98y2n+zUv!7gmfXK=)Tt&4j5Sz_3g^$`r8x-(h z3_&xYs6Cdr4Z$GUs9S?nUM8Lo1bCZb4qL*bsGQpsc!()QyhEuMc8H}W-l;(B5J#eh zQFkd2Tf#$a0K3SmM$0kLmC|-erR9Thu}7DcGlH z;xxRZsQbt-fVdgnZwB~);_54a(EuN^ls-U|WC47bc59&Y0V0>geMq%jdw}Q%nMFOS zz>Wa%XGlEiX(f%@0>t~oBI>IzH1Xn@He7P(UJt-Dz%9*upCi8QT5$w7Y|MV_?)Wm zb#`$dbR+6{#YVeb%%M)+qw0H`UCbo#v;z0rMcpibFAkEDe84V(sFVNFCFOj?E@-_u z>Lr?bqEYPP?^GiTJYyH*DD`F9CPzoL3lEk1%5c>vc5yY;_f;Ah@S;IKalR1XuazWw z`iWOa&0bUB>3-sNs^D2wg){vGdDv0sRG&ZBPkc=s<~Is_yPvp|>icGrDyW~J@6|-T zHBo{e_7kUO1AOO*>@Xh+Ap!yZZlbKwML?wOzo+#%NK%OD@F}C-Co_)<2Fe|?s0+${ z|1eNxBZs)|GDXL0qhWT^T%>IFS3Zr64kR2z63t zKZrMS$XJrEXok3kB+&HJOK(UbRgwHb+7lV#R?q;^3^@-;QYB+un1jfWq(KOq~Yg9`SwrAsEdX6m7hx%vXzLt~q84qP z!%@_tZ=p^sLOFu-Vv=YClk2!K$!eg}#NDHDBS6YXv>M69i6Jp&oF!Qi zMbLN!MT!vwO;Av@JQWc$QBjE(`_LjWlN6LJbQr*x$?1}2s`xwQOI6a%7JnruO+lB5 zLl{?L(iM~=S6^e~kw_!90F|eCzVm5Vbw|u`8r#HvBK+($NmvUjt*g*tPAG98)Spz8G~VYq&Oo{S=`qtAi$kQf zaDO9a(JHX>0O&+VG|^hQS{iSzw3@iCtXhlMpdc>HY-HJ}ActCh-n2<#MxyLHkljvA zWaIZya2_6N-G!FO)hZo{2k8$ZB1r!gMbiT@#2MB_$Dajh~k>U*c&ePh8QX zCLTz3NG+I=*yQ3bHogGQAia+8XbACpP!4tO zl{-d+?*>L#y*47kQn#>DZA2uE@lZC+NKJ-kI*6zk$I!B|rL>4*9Y+f6N5!*ZngC)#-I6?i*`wHqCr!scA9{T481udV9FJ z9;P|M{AdPxqWLB);2^V#Oq-bq0S`9g1Wbl`1S}6VyU0+OH^J@?HwT47Nz9jEd}GYf zC~<`O))Z9K3Y&kmKgpPO4=5Wx&)%Hlcq9j2iQI%KV9qGH=4%UpLzkG&F;fMNLwCzfe=&X=2JdP0aVu$HPr|r-?aAO7|el?;vv> zIFB;rohGKd)5Mf_nwVtfhnezD6Z3B9MYJjJG%@9!CZ@d8#FTfMn5!V~I8)wfV#+&B z%x7XT7ck|WCZ@d8#FTfMnDR~&Q{HJ}{y0a|+@`$K#FTfMnAbrgQcS-)O-5hQ55gTO z?=*=Ya|=mQ-f3b!1D4NSwam}WpX_bZUG;!rjhup}9)14-+ z{8yl7xYI#|LlhIyOI-65 zv`EmMCN8-YMMrMwP7~JxHF_==GpawyAnz)J-v_Wj6x)&?xYC(6JxO{h-i2WG6UCYVru-I+7*hsux zenf)U?xQg{euMG4G`xY0I!Td z3&DX75Ok-BtL{lj`C@>eJ55~mX=q!z(?rmnCa#8VnF=?T?lf^Vwn`9g?$4tDUNudE zx7h^UY2w;)odl0qcbbg3tQS=ZS9h9>jlUVzM63b_W37E-P0*btV_ipOTXXRo${#xx z)&VW=5Ok->*aQ+8O^fMvkFkj>P-|K_qqC4>-MMI0S~;UTO~xiE%z5(E$=GBCc?8{Q zGB%|{=361T96PaG$_{s$M9Vu(qSc)y*G<>7F}Vl9WH<%e0}`fx3Boc@Le5`MGtz(3 zrqGE9 zr@SyGF`imedE{r(-;QJ(r#>t%j7d(SBcL|^Ii5j!e{?{VkFuzI^1_(pU7%BKilKB(Scl`1MPj7f3R$`$tie7Iz1ByCMz7?U!d&WqakS3U%?JgV?Y zDqM0vl2jMQq)ZxtbQ_PyQ^}jglJDTF3uDGDD@2mh9j$4}s$F+8zRjBZ0@`%Vt1 z26R4$NXPhTL{`v+G2^EbBUJhasM7cuiYCX)-{WTuL}_t!Va)j16uk7p7$D@4&d1Ts zC*$+|5Nw>3n(OY#q^C07o!XZkM;FGpr>F?)!WbICxjuFr**uwH?D+3w7(2l)gM5*P zMiV*X_!_%H7*OIT#D9(`K^MkM7(*&XwW14SCb-@QL)0CkVeu!7CCw&lO&7*YNJx`V zq^$phL{V`v$K3u7kwE{t)|g)tLX>vT*8L>(l!iDkYs&%@}#n2F^& zG2@gM#!Par0uecKO-iC5F-BsWBr63PXg4Z{>#hWHQ{w2t7+0d72%=!!UG6>+#L07+o0Sn(Rl6HeFm+n-Q@% zx-iCNwHaL)6Gs=uxYAS>x-ce=E{t)ds|dO6os&O1$7~{%R5p-cp9KE06 z%2E+@VN4ud7~`6%BIv@HIJz*#m8~M^!kD-_Ne^T>7VT`N%DB7RYi7t$BRiw+oEK-ZME{q|PJkr%fPKcljV_eNDyC&$u7}o{` z1t@MdDo>5e({!#)l!?|OY@8essK?dhampUz+N`Q%T^K{dezbLA%mcu|k#*?2jqgUj zkw1qM9gr}E`~fo#9+GDM0nMkIi!s6(=1Gh<%xsp^!XrSpp`e5rGz`mv5-izKL9*{A z%v2>)-;Imwhe1hmi@3X;2ldMR` z(69jWZD@c^bB;x8J&@Wq8JWciC|0VqajA)MsCDX&g|a*xR*V94t%4ll6%b0jPC=34 zIk+~d*FP>Xqs2^^&eR)dp^#j<&e?!&RB6d#6N*l~iF|9CN-TgjrP3}tpbYUSB$2vP z<;xbIh5~9=&@{1;O6XAK<%s8l0PRv~^F&83pxp|ZFERoF-Kxs-h|Qp#`XdFc5Vxa8 zr{1P8D@7V4m3oIts}*-aWT|)F0g2(IQ86_eP$#9yeU?ul_0%q6RPM9f4pW!9UxC;< z$%3k+9*9PtlT(7*Fo2{Uq*COR;9IKX!^ApG2{a=C0#7|eO~W0j-4!JFNzl90V>C2V z-^zksrXE*ZVol>1T%y!xrvuLzIZxB3jF!g|Kcry%b%?d`Tks6h58^3@Gj-$+JR!%l zIY1lps6=~8qCHP&bbinBU9Kh!*Q*la4LsG_&R+f08z1S5CB9THTFM$oXKDu0ayqioYNpCc1^FRKObe;R zheW*fAt66)KB@dvC6z?E2BKm_pEP;6+=Qh{%5=oi87AX$=uKMMS~PKJK-$&cAj*6M zBG%0RLdA9S94KJ$^yG&PVgMr?sBTM$Nj;0B#hkuZ^P3>rL`NBrp zc3Qq8HCRTN*Ah=8{%48YbqY!rv#4pVr|v{HVn1P8)+AeOMrmm`s=hHzT%g9kNtKr) z&;F;~qRN{m)`HWtowSx{#I6u`!>>qdS80{vGD_=E&<1fMmA;EG)eL6=m9g873i0-| z!)vFZVxJJoBPxR?1Z96zK@QPE>>g22wD^Y79#c@VXrQ#m6_hRRq_ig#G*3KE(31*U zA>O8HKBb^q(M;t%O%RzMZD@Pi!#9AB!GC~I(hkWWow-Q+@%!LXy)Uv4>C*AzTKH-d zdsI)`I|UY1>?{DHWe_znf<$H+L>@*hbemd9b%?FR(Cv@Q){7KNiS>O7iWW6gnq@2F z#qWsZo!<7kouIoElqz1P0;J`n1)(8Stu93+M;HX{SFJZs{E5oDTS4=~*42QQ1H>^c z2t7zN?@`bSv70at9+8|?idiI_dr39vsCEI-lv{^nw_hU6`-vB6w{Ir4A5b9HZs;&} z+Jnf5RGiJOAyyw!sW_WmL6nYCd&{+(UsGP{KLD|Ru;wVu*slZyOx@GsI!4 z?Q_@2g5EX66w3R&;`u{EI0*R##nnYa{ESHTDDZPbTtUb$UMur{Wr)8KSHDmNZN>gA zQU0X@uVF$b+a&<&Wllfai1h>iGDB-mFhSuqh!;2AaKVI%$kfxl9uu&cb6xUzN* zA7tWJRPJk}X7t`MEDar#adrbKGVMbWq1^6B`^an4yQmg_>_h_D^rwlSw z5pSQ0hmF%ngh_iglFAkU>vie`vC^>F_-#NLeSA35igk7jKzu!d#DzAdA_dXS5|MpE zN%T^z(VU1h7rnt`$TMYQ=~HaRMwul+|27Kzr^pEn(_?9F@H;2P9HC56D2Jucfa!{l zr67^g5_y3W{@%^o81Cf$fGG;kQ80xGJ8-`&ap5DVW?x0pu^17o>UU!hrDS6!` z<&~I-W(&Z#Pi58DAiJ#k6u+vg@0_ZtPmxtmqFq#EBD%>CLb{CACg|6qb@jcf9^UI^ zeofNGA6#V94e}FZ&GyQg>5C_}Q_c74q_Fy;iIvbOK&U$|B+@470R*2^^xn1TgyC`~ z`ZE_7e9*qcWJ&O(BzOnnQsu{nPfBr}Aei3I1re(5mw+eBB2UU92aVOWDN>|Aks{3i zJbnSZM*XKcO^m?8d}@d%6${Z;(dpLj3ZU=tvGAm1;Sk~!3s1@-U-1?3v@D_*Fvvbt z0J8gZiIQ!R9-?8h2mOAKk5MpZa)O zCVBci$y?QBk|$TPSK10*30O&cnUwYkz*DwCqxH)r&r!INMKO7WWO6mZDJ1U_o&4~h z5WgSap9oG;{OW622B&p&HfVDAiQ3myjx4tRY+tY?oPgCEa9!5PQ z>mIb59!+*LtA$vKp`MYIPNk1PC)ctT6P;M%BWn!>N6O&jaR|oA;A?Pj^-(e?B|Vxn zCQI@gPwYaXNu<9iN}{!vB&!A~iT(xLF3I<{a*CAb_K9AJrbvk%BUtKhiag^zf09?C zDN>@>1D^8x2oy42r>dL;oPKdI;0fwW3mp%%D2Y#$5??wQ>EA>neUe;cV;x6Zl!PZs z2|tB&CE-*l;ZFgNmlB>L=}jdS=ohXkpuvFZv-OuT8O;oYpl?h?htv>=z&CWVS0Hs- zIG}xiro|xe8U+#%s7pg&G6KWW5txp^ixenCpfCdg4+3W>unK{nU|KzGJpwDTsMw5m zp|FjSii1)AMDC;Bxn8|iSJV2F9<|V1sfNEGTn*v88ozbGe(buJ-RECKASA_ z{SpDnmpu;&(|!+V4l-YM5P`d`vL3X4jcwopX9M)pq!cTqSZl2&eU%1U{Mm-gv_ddT znx>Ux#Ls5y+AMPM^p&K3Yo`GuA5Vd|0Gur~do@}A=LnRFR7Q%l7q^t<;D$kYx$kcQ zsLydqkaaxJJo|GZR6z>dI78R++Fbx^aghP>qUGI3sXsdqrNI2HsNxJTl0%>7TthG8 zkG~AXJxHB@EsbFJ0?a{LHEGmE09yVj#3Tbp4I#|hJ9x~}K(}XgUu3woo8w|`w;64hZ zBVb^oB{La;D-pKt^TAb```x(d zlw%>~Ur5yOCyOqX9oRGi1=#5huSImJZ2E(AJD096qDy7dAF=@YqEnRhMW;n{qjZ#Y zqx51Y+A1woZwCXqzJ$KYq(_m{j1MuryE#Udvq*lPDNLbgdWar3Ff@=296S)$3Frr2xH(M}bDcL?sqn~~RW7-?42L@739dRPaMTI8AftLV${Q^+#M=~il7}%?df?~*D%EAB%8HEbOZDbXK)O#C5-0do z)a}-%4p3>TunDr=lB^7}xMVAX1XB8VQ)Q1ss$`a`IX)07JHba26;MbM`&&rpUzoxG zbF$ltQN?17vyU*TaCU#fn$pLI0STq~Q>_*<`QYw%}vz3;R(Z19! ztNOsH1E^E4?rQ`UQRW{(S<3yhP{jXrGi(`FS!=H$h8{^n+-Ecceb!Z)iUEDLg%E?h z7JH!AVh4MTlH*dN6ymkF&Pxq!sMpS!eI}A9hxM7laAoHsymmj*e+VHXY+0W^V;5!7 zvZ^!K-^LE{DGe-~rFc?p@XCSLMw3bpyR_pD?`scD!-ezSLRItqVB_=+i{23u!(xDU zShRU%Or{N2_t4nKPZ&e} zEA2qVtih0E5Yksq0-b&!iV3y)Vj%TJvo8&er-uCSzPRs-iF(YxbR_(ZgEI3rt3e!X$m@^<%us{7+IK7WhlxU_GCcv*v%`Vgf6{(r9z{+7?{ z^Lce%pHF%qemlIR zJF-%oYV=@h`!*$)o`!exHm2*8=X>hz6WvO2S@>X5$y zhG+K`O<<12zm@9s00{*DdH!ZR-|Jc8EVOSV08*hpU&Q|$uah;`Yux5t>Z$qrfM9(A z5g_?1$8sS_2|i#SqiTd$Y(+q2RKya04Cx2G8H4$!HlQC&l>W`YAUt(gd=3Bgq{^Cg zWl5_ltJc>f)mGLft}9!&s&rLl+3G||3 zlNvVG;towI$m)NI`S0K)VWX&V)jun^vb4T(ZB;`eioKNI`qKL9|FqU+8yZkr>H5{B zb4EwydtSp{CA1u6|u0T5EmV; zE-ObkK-0Wf;KLh)S!<|TSB7+0llrO(+;EOC5ReaF+_vJ&8rH0>P2%(Qc8>(s) zg5{*N|sbY%GG856+jk9MdGZgSyx+CO{IHd@CLOXR9#(l30&21i8#=N7Ppcb zL{e6|&M*6=^2JesMxS(1PgNyUTV}4Pu31@HU0<@UbX8rAzqqXgKe8xx)mjCY*EW`{ zs#)JqS5u7$OadgWb&b^xRVz0(TvD;Rvh}5YM9Malt!lgkqiTJXN++dKbs;{4Mby{q zCAEz!tE*Ni+^Y5Xg%w{}R$1CqRYN)flZ;MVy;3nrP|f=F&^IWoO0|>&DcGrQtg~Y4 z%j%lS>Pl8a;&oLk8~f0`s)EUFpQ=}CSYWf{j}WfXMV&#OVkIFJ_G3iiTfG8dZwgfr zl)-QfRS7{9Us0hnh9ELANPshHnE(aI4AeCM5@}cggo1q`#H}u?tt(qq+EBK-#7hMP zNxJ@q4DGkBR_YNtZ)06`N&Tu)$g8fTYy${7AllOUs#PWBjq9Zdi5El?6?E7>z$coL z+PbPH6pADelx?Z31tLPwmS_#?j?~@I#jFlQXnhpweHlOjQywFGBmKfNe;`_CQ97&a z%*@Yk%x}Y={I8z1Dh#fGDcs(XJKQX^Jtzb@#OG`jSY-WqM%yE-koSDRx3Zz_tcI6gNYCUW0}S@s`c|w~916*k;S4saofYS0 zRk14?0vPkOBKB1+1HngI2;*aou(yYlGe<95%^R4>8+Z+I!`2w^g2&+7!TD?lJJgl< z#;z%u1v|LOg85nG>{`n+fc2h9WV+V=dj)lyJP)NDHuEG;8_vt0LHv;XT}xuuSr|^A;KvKKD=3ehL*)Y4kJoe} z@pPD5hTC%iycm{|3FzrHp7cb3zYJ^GRhQNFNb~GvYz=RZo=ODl?e>c1jvoE_(F``O7BBV8Xq`Pd#%S&~(3B!>Ps|B}532{HiC{~xjgoNDsSy9?Mm8+%5q z-Ug-I@nTzg=D05YMq6%I;_o)e>PQyttVs%zyI3CY^tS2e5cH$9+znB@8cfakXzjn( zoDT(iPD^2L3kJ#aw)5hQ6Zy#sZxAb-;=95Ov*)Nr!Z9LEC z-|@w4R>htFBxSZ=$^|0t%kww=Y}l0Osce`#EsOQTX0TPBqBb_?5DRO~-?_HF@eLNoo$Mc5&{5k_;FnuG>^<#l2Yb4uvyr`|f%U{9 zq;Tg%wlR;14A$ImJ=^G>U%a*8OFn}7c&&#C?nLeEteHAWKRZ2b_6m9~rAPjFJas$I zzz_4-vreZhhMDYMOa1U!vjO4fWw_h)Fo%bb&{gvBYp}*%zUZ?=%D#`idNuDk;Mzlm zD+@0G7P$7Td2#=i%b%Rm{QS~oMWFKbdR`8aJ7e%);~{m?8a_(V+#fd zCfuwU0&Qi@ZYJ`ISz`tZ^c;my+nQLTXVNk@+!(JfWdq!N`^{uN>}+9=os3mKJ3DBS zDEqOu*HYiJwO!ZLb+_s%cJ8rTp$0pR2D-h$zJ33;B{F!{&hL?dL(n-#&u8iRMQ^;x zYR;FiIs7a?zKDgl^5bBGt>xYPIAOAN9t;ZYBWF!#n;J&C<`nZGy9!RQ0o|+-Y7^MN z8roTKUgI8#Tiw96w-_T(w_en0-c;7?DeCChT{v@ZK|T}4Se)$t*RX(QfZLAqy$wG|K8QfAOGaj10-V zhPsx)qR--o**X0LaHpNE?EUIX{$YXP4$0)hlm5ux2PSuYh3+f~iV-&s|o6yw8`Wtb&F)9+@PovgZr$+sL z?8C4gMD$~~t&xpGdaUPfKe3y?$un6^1`Ek!HK4&F+gV93i{Xl!)#usq7JfdI)qsHy zna`FT=aPUjOuvEA3uuj?(E(4|kV z=M89iU;jq-2O;C;M~@@A2CE?@F(z)#qg$vjn@TfzQifmHfOfPg^53 z8QXB4FWC3yELM5;pQU_t_1SyI+%xm7g;jf}K*Re(^}kp`#vr(rl|woBvwQ-7tcW$k zM?)_uV)Z;4w(>k{K%=Z6BXBevenb@%qMP*~_zZ#<1G|l}PT6L8)jY;XG}+2>qdpYD z73PWQY>F{iuQuGFiAl>@&z4r!4FmuDmONuzC=Z_pZQZ*FuFmO7X33H|FVMlZ&8eV_{8U6nN;;ZG7aev~5OG zXksJmW(M2WVyw{FhZ>xb?d%i|=|jz*tjGYV9=-iE$6_+O5JqmvG3Ll9NGM>UobA<( zd>v+!ci&RnwKS83wz4HgwxVLpb0F`}ssJNvYj}GmyAz*Z`%_&58_>xb-13=6BQI<4 ztlhQy+9~LOfpAxqm`Aj-g+>z04Py9O!);cSbTspd^vty#Mou^@X=Nkw8rcfoYQ#sd zh+ei44tOK0=wTE2A$A7xehl(%?q=r@d=SCEUfs=td)Srk26&`yc4hmrj$5CkBKuRH zhwU=5Leq=b!1mn3YdY@c#}F3fZx{&?Jd-y*+r`8owjSQ6krT!*dzQ`VL^&R`c>|kA z6^;a#sO^poy>IX&RQF;(p20H_^S7o99(NUs@}S}NN+0?Kt(BFQ1C-wN&$SFT;1UO$ zeX8}|si?Gao>A7A0y5t;_ukoc0faj_?_{$*Y$kYN-wuLc%VjmM#jNM+vOIQD?`A=6 zR-ea$&a!$phOXtXOUw4`ezYJdH|f^B#@L8kUou9(uqkW(iB`_qTX;ENTm8%HJML!P zEuHK&I1^KP*=#pUg6_=su%reyA1QjgK8;OL;5c2BT2-|A`~Wr6TWZ z!7pqlZ21>mtlCJ_*$q0)NB+KrWaglto0=EGuEfYO0jjW&QZS*TN4zfta4^N~Zs|qq zwS!ACvM)vI&`?w#E&e*fhbY|5-a+u76@3BWJ5}_b5!_=%e}V8#D*7J?ZnL7dL!N(! zJU`pg%{m~^ix4Ogza8NZ5pL>cIG4wMN73EvAq3w*aA%0>)X=Kt3@FV>wxN~5bV18c zY3J+P-dJAr8}{QCW3kS9xAab67qs*2NXz-QbRN?IHP~L^LA!n(>B*D;_3gh$dU(4^ZAHqY27mQ9LiFxN^TSG7Pj~a^epm?IW4ig|wr^MQrXN zXwKR4UN)-dzn|2#4Jv2RZZ^4>eY_=)Wup5t)=^GHT|X!@r3~z|myC(L8KdO9l(eD8dxVvzA@i*|p*K#u$@5+0pWVxXE#K(v!%7I&6pF)ce3BDH;ORpg>Q!5-k-a7O=*KKm|wi4spuSw zD1THA0p&E3>s)$nODl>lTv(b^v@{d{ivKI?%rSnLckSm*X~k{)J^nGxzjd}uO%>zX z_h1A_*1Iq=bvKiQcE)<7Q<_0e>Cd_67@!|FbEkh2!tY?tWMlU=_XN-qg3g}c(y!z< zu|z1@%`M%me?=z`6gtMgrH#rdobvgzt- zW3}Bg=VCe#j`84LS;lhdA)|<|F>l;ne?+A4|^#d{n%dz%ZUKHes!Me22ar`d_MvfXzYqe9u8n3J5x;?3=*yN!LY_7EZt74aAzb4^mwHAO|&WG-Kny(H_- z;+HS*&-iCu{2bJQ4Zz^fDtk_|H`j8{kzYIuhn<%b(8-RN%HR7I%L3>Zcx-PeS1#wN zExjzPldXk9hC%vk+dDc~VEgVpZ3Ri`6&QoY>R--oE-tQXJO;@Z)fZhMg&*H1d|GAc z$DSFgg#W@yYFC?dALkryUYw7GmgaIcAdfZVF-JS=-_E9cSQgDBbi2oX@1v{$9cOYL z%gtbuJ(tVqPWyqjgI%O^qMePEQejKDo8Nu>t~Tlw0W8rSz!B(&o{71a4E;=_g1Mbj zB>_(dCJ!Ef{VIpIsJG1>kZXgdX0=Gk$~O-myV* z{)ox@{Vlxxbb4k5ds*Y%n8zJ#X-{t~A|r77CI|qTFd*A{<*FeIlJjAm7Wi~>bdfZK zB&M@#R>|KYi?uq~4;epDF-Fp5spX$0e&`rF(xLkZci9O(iWY(-PEb!9I~2}6KVdIb9b(UfpJy*% z?($5y=XmbJywVsSx@>XdHE+~E%0GhzxPH-&x`!6?BL0hC6k~}ou?@m~b+ufn^x1Tj z`^w<*t(SLw!9!1;uX?Vz*#v-GT`j~e5`7pJr3ZWd4G@24<^$oBAH9u3^XH0sKl9b(=- zn!ygkWm9c?(pyfrq$(JJ;|Nv|2U3msjLsSeV2% zdP=IWa#4Ql6l*$!wTm}1D~Y}x3TD{Zi<>b#v13LLe21TJZe^=7*zndWL_K9RD1%*Zpl#Lq9Q?3hJO}Z&Qf3#ceJ#27_ozR&ZE~XZz(EfSDt0z zs;|ETlw^o}Hk`mzUGFjJ{tvsg|OdCYAPd3rt@T+UDPqNN4A za_ij6#mktZoQ1T5!Z(}SkI9M24g&@S5npe{1PUY{&>QC0uUcLVZ-VDlY|nXQ)&{Ve zC0CH9H&Bq4w?Db67s1~%GBll6pOsVqR_cJa11{6N>?rXoI^>aza|%J*&zt)=h3f^6>Z5oYW+ z68HWQoia=lz!$W<@2|9zjvkB2>qjTX?iP>&wP;Qvt>PmX9s z@~u~7d~fNVQhQ?ZG82urjZpTF&6t$D$S=shAK>{h+!hQ~yptc`FXOidI?;vy-~HQ# zTrc{?_TgL_-bRT7mPmq8K#-@drYGr&T{+%d%TABKA!*a=?*%n@qghMM&FqZ-#Ltbc?QIHY~x=a zZuo!gF^FP12J=rhMCEA)-|+!7n|BkHjt{6a1Ab=;aFD=vWB}3L!vP5THkoP5^9MJX zk>I6`a|OPAQ0$UoN8PuzjIejpSf$WLwLEg*mqOdKpyAz4M$m6NnILOB8N2Fz+sOd@ zx06B6+D^vCx)q{0Yr7Uz@;@3K+_(f?WE$c2y#8`|a#JO&k zOmh>1wibXs*Mo&%LVST9%djk(v9-8(^=ZR_)-|CchBgy5{100?sT>DjsyE>!0r{(B zOmb?sS#r8h*SDpOSb~Kw%!7y(xvyf#{SqU6Z$4X*ft|I&m6_~mox5{$r{2L{!GcFb zJC^z;7av?a{gLIwu-x*e{Q72kz`K$Q1(2;w&1GSpUAT>(x%1dU4@<;0S@*8Y+#(j3 zXT*l(bYY7v0~3XeEzcBSdDO%1$3pIJ@OxY@&)=U@oS9pYla+!6Q*65p@W8b`Tf{!! za+Zhs|D}R>Xa~>j;M4ZPlWEV)%*o7W;qAy5*3M?MPhXW;#GV85NA*1R`z^HGu{|?C zEi0k$b@m7B_ua9jfn7ks+qX0%r)5DTJzkN>CjFjB@>x1uuo4fCn*uqUz$Rt8Pd-6X z7ItHV)6O@r(bzS}lPl?VF86xusJiJUiR3STWLHsc8%xhK#)S6Cp(wZh`;s{RJxRP> zSixSy{6q@5(|*s-n4@zV3vB(2X64?$QZO+cd?^IO0(;q}y!p#n*r6rMSYUZpVo@f# z!O1qWDHEd01Qu=8M+G!ifkeissHQO?=IYW4usbH!iP~O)X?^Hs*Z%ex+ z)#QZ27cP8q%iDroFJ9JFYHZk(le#niwlNdl`0@7VKb= z4Olf`L-IP_WX^W%BSdzy*3BOFfsx1dZO&ug8r?6j$X52{)vfF%=4PK??e_it%{WxB zYe!~!7wf&cob6;iub(Kw`WJV$rL%BMbT?yx@V`K(b+a4iTRQVI^V`_{o7>qr#67S% zgS}~Z>e+X z7f)QmPzO7JHM_$wf>3)sH@&@TL^hZLoq{$D%bdg%eo@12X4Zqt80uKc?PT>V|P|F0ZYC12$~)q#J0 zP_@K+z)ZS$(sl9qQtSg(Vc7{|I^SvX%|0^d;Wl{g)ASuj~-$7D% zzkUukLH-9x0sB0A@{@nivqyrr;ouefd-gbq>GSLn_8l5U*soAZ@p}1wDdgpYp4ZDq z(9g>!$nx@W2(-`32jK7J6KQp56h}*~5aNE|&?pFAdOq`eCp@kGfzzj#p7+E-QLp<8 z9U(u?dkqoW%XE{)_s-`Rs%BTQHQj}Wm(Lo{d8*i*axZ3GZx?%cZx%3&JX*n@>y4U9s1Q4dv#2IRA2%Me%53L}+0FPVnWiaBSrE zvLI|mz#p5)uxz*q%cO-pJaWqH;$7G7HAaRmEjo$Z>^GY;_V9e3eG-I>Y&}X zs%{qH{?M2dRn&pSG`7ARe$QMS4lCML$v)RRakPd-oVAMiXfrmt@_7fl-r$G$=Q&w( zvKJ*`)o2|1?Pj=Mw;TLCn12wC;;6G&F;N@FuVRa~DR1>O-b7l)I;5??6 zr)RE^od16FS#=P#nC&#U^Ax)t8<~+Ddybnt2f@f8p0fM8yXNsW{_+wWoe9n46Yt7z zo6lp?*_d)17{alk)dlOOfb^rZB94vVyv6x|9%%tXv>~V%`p%y93tEQ%dC`xtgpPgP za_k>`YRDD0j?E1cparVGV$Cgpy~gqoK6Eu9y~cRn($lnnv~7!8a+}GWcVkWVaV+q5 z<1p>maBNx|VxtAYiZ7tY?D(Pe~ z8EvfbP;p{D3-T0U?VeWgaDE{WtH2p*_ z^$pWE=Ho&%np8&12VPp}vokouEl=5(l&{xTHda-yF2R*m$_PrUQi3!04O-#M!Wq+M zvc!8;;-C^P2HnKN_7qTIQ2N*2$_^^`1}J0pMQ zA`Q2%mC#LJeTbLkE?l%Aclu(9id+i;&z!SJE0N`wiE^R2SS19rYCEkC1vZRCD*EnwlcYRcc!{(Q&|ZSqcNkTY-MA)wyA1eNul>uv69l& ztChM~gB59#M(Txu4O#H=QB9q1^qGOzI;e4^B6x=+G)-R%=S*9eQ!-=m!bNinNut$K zAF(1;vZ@+-gV9pH+)`KKbqk<-zPK9M5cS&nT<XMNA3h~poS<`Y07B84d z!*Ejx)vjcE1V)!4YM1PZl|8ct~$wHrE8 z-Ns9CEefdd|KaUj;N+@`{P9i#p+$uTQAY(CK`^4|gqOj`nvhILB+2wl_Y9LbNt4GU z8A&q3Op-}LNbs?W$}U0N6-Di=tKzP&pdjLk21VCJ*I#_Bvf?9%E3Bes{Rsk!{J(Wh zeXDNYb0-Ad-#;JaesA46b*k#rsq?t!_F%I#_BDJrv0-q-FbG2kzENq@O&g%d>cLTb zV-cDgW^WqBr!E^~+m0+>IatD96;nj_`!(;fWZg^zn@G7)B2i3-^P3S!miw*j@ zgwIe$)-B&UI9eLpx_+a47KLZ{-VZ9Q*Dl-Wsy1rU^+uNuZNyg>gDVGD4Q^No!RR6Q zZfXo)vOtj%8e=1hiJ#YH96Le(Y+Tqm|NMD%{PjFSsa;wpk5P>1^5s&zoDfBUE>WxDy zFCIg~N{nm{Rab|{hC=GwgaP8rGf>>^?8IMA^t+b0SlBhEcfl+q zQVC3HzM++gImG}w2jrH!|P*;Ls!cV)J)!z@ezNe zO&er*jd^)hW*ms)f_@m72_Fd&6hlwm4CCph0_6}I=!$bX7tC5*VsZ^VCleC2(B)#f zN0SeZZa_E5JU5IO9o!hX7l^}=zs4|Z#X*guwSN31gH)IqWL?%fcW!47@k<|B>zE~ z>y9;SE-|ZFbSDAH%A{%CnjI7%lXBhD1 z`o{8+k&ME%-r2LI^)Z^G$f`3+V%vK3LkL1&-ZWSmAKJJUIZ*q1nD`+?mX9u9k70bB zgn695wRG(`BS7oQc!)+RNji+vlrUst!nPc9ZR`VJO6LQUk0+Y>`3W(mb&`PPyUX~Y zbU~dWZ7eqvXB)J};qZpWhQV>4ajeAhA!;Wp1?X$jRLoEZZF;CFO*@tjG}tuIsh3Qx z#xkz$o3)^~vn5NSZ@97O@wgkzdAq)LC@aH~vUXdwr?FuE!ujZrm?}9qrsP)9@ z9o%}!roqvzvQ+i1z~+kigRNGe!h)_@a~gAdx)wI(&c|CX+^ElA*xA)v*FKS19fS-~3dVwt5~ui(^~)_17-$e@yyuB;L4ULk266_7zp$bbgr1oZ9A1_+O;j_C zeu(SFrV*@02c_eLxp!DehV^NqF*Y5l$~2&%EsNyV*nsub#hFIeUS_LwEW<=zOpB!r z!|2uG;V`cq9+AaaW5poyyC}@*lZQ|k$mEN8v1N5ge(V#73n?8FwEX5mW33Fyt1;gm z9xHWi=naOTUE*YJ6iIgF<~Y?xq6wKZAL8?B^E>BdYzes^i6*W&Z5_;&z5QfDM$Vj0 zbkNzDf6kFb6{ZugU@NNLC@Y@zVIYx}9u}gKLDsB{>z8d|`K9&5{U4ajdIq ztTKDnf(7TzntefI;jI3a?tzfRK-{vk(b{X6t+6U-AWh41&&RpZO=HW~3^rtLfcQbG zTZO%(FpXD_#JvECmhr}hP3R3eqJ~T#Ib}tS#8z50jGv+y#Fhzq*zm|jO%zv&@6BSZ5c%2RevL_H{_sqVn88t-Y zCfU-J%(w~eZ(wFoq>-!!FX-&7qSN+umKq3;Frk#FLy$MHm_s@X8&BEAYV3PRg<*RL zyI-&x**}ijn44T2##ouyibUzQvKQ&&R9rb@O@TDLF`G1AQ$x$n>gmDSwAI_Fu_ydY z%0kSm(V#dZ7xtu(6lBk0Y|}{CH)>o5>l8Oh7APW$_-jej}6Xkbr`m5G2}=Bi{ona11C*f zN17W;qZpIu5-Nz*>L}8x3~r$lNg%m#7S+1%R1nylP|D=iy>Zy0-0Rl%>ndWJ+wv^_?Z=+WY|qv&9RNuDN`Iwwj>{5+P@{Z zXk=@tF%N@FSm(^w#S6yb5H6;^4>aPtkhh=!niA^SCjH74;@id=~llJ%6QNHN}{IJ<6Z_`A9=^J?u1F*;&k z$V@^K@5apyT(L%JnUaOYM2-gT8n*RjZQ8gt>>;}bnuTR=w^NqUJ@XgM?V3o#*w=Eh zEfS(~AvNLE2;TICg#qRU8-_8EVt>bvL1g35a^a#b>A@JiB#LwkMn=oHjFSZvqA0wE zL0{bxcJPoF!w@g46P>K(w1a@srUe+yS7*mcq@*flxERea#;+O-d#)lQ3~}1wMl`#* zuT0Z97?UhzhqY#0LTCJDyzxCPUKlN!)2Ja$WkcUGu-DPj9@rt}64yCGI+@)wTZZSM z)kARWHY~fax`@-s!OcVQ_rgjtC)MR{oX>?RF46+m`ys$3lv>_luE1y@n-8HGB()=C zLpL59U8%`P_fA|Vvlg?kM(-TFKxqldOlr%xNKKVJe!Kz~pQ?B?DYpLN?wfZ)2?d`} zhhf{(g>0S%g`;W>EJlSttcYbg==o;ly20feWHuv9!Z5SV##=~G*%dw}>&rK79G17g zr45UaUFTviu`|AMD>X`q$vERhb#u$Q(SiWy5@s!&)d=$q%<4xGIFbbMR;+=o z2U**+ydKsJj~ELBtSTa#qAS;8vaZ1v)*mr4Q~2w5#HW!$Y!SMys8aExt+&t+KVL&yj5`u zKwbikA!jmXWY?8lI(n?t$n0LH4!@WkjNQ~coQl!vhd@r?vOBR z#hd_JBMX^O^u={hXa-u((?L7}u))&|W*&$Qd8chtk5=y?L~3Dm5XZaFL1jIU*_w1X z?JDsFlPrrczm@$MdEQb>Y|XIgWi@SFDW`b`M~3jzr6rlmK^Hk7;nrCvlSr10jM=mB z{v<>g!Vhn1*g#`)i*q3=td?7=4*TjhWMV2cHnt+$xG}0d5W)dCYq%12 z1(svCBJ7;6G}S4uC2F`-mMt~WF`k_vD?-xVL&sToi1h3s0)%}yHiu(M`U<@&uRi5P z!Uowu9a^336JbX5n$ATR%wJS1t;fd5D0d$*EMo>FJ}THki`yUEH-4)%Xk}POhzFdLPc^ zAv7{EHn+1rdmfG;)aTA$G{1(EgVMwG%^=35Rrqsxz3sEx@dM#6In$a})+Bhx8^aE3 zMEpcKmXMho$fMWLb#xH#fDlkEN9J_b+F!)UzS<@`-V=9EW(ZJBjumbfZHhCX?95jRaRm^L=8!aMD?VzO+k zk4+CVjjYX>)SEM4aad)B`AexWjFYyy3Uib2-p?WiV*$?2g&%*{$REaZL?-wg z(tH@R35L$%?N}lm8aANM3x_Y!K$s+kJ!)~WY($MPEZrxb+#Ti`8_kDJ zw%93obUM6r$qGSEl;##&*l{y)W_mB`U3eZ|1$52jhF~qcoQTVtq44$&-8nm`s`2HjTTch#s6@!omjGDbD?HDo_{EI=qKXo0cOO zBXj(GhqplHEMiznOLrHemv2O%uoX0{V?XBcWcgFvIG4M8{qjuQ;f#p9s1Ye~Cq;Jq z!s}QW?8d^GNtl77iL&^#0g#jVoYv{_g}Jk8^#x00$k&&&aU>19-V&m2SQw`l_V(a^ zc6=_Ro(A%=Ot~|>@+PM-rwa!GG1@gc`*Dap^EAxy;ivliML6Y>f7vRlLB0dTbdxUg z4qnQ=$(I(F#gl9s*wn-Iwilx3ch+q`Tpr6Juin)=dtS+oUS^ccv?F#ZaX3PcQR^6> zt2Lb*g=Itt`M6q?m6I%YvZIf?7-yg4Wx0%Yu4Zsq@KlU=Jmo-Bl7)qAb|Al*KV*&( z24^lt8!f(yp(W!En78V6D(uK z{6&3uqc$g;BlNvpOvL1Tu?)v}wI};iZn(8i+|q8~^M~`#@9fENSaRSyyZLi)Mn%4L z539WJdLT|z;*392)P!R-KNsI!$N^ZKkc}rau%RAaA&33%xCh^|;>f%OYEAl?{;A<$ zc}8BEYvO2iFQ_tF4zCOci^KMOM$eX|m>ms>trqq{FlO?kdeQl{RZ0 zPS9a=4xNUxSbLYrT^<>v*2~HyY7r*zcr!1rj^o=p_Dn=#%l34rF|Kd2(aM!-<`YHu zM40teSSBR=YZ={uosAcX*y3g<#P$#pmYnI6jS3rbQnrBch_z!4i}MW11F9Vaxx zUuS7KOU6@E816BIhnW)mfbk56z3KiqI>%HO_Hbl36h{W)uBaV}LFygeG>Qh6DO}tE zm$`-xi>38z#hU4QJwvZ&s(zM|;`cAubHGk#9RIyBtoQZI?z0W;Yk{2nL2mJ*OQTbJN=(5sc4-N8vD2Qr|j%2GuIDe zcB`Ifik8VUW}NY4PRx(!6Z$2N7&Ih%6Y{p=A*j&Om;r=T7QT6rV8L22e$5xh=NO@J zL5Y({e)3hiH5{7k3|ai27mnm~>MiGoSZ1wCze+J%lg2GBL@o zMOu1n*!8td8M7ozVq&NCuFE%G#syQ52IEc4MwRFyetvE^OUW2tq z4^Bq)#W4YIptyU7D-YtynVO=4_=sWt+{Ixo5O$ct=?7`Gm}kP<0*ILbd2~Z$@ND_|6uU{Sb5NTt&0f&82%ha-6h2wigqqF5aRUrJIcH|e z^0KwJ!UOTeyc`I?pH5ndPXj_HP1x)m4v#!ZFv&`WuSKLMBlP1St3xo?MVSWINmXn* zX zM3yUB+ep(;Tw~aGg|dlY-5#e?k&@AOLxhH7H*%UT^euU@H2oYjpjQ~T=42x!%wz09 z32Qoj!xJ)F=B=URpVB6L6^E}|WOuTG&0{Rk*T_0v?%TtE(8&JcPUOl|8RKxPMHomz za7L4|nVtK%P?xWg<20*P07f>WCx$Pl+i z$KotGoIG|(_zcB%K+qAx2+$G++Ph>26WU=OixuKnOFxR!XOB7UFd$5D#2B-3oquTe9C4N704*OXg=tPBd>rv_VQ8(~Kf`45vcoyZha zperYwh3|_;SBiMBvB43WZq$QO){}!Lx&PQ2^yoFZ&mfzmhT=}#F2R7xnoR-JpP5vICE(VcY<@Ima4jaLr zO2kL+cvB-IHS(uy79u8wHsA?5&xQ?hKEa%iJZwWxc*!UkE1a&CIHZ5FTpXapwc$&q zYB)0BA%&)t2@DbyUk+pOjl&EQYT>{-CqsB^8qT)ZMzZ%BnT>}&qpK^)8So?rL)pCu zJJ32VS>@Vu{Cur?(BnYPjm7g-W}PlsVR^n|#E8 z6HNJN#rfWt6Qtc*wpf^Vb7b}LoXpmEE$)mrq?t1+SbxG+ww&gaeI9wuhR=uMPG(FW z@wYPgqR1_e^U8eT8QQgm^JE8h7dV6mVZTD}UOj>|p-A`l0>W!o;lKA*i{ zK7JrXC#ccd>@pDIczh|GHI{(Oc^ek#$F7*2!+hCCmUH4^;{uc7aO6sQ87i02R`&1Y zbPtZ1xF<8)!)M}GQ^HPyj%m8h<{vVJQLiO?hIsR3Q)xt&Ng3(fR-Dyye(yq6Vseh3|JCH+JiD`x(b@E`zp0Sv1^)4myv3$d;vOGbE`F;T zVkW;NvJjo!h410rW9MO0B!+BP-~2h4#Q7r~h~v3V-H8T6m>9_Cr*SltQ9phMX~{Z- zRG3fDzJqk7IM3jAp4ZMJxf)ZJQ2ZA+-0g9y zrfGNsgE-fXfOrTmezqKDq~YTV`9Q^$GjE1~yKp`Zxo7rvoe%S4JzV7~A#dVufn(;~ z+E?MCIdNkmNtt-H5{{zCo3ij_q>jrrEOU0EKZb&sTJ=l}7jk;DRabR#|ab%_?eC4m;wtoH? zSFn2Ygr8<%j?Z<6{Q5%p*%E6a%xNS6!8XP(M!%S8!z(G-kk-*fHp(Ra`Msp$!LnWE5J2j46RUsxCYSz>%^4bRB5#bQK10|gxu z*p(wVp@Ku2_^ardpWFm*{u6HgXfws=Ng??uXZfYZ4On?DUm@>~Wl(q=S@GA2^~Z|w zIrz$rqgV)pqdD=B&A_4g=D~IPbH-<&Q!zJ}*2=iBe8Wm?e&QtBHd#u}D4}kd(B*{a z{dAK`hK#uN;p?p-eEx^62)uX1)N0+fGrWYn*FkNvz(lt~vWkbHv}SzT6H83bst9S3 zE4*6APRCkI_l7SXl9N=JOiKWBfI_UxxWcBv2C(;pwHr6eN+Q1AmcvS6_#Ymzp9cwZ z38*)ULj|i>PM>kk%PeX{Cf>l{$l{oFHY_a3CJSZcpG$NNCrJaZr)9$JKg1N~2`CPK z4`J$pBUCNgg|qkZRk=>AvF9MCZZHv#GY%~M*W$Be{Qg>)`G_Vf>P9zzgwO_{f0nV)=?8d~k@b#NtQk z*wP87*rPwf(jAAF<)lSRt_ib(O&h|}WZm*@IEpSm!vu$+E3HHOgai4(rYKih&DI;? z&^UfoEn13Gv|(!l9NAEeIXNRD%oiBo*r1Z%Pe2)+78W$I?2)sbf*kof5Aq9O;ov&L z41+-YO)c$%E_`?mR+()7(AU9>bu+%c^wx$0kru7Xvvi0&oYUVHeJ#-vT0o+>wHZXg zOziQe;t(VjYuYLrZ7?^!FLZ0eL7C`4D!{307}T;3M5&gTMBkBb&Z5XT`?o9+rg1PY zyfsI?`7UR_)+K2~kJNac2yP8k594%;q+@i8aE#Q$A^hfq8^ZA?WW+Fwl-3QsQB;!; z$A!iEH^#Qd8;&S44ry8v!%{|(u-vh{8&YD>9aVD?2gnc10K?i%p2{xR`j8-EhL>!d zA?=mlb;ZBi;srnNJzggM$M~E5LaPve#A*1O60QIC>h0I`I;qr4$l{YqHNxvv61ZB$ zluCQ_(G8i(h=1y|3h_NoOO&Flo0aDv)j3O@kTpQ>ypji0;FIx_&hk$@M?6<)Q%d7| zOT4LO7>V~}8F};B3?uO`vW&4p|1VWJL78A9;h9FN5e^xtm+%8dsuA93q~4npQip>$ zg90a&>V)qzL4AZSyH43(F|InHSJ&sJMnr>I$D~p>;q@kHfY7V!POIxqs~dRy>Uvn+ z$E>=ggkD`wT3t_C-O|Ueu0Ivj|M;aAr==F>OEFHaR68b@&TLM^Lz}0RHnuf+!-7*v zo7*NVd9q4B3MJn;sXXKP3H{tJ%)JI6yp$AW-!Rc12hw$A-8X$BHdZ@u4oogc5G-*<)pQWfQNdKh*T*eUSBJ zg;b$n?4~DJEyixb`%HEptHYlH3;!mS`Y8LEMyeBfb;;P>uH4Vlt0Yb0nNF(^&vIIl zTq$ds@*?w>T})lCqX6540p?@d7Q$ zvdScUox%we~yAjAR`^mM<&IE1Tz$j}3zEfNW%+?#CCw4P zSMxGx9mKnxhCfvj+v_9vD?;*5_=rF5v?RN;&Yzp+y@U@aDP+i1Dr3D~3)3cru_VS~ z!nbP8=%4RX_}40`pv(SBtA5n9>Z1aeTdBmwEcLLKl020!R+QgZjm$J{hR*SqiOIh`hzl74@$ z3i!1PBBUOZOJm-kidc+11wDX|=#WETDe_rf%;Zw)jXi4TS1c08%fv6h-w>03NGI*Y z)10PeM;`evWqns=VX{bgj20`fN6C=V=rjY1YLuy90KHfAIfzrkr0;x{@i(SWkXl?NJl14KlY zON}L&8>TGD7Dmd_ldou(R&aGjU*dN=twP*%S{w0m@F(8nAEx^IOT0N=iD;@e;uD-! zA%3pY%EYh93XHP-zts48)db!nyh}-8Y@@Ijn6QF%0)??820TJ4h!KIJPEk?dBBZJX zvw`ocHa|5*YZP>*2}&|MOHmC;3i)D1iGt-=oA40-S~ZZFI`K1Ig(C6P(Cte!t*V4E zy-KGfuH$b3%D)g2yy;bRZW01?&Rxs|Rg1RZ_ zl_sc`3QF8^yK3?^)2K=~%LMhMf|A+LWaWOgl}d)MtF#Vkifv57C#Lj8TE_~#N)r*U zc3Oq_bxvy|zQk$m#4kH0wr1D`;LXdGh)UXtU*WVi;#WDXLi|@wOY$m>7*s_H@+w(& z7)zb-6Glo}A}!U;Qq;d-$e_SancylREiA|y+mxFXph*c2QrAp%%dCuhi03)2LfqxF zHsYI{)=s?FX>G)}Ijusx&uL}iyPVce{6nX;5&y_(72+Q|txUY%Y3;;!JFSiQr%tO7 zKj5@7@lnUd*px8zoD)$+pPlABW#WH#S_knromM7(>eEbq2l25^OTw3Ro};o5zJ#4h z3IiMEe?Lo{$N-kakVSaA$seGo|1eUW@KGZrON3YHqn*Z5qoDhpl-G!*sD=zsEOxIJ zD;n5XZb62JctB}WF-MAn9xfl!&key>3Nw*B|gPz72=mTt&R9iPU|3ki__YO zuW(w0_^nP$dI)u!t~><^o-C&sOP!Fl7NlyHI@?Nh=fn5;`Y6LfNYx9PX_uDTtydXW ziSKe+JMj;lRwh3BILjmL#K$=;@e=F&n972e2ya$W$Rm{hUs+<_YzkvZT}8>eTv2YCqp}wa+LA!T8??7NFHTB*<3%8 z?Dw?mvkv1KFB4zvw07ckPAd~Poz_nLL8m3n%{pJHJZNsh^OY2uoANhhiFqec7)zqL z3D=nXK8hMMQl0SaMoOA{wmw>6EHw&xvy<`~vD9mnMVgz%UZ0^IN;%3{s^!?+Me->7 zI;$gX?mhZ!uknnRiT~uZcH+mJRwh2<=}~i;g%H2YX-RXl&TptJG&kY*l@ywr^2;hK z5c5u=FqTAf6Fy?{`zUIviUJqmbB&ZV_jgpl116|OLC>;MwY)|w^#d&>&CO!RX|bYF zw5S|q98g(o?jm`V{SvDqZSK2O4&@c(`4&}V|` ztnQOeN(I#?GNqxVBua=W5feMYH)Pm|-((e532(}<5mOmRBcy>vp-G2kEX?apmWOZCQq{otd(tXPGZPR+ZO#FSPRfvD;v^L`VoYqeK`e#ISkfb_@-{7=%;x{_2 zjrgyfRv~_~)5^r(cUni@c-nP9bwijE{z*xN`Hki7wsLhss)tUT*Px(Z|4{{WsFDa| zminNR@@lixi_El+X1-Wa#IPJ|6CUDDleN8{_%c_aNIW&9hYNb)T9q(nl9Iiqsy<>3 zcoClPT#)i4bEN&sGv%2UQ)S{WDlKdm@n&y^k@&mMiiHDX-tDa6X<87`GF{l6pk6Gm+*Qc^?gU-T}J99+;615 z-zofqk$MSB>Ko{FtitCQsh6IW%FywQA9C8SBhmiO14sw2(E z1dxy_Pbw{Ai?QO#rI}5J7Ha`pUied0IJ@ZN(xwtITV---bBXu{<;NaAeMsF4w)Gb% zcaN1yR`&bV89y~gjhBgk>$D2-@0`{~{Gij?iGT03X~YjXt%LYaPMbme-DgKPA-^3c z@#a62h*5Y3@%Nn8L42pvrV;kREd#ZS?CgfFjsfviei7W_w1lT{Q*gc<3{ zx`5JeQB9EO2*0ePDW$QCnyiu57bL`^m4B9tA~$_?kWw$wQbp4wO3v~Svo@~zc+UpL zX`K?)IMv*IS>DT~e7Pe^h@`1gPp(kVu$#qZrKd7Z`+{->r}1W=7d-?&E>vzWHISA{ zcA%-|DzA%>F&=c{O@Z!Dw86J&RV;T{>FV7(Em9bek(&26%O0v4lvWTym#Z3V6*86jHB(g%JgPR9U5;5`V@dRV%6tB^7n&OO^ed zR;)%_SgfF#S?a2c0{LQxQk(Fw<`0;x?ft}eyH<1ytASR8RJ5o@K3k%`kaq#Z^%Jb+ z58x}Rc+;;}VI;mW%a{)l*05S@K!_0jLpB=Tq(c72gcXDcg|Q?;gs`gRFw5*!NWBV9 zEB{EVzT32_628&|^-<6zPRg72Efqi(If|Xb zH7U!nHsK+@#bj;oCw6;lw3pQ&hzO~uNF#RtCd%(syYA7egbQ)+bEAX8I+-^YDNz`S zXP=m1%sZ7e{L(zwOZX=x70%~a?g1-TCp=GeKuYOTNEHgQOq;U2P_;zM&&(_N5#{-` zNv;yISi$;WhH_I0iK&X#!eT{n_D418$yQs^E_s%s03y%PDn@vSPczzBKQYyXCDfR9 zgG7bhlLL7#Rn@j0^W=D$xZi0N;w4UNBOY*CJMmJdO(S0Bv<~7`PMblz?s-v51nK3I zc(Y!K2+|qE8=TfbJmR!z#G_7YC*J6^HsZ}rs}PSntxP=gq>O?Sd32pxhNMgQMkN(? z4z|Q)R<2Iy^EOyM zkjh?mnaaLOuh+rECkr=EN~Z|^nr8Vo7=28G$|cbGdHY^5hz zYc)!_e{=`65$zexY%K_9J!}JzKCAV3R5yOAB)SA#&(o^u5s(NErIoU39k1rMn;WWx zu4!MYY2Tq#$co5|c>4U#oUcl+*QUDNnyf~C8dK1bS?ZlyN?bgVoN>9zwsFkT3an)%R;y$Of5r182VJ^s< zZ)6yW|J`X7;%_>wOngsPVBR0pc$qR`SR~wT<%*Ua`moE&)d{H!CWv_z3g(ROQUPSe zEN)(2$xkcKtyWpGu-~SS-fAq#fS6|~>PO`H8x%~Lj17P+KB(;w07dhoHmWPbaHeV;;n;ts?%l=-=s9e)}Bec`Amk9_-3bd5Z~go zX~h5Hw07cKoz_PDMWj!FDUr*#nD;IwJPpLSY1@l8%^ zBfi;b72>^4D-%C(YDU3)oU+N!SIf|uE>O5uuVIc!YyZvpCK9#USn7nX!qu1WoTyyG z%5@XoV5Fr~;73O4COk)t#>|ZHvr0ljy=o_K?sh)HtIapy&F#6~+L0nF`71mM&4o)RygT)48hAU+ER1-lFhI zC%sGId!1C#3TXujE>KdpUO{Ro9CXsK!c9)f$MhNMF7_q7dVDc4`xU;KdJ6G6<(DO% z!i@i}Nc>0n^rIww`f{fFMrg#$Em+DkoY)0~jhMa%8zG}Z*ofHyz(z=Ig)Q%l*=o@y zGqOfq8KVVrD3*GImJ-SNVh5`&TaNhsCTpypm@dRXUnHIyGGl{{9;D3$Qv`+vy@)=Q zCce@OqNk41D;huVx|Ah3omSD(&zV?C%92QF*V5A_mXfk0QaZHsD<+nbvLsSwYU%Uz zDpOM8c}}YkFLYWPahKEDiEB=qMqGDV2k{c8%^?2WwAeHl%-ZS*!^Q>HzkkX;Tdv|_VpWonogf1U^dHGvZ)gPGqYBY@@ z3++?KB#R{qxv70ILQKbmUEX2w72qt6;kVsq)VXwM|QNN# zvGbMqeP+tjpEu+*<)L$sO(>G~gEUd8bG39)U{P|GhqznIF|b(WsL9*ZPrN0^o7d%X zeg1kYJ6id2zhtMJX zl#&WVhvlxaa&Vy}l4w%H} zRVbL(Z&v~T*UTwcp3POJQ_Q^SP2!hXbpx#K;~6&Mo1Kl2jww1I&Khsinx*ZDe`+>Y z30;XAm3W;g(b3$d`0q`LD&ZYQsu8+g>E0mq`tOWh#8XXFmGCqp^&LzvdPJ-w{#Pqn zC8UB#Lxcy@^$3+vaY^q|xZ6qjh23k{Pfnuy=$L|DUC|DCs$QkD62H-D9mH2StxWuHPD|!4ls`{-(5J6c_#r2K zO5t87<-J2eoyJlp+-9V{Hz}k_1%uRbWx3c&B~yo&>Z8BXtAt`+pCTUeFR*fB{lq)1 zx&bOlN1$2g3)efzzx!0ceiJ@kCO-A0Q9ZO?JMjygRwnLuT08MlrzO(>)_K1v-%I#= zC54Pk`5h{&File!OJYtzc#@Vwb5Ybwj8rF_Youf~_AJ*2POA_PJFSiQ zgHCHF{*cq!h(GMK3i0($D-(agY3;;cbXptnUZ+)vzvHwd5clh|0~sFT4ox}|{KV6p zRwiEIw07b(PMfgKKWd#wU4%zyu@L8!|MDy`A8Is!B@z6DFV=Dheu|o5q&i{MNJ$_} z(MK;ZmKp_J;H11pEJZaW&{=G*7Ap#VmOCoLL;P%|G5Cw*QTA$6t(sSDL?2zQSBY%m zy-sT*0o%r`oOIn+CUa352ZNhgcDYQ1_-;pIwWB^ObW}otZ-sJaD)Yptu zC){tOq_wZnM>iWwje_oSQeGpLq8ie&EcQJuR@B-o_x=nI@jok#tz9IKvL7_ns(IB) z(<5b?UZu5(Z&g}YSny_VhLQLm&xk?-<3u&QS_`6W2^&@cUPgUEZ@!ZyP9&_)gmn}C zvylcU>JB4y6H?WJ+1QYB@32x;LJAD8jDDogDXQ>25`|?-?%8>7S~5K+ezrREReF_U z84BO(q`YHhtLSy6e2rEAx04>PlmubESW#fIwh%>~K61zB!1mO3Fz;qR1fNhXtfmH!Samxw0I?Z#3kWT`^Y`;`9=dX?TqeC9c^ zHPC7HOybQ9B?=?)H_y#5=39_8EITtkLGL2mb{0u}mz*8p`}7K~v$Uq2dIgE_Z;jOV z9)+JYQtyKb7r)HJU#jraPC7xAzEQ6QO`57+r|QRBbxWz|HY3#u>6n7e1j=4wZs{gG z%mmda+XW^2rW8cYCY5>!yUdx5)W1D+^@p5`)xFI$=pnq%JlA+c;juI5-^Sl5yva$A zD7?k|+lcJ`-?wY~f8XL@*$)*`U%Zrmm+JRp({ma1yg>EDw+p*=HZRn>p`JSvzOmig{5xbq%1+G&&g^iePbvSux@p~`bF4?-A8?d^p&s?yWjc<8AQUC`m&F1 zrB8*8*!|n*0TdDa%RmmrlAsx&hl-TARD)HD5;LYT5ED`fVasd5-g}J&b1m;3?EK_C z0aD)Tg8iYqY{dKi9nHM>NX^#}srgDGbs`&>K#Fs9zFuTbR{F&9>vh^O*a1byq8F2|L^4<%FYZ0 zsoqa8qcfK9_0vR6!0M!<$Ysg9aXHTJ{niWu)$Qg|su1YCdjUy|k2Of-8-x zWJB;2)sIS{%Ur&*pmSZmlL?XX11D?9^tkkxD}9lvUXWG#qHOn8=6fHf(F{U}SENZ33R)=jwENCOo0T_bf9QdLA=UiQ_>&C+oE z6+4f3MP&QAUIXzMwRfZ04bHr{vvVbpV@}AGD@Z%TsS>+({z{3Dnmtv*j0(FF6$&ic zy|b3n3l{C(c~VZZK+IdTUQ7OsUXj)aZ!^+jLV65AN9ohG78E3;{so~~p#7emds6N9 z>^xWHF4HTtPuKdlYss&hs#QW)wQq4w6jaT-;RV_XE37qY3>h|5!NezDN-}%CSW&iT zxz$>m@DRVjXk-1v^ctozMdGO;y#Y2_Pt!r7BfYmIQ`KGSsQ2j=-8%0mvb@t+>Vzy+ zxRT$k{Qqp_647M&ps~~mS*lR<9_9a(UL}hW-{`ao@n@XYM*J^MYbXA^)20#M>a-5x zuR3i8@rV8@I!<=NOB25_Xaa>n5Zj*nr6ERj?<~qXJl~r0vT- zqg6lC>;W;a!UwhF$MrfD!|(Q~C%5tbE$Sdhyl*=-ImwIyah~2}>b`F~>ps@&zHfWJ z?uRux{#xsnzMiia16RIQkn(kc#OhhI2qQjxW~>@)n-y*|QZFHO1s7e$P$%h)o#X#y zd(fp|+FcY)yD#%H5gn$6Q9|&WDo@KW^sz-}sEQz^ExL@=vlT^H-YAr$NjJ@mI)Ld#VTPB*2hhoaPz)ul7_im^5?y;(Zy~U5d|j)9&2C z8~RofB5}sgckbZLP3mu9B>uM2kOm1e&2i@r-q2M=S(n;Vb2QnWodqi697Gxhdv+Go zn{Jp~e-KZxD$$LY&Ot6GWaUME0vo+Vb%c$WUH}{6!5mVb9fPT%R~$t8BjKF*2>z}s zT%?GY)gTelp5j32D^iU1GHM_#uPf8nwc5JyF<~a7r8%U4DNSa(wBbHr4VcUY$ns8O zsS~nP;ap&k@_*6FC8Ei4qp{QpS*lR5w78!MNHCd4oKa-6Z$30bO8bi4AOVdWBskmdQt zQYU1oLeVpozst%cqRBGHSn7ldn1+MNz^Bjg%}3Q}w&) zhYL*o8vQ`aFqRU!k==w{7etF>TvkZ?K_aC6*hC@xqk0EFR&iL9H&wH{Mo2GV_P1*X zZ|En;Bm9!tU88sY(@5Qf-nhw`k<>dq^v;>)on`dSjn=r!QX_k4!M~sD z)5n}^Wmk0PJ$l93C?5bI(ZFw;fjxvLYDWN9l;r>Yv34+8Bl8U68ERqplY_iD-^{Mk zYldvNwq4@M*=JcJBCDM`$x0UIH^maq}i z#b6_3cM~>Z8V@$w&fX?$#55CZf1Z^Csg(nVX63-4S(zl2Vk-v@&B`RtbaANXJ(!n$Wa+n4-mFZlgc7sQ^6i>^Hc=hSamcQOp6<-mv?G(|na)D4=FME| z<%#b z8ZoCDSno0NXoVasW-C%jDN5|ksK&T{3_)s9u;X{4DtexWq?eEAJ^JV=Hi*{Jv9Oko zg~^zm3K~cS4WxpSl$94G?+SJ_^Rgl}FD_E^Hr}7u*vPZw#TU#t->mb1rp*TuDPKsY z3<*o8`nkvaT_wCwNs~)E^XiqJtw zppk0ONHs{Jgc@*FaCm7)>DA9}^41$?S*qBwRIz2LV#`v+mZgd%bAHb6Iiti_b?uIC zYJ^d(Ks;E7lFu1Geg+5JMz^A&U{o9RJ^;W;@vwIrxows!HTc&F?RQk59v)t zo83j)>`n&M_v--pQJdLR3E3b;3Gi}dCr?2NIiQQ5-`XMwztpez_fD%2KkT$N;y*a8 zo%oMVn@0So(>jQ!>YHeJ6G?njJ+_8yh8)J5qm?L(#1*G?5FhKbX~f4lt)2K8PHQ7> zb6SPC-DzdwTa*?Q%tsDAdWu?x-5SDkl@wlCUaLa>!Gsn30xgBHB<6I4R1l5&EEPe$ z3flQuTJ=WrcSnhKw@=ytF0&lU9*74e-XCWX>B6 zJ6J=!(dz3vN(&xq^;HRnjnqdKKI0_9TZ~jqwdy+*A5T|pUTIp@*l!qV1w%SZb!sUI z#(c4&04*v<87ocJSU>Rrvu`QwV>MV<5K_^i8uw~<`Gs|x@iOtSZoeSQ?4QD$5hcpz zG4ZksEnn`Rl21ph;YqsTjdVnKf|5cyI!}dMV8RO05rwfN(h=cIRSeCM*Q=m~9#wm< zQx(KF#7)z*O87hz-k|XPP9mJ5s*5n)I87nlRn#8T>mwPxh(G3f5xQQ>QoWWP znqJGEh+ePD=tVs4dKK09M8t2&h$nvY|DO22&4?#{hl?kCnl)`7z4|v!x>s=6tcD&cbr6O?ZfBo2<+FiP_`@Ed~aJz(5oay;#E$o z5U+Mx8}VAFwG$6HZ5r`9r*#l-cG?W$w=VI7d^m63rbL;*62IMP9mId*v}wdwIjx=e zYNxdkU*oh2@wHAX6aPjRS~9d8o*yyj(aZYd6O0&yJ&Q@I5nim~v5MNi?VWn_L%kyN z6V7}seFDBMdh@+3@qWG8XUc(-H@{F~!B|3lKW6&Y3Ej@C@7y+#ouAhh#LGCsOu4;D zxm%R~VXaT1lK2_spk;Yq2wUEoqJXCO3sscx5N|N?wVet-=p@1$loWnP|1VYJC>17Z z5FcxGRtX!{;!BHaWE8B?HpcXbG4Nd74*}_kxQCt=y@;RddJ(!_g$+H0kf8p$$hEH%P$C55EI8)h72Wx|%^n+ur=8-u=dUTrc56 zEsVUIq}#|CnFxiinR|=OOlJ&v zRWQ`i%$XTQh#4_@yph6!u$LrG18B-SB{&5!mxX)C5H-*%mc^IKSa+X9&MOlv3t1JeIk8@gu_!&-X zBW`nAJMpueHjVh%PU|2(*=aL~PhSzW$69OmRNlNqiLw|ZeyP(sh^ISk8u6JG(Wb6SOXrqjyAGgfC5%sZVPy-Y2W#h}97dJWr$GgNTDUJJjQsZ5#O5xup^$KmDh-R-{9*c`+6n|aD%1Z3XGIN+( zF3cAbT8lBbVL8?&JjDNQvNrb<(@3aLBtCC8*yvT}@B-yIyJP#yAI04!TW2J228MVd zWH5xu7;kR5DB1_Ue6SZpEJ%5Gyi^5vh%KW@9!|;B10NHxA9)8!rWD{xgKk+~1Dae@ zO`s$pyFxITH}nVi2wUc<1%Aj^nICB|9N(9WvUw&fEjS##LQ^Srzwp~AygSblY@KkV zg^_pT&Pe#y7DnD(m2=hy`s6ktB@(FVA1}Q z$7i`G$1=4vS}ro@-W=cIkuR_3FO=vLsS2 z($a6!t87~kU%WONDBA~5;?0N>g^_saNQN=*6xMLx2WQ=Q8TK$w+lVm!0H6 z%Kk5Ft8PN~!BWb;+I+Ay^}$m5;2Y+arK!QmSnvn6ign1A^wv+R5x1H#RYHmkd~_r& z48-VT|L-2PjRwi!%i0#cF7gSDxLaw+O@xmasgXBaN-_`@ndOb83h5Ngg$R4K^`#`O zIa|X(Xv7Q+6eXmc!sZ4>bTBg;88eAjnoU(gnh7^vF@7k92FARpf%xYd8w&rW=8j~{ zCEnrY68_vs1BYTPmhpL0LHctIMbW?1%r|7rB>q2UQef#$n}wm``AVn6LPD4b&g#6-@iKG8P$aNWuAXe^ND`qQh$_muLEWeYj^sd?HH+ zh13`%1{3uKX(B=2@Y?onveQg;G9U@2h>$)JHkv2yNYV?ex0cy?bmEodPjO1eL@Ea zjpqMTW}qehg88mW_zNQ~IaY^Zs!`P63wq3*TRA(-^q4!h7W9}qw{nKa=^=c1=hjj6 zS*9D^xs_(H7YEL~*H6-*IY+Np)bH9VD+M~{UVShHD}!c5O?|Om12HeMz`*;947|U{ z!262~ynpLuse$(w8F+uPB7Q(seZ*R+O8BUe^dl;_grP#WNJA2P_)KpSueQF|O~?I8 zNm7*f_ePuEB!0PSA$-IhjWaD8sjcu4mo?sS5{aSre47c*Y!V+V9Dk+Di#D^MO3fyl zf08Up|FCBwLmcn~L-iw-aY!v9)qNe&ziSIW=G{Nf@&kRuO8@Mv{G(i5lksV0{@>jx zPdU#+g{U)L(55>EC3W!2Y#mo6ykAM^nY)s}eYrj)6Wq3Id}>~WJQsep9b6|Ts-C6N z=sRhIaqHyS1{=4C%Qo0}vR=qb6eIqEj1GOd z49ICxPPV*Cn!=CPs}`-~t6<8f(tmayeITbRx@XYU#x{;1_8_kc=bxNVltcQOTAp@1 zDNIe+#mGAlq`bU~bo3k2Yrzg=%91#8L`!d;SW3#0NZF;O->FyGSR}s7Y3;;6bXtuL^s^&etUmyL$^*~5P~oecv{WG_75I+^9d4!S6tuuesi36YN0j@$ zdX;u3UbHdlkDcc|NAjksL}4VpWmATcH+z*RjKp8k5iCf|JBO-#-VEp^eAr0cgpVpI z97mr>)OW00VmQkWjK#v(izd9tNZnm(?a68kxW1t9znygV<|yN{x;q1|M-(2Z7K3!0 z!c&~IP9gmQuDmJK^FK%96PZyzsQ3@2=u#@W)taZHN&I5dbSag;T}dL1_y{k$GOwH?8VAh*c2OUDG>$TJ;z52X{WsPNaK7`lq@w68u zsh#CkYk8~{c5iO-ZrplEosgX-GBR4(IU|(;`%(?qNafu*7RGf#Ms{SJ$Tn6zsdQn! zUXWNRWq~x2AZ9A$3qtx0tLxNjwTT41Mg1fFgV?ofP)kb0B!-ZQE&LXnI)qLH8;x12 zkA#hw1{Q_?F{;p6dWA!GrOUZIR|uB8jkC1sh1OhE!fqq=5cV6XK{#Nf-n{G^RlWbz zD|!kYa+H@MbiX7YT%D~c;T?K~Ai`UXlvMvJ&B08+lS}iO9DLYjLZhddZH1OMB`*se z-?urD7O8o8k@|QNF?i&a11T>Hq{kODkO~?|1tlB*c^lDhQbDy;P%W>~LUsJLdM((q z-*Mb(ladQ}HQ>b#eaK-Lz9+m|A5AJPA>6H`DWz?bn!Ndu^AX;i z<>Spg&PVu5BUK5Xt~Q}o!geE7U!t(#B*Jkc^$^}@r0Q1`-r=NQDg1+8gHgOGsT-jN z;ggJ1C48oldI(=(q-tFun?z(y@b3h3#PU4H_muDhW2qAU#z>2gR3nbkE83CJ-M4sa zqS4}fb-R^tlU^s6Ufv}BoYL^?3AZa`OM;X)S4t|ET~1LnO|MXskYR_QB-A%Qr75LN zlbXEIWtI>pH+QO>x4ArqNXQ3XKm+ky2YeDLv!b_zy718R+rK{I6a39oX zLVH;8bF9KTA%j8KOs<06dZoW7m(DQX->T2B2BPopa1uKnm6=rPPkT>4Tj)({p~xq8 zz0%zTzU<264ML_s3>t)N0JJS3lO4DS*#O`oWLg6kA^Rw}2&pKz)PB1hB)Xn&EzwJ* z{>4eu;2tNX)g{reKr3cxH0ee8VnQ?hazI-FaW`Hj<^Ts;h4^qS2U;63hbT$&#BI(u zjrd#@d>HmQADhCvmsa=#^k2|f6_>)en5btpsLo(;(Qt5e0L1sBs;h>X-Rl=2eJ;>BTPdJtE%YZD!`aw$S zRl<|4u5Lp57s~;<%d1aj+7!Ih1o4LiO0*+nNZz=by*i^R-Qz_G?^9AJ%9~$1adMM4 zPt#rj&M8gaoMK(2&Z*ISClUUWkroqv*`#gU(d5k!oVc^en?G9NUcxCFXi#NmlQ(oB zT8^;W`3`IHW`z?EZ}Mi$iBp@rVNygjM_7jZJLfDndGlc>KB>u@FFNtaCU2f@@l_{$ zsgV{F&NosoAwz9aX))n7&PDhhB?Zs$#-lSyUdL!lv-=~R(s`Gg^cvxtP5Ri*CU4k( z3oIF zn!MR)VbxE##ljDKyt&!=2pO)Bx6@+xznqVd!&j)+ZZs;OA0zh|3l!ALn=_n`Epn2z zNI&7J)*>j%o70>)xyc)b7V0H@h4W2n@}}1-AzYH>P<4=t2G!d&?}|^Usd>Zy|$G`N=H6+;qGGysCm-7|=}FG9$|eFZz9_ z%3)@d-Q^!E?IEjnF(JciN@=TS$-^zI785e!L>%#{&PMn`BUK4cSJGi{SbLNCjFBYr zh?&J;1t9~ZXpelKy5@&^eJU!*G%CsW=wq}YA%`#=g`Cvn4TmrgeLO3x$3UFYK4X}}L%t(s~uT~NcUhQb|<|9tr+2qYP ztZ*;kcZ?5<4&Kl;Xc5BG)LXC@voF0_%)8$GQ?8^w*iKdixOltCmoddIM!fn%#h&PMpK zk*b7`Dk&~;@(EDn<)cMtX|N=3SmtOWb?eoaIH6HV=IDqvB=mt2OPt%ZI0wQo>hNZt zK15-{?jbd0y zrK1>DQt2p$l@v#@Z@ZR9GEH&1IJiCAvI7+24TAyB z$oGH+>SShTe7&2W(#R1qHoz=Pjsu)8xMtNJRdSChTcxtkuq-o>4!Kn-IN!PQin5DR zQCSMTQI%(83GJEMH9D-<^yHNnwpXc&y{2lQK{A;JR5g%|`h4_D*Rwn-OlcMLK^EBe0 zIIW%d9;dYt-|Msr@d2lmiMJlZ>G7*iyus?(FcY=WM550& zwR;I?d)rQGzDaM~yk463G&8T4@Dw90?oxP>k$MT&C@BO5Z|E!#CpGD=uX8STFQ1ouT7gGSuj$zM?yE@JI#eXgx8r1F@59B^-i4J2@P8bvY(Dmyt8lFII?W*Yly^LGznT}e2Rx3kF`ri8RwKA|fP zS}h&&Z(c1SeH5yFJck?(+s{6wNvG^FKP{$V3?${G9RpVJVnP~lM36cC_$CRo2!jyY z_9I@LrciIKDBrvVBN$uvQq@{2mWH%Oq3-s8+EXKYkXOPUPHtH4G(8D~a)hrlQk8Iu zP6oh5_;e#Jo~`gRM(QQ}f{_*z{@6&>`xLqhl6P@GRMVX$8T-iMUg{>i+)U{qe2bF8 z#sF`wapL4AZ$9jWzoPIlClR_Ime3F5W?>KErAi95^5%_BoZRHiwO*Kz&cvujNM~Z- zp3ps%gxdbZiOJwZmOIVDe!?lHCiWnCbF``1|7wM>m$1JD4gcz&2E(k z;^Zc87-)DWG^I%&yj1PNvY&9Cl0wbAVUVC^+Iou@C1j99ON`Rqt9 zJ)*&+N&abS(R)c&n)B6K_RiO05Auqis+zq*uaoi0gqSMg zA68%60*H-ksPOqY!+_5W+`TfpR~s&y-bz(7ET05Tv#6W|aY z4wI0C1P?GI0U`!6WI}i*H9b8wnI=8mV|Pzpgk*Sl0YMo=0Was8;UOS!4~ZNkTtx#M zjsjN<8WlxlID9G(k%(N(1uxm)X+uc|_5L5=`L%=p$D9o7*4mE@#bII-*LTzKfjKz#BB{take>ofX9CAU!jfG9BqfI5!J(%@kv6h?q(W|ZJp{Qhx0HKenb*BA zly-{v4jiM5+$(j}2qsucnNO41C7uI*6{dE9XWQmvE2O7^ss>8_G>bKo|BS_&$bZ&i zIr6hCHjaFo#ahVEwb&H$qr;ommJEAL@cu+`a0>Y`5EQJ1{N5HDNB-j$%aL!gSQGjE zE!IdrXR!wIC1BFThCL=KR&WaWK8v-GuUc#z`MSk&5aVU_nH^wI}zfIRh5xbIEDP*EY?E)?-ml^XWjeqnBM@1J zOsl%S9p^M&nT_10D|(w(rueaWrR#^5q$doi22*_5yfVv|8SqKHmzX?*BFhNZ6@gqw z1ajRF$aO*>*9AU~5OIFZDpyZRv?kG&sLAJtRRbkICamN(vMi6-x;CwnuU+MqNf~qt zrLYw5u1$FNGlcZ`(35tuCjydTYt?EdR#`c+yd_D?F~MR;vq@GhMAzreXk5AtP`7nn#uupBCAaweZ>S@x0L2zDDvd0ZSS81Y(A~ zhfg4~3&I(ojcjKKCB~(TkWJaT&_LdXYko3Z^W7FEYhOl-VGt-;V~O*995Jr4E;Nz9 zFN{JvSvE%9l9-^YGRF)FGFd&7 z-2<9T5+o)?C33?r4;&GQ1?9X3C*{~1C)Z9f-gmsmsn0g-7y6l9nmy_$*f zVQ4PA66{YxsGV`JWo~Er@}Upy%-gn?_GIHobodwG*3rmL&G6(Wg)X#_y&!C|^Ifl$ zCOx#xcs@g8-J0(|tLvGNZOooXY?Mj(?Q*&86Gmj`tIa9jPZqrAL%S}4*+);8P)tQ|HU z*&wkdzQ$q1Ya?q1nFYzpNt|o^3q1Z6+Kj5^b?D_!g~Mn|ct1ga&ZFd*6SGm6TSD58 zw8<=y9pQqSa+feczog8rTLQ5O(<^~orv!2{ zqRdYgWqz_KiIHg$8UUX=kTJn6?H9IPgq11vopk4YHWX%WZNJZ=-imVEW7|BP+%23B z6Q!rL&3@ilkhWbev2dYbib_CO8SERfz#?m#TEb8xru=^bRSRA6&sZ!+{>K(WF>Q6y z){&4A56C_dLJ1G1350;iv2Ax-6fZFO@9{Hm}OYKQZiS@`DNUsG|MJE3(i#3w}w#Ayrzhki+`S&c= zME>smteKzQYpmk8!{t3WO2AvK{eOG=E zOW8)OJI)3DZ=kOH_aV=H=6@jVeZ=xVMm|3UeTVrv4rckct@_OvsK$d%1id0LfSHV^ z0zUz?6?FMWEYF8P&p1a;+m zfR{ikpm%@7@=IZV1?cVDncueRzq^+y@#wt`-2-%QP&XdiD}N2_+yc59^o|Vs+be(I zKE}gl&uQ?xCdeO=GwG8+w^{#iqj%OgLpwnq0euwo51>ZM{{8(ChJOomGw6GuR?=|W zE8lUH(OU)jCD09^u6!>S%!9;VQ6EUp%Xw& z%Kpu=H`}q-3VYK*+dd@wzlOgrgT4;>e)AiI-;J>Id-%Bpv}d*{`^%s^;K7H35)VKa zIoj!fy|)oZ>e)ydj&i+_{~YMepdVEJ-(ZLJyawgkS~=Zz@EFR$a=(#Le#Y&1#Eb1{ zTlFW-H6@-3`p=-#K@;%+9)R|MUIe-XbR}p)|2%_~K`#a!0=*0Leo$9`!375C1PwqJ zg1Yj=2XOp(&EG93MS4*pGoAIs^Fqi`?e zDBrymdCI*AJ=$d)9rNDXkb4L8JM4?$i3DR-wM_il##uYkV@`W9%Ge2Dj& zoJWD~2D&%sSkNOtCxW{EdcbLia%X4AZ!I6!{>89!Ip|%Wk7U??9e5M!^{=3fs7KfS zWE^+f!wlfBJ9b=s+TB`vIkeAcjsu+p>e@RVe!BK%0v`iC+H>{UKPb1g{3w4J>~Bq; zUv&On)#Us*D8DtmzTe>dfb+9R^CQ!)zqEG}?3@PbgMLu?LD;zg^fpj_yxFzCz4H8G z^PM$g$^D`*KOM}kiMsiHPL-sGr-hW42`Oz4Df%RSB?}46oi5n@C&eGoqy-`3%y0H40xR`BB?z+{NVZGtdv} zAIrnHp52Rb@f~1pdH90W7m@!3~<_Z2#BetnSV%Y$xk^j-N^0W_lD@TDA|LfVz*Lx0zy zU+@jajpz@2z;_5~K2OU>W%!uL*D~(s_^9pkIg#JOzn4H?0d>p!e&rv4y@x=VUzYuC zmFKP1ywf>{_QN~0-FvDN`Qg5uyFsbP+nxC=z%bg))w>%Dyn!&hTkvD9Wt09-*ySCI z>(TBvfHuG`Z(nrnx>jF>y+48e4RmsYD{0anmi#E#-vzW~JM-ICecsPA7xsB~FYo+x zL?Za!XE$gl4JB8M(hW3yv zSL#9Y!g7CeXMeHO^{HZ)r&B%oT94PRxlPT$I1{V5$7=mV_Lubmi-LuQ}-PyQ}%$!0+i2U8cO|LcLP0Nrr}8RFH#8L0K1F z?Mc43SdiQ+VpIM!>x_)i&YGweD!siySq^puo&5{_d^KNQ7$}oESuA%eE9OvVXEj*N zRH;}F$V+g@mMW5&k%uL>HnunY2~kiT6pJqJhnPi34|NP;5(&{};ojb|h3_}}>B_l6?M`eE&r?VO|7GIA`tnx`9}^V*pcEL z*D=w9BW1Mb`Xr8z^tkSb<2!m>PsH(29@hzRd?%0de;nUAoZsVkgU9(gj_=}e9**O? zdYoV5_~>xnjN`j`oDbvp?jGm4IR3G4{)*#!c$}Bwc%#R8CywvwaXyLTV?53iaeOb2 z<9{6A+vB(%$M^9#UdQo|dmM-3_`V*;*ErtfaomjKSbRo7;YWJ=JBUe+^qj>4q(*uN zWXNN&>Kq;E9q1q?Inp~Q1J5OJ)lYVil{ME<6j1$rNAJ&Dm?l*oj*wNETaRk|AK@kI zaf-&1^>~WlD&N7S!bE--2tUHJab`ch2>49QTO1#hy0X*As}iu4<-b`6HhNRAet@`l zy|%xHw`neOG)L4}G{Q^zf3M&w-%VrV@{bCh7Pn_1-wHq1N?QHikpId~%f&kBy<>>C zgP7I$3Ilu`+3XK|6RsktxTxPzz}KsVviy$6U^^YScd5Z&m$dqI0^f9*NwXT%azw>{ z0C65RhrO#I-*>qIuzm4X178DtFUWrfc*nH{C<1>T_@Jr?`Ryuc_1g@5=<_E1TQjYA zdr3J|95%oX)V!mCcYM*v6F&|3Cg4|^!(IXSz?TdF;;A=UD*KJs8GL8>a})5~puyjg zwEEpk{05Wei+BGWc+0;Sd=&iuCGdeEgY!+De*xZlyTMWY-e{TRlt1f%quAa-z}xOH z@;@=eI}v#6JqEZP{$BvR@jiq99UHe5#2+yD_rwqNyAk-N2Tl4?`2QgAq5oy@Lw7dx zS>VHune=RQ$hRoJ!Qg!R$?jrLm8B6Yw{H=N!C2_65q$dhT~1zc=vQxh7xs-@||p0q=nPWZ>R; zars%m2Y^%F2R`h`FVVQH2OK{?54^*{Z-kwW^G&|AudcG`asj9R>TJ2fTQ4y3jN7BY zhk(=0M&RCsarxf??*LAD_420?^8J7T$4~Vwd+iV8>5sY!sQsC5>|;3a#seP)PWvZN zeu0sv9rgK8Z67%0=L66Aarw^y9|BJKOM!bGarqm84*;k9oxq13`R@Sl$QwJ1^Hadr zJNR#b=Q@o%?Y{|pz`;jL|4`)}2F^Hq5_m@;?*B2A2hKR33Vfi;$P=FrJQu|MQ7@rU z`3?YY@yzcsjqmOaIrV-s7!w$X?xOe;ronaI5RiC?7?Jeiv>MDZ5 zTOIsB;2jP=1^9r2pAUSPM%z7qJbgI}+4nZ3JBJQ=suz*`-BE${*0Gg02h zfe$mH!;5i2$CwSVrYgz_=dIsJuxSFR1N11%r z$b6=LUBFv+G5AX|UaMb!hMg}$emH03zi-67+XPqZ1~C(`heoD(TWvTjJoO23N zA3Q6=P9a0So`I_`lc{nI-DdKXZl!;B0v`k}N&R~w!_G#^W4%E;uVu);C3spK)K&g8 z{GbeclHh6aIXwecZ#GM_U(Ud<%CPf|4Ecw&y!?5_#Ov!=2R;pa!z%`#Wr+6z@Rn~F zfN#tAEAWmXgG)2hKXtc*s;>=~n>3b>-ccHdP=w4CJgvOyYO=D^fql)v(5YqExfb$+ zkRJ#6)q?LS>&7l;-M9|&El(T4ClQAq6MxL$+}FGUeBi4FubXb>si7*(fAtlhG`vM{ zRj$D?#=x=g^VAIad0HMq5z-4gxxI`Xo>{mOxHr<^SEF3FWY}3Nc$%L-$iRnTf789j z8IBw8X!$>HX~FuLuBw+r>hhu?NVCzuCc)G4JzC3C+fwz~ptOE;0qnP3V`SC-S^X}_ zkiQD@EpHmRUPHV)GUU~pjMDu4Nd`Ww?Ih2qsrMJ9`TtG^zS|z@^0^HBp9N3zb5;i4 zlVN8?hWuAE}zbHd~RfhZx8XxTqqXBY$xi7=ccQWv2GVs@6-@DHgf&EAZH{HM5 zFkXq6{_Uf2BqHRH4E(eV{M-z@A~^GknD>@t$bUiOGLK_^k?B?cZq1N?G6VmO;A#23 zmLWev8jl)(a^E!hU5R}6);JOoawy~no$>z!!PD}coq=DFffr$)cTvBLyf4;x#1XJx z&9L+B4E*T~JHOJnobST*vI{XzzMf%cN16C?Nq4-x1Q(UW??}PZ;xk#x%lV(XjLO5% zoSk8(0QpVJjo`76UnY2({cAGtJG31rN614N@=t4dS+}6xWjfQp-(<+Yk%7OHf$y|; zdffIAJgr>EW#Ff0*y+&tXm4Pwsn{a?uV>h~6!INTJHHut8}<<=VZU>a#$hx<9?QUA z6g;h5TVQ{{8L#$~4NIE*L4v2Xx7G}NUIyNkf!8zem4c`FvpNI+eg^*24E%S3t8r<~ zZ6=ssL`+A?{S11%deZ>1P1e5yfDhem(ly}637+O>dj=k4;7eh@4c8a0hy9y?4;^gU z)h~eGqwV~8OApr7fW7;*JX4nbdj|e%*k9v}&+lZ&@3U`udpJ_#a{e6i3*$CP@U-}x zm|gw0!S{ot)GDAI*?|8uA0TnEY->zApi9 zdCmZwPe;fJs75(I;I6}W*Ep0TWIw@GdmH$I0iVIKlQkX@1bbeFol=JU)fw`G8S-~% zT&_#*XWCmH3#o5s*m+FwJ-vOs_5BBH579lmU((K3jN|G)5cPXA!_G*#l&j*f=}{xc zy4w$U+mOMzUY)FQgGK+ImVx_%(`Hn@k|BRnhWs}&pJC^X4E)^; z`+M%6?*HL}=a5&Fd|Gf7&moLslTi3J;Em4srrze3HqQ5F;MZi}cL|;r=SQ@>jJHm| zdp5()rVM-!*=VQP-%oH=-d60#e~4g=*LXBChM%5+cV*yL2%eVj%^CQu8TkDf_J5#p zX+JnGfzzMfFMtm}X#D2Bc7L69IP{FL#R&Au(L?; zv^Wf8$bU0K{_za_XWEX`<8#Il?&JQHVSkj|qLEhK{RB_*^RNv3cx^|uzy_!eouz|M`6Da11i@i!x?to&9JkV+^UimpCdBxX&RSShIYbn zY<`A(Jp;c^@U-~fk|F;$0D{-@<(kadH>a$8TNNQDBYj^GVrm2r^Riu#w9*C z8E-BhVQ4$>K71hg|Dpp28FuO!_;rG(#qHJ%T)kCNuOD78esCSK5%?Oc$Jmd4ukmOk z4gZedY5DG)OOJzB$d^j~!rn^RuhsL_x>u;yYxVx_?&gB$`_t#np5xE@O#58lm(+|{ z>h$T6LtPbrVX4xYFZuc*4nN<&)RSj2`bt4P=xUxk>Dcj}I^Y+(ma5dTo_P+WtG~B* z8S^>i%o#eHQ|Fv~#wk8iDjV`P7yZPD&ZV!X&+iR-3;9Bi^^yHBxnz+#eAu_JgA1ybaA&D)YM}xbC=1>YN+UU1@dG_Wtq3U*z2Fcocx7BeRf}6 zJrk3_=LEI>QvD3Em0uXKQx2ARp{IVO^P-?o_j~f?u97@lW3%h727%N?r5aO~NcH*M z{pEtMDy%bKSY$OMEVZC2kLZ+&wR-w-Jin8EP%6GI(W2dWd5X2Rs+d*J$s`V_hk|N# z_1sPTki^EsV0xu15&%#N zVy&8Q9)GNxiMEe}Q|&>T=*urFRq|a%V8VDSP{`LJsuL#IBjTO)9Ey=_RWk{qsuQiM z&b7N*>Gk9JPPQUaPc!5Ju4O@&iA)%EIbgGm$s56V2z|d$DN7&eFVwwKpnGGap%;Qk zB3N1obZzffU7m=|xCWCZbNMuTRX(_B7q~k)SgNHIE8LuaUrKzRFLq?Hmpr0mWwlb(V zNGRjlgkT(&_{fAKV{qtXh}Z~AH5j2;GNy)tAsV+R6IH7C=lbQ@OS-LxuxT=vtNDc> zYWoy52&XiD)e`hEJ#?oj$1S#T`$yL%Pw zmdKTshs<~x6wQJHM{Cx|KV_~z_vC4_PVteg&DHuIwqCz;nZHN|xcGP;_I0UJX|#1U z{go=^g^{tCy;m((T3b(>^_gkY{RzzznkRYEvV9q+D+M!i21~t~OzeJFr7VK&C%4a< z5HVwxEj3>^XUB_ZKaTqsIbwQ+Ety&-Id-J|nZY2e593*1y{Z?hI_hewkvb4Z7OE9Z z)$grz^_OJHBg2@?pVeBR{>r1vax6M0b?Vk7^;M6QN)O|zOtR)M7K$}rrbn0y^N3Di zwg_U&*CETxV#wFeIM-`cS=9<&Qp+@1=sHC-vj|&{X;r~eHH^dqXS+ijx8qwJS6x?+ zTY5;cE_Mbz`Nc(9Tq|F@B%f-rvtO-+rDe*ZsWV?I7Q$7yJX}uCOuVffv?8{`P)yZ^ zts5(EwivQj>T(JePMmT7^O1Qcek2@}bOqa0i3)O8(47x!4$JgfU6x4dxpvdb!%pRw zg2jQ%*L`}QQ7iXVWtrF=X$z(m__BzU>hG&5rl>X`ey!ML_bp+BOx@`rC1RvkxrMIk zYmZf&Ws^|#`}KClv@+RXh?CMn%d((Tl_Fg>UhL>R=m)xO#Ra57F>^{cF3ThQVz4V% zs(Vbtp|AmnV-XmIEd}L;^&Tf{kqqY+&O5T5;TRd#y(+4$4{1u#<)axdd^N@_DN65H z5)>Eq)Wa>@v`VGqN$2Sf{GeC1Gx8L_uiro*!4Rk71C?!7*c?R)qIN{`s)8Vp(O3Aw zBEQhH$nVYx-F`-qhU1Y+R>1!voi@LBj ze0t3hX_mU5*uzqCv*WWfgK3+p93m!7E*Tc3Ze~Hfr&SC6Wnne9o2JdZ{4AN8PCMoN zK;9Ig`$i=GsxQd)P466>n3=BNfM&pm1Vx;Sq{3$Jj(ZUq*tO-4DtWT`4NSwd0>(K^zy9z23ffBy~8{EaS}HvXJrF=;Mt=*QIsMY%$^@(Tzqp*LOgS2itk&d`j++k*yf2wQzoTSUUs);+oyM! z`LaxbY9V4w>r+?Ss4UpZkvdS_R}HpHszn)TZH_^2UwxV1ZS~A#>POCh$r-3nUe-Ob z!(xC{&&fO$#MP^`?0O|KNT_ZuC9n1L*Sji9$`M~wq;$WKrIECN?w0i7Ky9N;m~4o~ zPxNHcm7UQt38~!$$E!)TTpcDoRnT$quMcw+he&_L3#pr`f1ZlrslHXs{(c~OfV ze^lM-II6)wp9ZsG!zkTXk<*D%3#LaziXQE_PP3OW!Zdr#v(gASLs5F|7_^0OBsQ%Cd}l{0ZsXDrXW=^)i3l3!pMA4?w51BiP=J=!aIrbG1}9Xv$krXXbnpBvHz!V1b!CtlK+Ol~#jfb`7BSqE!E z&5!h4HQLD1Q>`%^E8KzU*qRYGc78g{-q90BXP9$-rla}3yg*4Ua-_4GvzuyAaSMYA zO4;UH|FQbRbS6vWaPug&uGXSf)K;EUusKcc2YTqSGGVQ#F{C2riehcS^iO|cOT?|N9o#?5VO=DyPE|db96K(O*ms@NA7=;qe z41_nUqa1kgR1v(H*Bg>ZMXc>7yEOtH=ZuF zClY#IQ_ZG7askFJ7bW8A9Iq`fn@4OwM0v`xvrdZ2nF-ln>Ai&N8hDvH4#kh})T{xvl=x|(o`YM_= zXJ6DjVaui#xEzaOElduWE+9Ede~V;km9f}x&tjOls!&lYKGiIpZA7$bn_d;$<5~ZE zD~kiayHZ_}uXZV~RogIUob()+Hs4{yixg1xEOix4ox+H~VXxE;xrU{Z&A~LhaH*@x z95xeqeVmN}yOchmF0nHEbYETQkg-;-<%Oa;C)HbIC9C+URf!tsWr$)okh4&;ZjDuFtrO#wTiXbqur;skJxE^tAoldRODJu#8hM+ zkSyi2GMl|WA-X7qHXEdx996*7Ng4Mts$2qEnpaBH{tJ6dS%Clm diff --git a/thinkphp/tests/extensions/7.0/redis.so b/thinkphp/tests/extensions/7.0/redis.so deleted file mode 100644 index e3aea8fcb15ca3b61d31dcedc298f7ae33ff39ee..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1541380 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

L#heBF9KImYV-??loSF1sjBNOsn#Ub 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∓e(x=!Bd{ljS09 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%0Du^0q=okxfPkxq<$4K+#KKv}7 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

)mv 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�abM0n`xn0WFhHg%}c>O>;~gH+O4g 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

q4_+O$Rr-0X@pB+e_5T(|#~5QD)n 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 o()Po>PmG7S@)%ll -// +---------------------------------------------------------------------- - -// 测试入口文件 -$_SERVER['REQUEST_METHOD'] = 'GET'; -// 定义项目测试基础路径 -define('TEST_PATH', __DIR__ . '/'); -// 定义项目路径 -define('APP_PATH', __DIR__ . '/application/'); -// 加载框架基础文件 -require __DIR__ . '/../base.php'; -\think\Loader::addNamespace('tests', TEST_PATH); diff --git a/thinkphp/tests/script/install.sh b/thinkphp/tests/script/install.sh deleted file mode 100644 index 0adee7ed..00000000 --- a/thinkphp/tests/script/install.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -if [ $(phpenv version-name) != "hhvm" ]; then - cp tests/extensions/$(phpenv version-name)/*.so $(php-config --extension-dir) - - if [ $(phpenv version-name) = "7.0" ]; then - phpenv config-add tests/conf/apcu_bc.ini - else - phpenv config-add tests/conf/apcu.ini - fi - - phpenv config-add tests/conf/memcached.ini - phpenv config-add tests/conf/redis.ini - - phpenv config-add tests/conf/timezone.ini -fi - -composer install --no-interaction --ignore-platform-reqs diff --git a/thinkphp/tests/thinkphp/baseTest.php b/thinkphp/tests/thinkphp/baseTest.php deleted file mode 100644 index 18f1d3dd..00000000 --- a/thinkphp/tests/thinkphp/baseTest.php +++ /dev/null @@ -1,39 +0,0 @@ - -// +---------------------------------------------------------------------- - -/** - * 保证运行环境正常 - */ -class baseTest extends \PHPUnit_Framework_TestCase -{ - public function testConstants() - { - $this->assertNotEmpty(THINK_START_TIME); - $this->assertNotEmpty(THINK_START_MEM); - $this->assertNotEmpty(THINK_VERSION); - $this->assertNotEmpty(DS); - $this->assertNotEmpty(THINK_PATH); - $this->assertNotEmpty(LIB_PATH); - $this->assertNotEmpty(EXTEND_PATH); - $this->assertNotEmpty(CORE_PATH); - $this->assertNotEmpty(TRAIT_PATH); - $this->assertNotEmpty(APP_PATH); - $this->assertNotEmpty(RUNTIME_PATH); - $this->assertNotEmpty(LOG_PATH); - $this->assertNotEmpty(CACHE_PATH); - $this->assertNotEmpty(TEMP_PATH); - $this->assertNotEmpty(VENDOR_PATH); - $this->assertNotEmpty(EXT); - $this->assertNotEmpty(ENV_PREFIX); - $this->assertTrue(!is_null(IS_WIN)); - $this->assertTrue(!is_null(IS_CLI)); - } -} diff --git a/thinkphp/tests/thinkphp/library/think/appTest.php b/thinkphp/tests/thinkphp/library/think/appTest.php deleted file mode 100644 index 016bbf9c..00000000 --- a/thinkphp/tests/thinkphp/library/think/appTest.php +++ /dev/null @@ -1,90 +0,0 @@ - -// +---------------------------------------------------------------------- - -/** - * app类测试 - * @author Haotong Lin - */ - -namespace tests\thinkphp\library\think; - -use think\App; -use think\Config; -use think\Request; - -function func_trim($value) -{ - return trim($value); -} - -function func_strpos($haystack, $needle) -{ - return strpos($haystack, $needle); -} - -class AppInvokeMethodTestClass -{ - public static function staticRun($string) - { - return $string; - } - - public function run($string) - { - return $string; - } -} - -class appTest extends \PHPUnit_Framework_TestCase -{ - public function testRun() - { - $response = App::run(Request::create("http://www.example.com")); - - $expectOutputString = '

'; - - $this->assertEquals($expectOutputString, $response->getContent()); - $this->assertEquals(200, $response->getCode()); - - $this->assertEquals(true, function_exists('lang')); - $this->assertEquals(true, function_exists('config')); - $this->assertEquals(true, function_exists('input')); - - $this->assertEquals(Config::get('default_timezone'), date_default_timezone_get()); - - } - - // function调度 - public function testInvokeFunction() - { - $args1 = ['a b c ']; - $this->assertEquals( - trim($args1[0]), - App::invokeFunction('tests\thinkphp\library\think\func_trim', $args1) - ); - - $args2 = ['abcdefg', 'g']; - $this->assertEquals( - strpos($args2[0], $args2[1]), - App::invokeFunction('tests\thinkphp\library\think\func_strpos', $args2) - ); - } - - // 类method调度 - public function testInvokeMethod() - { - $result = App::invokeMethod(['tests\thinkphp\library\think\AppInvokeMethodTestClass', 'run'], ['thinkphp']); - $this->assertEquals('thinkphp', $result); - - $result = App::invokeMethod('tests\thinkphp\library\think\AppInvokeMethodTestClass::staticRun', ['thinkphp']); - $this->assertEquals('thinkphp', $result); - } -} diff --git a/thinkphp/tests/thinkphp/library/think/behavior/One.php b/thinkphp/tests/thinkphp/library/think/behavior/One.php deleted file mode 100644 index 1ec6e66e..00000000 --- a/thinkphp/tests/thinkphp/library/think/behavior/One.php +++ /dev/null @@ -1,15 +0,0 @@ - -// +---------------------------------------------------------------------- - -/** - * build测试 - * @author 刘志淳 - */ - -namespace tests\thinkphp\library\think; - -use think\Build; - -class buildTest extends \PHPUnit_Framework_TestCase -{ - public function testRun() - { - $build = [ - // Test run directory - '__dir__' => ['runtime/cache', 'runtime/log', 'runtime/temp', 'runtime/template'], - '__file__' => ['common.php'], - - // Test generation module - 'demo' => [ - '__file__' => ['common.php'], - '__dir__' => ['behavior', 'controller', 'model', 'view', 'service'], - 'controller' => ['Index', 'Test', 'UserType'], - 'model' => ['User', 'UserType'], - 'service' => ['User', 'UserType'], - 'view' => ['index/index'], - ], - ]; - Build::run($build); - - $this->buildFileExists($build); - } - - protected function buildFileExists($build) - { - foreach ($build as $module => $list) { - if ('__dir__' == $module || '__file__' == $module) { - foreach ($list as $file) { - $this->assertFileExists(APP_PATH . $file); - } - } else { - foreach ($list as $path => $moduleList) { - if ('__file__' == $path || '__dir__' == $path) { - foreach ($moduleList as $file) { - $this->assertFileExists(APP_PATH . $module . '/' . $file); - } - } else { - foreach ($moduleList as $file) { - if ('view' == $path) { - $file_name = APP_PATH . $module . '/' . $path . '/' . $file . '.html'; - } else { - $file_name = APP_PATH . $module . '/' . $path . '/' . $file . EXT; - } - $this->assertFileExists($file_name); - } - } - } - $this->assertFileExists(APP_PATH . ($module ? $module . DS : '') . 'config.php'); - } - } - } -} diff --git a/thinkphp/tests/thinkphp/library/think/cache/driver/cacheTestCase.php b/thinkphp/tests/thinkphp/library/think/cache/driver/cacheTestCase.php deleted file mode 100644 index 5b2f2a3e..00000000 --- a/thinkphp/tests/thinkphp/library/think/cache/driver/cacheTestCase.php +++ /dev/null @@ -1,207 +0,0 @@ - -// +---------------------------------------------------------------------- - -/** - * 缓存抽象类,提供一些测试 - * @author simon - */ - -namespace tests\thinkphp\library\think\cache\driver; - -use think\Cache; - -abstract class cacheTestCase extends \PHPUnit_Framework_TestCase -{ - - /** - * 获取缓存句柄,子类必须有 - * @access protected - */ - abstract protected function getCacheInstance(); - - /** - * tearDown函数 - */ - protected function tearDown() - { - } - - /** - * 设定一组测试值,包括测试字符串、整数、数组和对象 - * @return mixed - * @access public - */ - public function prepare() - { - $cache = $this->getCacheInstance(); - $cache->clear(); - $cache->set('string_test', 'string_test'); - $cache->set('number_test', 11); - $cache->set('array_test', ['array_test' => 'array_test']); - return $cache; - } - - /** - * 测试缓存设置,包括测试字符串、整数、数组和对象 - * @return mixed - * @access public - */ - public function testSet() - { - $cache = $this->getCacheInstance(); - $this->assertTrue($cache->set('string_test', 'string_test')); - $this->assertTrue($cache->set('number_test', 11)); - $this->assertTrue($cache->set('array_test', ['array_test' => 'array_test'])); - } - - /** - * 测试缓存自增 - * @return mixed - * @access public - */ - public function testInc() - { - $cache = $this->getCacheInstance(); - $this->assertEquals(14, $cache->inc('number_test', 3)); - } - - /** - * 测试缓存自减 - * @return mixed - * @access public - */ - public function testDec() - { - $cache = $this->getCacheInstance(); - $this->assertEquals(8, $cache->dec('number_test', 6)); - } - - /** - * 测试缓存读取,包括测试字符串、整数、数组和对象 - * @return mixed - * @access public - */ - public function testGet() - { - $cache = $this->prepare(); - $this->assertEquals('string_test', $cache->get('string_test')); - $this->assertEquals(11, $cache->get('number_test')); - $array = $cache->get('array_test'); - $this->assertArrayHasKey('array_test', $array); - $this->assertEquals('array_test', $array['array_test']); - - $result = $cache->set('no_expire', 1, 0); - $this->assertTrue($result); - } - - /** - * 测试缓存存在情况,包括测试字符串、整数、数组和对象 - * @return mixed - * @access public - */ - public function testExists() - { - $cache = $this->prepare(); - $this->assertNotEmpty($cache->has('string_test')); - $this->assertNotEmpty($cache->has('number_test')); - $this->assertFalse($cache->has('not_exists')); - } - - /** - * 测试缓存不存在情况,包括测试字符串、整数、数组和对象 - * @return mixed - * @access public - */ - public function testGetNonExistent() - { - $cache = $this->getCacheInstance(); - $this->assertFalse($cache->get('non_existent_key', false)); - } - - /** - * 测试特殊值缓存,包括测试字符串、整数、数组和对象 - * @return mixed - * @access public - */ - public function testStoreSpecialValues() - { - $cache = $this->getCacheInstance(); - $cache->set('null_value', null); - //清空缓存后,返回null而不是false - $this->assertTrue(is_null($cache->get('null_value'))); - } - - /** - * 缓存过期测试 - * @return mixed - * @access public - */ - public function testExpire() - { - $cache = $this->getCacheInstance(); - $this->assertTrue($cache->set('expire_test', 'expire_test', 1)); - usleep(600000); - $this->assertEquals('expire_test', $cache->get('expire_test')); - usleep(800000); - $this->assertFalse($cache->get('expire_test')); - } - - /** - * 删除缓存测试 - * @return mixed - * @access public - */ - public function testDelete() - { - $cache = $this->prepare(); - $this->assertNotNull($cache->rm('number_test')); - $this->assertFalse($cache->get('number_test')); - } - - /** - * 获取并删除缓存测试 - * @return mixed - * @access public - */ - public function testPull() - { - $cache = $this->prepare(); - $this->assertEquals(11, $cache->pull('number_test')); - $this->assertFalse($cache->get('number_test')); - } - - /** - * 清空缓存测试 - * @return mixed - * @access public - */ - public function testClear() - { - $cache = $this->prepare(); - $this->assertTrue($cache->clear()); - $this->assertFalse($cache->get('number_test')); - } - - public function testStaticCall() - { - $this->assertTrue(Cache::set('a', 1)); - $this->assertEquals(1, Cache::get('a')); - $this->assertEquals(2, Cache::inc('a')); - $this->assertEquals(4, Cache::inc('a', 2)); - $this->assertEquals(4, Cache::get('a')); - $this->assertEquals(3, Cache::dec('a')); - $this->assertEquals(1, Cache::dec('a', 2)); - $this->assertEquals(1, Cache::get('a')); - $this->assertNotNull(Cache::rm('a')); - $this->assertNotNull(Cache::clear()); - } - -} diff --git a/thinkphp/tests/thinkphp/library/think/cache/driver/fileTest.php b/thinkphp/tests/thinkphp/library/think/cache/driver/fileTest.php deleted file mode 100644 index eb2099ce..00000000 --- a/thinkphp/tests/thinkphp/library/think/cache/driver/fileTest.php +++ /dev/null @@ -1,46 +0,0 @@ - -// +---------------------------------------------------------------------- - -/** - * File缓存驱动测试 - * @author 刘志淳 - */ - -namespace tests\thinkphp\library\think\cache\driver; - -class fileTest extends cacheTestCase -{ - private $_cacheInstance = null; - - /** - * 基境缓存类型 - */ - protected function setUp() - { - \think\Cache::connect(['type' => 'File', 'path' => CACHE_PATH]); - } - - /** - * @return FileCache - */ - protected function getCacheInstance() - { - if (null === $this->_cacheInstance) { - $this->_cacheInstance = new \think\cache\driver\File(); - } - return $this->_cacheInstance; - } - - // skip testExpire - public function testExpire() - { - } -} diff --git a/thinkphp/tests/thinkphp/library/think/cache/driver/liteTest.php b/thinkphp/tests/thinkphp/library/think/cache/driver/liteTest.php deleted file mode 100644 index 19cbb9ef..00000000 --- a/thinkphp/tests/thinkphp/library/think/cache/driver/liteTest.php +++ /dev/null @@ -1,69 +0,0 @@ - -// +---------------------------------------------------------------------- - -/** - * Lite缓存驱动测试 - * @author 刘志淳 - */ - -namespace tests\thinkphp\library\think\cache\driver; - -use think\Cache; - -class liteTest extends \PHPUnit_Framework_TestCase -{ - protected function getCacheInstance() - { - return Cache::connect(['type' => 'Lite', 'path' => CACHE_PATH]); - } - - /** - * 测试缓存读取 - * @return mixed - * @access public - */ - public function testGet() - { - $cache = $this->getCacheInstance(); - $this->assertFalse($cache->get('test')); - } - - /** - * 测试缓存设置 - * @return mixed - * @access public - */ - public function testSet() - { - $cache = $this->getCacheInstance(); - $this->assertNotEmpty($cache->set('test', 'test')); - } - - /** - * 删除缓存测试 - * @return mixed - * @access public - */ - public function testRm() - { - $cache = $this->getCacheInstance(); - $this->assertTrue($cache->rm('test')); - } - - /** - * 清空缓存测试 - * @return mixed - * @access public - */ - public function testClear() - { - } -} diff --git a/thinkphp/tests/thinkphp/library/think/cache/driver/memcacheTest.php b/thinkphp/tests/thinkphp/library/think/cache/driver/memcacheTest.php deleted file mode 100644 index 8975fa20..00000000 --- a/thinkphp/tests/thinkphp/library/think/cache/driver/memcacheTest.php +++ /dev/null @@ -1,49 +0,0 @@ - -// +---------------------------------------------------------------------- - -/** - * Memcache缓存驱动测试 - * @author 刘志淳 - */ - -namespace tests\thinkphp\library\think\cache\driver; - -class memcacheTest extends cacheTestCase -{ - private $_cacheInstance = null; - - /** - * 基境缓存类型 - */ - protected function setUp() - { - if (!extension_loaded('memcache')) { - $this->markTestSkipped("Memcache没有安装,已跳过测试!"); - } - \think\Cache::connect(['type' => 'memcache', 'expire' => 2]); - } - - /** - * @return ApcCache - */ - protected function getCacheInstance() - { - if (null === $this->_cacheInstance) { - $this->_cacheInstance = new \think\cache\driver\Memcache(['length' => 3]); - } - return $this->_cacheInstance; - } - - // skip testExpire - public function testExpire() - { - } -} diff --git a/thinkphp/tests/thinkphp/library/think/cache/driver/memcachedTest.php b/thinkphp/tests/thinkphp/library/think/cache/driver/memcachedTest.php deleted file mode 100644 index d528dd22..00000000 --- a/thinkphp/tests/thinkphp/library/think/cache/driver/memcachedTest.php +++ /dev/null @@ -1,72 +0,0 @@ - -// +---------------------------------------------------------------------- - -/** - * Memcached缓存驱动测试 - * @author 7IN0SAN9 - */ - -namespace tests\thinkphp\library\think\cache\driver; - -class memcachedTest extends cacheTestCase -{ - private $_cacheInstance = null; - /** - * 基境缓存类型 - */ - protected function setUp() - { - if (!extension_loaded("memcached") && !extension_loaded('memcache')) { - $this->markTestSkipped("Memcached或Memcache没有安装,已跳过测试!"); - } - \think\Cache::connect(array('type' => 'memcached', 'expire' => 2)); - } - /** - * @return ApcCache - */ - protected function getCacheInstance() - { - if (null === $this->_cacheInstance) { - $this->_cacheInstance = new \think\cache\driver\Memcached(['length' => 3]); - } - return $this->_cacheInstance; - } - /** - * 缓存过期测试《提出来测试,因为目前看通不过缓存过期测试,所以还需研究》 - * @return mixed - * @access public - */ - public function testExpire() - { - } - - public function testStaticCall() - { - } - - /** - * 测试缓存自增 - * @return mixed - * @access public - */ - public function testInc() - { - } - - /** - * 测试缓存自减 - * @return mixed - * @access public - */ - public function testDec() - { - } -} diff --git a/thinkphp/tests/thinkphp/library/think/cache/driver/redisTest.php b/thinkphp/tests/thinkphp/library/think/cache/driver/redisTest.php deleted file mode 100644 index 839e5165..00000000 --- a/thinkphp/tests/thinkphp/library/think/cache/driver/redisTest.php +++ /dev/null @@ -1,66 +0,0 @@ - -// +---------------------------------------------------------------------- - -/** - * Redis缓存驱动测试 - * @author 7IN0SAN9 - */ - -namespace tests\thinkphp\library\think\cache\driver; - -class redisTest extends cacheTestCase -{ - private $_cacheInstance = null; - - protected function setUp() - { - if (!extension_loaded("redis")) { - $this->markTestSkipped("Redis没有安装,已跳过测试!"); - } - \think\Cache::connect(array('type' => 'redis', 'expire' => 2)); - } - - protected function getCacheInstance() - { - if (null === $this->_cacheInstance) { - $this->_cacheInstance = new \think\cache\driver\Redis(['length' => 3]); - } - return $this->_cacheInstance; - } - - public function testGet() - { - $cache = $this->prepare(); - $this->assertEquals('string_test', $cache->get('string_test')); - $this->assertEquals(11, $cache->get('number_test')); - $result = $cache->get('array_test'); - $this->assertEquals('array_test', $result['array_test']); - } - - public function testStoreSpecialValues() - { - $redis = new \think\cache\driver\Redis(['length' => 3]); - $redis->set('key', 'value'); - $redis->get('key'); - - $redis->handler()->setnx('key', 'value'); - $value = $redis->handler()->get('key'); - $this->assertEquals('value', $value); - - $redis->handler()->hset('hash', 'key', 'value'); - $value = $redis->handler()->hget('hash', 'key'); - $this->assertEquals('value', $value); - } - - public function testExpire() - { - } -} diff --git a/thinkphp/tests/thinkphp/library/think/config/driver/fixtures/config.ini b/thinkphp/tests/thinkphp/library/think/config/driver/fixtures/config.ini deleted file mode 100644 index 2a17cc0d..00000000 --- a/thinkphp/tests/thinkphp/library/think/config/driver/fixtures/config.ini +++ /dev/null @@ -1 +0,0 @@ -inifile=1 \ No newline at end of file diff --git a/thinkphp/tests/thinkphp/library/think/config/driver/fixtures/config.json b/thinkphp/tests/thinkphp/library/think/config/driver/fixtures/config.json deleted file mode 100644 index 716ed064..00000000 --- a/thinkphp/tests/thinkphp/library/think/config/driver/fixtures/config.json +++ /dev/null @@ -1 +0,0 @@ -{"jsonstring":1} \ No newline at end of file diff --git a/thinkphp/tests/thinkphp/library/think/config/driver/fixtures/config.xml b/thinkphp/tests/thinkphp/library/think/config/driver/fixtures/config.xml deleted file mode 100644 index 3c3266a1..00000000 --- a/thinkphp/tests/thinkphp/library/think/config/driver/fixtures/config.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - 1 - - \ No newline at end of file diff --git a/thinkphp/tests/thinkphp/library/think/config/driver/iniTest.php b/thinkphp/tests/thinkphp/library/think/config/driver/iniTest.php deleted file mode 100644 index 2575157c..00000000 --- a/thinkphp/tests/thinkphp/library/think/config/driver/iniTest.php +++ /dev/null @@ -1,33 +0,0 @@ - -// +---------------------------------------------------------------------- - -/** - * Ini配置测试 - * @author 7IN0SAN9 - */ - -namespace tests\thinkphp\library\think\config\driver; - -use think\config; - -class iniTest extends \PHPUnit_Framework_TestCase -{ - public function testParse() - { - Config::parse('inistring=1', 'ini'); - $this->assertEquals(1, Config::get('inistring')); - Config::reset(); - Config::parse(__DIR__ . '/fixtures/config.ini'); - $this->assertTrue(Config::has('inifile')); - $this->assertEquals(1, Config::get('inifile')); - Config::reset(); - } -} diff --git a/thinkphp/tests/thinkphp/library/think/config/driver/jsonTest.php b/thinkphp/tests/thinkphp/library/think/config/driver/jsonTest.php deleted file mode 100644 index 9d438d40..00000000 --- a/thinkphp/tests/thinkphp/library/think/config/driver/jsonTest.php +++ /dev/null @@ -1,33 +0,0 @@ - -// +---------------------------------------------------------------------- - -/** - * Xml配置测试 - * @author 7IN0SAN9 - */ - -namespace tests\thinkphp\library\think\config\driver; - -use think\config; - -class jsonTest extends \PHPUnit_Framework_TestCase -{ - public function testParse() - { - Config::parse('{"jsonstring":1}', 'json'); - $this->assertEquals(1, Config::get('jsonstring')); - Config::reset(); - Config::parse(__DIR__ . '/fixtures/config.json'); - $this->assertTrue(Config::has('jsonstring')); - $this->assertEquals(1, Config::get('jsonstring')); - Config::reset(); - } -} diff --git a/thinkphp/tests/thinkphp/library/think/config/driver/xmlTest.php b/thinkphp/tests/thinkphp/library/think/config/driver/xmlTest.php deleted file mode 100644 index 9ab1d257..00000000 --- a/thinkphp/tests/thinkphp/library/think/config/driver/xmlTest.php +++ /dev/null @@ -1,33 +0,0 @@ - -// +---------------------------------------------------------------------- - -/** - * Xml配置测试 - * @author 7IN0SAN9 - */ - -namespace tests\thinkphp\library\think\config\driver; - -use think\config; - -class xmlTest extends \PHPUnit_Framework_TestCase -{ - public function testParse() - { - Config::parse('1', 'xml'); - $this->assertEquals(1, Config::get('xmlstring')); - Config::reset(); - Config::parse(__DIR__ . '/fixtures/config.xml'); - $this->assertTrue(Config::has('xmlfile.istrue')); - $this->assertEquals(1, Config::get('xmlfile.istrue')); - Config::reset(); - } -} diff --git a/thinkphp/tests/thinkphp/library/think/configTest.php b/thinkphp/tests/thinkphp/library/think/configTest.php deleted file mode 100644 index 166f0f8a..00000000 --- a/thinkphp/tests/thinkphp/library/think/configTest.php +++ /dev/null @@ -1,169 +0,0 @@ - -// +---------------------------------------------------------------------- - -/** - * 配置测试 - * @author Haotong Lin - */ - -namespace tests\thinkphp\library\think; - -use ReflectionClass; -use think\Config; - -class configTest extends \PHPUnit_Framework_TestCase -{ - public function testRange() - { - $reflectedClass = new ReflectionClass('\think\Config'); - $reflectedPropertyRange = $reflectedClass->getProperty('range'); - $reflectedPropertyRange->setAccessible(true); - $reflectedPropertyConfig = $reflectedClass->getProperty('config'); - $reflectedPropertyConfig->setAccessible(true); - // test default range - $this->assertEquals('_sys_', $reflectedPropertyRange->getValue()); - $config = $reflectedPropertyConfig->getValue(); - $this->assertTrue(is_array($config)); - // test range initialization - Config::range('_test_'); - $this->assertEquals('_test_', $reflectedPropertyRange->getValue()); - $config = $reflectedPropertyConfig->getValue(); - $this->assertEquals([], $config['_test_']); - } - - // public function testParse() - // { - // see \think\config\driver\...Test.php - // } - - public function testLoad() - { - $file = APP_PATH . 'config' . EXT; - $config = array_change_key_case(include $file); - $name = '_name_'; - $range = '_test_'; - - $reflectedClass = new ReflectionClass('\think\Config'); - $reflectedPropertyConfig = $reflectedClass->getProperty('config'); - $reflectedPropertyConfig->setAccessible(true); - $reflectedPropertyConfig->setValue([]); - - $this->assertEquals($config, Config::load($file, $name, $range)); - $this->assertNotEquals(null, Config::load($file, $name, $range)); - } - - public function testHas() - { - $range = '_test_'; - $this->assertFalse(Config::has('abcd', $range)); - $reflectedClass = new ReflectionClass('\think\Config'); - $reflectedPropertyConfig = $reflectedClass->getProperty('config'); - $reflectedPropertyConfig->setAccessible(true); - - // if (!strpos($name, '.')): - $reflectedPropertyConfig->setValue([ - $range => ['abcd' => 'value'], - ]); - $this->assertTrue(Config::has('abcd', $range)); - - // else ... - $this->assertFalse(Config::has('abcd.efg', $range)); - - $reflectedPropertyConfig->setValue([ - $range => ['abcd' => ['efg' => 'value']], - ]); - $this->assertTrue(Config::has('abcd.efg', $range)); - } - - public function testGet() - { - $range = '_test_'; - $reflectedClass = new ReflectionClass('\think\Config'); - $reflectedPropertyConfig = $reflectedClass->getProperty('config'); - $reflectedPropertyConfig->setAccessible(true); - // test all configurations - $reflectedPropertyConfig->setValue([$range => []]); - $this->assertEquals([], Config::get(null, $range)); - $this->assertEquals(null, Config::get(null, 'does_not_exist')); - $value = 'value'; - // test getting configuration - $reflectedPropertyConfig->setValue([$range => ['abcd' => 'efg']]); - $this->assertEquals('efg', Config::get('abcd', $range)); - $this->assertEquals(null, Config::get('does_not_exist', $range)); - $this->assertEquals(null, Config::get('abcd', 'does_not_exist')); - // test getting configuration with dot syntax - $reflectedPropertyConfig->setValue([$range => [ - 'one' => ['two' => $value], - ]]); - $this->assertEquals($value, Config::get('one.two', $range)); - $this->assertEquals(null, Config::get('one.does_not_exist', $range)); - $this->assertEquals(null, Config::get('one.two', 'does_not_exist')); - } - - public function testSet() - { - $range = '_test_'; - $reflectedClass = new ReflectionClass('\think\Config'); - $reflectedPropertyConfig = $reflectedClass->getProperty('config'); - $reflectedPropertyConfig->setAccessible(true); - $reflectedPropertyConfig->setValue([]); - // if (is_string($name)): - // without dot syntax - $name = 'name'; - $value = 'value'; - Config::set($name, $value, $range); - $config = $reflectedPropertyConfig->getValue(); - $this->assertEquals($value, $config[$range][$name]); - // with dot syntax - $name = 'one.two'; - $value = 'dot value'; - Config::set($name, $value, $range); - $config = $reflectedPropertyConfig->getValue(); - $this->assertEquals($value, $config[$range]['one']['two']); - // if (is_array($name)): - // see testLoad() - // ... - // test getting all configurations...? - // return self::$config[$range]; ?? - $value = ['all' => 'configuration']; - $reflectedPropertyConfig->setValue([$range => $value]); - $this->assertEquals($value, Config::set(null, null, $range)); - $this->assertNotEquals(null, Config::set(null, null, $range)); - } - - public function testReset() - { - $range = '_test_'; - $reflectedClass = new ReflectionClass('\think\Config'); - $reflectedPropertyConfig = $reflectedClass->getProperty('config'); - $reflectedPropertyConfig->setAccessible(true); - $reflectedPropertyConfig->setValue([$range => ['abcd' => 'efg']]); - - // clear all configurations - Config::reset(true); - $config = $reflectedPropertyConfig->getValue(); - $this->assertEquals([], $config); - // clear the configuration in range of parameter. - $reflectedPropertyConfig->setValue([ - $range => [ - 'abcd' => 'efg', - 'hijk' => 'lmn', - ], - 'a' => 'b', - ]); - Config::reset($range); - $config = $reflectedPropertyConfig->getValue(); - $this->assertEquals([ - $range => [], - 'a' => 'b', - ], $config); - } -} diff --git a/thinkphp/tests/thinkphp/library/think/controller/.gitignore b/thinkphp/tests/thinkphp/library/think/controller/.gitignore deleted file mode 100644 index c96a04f0..00000000 --- a/thinkphp/tests/thinkphp/library/think/controller/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore \ No newline at end of file diff --git a/thinkphp/tests/thinkphp/library/think/controllerTest.php b/thinkphp/tests/thinkphp/library/think/controllerTest.php deleted file mode 100644 index fba8d6c5..00000000 --- a/thinkphp/tests/thinkphp/library/think/controllerTest.php +++ /dev/null @@ -1,194 +0,0 @@ - -// +---------------------------------------------------------------------- - -/** - * 控制器测试 - * @author Haotong Lin - */ - -namespace tests\thinkphp\library\think; - -use ReflectionClass; -use think\Controller; -use think\Request; -use think\View; - -require_once CORE_PATH . '../../helper.php'; - -class Foo extends Controller -{ - public $test = 'test'; - - public function _initialize() - { - $this->test = 'abcd'; - } - - public function assignTest() - { - $this->assign('abcd', 'dcba'); - $this->assign(['key1' => 'value1', 'key2' => 'value2']); - } - - public function fetchTest() - { - $template = dirname(__FILE__) . '/display.html'; - return $this->fetch($template, ['name' => 'ThinkPHP']); - } - - public function displayTest() - { - $template = dirname(__FILE__) . '/display.html'; - return $this->display($template, ['name' => 'ThinkPHP']); - } - public function test() - { - $data = [ - 'username' => 'username', - 'nickname' => 'nickname', - 'password' => '123456', - 'repassword' => '123456', - 'email' => 'abc@abc.com', - 'sex' => '0', - 'age' => '20', - 'code' => '1234', - ]; - - $validate = [ - ['username', 'length:5,15', '用户名长度为5到15个字符'], - ['nickname', 'require', '请填昵称'], - ['password', '[\w-]{6,15}', '密码长度为6到15个字符'], - ['repassword', 'confirm:password', '两次密码不一到致'], - ['email', 'filter:validate_email', '邮箱格式错误'], - ['sex', 'in:0,1', '性别只能为为男或女'], - ['age', 'between:1,80', '年龄只能在10-80之间'], - ]; - return $this->validate($data, $validate); - } -} - -class Bar extends Controller -{ - public $test = 1; - - public $beforeActionList = ['action1', 'action2']; - - public function action1() - { - $this->test += 2; - return 'action1'; - } - - public function action2() - { - $this->test += 4; - return 'action2'; - } -} - -class Baz extends Controller -{ - public $test = 1; - - public $beforeActionList = [ - 'action1' => ['only' => 'index'], - 'action2' => ['except' => 'index'], - 'action3' => ['only' => 'abcd'], - 'action4' => ['except' => 'abcd'], - ]; - - public function action1() - { - $this->test += 2; - return 'action1'; - } - - public function action2() - { - $this->test += 4; - return 'action2'; - } - - public function action3() - { - $this->test += 8; - return 'action2'; - } - - public function action4() - { - $this->test += 16; - return 'action2'; - } -} - -class controllerTest extends \PHPUnit_Framework_TestCase -{ - public function testInitialize() - { - $foo = new Foo(Request::instance()); - $this->assertEquals('abcd', $foo->test); - } - - public function testBeforeAction() - { - $obj = new Bar(Request::instance()); - $this->assertEquals(7, $obj->test); - - $obj = new Baz(Request::instance()); - $this->assertEquals(19, $obj->test); - } - - private function getView($controller) - { - $view = new View(); - $rc = new ReflectionClass(get_class($controller)); - $property = $rc->getProperty('view'); - $property->setAccessible(true); - $property->setValue($controller, $view); - return $view; - } - - public function testFetch() - { - $controller = new Foo(Request::instance()); - $view = $this->getView($controller); - $template = dirname(__FILE__) . '/display.html'; - $viewFetch = $view->fetch($template, ['name' => 'ThinkPHP']); - $this->assertEquals($controller->fetchTest(), $viewFetch); - } - - public function testDisplay() - { - $controller = new Foo; - $view = $this->getView($controller); - $template = dirname(__FILE__) . '/display.html'; - $viewFetch = $view->display($template, ['name' => 'ThinkPHP']); - - $this->assertEquals($controller->displayTest(), $viewFetch); - } - - public function testAssign() - { - $controller = new Foo(Request::instance()); - $view = $this->getView($controller); - $controller->assignTest(); - $expect = ['abcd' => 'dcba', 'key1' => 'value1', 'key2' => 'value2']; - $this->assertAttributeEquals($expect, 'data', $view); - } - - public function testValidate() - { - $controller = new Foo(Request::instance()); - $result = $controller->test(); - $this->assertTrue($result); - } -} diff --git a/thinkphp/tests/thinkphp/library/think/cookieTest.php b/thinkphp/tests/thinkphp/library/think/cookieTest.php deleted file mode 100644 index 24cb153e..00000000 --- a/thinkphp/tests/thinkphp/library/think/cookieTest.php +++ /dev/null @@ -1,150 +0,0 @@ - -// +---------------------------------------------------------------------- - -/** - * Cookie测试 - * @author Haotong Lin - */ - -namespace tests\thinkphp\library\think; - -use ReflectionClass; -use think\Cookie; - -class cookieTest extends \PHPUnit_Framework_TestCase -{ - protected $ref; - - protected $default = [ - // cookie 名称前缀 - 'prefix' => '', - // cookie 保存时间 - 'expire' => 0, - // cookie 保存路径 - 'path' => '/', - // cookie 有效域名 - 'domain' => '', - // cookie 启用安全传输 - 'secure' => false, - // httponly设置 - 'httponly' => '', - // 是否使用 setcookie - 'setcookie' => false, - ]; - - protected function setUp() - { - $reflectedClass = new ReflectionClass('\think\Cookie'); - $reflectedPropertyConfig = $reflectedClass->getProperty('config'); - $reflectedPropertyConfig->setAccessible(true); - $reflectedPropertyConfig->setValue($this->default); - $this->ref = $reflectedPropertyConfig; - } - - public function testInit() - { - $config = [ - // cookie 名称前缀 - 'prefix' => 'think_', - // cookie 保存时间 - 'expire' => 0, - // cookie 保存路径 - 'path' => '/path/to/test/', - // cookie 有效域名 - 'domain' => '.thinkphp.cn', - // cookie 启用安全传输 - 'secure' => true, - // httponly设置 - 'httponly' => '1', - ]; - Cookie::init($config); - - $this->assertEquals( - array_merge($this->default, array_change_key_case($config)), - $this->ref->getValue() - ); - } - - public function testPrefix() - { - $this->assertEquals($this->default['prefix'], Cookie::prefix()); - - $prefix = '_test_'; - $this->assertNotEquals($prefix, Cookie::prefix()); - Cookie::prefix($prefix); - - $config = $this->ref->getValue(); - $this->assertEquals($prefix, $config['prefix']); - } - - public function testSet() - { - $value = 'value'; - - $name = 'name1'; - Cookie::set($name, $value, 10); - $this->assertEquals($value, $_COOKIE[$this->default['prefix'] . $name]); - - $name = 'name2'; - Cookie::set($name, $value, null); - $this->assertEquals($value, $_COOKIE[$this->default['prefix'] . $name]); - - $name = 'name3'; - Cookie::set($name, $value, 'expire=100&prefix=pre_'); - $this->assertEquals($value, $_COOKIE['pre_' . $name]); - - $name = 'name4'; - $value = ['_test_中文_']; - Cookie::set($name, $value); - $this->assertEquals('think:' . json_encode([urlencode('_test_中文_')]), $_COOKIE[$name]); - } - - public function testGet() - { - $_COOKIE = [ - 'a' => 'b', - 'pre_abc' => 'c', - 'd' => 'think:' . json_encode([urlencode('_test_中文_')]), - ]; - $this->assertEquals('b', Cookie::get('a')); - $this->assertEquals(null, Cookie::get('does_not_exist')); - $this->assertEquals('c', Cookie::get('abc', 'pre_')); - $this->assertEquals(['_test_中文_'], Cookie::get('d')); - } - - public function testDelete() - { - $_COOKIE = [ - 'a' => 'b', - 'pre_abc' => 'c', - ]; - $this->assertEquals('b', Cookie::get('a')); - Cookie::delete('a'); - $this->assertEquals(null, Cookie::get('a')); - - $this->assertEquals('c', Cookie::get('abc', 'pre_')); - Cookie::delete('abc', 'pre_'); - $this->assertEquals(null, Cookie::get('abc', 'pre_')); - } - - public function testClear() - { - $_COOKIE = []; - $this->assertEquals(null, Cookie::clear()); - - $_COOKIE = [ - 'a' => 'b', - 'pre_abc' => 'c', - ]; - Cookie::clear('pre_'); - $this->assertEquals(['a' => 'b'], $_COOKIE); - } -} diff --git a/thinkphp/tests/thinkphp/library/think/db/driver/.gitignore b/thinkphp/tests/thinkphp/library/think/db/driver/.gitignore deleted file mode 100644 index c96a04f0..00000000 --- a/thinkphp/tests/thinkphp/library/think/db/driver/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore \ No newline at end of file diff --git a/thinkphp/tests/thinkphp/library/think/dbTest.php b/thinkphp/tests/thinkphp/library/think/dbTest.php deleted file mode 100644 index 5724ee21..00000000 --- a/thinkphp/tests/thinkphp/library/think/dbTest.php +++ /dev/null @@ -1,352 +0,0 @@ - -// +---------------------------------------------------------------------- - -/** - * Db类测试 - * @author: 刘志淳 - */ - -namespace tests\thinkphp\library\think; - -use think\Db; - -class dbTest extends \PHPUnit_Framework_TestCase -{ - // 获取测试数据库配置 - private function getConfig() - { - return [ - // 数据库类型 - 'type' => 'mysql', - // 服务器地址 - 'hostname' => '127.0.0.1', - // 数据库名 - 'database' => 'test', - // 用户名 - 'username' => 'root', - // 密码 - 'password' => '', - // 端口 - 'hostport' => '', - // 连接dsn - 'dsn' => '', - // 数据库连接参数 - 'params' => [], - // 数据库编码默认采用utf8 - 'charset' => 'utf8', - // 数据库表前缀 - 'prefix' => 'tp_', - // 数据库调试模式 - 'debug' => true, - // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器) - 'deploy' => 0, - // 数据库读写是否分离 主从式有效 - 'rw_separate' => false, - // 读写分离后 主服务器数量 - 'master_num' => 1, - // 指定从服务器序号 - 'slave_no' => '', - // 是否严格检查字段是否存在 - 'fields_strict' => true, - // 数据集返回类型 array 数组 collection Collection对象 - 'resultset_type' => 'array', - // 是否自动写入时间戳字段 - 'auto_timestamp' => false, - // 是否需要进行SQL性能分析 - 'sql_explain' => false, - ]; - } - - // 获取创建数据库 SQL - private function getCreateTableSql() - { - $sql[] = <<getConfig(); - $result = Db::connect($config)->execute('show databases'); - $this->assertNotEmpty($result); - } - - public function testExecute() - { - $config = $this->getConfig(); - $sql = $this->getCreateTableSql(); - foreach ($sql as $one) { - Db::connect($config)->execute($one); - } - $tableNum = Db::connect($config)->execute("show tables;"); - $this->assertEquals(4, $tableNum); - } - - public function testQuery() - { - $config = $this->getConfig(); - $sql = $this->getCreateTableSql(); - Db::connect($config)->batchQuery($sql); - - $tableQueryResult = Db::connect($config)->query("show tables;"); - - $this->assertTrue(is_array($tableQueryResult)); - - $tableNum = count($tableQueryResult); - $this->assertEquals(4, $tableNum); - } - - public function testBatchQuery() - { - $config = $this->getConfig(); - $sql = $this->getCreateTableSql(); - Db::connect($config)->batchQuery($sql); - - $tableNum = Db::connect($config)->execute("show tables;"); - $this->assertEquals(4, $tableNum); - } - - public function testTable() - { - $config = $this->getConfig(); - $tableName = 'tp_user'; - $result = Db::connect($config)->table($tableName); - $this->assertEquals($tableName, $result->getOptions()['table']); - } - - public function testName() - { - $config = $this->getConfig(); - $tableName = 'user'; - $result = Db::connect($config)->name($tableName); - $this->assertEquals($config['prefix'] . $tableName, $result->getTable()); - } - - public function testInsert() - { - $config = $this->getConfig(); - $data = [ - 'username' => 'chunice', - 'password' => md5('chunice'), - 'status' => 1, - 'create_time' => time(), - ]; - $result = Db::connect($config)->name('user')->insert($data); - $this->assertEquals(1, $result); - } - - public function testUpdate() - { - $config = $this->getConfig(); - $data = [ - 'username' => 'chunice_update', - 'password' => md5('chunice'), - 'status' => 1, - 'create_time' => time(), - ]; - $result = Db::connect($config)->name('user')->where('username', 'chunice')->update($data); - $this->assertEquals(1, $result); - } - - public function testFind() - { - $config = $this->getConfig(); - $mustFind = Db::connect($config)->name('user')->where('username', 'chunice_update')->find(); - $this->assertNotEmpty($mustFind); - $mustNotFind = Db::connect($config)->name('user')->where('username', 'chunice')->find(); - $this->assertEmpty($mustNotFind); - } - - public function testInsertAll() - { - $config = $this->getConfig(); - - $data = [ - ['username' => 'foo', 'password' => md5('foo'), 'status' => 1, 'create_time' => time()], - ['username' => 'bar', 'password' => md5('bar'), 'status' => 1, 'create_time' => time()], - ]; - - $insertNum = Db::connect($config)->name('user')->insertAll($data); - $this->assertEquals(count($data), $insertNum); - } - - public function testSelect() - { - $config = $this->getConfig(); - $mustFound = Db::connect($config)->name('user')->where('status', 1)->select(); - $this->assertNotEmpty($mustFound); - $mustNotFound = Db::connect($config)->name('user')->where('status', 0)->select(); - $this->assertEmpty($mustNotFound); - } - - public function testValue() - { - $config = $this->getConfig(); - $username = Db::connect($config)->name('user')->where('id', 1)->value('username'); - $this->assertEquals('chunice_update', $username); - $usernameNull = Db::connect($config)->name('user')->where('id', 0)->value('username'); - $this->assertEmpty($usernameNull); - } - - public function testColumn() - { - $config = $this->getConfig(); - $username = Db::connect($config)->name('user')->where('status', 1)->column('username'); - $this->assertNotEmpty($username); - $usernameNull = Db::connect($config)->name('user')->where('status', 0)->column('username'); - $this->assertEmpty($usernameNull); - - } - - public function testInsertGetId() - { - $config = $this->getConfig(); - $id = Db::connect($config)->name('user')->order('id', 'desc')->value('id'); - - $data = [ - 'username' => uniqid(), - 'password' => md5('chunice'), - 'status' => 1, - 'create_time' => time(), - ]; - $lastId = Db::connect($config)->name('user')->insertGetId($data); - $this->assertEquals($id + 1, $lastId); - - } - - public function testGetLastInsId() - { - $config = $this->getConfig(); - $data = [ - 'username' => uniqid(), - 'password' => md5('chunice'), - 'status' => 1, - 'create_time' => time(), - ]; - $lastId = Db::connect($config)->name('user')->insertGetId($data); - - $lastInsId = Db::connect($config)->name('user')->getLastInsID(); - $this->assertEquals($lastId, $lastInsId); - } - - public function testSetField() - { - $config = $this->getConfig(); - - $setFieldNum = Db::connect($config)->name('user')->where('id', 1)->setField('username', 'chunice_setField'); - $this->assertEquals(1, $setFieldNum); - - $setFieldNum = Db::connect($config)->name('user')->where('id', 1)->setField('username', 'chunice_setField'); - $this->assertEquals(0, $setFieldNum); - } - - public function testSetInc() - { - $config = $this->getConfig(); - $originCreateTime = Db::connect($config)->name('user')->where('id', 1)->value('create_time'); - Db::connect($config)->name('user')->where('id', 1)->setInc('create_time'); - $newCreateTime = Db::connect($config)->name('user')->where('id', 1)->value('create_time'); - $this->assertEquals($originCreateTime + 1, $newCreateTime); - - } - - public function testSetDec() - { - $config = $this->getConfig(); - $originCreateTime = Db::connect($config)->name('user')->where('id', 1)->value('create_time'); - Db::connect($config)->name('user')->where('id', 1)->setDec('create_time'); - $newCreateTime = Db::connect($config)->name('user')->where('id', 1)->value('create_time'); - $this->assertEquals($originCreateTime - 1, $newCreateTime); - } - - public function testDelete() - { - $config = $this->getConfig(); - Db::connect($config)->name('user')->where('id', 1)->delete(); - $result = Db::connect($config)->name('user')->where('id', 1)->find(); - $this->assertEmpty($result); - } - - public function testChunk() - { - // todo 暂未想到测试方法 - } - - public function testCache() - { - $config = $this->getConfig(); - $result = Db::connect($config)->name('user')->where('id', 1)->cache('key', 60)->find(); - $cache = \think\Cache::get('key'); - $this->assertEquals($result, $cache); - - $updateCache = Db::connect($config)->name('user')->cache('key')->find(1); - $this->assertEquals($cache, $updateCache); - } - -} diff --git a/thinkphp/tests/thinkphp/library/think/debugTest.php b/thinkphp/tests/thinkphp/library/think/debugTest.php deleted file mode 100644 index fc2fdd47..00000000 --- a/thinkphp/tests/thinkphp/library/think/debugTest.php +++ /dev/null @@ -1,179 +0,0 @@ - -// +---------------------------------------------------------------------- - -/** - * Debug测试 - * @author 大漠 - */ - -namespace tests\thinkphp\library\think; - -use think\Debug; - -class debugTest extends \PHPUnit_Framework_TestCase -{ - - /** - * - * @var Debug - */ - protected $object; - - /** - * Sets up the fixture, for example, opens a network connection. - * This method is called before a test is executed. - */ - protected function setUp() - { - $this->object = new Debug(); - } - - /** - * Tears down the fixture, for example, closes a network connection. - * This method is called after a test is executed. - */ - protected function tearDown() - {} - - /** - * @covers think\Debug::remark - * @todo Implement testRemark(). - */ - public function testRemark() - { - $name = "testremarkkey"; - Debug::remark($name); - } - - /** - * @covers think\Debug::getRangeTime - * @todo Implement testGetRangeTime(). - */ - public function testGetRangeTime() - { - $start = "testGetRangeTimeStart"; - $end = "testGetRangeTimeEnd"; - Debug::remark($start); - usleep(20000); - // \think\Debug::remark($end); - - $time = Debug::getRangeTime($start, $end); - $this->assertLessThan(0.03, $time); - //$this->assertEquals(0.03, ceil($time)); - } - - /** - * @covers think\Debug::getUseTime - * @todo Implement testGetUseTime(). - */ - public function testGetUseTime() - { - $time = Debug::getUseTime(); - $this->assertLessThan(20, $time); - } - - /** - * @covers think\Debug::getThroughputRate - * @todo Implement testGetThroughputRate(). - */ - public function testGetThroughputRate() - { - usleep(100000); - $throughputRate = Debug::getThroughputRate(); - $this->assertLessThan(10, $throughputRate); - } - - /** - * @covers think\Debug::getRangeMem - * @todo Implement testGetRangeMem(). - */ - public function testGetRangeMem() - { - $start = "testGetRangeMemStart"; - $end = "testGetRangeMemEnd"; - Debug::remark($start); - $str = ""; - for ($i = 0; $i < 10000; $i++) { - $str .= "mem"; - } - - $rangeMem = Debug::getRangeMem($start, $end); - - $this->assertLessThan(33, explode(" ", $rangeMem)[0]); - } - - /** - * @covers think\Debug::getUseMem - * @todo Implement testGetUseMem(). - */ - public function testGetUseMem() - { - $useMem = Debug::getUseMem(); - - $this->assertLessThan(35, explode(" ", $useMem)[0]); - } - - /** - * @covers think\Debug::getMemPeak - * @todo Implement testGetMemPeak(). - */ - public function testGetMemPeak() - { - $start = "testGetMemPeakStart"; - $end = "testGetMemPeakEnd"; - Debug::remark($start); - $str = ""; - for ($i = 0; $i < 100000; $i++) { - $str .= "mem"; - } - $memPeak = Debug::getMemPeak($start, $end); - $this->assertLessThan(500, explode(" ", $memPeak)[0]); - } - - /** - * @covers think\Debug::getFile - * @todo Implement testGetFile(). - */ - public function testGetFile() - { - $count = Debug::getFile(); - - $this->assertEquals(count(get_included_files()), $count); - - $info = Debug::getFile(true); - $this->assertEquals(count(get_included_files()), count($info)); - - $this->assertContains("KB", $info[0]); - } - - /** - * @covers think\Debug::dump - * @todo Implement testDump(). - */ - public function testDump() - { - if (strstr(PHP_VERSION, 'hhvm')) { - return; - } - - $var = []; - $var["key"] = "val"; - $output = Debug::dump($var, false, $label = "label"); - $array = explode("array", json_encode($output)); - if (IS_WIN) { - $this->assertEquals("(1) {\\n [\\\"key\\\"] => string(3) \\\"val\\\"\\n}\\n\\r\\n\"", end($array)); - } elseif (strstr(PHP_OS, 'Darwin')) { - $this->assertEquals("(1) {\\n [\\\"key\\\"] => string(3) \\\"val\\\"\\n}\\n\\n\"", end($array)); - } else { - $this->assertEquals("(1) {\\n 'key' =>\\n string(3) \\\"val\\\"\\n}\\n\\n\"", end($array)); - } - } -} diff --git a/thinkphp/tests/thinkphp/library/think/display.html b/thinkphp/tests/thinkphp/library/think/display.html deleted file mode 100644 index e99d3025..00000000 --- a/thinkphp/tests/thinkphp/library/think/display.html +++ /dev/null @@ -1 +0,0 @@ -{$name??'default'} \ No newline at end of file diff --git a/thinkphp/tests/thinkphp/library/think/exceptionTest.php b/thinkphp/tests/thinkphp/library/think/exceptionTest.php deleted file mode 100644 index 66957ce6..00000000 --- a/thinkphp/tests/thinkphp/library/think/exceptionTest.php +++ /dev/null @@ -1,52 +0,0 @@ - -// +---------------------------------------------------------------------- - -/** - * exception类测试 - * @author Haotong Lin - */ - -namespace tests\thinkphp\library\think; - -use ReflectionMethod; -use think\Exception as ThinkException; -use think\exception\HttpException; - -class MyException extends ThinkException -{ - -} - -class exceptionTest extends \PHPUnit_Framework_TestCase -{ - public function testGetHttpStatus() - { - try { - throw new HttpException(404, "Error Processing Request"); - } catch (HttpException $e) { - $this->assertEquals(404, $e->getStatusCode()); - } - } - - public function testDebugData() - { - $data = ['a' => 'b', 'c' => 'd']; - try { - $e = new MyException("Error Processing Request", 1); - $method = new ReflectionMethod($e, 'setData'); - $method->setAccessible(true); - $method->invokeArgs($e, ['test', $data]); - throw $e; - } catch (MyException $e) { - $this->assertEquals(['test' => $data], $e->getData()); - } - } -} diff --git a/thinkphp/tests/thinkphp/library/think/extend.html b/thinkphp/tests/thinkphp/library/think/extend.html deleted file mode 100644 index 922192dc..00000000 --- a/thinkphp/tests/thinkphp/library/think/extend.html +++ /dev/null @@ -1,2 +0,0 @@ -{extend name="extend2" /} -{block name="head"}header{/block} \ No newline at end of file diff --git a/thinkphp/tests/thinkphp/library/think/extend2.html b/thinkphp/tests/thinkphp/library/think/extend2.html deleted file mode 100644 index eb22e1da..00000000 --- a/thinkphp/tests/thinkphp/library/think/extend2.html +++ /dev/null @@ -1,17 +0,0 @@ -{layout name="layout2" replace="[__REPLACE__]" /} -{block name="head"}{/block} -
- {include file="include" name="info" value="$info.value" /} -{block name="main"} -{block name="side"} - side -{/block} -{block name="mainbody"} - -{/block} -{/block} -{literal} - {$name} -{/literal} - -
\ No newline at end of file diff --git a/thinkphp/tests/thinkphp/library/think/hookTest.php b/thinkphp/tests/thinkphp/library/think/hookTest.php deleted file mode 100644 index 930ecf53..00000000 --- a/thinkphp/tests/thinkphp/library/think/hookTest.php +++ /dev/null @@ -1,67 +0,0 @@ - -// +---------------------------------------------------------------------- - -/** - * Hook类测试 - * @author liu21st - */ - -namespace tests\thinkphp\library\think; - -use think\Hook; - -class hookTest extends \PHPUnit_Framework_TestCase -{ - - public function testRun() - { - Hook::add('my_pos', '\tests\thinkphp\library\think\behavior\One'); - Hook::add('my_pos', ['\tests\thinkphp\library\think\behavior\Two']); - Hook::add('my_pos', '\tests\thinkphp\library\think\behavior\Three', true); - $data['id'] = 0; - $data['name'] = 'thinkphp'; - Hook::listen('my_pos', $data); - $this->assertEquals(2, $data['id']); - $this->assertEquals('thinkphp', $data['name']); - $this->assertEquals([ - '\tests\thinkphp\library\think\behavior\Three', - '\tests\thinkphp\library\think\behavior\One', - '\tests\thinkphp\library\think\behavior\Two'], - Hook::get('my_pos')); - } - - public function testImport() - { - Hook::import(['my_pos' => [ - '\tests\thinkphp\library\think\behavior\One', - '\tests\thinkphp\library\think\behavior\Three'], - ]); - Hook::import(['my_pos' => ['\tests\thinkphp\library\think\behavior\Two']], false); - Hook::import(['my_pos' => ['\tests\thinkphp\library\think\behavior\Three', '_overlay' => true]]); - $data['id'] = 0; - $data['name'] = 'thinkphp'; - Hook::listen('my_pos', $data); - $this->assertEquals(3, $data['id']); - - } - - public function testExec() - { - $data['id'] = 0; - $data['name'] = 'thinkphp'; - $this->assertEquals(true, Hook::exec('\tests\thinkphp\library\think\behavior\One')); - $this->assertEquals(false, Hook::exec('\tests\thinkphp\library\think\behavior\One', 'test', $data)); - $this->assertEquals('test', $data['name']); - $this->assertEquals('Closure', Hook::exec(function (&$data) {$data['name'] = 'Closure';return 'Closure';})); - - } - -} diff --git a/thinkphp/tests/thinkphp/library/think/include.html b/thinkphp/tests/thinkphp/library/think/include.html deleted file mode 100644 index e01ae9ef..00000000 --- a/thinkphp/tests/thinkphp/library/think/include.html +++ /dev/null @@ -1,2 +0,0 @@ - -{include file="include2" /} \ No newline at end of file diff --git a/thinkphp/tests/thinkphp/library/think/include2.html b/thinkphp/tests/thinkphp/library/think/include2.html deleted file mode 100644 index 24bdacb3..00000000 --- a/thinkphp/tests/thinkphp/library/think/include2.html +++ /dev/null @@ -1 +0,0 @@ -{$info.value}: \ No newline at end of file diff --git a/thinkphp/tests/thinkphp/library/think/lang/lang.php b/thinkphp/tests/thinkphp/library/think/lang/lang.php deleted file mode 100644 index 96880b15..00000000 --- a/thinkphp/tests/thinkphp/library/think/lang/lang.php +++ /dev/null @@ -1,4 +0,0 @@ -'加载', -]; diff --git a/thinkphp/tests/thinkphp/library/think/langTest.php b/thinkphp/tests/thinkphp/library/think/langTest.php deleted file mode 100644 index 360ee43d..00000000 --- a/thinkphp/tests/thinkphp/library/think/langTest.php +++ /dev/null @@ -1,76 +0,0 @@ - -// +---------------------------------------------------------------------- - -/** - * Lang测试 - * @author liu21st - */ - -namespace tests\thinkphp\library\think; - -use think\Config; -use think\Lang; - -class langTest extends \PHPUnit_Framework_TestCase -{ - - public function testSetAndGet() - { - Lang::set('hello,%s', '欢迎,%s'); - $this->assertEquals('欢迎,ThinkPHP', Lang::get('hello,%s', ['ThinkPHP'])); - Lang::set('hello,%s', '歡迎,%s', 'zh-tw'); - $this->assertEquals('歡迎,ThinkPHP', Lang::get('hello,%s', ['ThinkPHP'], 'zh-tw')); - Lang::set(['hello' => '欢迎', 'use' => '使用']); - $this->assertEquals('欢迎', Lang::get('hello')); - $this->assertEquals('欢迎', Lang::get('HELLO')); - $this->assertEquals('使用', Lang::get('use')); - - Lang::set('hello,{:name}', '欢迎,{:name}'); - $this->assertEquals('欢迎,liu21st', Lang::get('hello,{:name}', ['name' => 'liu21st'])); - } - - public function testLoad() - { - Lang::load(__DIR__ . DS . 'lang' . DS . 'lang.php'); - $this->assertEquals('加载', Lang::get('load')); - Lang::load(__DIR__ . DS . 'lang' . DS . 'lang.php', 'test'); - $this->assertEquals('加载', Lang::get('load', [], 'test')); - } - - public function testDetect() - { - - Config::set('lang_list', ['zh-cn', 'zh-tw']); - Lang::set('hello', '欢迎', 'zh-cn'); - Lang::set('hello', '歡迎', 'zh-tw'); - - Config::set('lang_detect_var', 'lang'); - Config::set('lang_cookie_var', 'think_cookie'); - - $_GET['lang'] = 'zh-tw'; - Lang::detect(); - $this->assertEquals('歡迎', Lang::get('hello')); - - $_GET['lang'] = 'zh-cn'; - Lang::detect(); - $this->assertEquals('欢迎', Lang::get('hello')); - - } - - public function testRange() - { - $this->assertEquals('zh-cn', Lang::range()); - Lang::set('hello', '欢迎', 'test'); - Lang::range('test'); - $this->assertEquals('test', Lang::range()); - $this->assertEquals('欢迎', Lang::get('hello')); - } -} diff --git a/thinkphp/tests/thinkphp/library/think/layout.html b/thinkphp/tests/thinkphp/library/think/layout.html deleted file mode 100644 index be8d4a07..00000000 --- a/thinkphp/tests/thinkphp/library/think/layout.html +++ /dev/null @@ -1,2 +0,0 @@ -
{__CONTENT__} -
\ No newline at end of file diff --git a/thinkphp/tests/thinkphp/library/think/layout2.html b/thinkphp/tests/thinkphp/library/think/layout2.html deleted file mode 100644 index a5b75729..00000000 --- a/thinkphp/tests/thinkphp/library/think/layout2.html +++ /dev/null @@ -1,2 +0,0 @@ - \ No newline at end of file diff --git a/thinkphp/tests/thinkphp/library/think/loader/test/Hello.php b/thinkphp/tests/thinkphp/library/think/loader/test/Hello.php deleted file mode 100644 index c1414561..00000000 --- a/thinkphp/tests/thinkphp/library/think/loader/test/Hello.php +++ /dev/null @@ -1,7 +0,0 @@ - -// +---------------------------------------------------------------------- - -/** - * Loader测试 - * @author liu21st - */ - -namespace tests\thinkphp\library\think; - -use think\Loader; - -class loaderTest extends \PHPUnit_Framework_TestCase -{ - - public function testAutoload() - { - $this->assertEquals(false, Loader::autoload('\think\Url')); - $this->assertEquals(false, Loader::autoload('think\Test')); - $this->assertEquals(false, Loader::autoload('my\HelloTest')); - } - - public function testAddClassMap() - { - Loader::addClassMap('my\hello\Test', __DIR__ . DS . 'loader' . DS . 'Test.php'); - } - - public function testAddNamespace() - { - Loader::addNamespace('top', __DIR__ . DS . 'loader' . DS); - $this->assertEquals(true, Loader::autoload('top\test\Hello')); - } - - public function testAddNamespaceAlias() - { - Loader::addNamespaceAlias('top', 'top\test'); - Loader::addNamespaceAlias(['top' => 'top\test', 'app' => 'app\index']); - //$this->assertEquals(true, Loader::autoload('top\Hello')); - } - - public function testTable() - { - Loader::db('mysql://root@127.0.0.1/test#utf8'); - } - - public function testImport() - { - $this->assertEquals(false, Loader::import('think.log.driver.MyTest')); - } - - public function testParseName() - { - $this->assertEquals('HelloTest', Loader::parseName('hello_test', 1)); - $this->assertEquals('hello_test', Loader::parseName('HelloTest', 0)); - } - - public function testParseClass() - { - $this->assertEquals('app\index\controller\User', Loader::parseClass('index', 'controller', 'user')); - $this->assertEquals('app\index\controller\user\Type', Loader::parseClass('index', 'controller', 'user.type')); - $this->assertEquals('app\admin\model\UserType', Loader::parseClass('admin', 'model', 'user_type')); - } -} diff --git a/thinkphp/tests/thinkphp/library/think/log/driver/fileTest.php b/thinkphp/tests/thinkphp/library/think/log/driver/fileTest.php deleted file mode 100644 index ad6dd224..00000000 --- a/thinkphp/tests/thinkphp/library/think/log/driver/fileTest.php +++ /dev/null @@ -1,34 +0,0 @@ - -// +---------------------------------------------------------------------- - -/** - * Test File Log - */ -namespace tests\thinkphp\library\think\log\driver; - -use think\Log; - -class fileTest extends \PHPUnit_Framework_TestCase -{ - protected function setUp() - { - Log::init(['type' => 'file']); - } - - public function testRecord() - { - $record_msg = 'record'; - Log::record($record_msg, 'notice'); - $logs = Log::getLog(); - - $this->assertEquals([], $logs); - } -} diff --git a/thinkphp/tests/thinkphp/library/think/logTest.php b/thinkphp/tests/thinkphp/library/think/logTest.php deleted file mode 100644 index e786b173..00000000 --- a/thinkphp/tests/thinkphp/library/think/logTest.php +++ /dev/null @@ -1,39 +0,0 @@ - -// +---------------------------------------------------------------------- - -/** - * Log测试 - * @author liu21st - */ -namespace tests\thinkphp\library\think; - -use think\Log; - -class logTest extends \PHPUnit_Framework_TestCase -{ - - public function testSave() - { - Log::init(['type' => 'test']); - Log::clear(); - Log::record('test'); - Log::record([1, 2, 3]); - $this->assertTrue(Log::save()); - } - - public function testWrite() - { - Log::init(['type' => 'test']); - Log::clear(); - $this->assertTrue(Log::write('hello', 'info')); - $this->assertTrue(Log::write([1, 2, 3], 'log')); - } -} diff --git a/thinkphp/tests/thinkphp/library/think/model/.gitignore b/thinkphp/tests/thinkphp/library/think/model/.gitignore deleted file mode 100644 index c96a04f0..00000000 --- a/thinkphp/tests/thinkphp/library/think/model/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore \ No newline at end of file diff --git a/thinkphp/tests/thinkphp/library/think/paginateTest.php b/thinkphp/tests/thinkphp/library/think/paginateTest.php deleted file mode 100644 index 8cd45507..00000000 --- a/thinkphp/tests/thinkphp/library/think/paginateTest.php +++ /dev/null @@ -1,40 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace tests\thinkphp\library\think; - -use think\paginator\driver\Bootstrap; - -class paginateTest extends \PHPUnit_Framework_TestCase -{ - public function testPaginatorInfo() - { - $p = Bootstrap::make($array = ['item3', 'item4'], 2, 2, 4); - - $this->assertEquals(4, $p->total()); - - $this->assertEquals(2, $p->listRows()); - - $this->assertEquals(2, $p->currentPage()); - - $p2 = Bootstrap::make($array2 = ['item3', 'item4'], 2, 2, 2); - $this->assertEquals(1, $p2->currentPage()); - } - - public function testPaginatorRender() - { - $p = Bootstrap::make($array = ['item3', 'item4'], 2, 2, 100); - $render = ''; - - $this->assertEquals($render, $p->render()); - } - -} diff --git a/thinkphp/tests/thinkphp/library/think/requestTest.php b/thinkphp/tests/thinkphp/library/think/requestTest.php deleted file mode 100644 index f86546e6..00000000 --- a/thinkphp/tests/thinkphp/library/think/requestTest.php +++ /dev/null @@ -1,187 +0,0 @@ - -// +---------------------------------------------------------------------- - -/** - * Db类测试 - */ - -namespace tests\thinkphp\library\think; - -use think\Config; -use think\Request; - -class requestTest extends \PHPUnit_Framework_TestCase -{ - protected $request; - - public function setUp() - { - //$request = Request::create('http://www.domain.com/index/index/hello/?name=thinkphp'); - - } - - public function testCreate() - { - $request = Request::create('http://www.thinkphp.cn/index/index/hello.html?name=thinkphp'); - $this->assertEquals('http://www.thinkphp.cn', $request->domain()); - $this->assertEquals('/index/index/hello.html?name=thinkphp', $request->url()); - $this->assertEquals('/index/index/hello.html', $request->baseurl()); - $this->assertEquals('index/index/hello.html', $request->pathinfo()); - $this->assertEquals('index/index/hello', $request->path()); - $this->assertEquals('html', $request->ext()); - $this->assertEquals('name=thinkphp', $request->query()); - $this->assertEquals('www.thinkphp.cn', $request->host()); - $this->assertEquals(80, $request->port()); - $this->assertEquals($_SERVER['REQUEST_TIME'], $request->time()); - $this->assertEquals($_SERVER['REQUEST_TIME_FLOAT'], $request->time(true)); - $this->assertEquals('GET', $request->method()); - $this->assertEquals(['name' => 'thinkphp'], $request->param()); - $this->assertFalse($request->isSsl()); - $this->assertEquals('http', $request->scheme()); - } - - public function testDomain() - { - $request = Request::instance(); - $request->domain('http://thinkphp.cn'); - $this->assertEquals('http://thinkphp.cn', $request->domain()); - } - - public function testUrl() - { - $request = Request::instance(); - $request->url('/index.php/index/hello?name=thinkphp'); - $this->assertEquals('/index.php/index/hello?name=thinkphp', $request->url()); - $this->assertEquals('http://thinkphp.cn/index.php/index/hello?name=thinkphp', $request->url(true)); - } - - public function testBaseUrl() - { - $request = Request::instance(); - $request->baseurl('/index.php/index/hello'); - $this->assertEquals('/index.php/index/hello', $request->baseurl()); - $this->assertEquals('http://thinkphp.cn/index.php/index/hello', $request->baseurl(true)); - } - - public function testbaseFile() - { - $request = Request::instance(); - $request->basefile('/index.php'); - $this->assertEquals('/index.php', $request->basefile()); - $this->assertEquals('http://thinkphp.cn/index.php', $request->basefile(true)); - } - - public function testroot() - { - $request = Request::instance(); - $request->root('/index.php'); - $this->assertEquals('/index.php', $request->root()); - $this->assertEquals('http://thinkphp.cn/index.php', $request->root(true)); - } - - public function testType() - { - $request = Request::instance(); - $request->server(['HTTP_ACCEPT' => 'application/json']); - - $this->assertEquals('json', $request->type()); - $request->mimeType('test', 'application/test'); - $request->mimeType(['test' => 'application/test']); - $request->server(['HTTP_ACCEPT' => 'application/test']); - - $this->assertEquals('test', $request->type()); - } - - public function testmethod() - { - $_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'] = 'DELETE'; - - $request = Request::create('', ''); - $this->assertEquals('DELETE', $request->method()); - $this->assertEquals('GET', $request->method(true)); - - Config::set('var_method', '_method'); - $_POST['_method'] = 'POST'; - $request = Request::create('', ''); - $this->assertEquals('POST', $request->method()); - $this->assertEquals('GET', $request->method(true)); - $this->assertTrue($request->isPost()); - $this->assertFalse($request->isGet()); - $this->assertFalse($request->isPut()); - $this->assertFalse($request->isDelete()); - $this->assertFalse($request->isHead()); - $this->assertFalse($request->isPatch()); - $this->assertFalse($request->isOptions()); - } - - public function testCli() - { - $request = Request::instance(); - $this->assertTrue($request->isCli()); - } - - public function testVar() - { - Config::set('app_multi_module', true); - $request = Request::create(''); - $request->route(['name' => 'thinkphp', 'id' => 6]); - $request->get(['id' => 10]); - $request->post(['id' => 8]); - $request->put(['id' => 7]); - $request->request(['test' => 'value']); - $this->assertEquals(['name' => 'thinkphp', 'id' => 6], $request->route()); - //$this->assertEquals(['id' => 10], $request->get()); - $this->assertEquals('thinkphp', $request->route('name')); - $this->assertEquals('default', $request->route('test', 'default')); - $this->assertEquals(10, $request->get('id')); - $this->assertEquals(0, $request->get('ids', 0)); - $this->assertEquals(8, $request->post('id')); - $this->assertEquals(7, $request->put('id')); - $this->assertEquals('value', $request->request('test')); - $this->assertEquals('thinkphp', $request->param('name')); - $this->assertEquals(6, $request->param('id')); - $this->assertFalse($request->has('user_id')); - $this->assertTrue($request->has('test', 'request')); - $this->assertEquals(['id' => 6], $request->only('id')); - $this->assertEquals(['name' => 'thinkphp', 'lang' => 'zh-cn'], $request->except('id')); - $this->assertEquals('THINKPHP', $request->param('name', '', 'strtoupper')); - } - - public function testIsAjax() - { - $request = Request::create(''); - $_SERVER['HTTP_X_REQUESTED_WITH'] = 'xmlhttprequest'; - $this->assertTrue($request->isAjax()); - } - - public function testIsPjax() - { - $request = Request::create(''); - $_SERVER['HTTP_X_PJAX'] = true; - $this->assertTrue($request->isPjax()); - } - - public function testIsMobile() - { - $request = Request::create(''); - $_SERVER['HTTP_VIA'] = 'wap'; - $this->assertTrue($request->isMobile()); - } - - public function testBind() - { - $request = Request::create(''); - $request->user = 'User1'; - $request->bind(['user' => 'User2']); - $this->assertEquals('User2', $request->user); - } - -} diff --git a/thinkphp/tests/thinkphp/library/think/responseTest.php b/thinkphp/tests/thinkphp/library/think/responseTest.php deleted file mode 100644 index 62d15747..00000000 --- a/thinkphp/tests/thinkphp/library/think/responseTest.php +++ /dev/null @@ -1,95 +0,0 @@ - -// +---------------------------------------------------------------------- - -/** - * Response测试 - * @author 大漠 - */ - -namespace tests\thinkphp\library\think; - -use think\Config; -use think\Request; -use think\Response; - -class responseTest extends \PHPUnit_Framework_TestCase -{ - - /** - * - * @var \think\Response - */ - protected $object; - - protected $default_return_type; - - protected $default_ajax_return; - - /** - * Sets up the fixture, for example, opens a network connection. - * This method is called before a test is executed. - */ - protected function setUp() - { - // 1. - // restore_error_handler(); - // Warning: Cannot modify header information - headers already sent by (output started at PHPUnit\Util\Printer.php:173) - // more see in https://www.analysisandsolutions.com/blog/html/writing-phpunit-tests-for-wordpress-plugins-wp-redirect-and-continuing-after-php-errors.htm - - // 2. - // the Symfony used the HeaderMock.php - - // 3. - // not run the eclipse will held, and travis-ci.org Searching for coverage reports - // **> Python coverage not found - // **> No coverage report found. - // add the - // /** - // * @runInSeparateProcess - // */ - if (!$this->default_return_type) { - $this->default_return_type = Config::get('default_return_type'); - } - if (!$this->default_ajax_return) { - $this->default_ajax_return = Config::get('default_ajax_return'); - } - } - - /** - * Tears down the fixture, for example, closes a network connection. - * This method is called after a test is executed. - */ - protected function tearDown() - { - Config::set('default_ajax_return', $this->default_ajax_return); - Config::set('default_return_type', $this->default_return_type); - } - - /** - * @covers think\Response::send - * @todo Implement testSend(). - */ - public function testSend() - { - $dataArr = []; - $dataArr["key"] = "value"; - - $response = Response::create($dataArr, 'json'); - $result = $response->getContent(); - $this->assertEquals('{"key":"value"}', $result); - $request = Request::instance(); - $request->get(['callback' => 'callback']); - $response = Response::create($dataArr, 'jsonp'); - $result = $response->getContent(); - $this->assertEquals('callback({"key":"value"});', $result); - } - -} diff --git a/thinkphp/tests/thinkphp/library/think/routeTest.php b/thinkphp/tests/thinkphp/library/think/routeTest.php deleted file mode 100644 index 31e1b861..00000000 --- a/thinkphp/tests/thinkphp/library/think/routeTest.php +++ /dev/null @@ -1,287 +0,0 @@ - -// +---------------------------------------------------------------------- - -/** - * Route测试 - * @author liu21st - */ - -namespace tests\thinkphp\library\think; - -use think\Config; -use think\Request; -use think\Route; - -class routeTest extends \PHPUnit_Framework_TestCase -{ - - protected function setUp() - { - Config::set('app_multi_module', true); - } - - public function testRegister() - { - $request = Request::instance(); - Route::get('hello/:name', 'index/hello'); - Route::get(['hello/:name' => 'index/hello']); - Route::post('hello/:name', 'index/post'); - Route::put('hello/:name', 'index/put'); - Route::delete('hello/:name', 'index/delete'); - Route::patch('hello/:name', 'index/patch'); - Route::any('user/:id', 'index/user'); - $result = Route::check($request, 'hello/thinkphp'); - $this->assertEquals([null, 'index', 'hello'], $result['module']); - $this->assertEquals(['hello' => true, 'user/:id' => true, 'hello/:name' => ['rule' => 'hello/:name', 'route' => 'index/hello', 'var' => ['name' => 1], 'option' => [], 'pattern' => []]], Route::rules('GET')); - Route::rule('type1/:name', 'index/type', 'PUT|POST'); - Route::rule(['type2/:name' => 'index/type1']); - Route::rule([['type3/:name', 'index/type2', ['method' => 'POST']]]); - Route::rule(['name', 'type4/:name'], 'index/type4'); - } - - public function testImport() - { - $rule = [ - '__domain__' => ['subdomain2.thinkphp.cn' => 'blog1'], - '__alias__' => ['blog1' => 'blog1'], - '__rest__' => ['res' => ['index/blog']], - 'bbb' => ['index/blog1', ['method' => 'POST']], - 'ddd' => '', - ['hello1/:ddd', 'index/hello1', ['method' => 'POST']], - ]; - Route::import($rule); - } - - public function testResource() - { - $request = Request::instance(); - Route::resource('res', 'index/blog'); - Route::resource(['res' => ['index/blog']]); - $result = Route::check($request, 'res'); - $this->assertEquals(['index', 'blog', 'index'], $result['module']); - $result = Route::check($request, 'res/create'); - $this->assertEquals(['index', 'blog', 'create'], $result['module']); - $result = Route::check($request, 'res/8'); - $this->assertEquals(['index', 'blog', 'read'], $result['module']); - $result = Route::check($request, 'res/8/edit'); - $this->assertEquals(['index', 'blog', 'edit'], $result['module']); - - Route::resource('blog.comment', 'index/comment'); - $result = Route::check($request, 'blog/8/comment/10'); - $this->assertEquals(['index', 'comment', 'read'], $result['module']); - $result = Route::check($request, 'blog/8/comment/10/edit'); - $this->assertEquals(['index', 'comment', 'edit'], $result['module']); - - } - - public function testRest() - { - $request = Request::instance(); - Route::rest('read', ['GET', '/:id', 'look']); - Route::rest('create', ['GET', '/create', 'add']); - Route::rest(['read' => ['GET', '/:id', 'look'], 'create' => ['GET', '/create', 'add']]); - Route::resource('res', 'index/blog'); - $result = Route::check($request, 'res/create'); - $this->assertEquals(['index', 'blog', 'add'], $result['module']); - $result = Route::check($request, 'res/8'); - $this->assertEquals(['index', 'blog', 'look'], $result['module']); - - } - - public function testMixVar() - { - $request = Request::instance(); - Route::get('hello-', 'index/hello', [], ['name' => '\w+']); - $result = Route::check($request, 'hello-thinkphp'); - $this->assertEquals([null, 'index', 'hello'], $result['module']); - Route::get('hello-', 'index/hello', [], ['name' => '\w+', 'id' => '\d+']); - $result = Route::check($request, 'hello-thinkphp2016'); - $this->assertEquals([null, 'index', 'hello'], $result['module']); - Route::get('hello-/[:id]', 'index/hello', [], ['name' => '\w+', 'id' => '\d+']); - $result = Route::check($request, 'hello-thinkphp/2016'); - $this->assertEquals([null, 'index', 'hello'], $result['module']); - } - - public function testParseUrl() - { - $result = Route::parseUrl('hello'); - $this->assertEquals(['hello', null, null], $result['module']); - $result = Route::parseUrl('index/hello'); - $this->assertEquals(['index', 'hello', null], $result['module']); - $result = Route::parseUrl('index/hello?name=thinkphp'); - $this->assertEquals(['index', 'hello', null], $result['module']); - $result = Route::parseUrl('index/user/hello'); - $this->assertEquals(['index', 'user', 'hello'], $result['module']); - $result = Route::parseUrl('index/user/hello/name/thinkphp'); - $this->assertEquals(['index', 'user', 'hello'], $result['module']); - $result = Route::parseUrl('index-index-hello', '-'); - $this->assertEquals(['index', 'index', 'hello'], $result['module']); - } - - public function testCheckRoute() - { - Route::get('hello/:name', 'index/hello'); - Route::get('blog/:id', 'blog/read', [], ['id' => '\d+']); - $request = Request::instance(); - $this->assertEquals(false, Route::check($request, 'test/thinkphp')); - $this->assertEquals(false, Route::check($request, 'blog/thinkphp')); - $result = Route::check($request, 'blog/5'); - $this->assertEquals([null, 'blog', 'read'], $result['module']); - $result = Route::check($request, 'hello/thinkphp/abc/test'); - $this->assertEquals([null, 'index', 'hello'], $result['module']); - } - - public function testCheckRouteGroup() - { - $request = Request::instance(); - Route::pattern(['id' => '\d+']); - Route::pattern('name', '\w{6,25}'); - Route::group('group', [':id' => 'index/hello', ':name' => 'index/say']); - $this->assertEquals(false, Route::check($request, 'empty/think')); - $result = Route::check($request, 'group/think'); - $this->assertEquals(false, $result['module']); - $result = Route::check($request, 'group/10'); - $this->assertEquals([null, 'index', 'hello'], $result['module']); - $result = Route::check($request, 'group/thinkphp'); - $this->assertEquals([null, 'index', 'say'], $result['module']); - Route::group('group2', function () { - Route::group('group3', [':id' => 'index/hello', ':name' => 'index/say']); - Route::rule(':name', 'index/hello'); - Route::auto('index'); - }); - $result = Route::check($request, 'group2/thinkphp'); - $this->assertEquals([null, 'index', 'hello'], $result['module']); - $result = Route::check($request, 'group2/think'); - $this->assertEquals(['index', 'group2', 'think'], $result['module']); - $result = Route::check($request, 'group2/group3/thinkphp'); - $this->assertEquals([null, 'index', 'say'], $result['module']); - Route::group('group4', function () { - Route::group('group3', [':id' => 'index/hello', ':name' => 'index/say']); - Route::rule(':name', 'index/hello'); - Route::miss('index/__miss__'); - }); - $result = Route::check($request, 'group4/thinkphp'); - $this->assertEquals([null, 'index', 'hello'], $result['module']); - $result = Route::check($request, 'group4/think'); - $this->assertEquals([null, 'index', '__miss__'], $result['module']); - - Route::group(['prefix' => 'prefix/'], function () { - Route::rule('hello4/:name', 'hello'); - }); - Route::group(['prefix' => 'prefix/'], [ - 'hello4/:name' => 'hello', - ]); - $result = Route::check($request, 'hello4/thinkphp'); - $this->assertEquals([null, 'prefix', 'hello'], $result['module']); - Route::group('group5', [ - [':name', 'hello', ['method' => 'GET|POST']], - ':id' => 'hello', - ], ['prefix' => 'prefix/']); - $result = Route::check($request, 'group5/thinkphp'); - $this->assertEquals([null, 'prefix', 'hello'], $result['module']); - } - - public function testControllerRoute() - { - $request = Request::instance(); - Route::controller('controller', 'index/Blog'); - $result = Route::check($request, 'controller/info'); - $this->assertEquals(['index', 'Blog', 'getinfo'], $result['module']); - Route::setMethodPrefix('GET', 'read'); - Route::setMethodPrefix(['get' => 'read']); - Route::controller('controller', 'index/Blog'); - $result = Route::check($request, 'controller/phone'); - $this->assertEquals(['index', 'Blog', 'readphone'], $result['module']); - } - - public function testAliasRoute() - { - $request = Request::instance(); - Route::alias('alias', 'index/Alias'); - $result = Route::check($request, 'alias/info'); - $this->assertEquals('index/Alias/info', $result['module']); - } - - public function testRouteToModule() - { - $request = Request::instance(); - Route::get('hello/:name', 'index/hello'); - Route::get('blog/:id', 'blog/read', [], ['id' => '\d+']); - $this->assertEquals(false, Route::check($request, 'test/thinkphp')); - $this->assertEquals(false, Route::check($request, 'blog/thinkphp')); - $result = Route::check($request, 'hello/thinkphp'); - $this->assertEquals([null, 'index', 'hello'], $result['module']); - $result = Route::check($request, 'blog/5'); - $this->assertEquals([null, 'blog', 'read'], $result['module']); - } - - public function testRouteToController() - { - $request = Request::instance(); - Route::get('say/:name', '@index/hello'); - $this->assertEquals(['type' => 'controller', 'controller' => 'index/hello', 'var' => []], Route::check($request, 'say/thinkphp')); - } - - public function testRouteToMethod() - { - $request = Request::instance(); - Route::get('user/:name', '\app\index\service\User::get', [], ['name' => '\w+']); - Route::get('info/:name', '\app\index\model\Info@getInfo', [], ['name' => '\w+']); - $this->assertEquals(['type' => 'method', 'method' => '\app\index\service\User::get', 'var' => []], Route::check($request, 'user/thinkphp')); - $this->assertEquals(['type' => 'method', 'method' => ['\app\index\model\Info', 'getInfo'], 'var' => []], Route::check($request, 'info/thinkphp')); - } - - public function testRouteToRedirect() - { - $request = Request::instance(); - Route::get('art/:id', '/article/read/id/:id', [], ['id' => '\d+']); - $this->assertEquals(['type' => 'redirect', 'url' => '/article/read/id/8', 'status' => 301], Route::check($request, 'art/8')); - } - - public function testBind() - { - $request = Request::instance(); - Route::bind('index/blog'); - Route::get('blog/:id', 'index/blog/read'); - $result = Route::check($request, 'blog/10'); - $this->assertEquals(['index', 'blog', 'read'], $result['module']); - $result = Route::parseUrl('test'); - $this->assertEquals(['index', 'blog', 'test'], $result['module']); - - Route::bind('\app\index\controller', 'namespace'); - $this->assertEquals(['type' => 'method', 'method' => ['\app\index\controller\Blog', 'read'], 'var' => []], Route::check($request, 'blog/read')); - - Route::bind('\app\index\controller\Blog', 'class'); - $this->assertEquals(['type' => 'method', 'method' => ['\app\index\controller\Blog', 'read'], 'var' => []], Route::check($request, 'read')); - } - - public function testDomain() - { - $request = Request::create('http://subdomain.thinkphp.cn'); - Route::domain('subdomain.thinkphp.cn', 'sub?abc=test&status=1'); - $rules = Route::rules('GET'); - Route::checkDomain($request, $rules); - $this->assertEquals('sub', Route::getbind('module')); - $this->assertEquals('test', $_GET['abc']); - $this->assertEquals(1, $_GET['status']); - - Route::domain('subdomain.thinkphp.cn', '\app\index\controller'); - $rules = Route::rules('GET'); - Route::checkDomain($request, $rules); - $this->assertEquals('\app\index\controller', Route::getbind('namespace')); - - Route::domain(['subdomain.thinkphp.cn' => '@\app\index\controller\blog']); - $rules = Route::rules('GET'); - Route::checkDomain($request, $rules); - $this->assertEquals('\app\index\controller\blog', Route::getbind('class')); - - } -} diff --git a/thinkphp/tests/thinkphp/library/think/session/.gitignore b/thinkphp/tests/thinkphp/library/think/session/.gitignore deleted file mode 100644 index c96a04f0..00000000 --- a/thinkphp/tests/thinkphp/library/think/session/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore \ No newline at end of file diff --git a/thinkphp/tests/thinkphp/library/think/sessionTest.php b/thinkphp/tests/thinkphp/library/think/sessionTest.php deleted file mode 100644 index 5fd95f10..00000000 --- a/thinkphp/tests/thinkphp/library/think/sessionTest.php +++ /dev/null @@ -1,319 +0,0 @@ - -// +---------------------------------------------------------------------- - -/** - * Session测试 - * @author 大漠 - */ - -namespace tests\thinkphp\library\think; - -use think\Session; - -class sessionTest extends \PHPUnit_Framework_TestCase -{ - - /** - * - * @var \think\Session - */ - protected $object; - - /** - * Sets up the fixture, for example, opens a network connection. - * This method is called before a test is executed. - */ - protected function setUp() - { - // $this->object = new Session (); - // register_shutdown_function ( function () { - // } ); // 此功能无法取消,需要回调函数配合。 - set_exception_handler(function () {}); - set_error_handler(function () {}); - } - - /** - * Tears down the fixture, for example, closes a network connection. - * This method is called after a test is executed. - */ - protected function tearDown() - { - register_shutdown_function('think\Error::appShutdown'); - set_error_handler('think\Error::appError'); - set_exception_handler('think\Error::appException'); - } - - /** - * @covers think\Session::prefix - * - * @todo Implement testPrefix(). - */ - public function testPrefix() - { - Session::prefix(null); - Session::prefix('think_'); - - $this->assertEquals('think_', Session::prefix()); - } - - /** - * @covers think\Session::init - * - * @todo Implement testInit(). - */ - public function testInit() - { - Session::prefix(null); - $config = [ - // cookie 名称前缀 - 'prefix' => 'think_', - // cookie 保存时间 - 'expire' => 60, - // cookie 保存路径 - 'path' => '/path/to/test/session/', - // cookie 有效域名 - 'domain' => '.thinkphp.cn', - 'var_session_id' => 'sessionidtest', - 'id' => 'sess_8fhgkjuakhatbeg2fa14lo84q1', - 'name' => 'session_name', - 'use_trans_sid' => '1', - 'use_cookies' => '1', - 'cache_limiter' => '60', - 'cache_expire' => '60', - 'type' => '', // memcache - 'namespace' => '\\think\\session\\driver\\', // ? - 'auto_start' => '1', - ]; - - $_REQUEST[$config['var_session_id']] = $config['id']; - Session::init($config); - - // 开始断言 - $this->assertEquals($config['prefix'], Session::prefix()); - $this->assertEquals($config['id'], $_REQUEST[$config['var_session_id']]); - $this->assertEquals($config['name'], session_name()); - - $this->assertEquals($config['path'], session_save_path()); - $this->assertEquals($config['use_cookies'], ini_get('session.use_cookies')); - $this->assertEquals($config['domain'], ini_get('session.cookie_domain')); - $this->assertEquals($config['expire'], ini_get('session.gc_maxlifetime')); - $this->assertEquals($config['expire'], ini_get('session.cookie_lifetime')); - - $this->assertEquals($config['cache_limiter'], session_cache_limiter($config['cache_limiter'])); - $this->assertEquals($config['cache_expire'], session_cache_expire($config['cache_expire'])); - - // 检测分支 - $_REQUEST[$config['var_session_id']] = null; - session_write_close(); - session_destroy(); - - Session::init($config); - - // 测试auto_start - // PHP_SESSION_DISABLED - // PHP_SESSION_NONE - // PHP_SESSION_ACTIVE - // session_status() - if (strstr(PHP_VERSION, 'hhvm')) { - $this->assertEquals('', ini_get('session.auto_start')); - } else { - $this->assertEquals(0, ini_get('session.auto_start')); - } - - $this->assertEquals($config['use_trans_sid'], ini_get('session.use_trans_sid')); - - Session::init($config); - $this->assertEquals($config['id'], session_id()); - } - - /** - * 单独重现异常 - * @expectedException \think\Exception - */ - public function testException() - { - $config = [ - // cookie 名称前缀 - 'prefix' => 'think_', - // cookie 保存时间 - 'expire' => 0, - // cookie 保存路径 - 'path' => '/path/to/test/session/', - // cookie 有效域名 - 'domain' => '.thinkphp.cn', - 'var_session_id' => 'sessionidtest', - 'id' => 'sess_8fhgkjuakhatbeg2fa14lo84q1', - 'name' => 'session_name', - 'use_trans_sid' => '1', - 'use_cookies' => '1', - 'cache_limiter' => '60', - 'cache_expire' => '60', - 'type' => '\\think\\session\\driver\\Memcache', // - 'auto_start' => '1', - ]; - - // 测试session驱动是否存在 - // @expectedException 异常类名 - $this->setExpectedException('\think\exception\ClassNotFoundException', 'error session handler'); - - Session::init($config); - } - - /** - * @covers think\Session::set - * - * @todo Implement testSet(). - */ - public function testSet() - { - Session::prefix(null); - Session::set('sessionname', 'sessionvalue'); - $this->assertEquals('sessionvalue', $_SESSION['sessionname']); - - Session::set('sessionnamearr.subname', 'sessionvalue'); - $this->assertEquals('sessionvalue', $_SESSION['sessionnamearr']['subname']); - - Session::set('sessionnameper', 'sessionvalue', 'think_'); - $this->assertEquals('sessionvalue', $_SESSION['think_']['sessionnameper']); - - Session::set('sessionnamearrper.subname', 'sessionvalue', 'think_'); - $this->assertEquals('sessionvalue', $_SESSION['think_']['sessionnamearrper']['subname']); - } - - /** - * @covers think\Session::get - * - * @todo Implement testGet(). - */ - public function testGet() - { - Session::prefix(null); - - Session::set('sessionnameget', 'sessionvalue'); - $this->assertEquals(Session::get('sessionnameget'), $_SESSION['sessionnameget']); - - Session::set('sessionnamegetarr.subname', 'sessionvalue'); - $this->assertEquals(Session::get('sessionnamegetarr.subname'), $_SESSION['sessionnamegetarr']['subname']); - - Session::set('sessionnamegetarrperall', 'sessionvalue', 'think_'); - $this->assertEquals(Session::get('', 'think_')['sessionnamegetarrperall'], $_SESSION['think_']['sessionnamegetarrperall']); - - Session::set('sessionnamegetper', 'sessionvalue', 'think_'); - $this->assertEquals(Session::get('sessionnamegetper', 'think_'), $_SESSION['think_']['sessionnamegetper']); - - Session::set('sessionnamegetarrper.subname', 'sessionvalue', 'think_'); - $this->assertEquals(Session::get('sessionnamegetarrper.subname', 'think_'), $_SESSION['think_']['sessionnamegetarrper']['subname']); - } - - public function testPull() - { - Session::prefix(null); - Session::set('sessionnamedel', 'sessionvalue'); - $this->assertEquals('sessionvalue', Session::pull('sessionnameget')); - $this->assertNull(Session::get('sessionnameget')); - } - - /** - * @covers think\Session::delete - * - * @todo Implement testDelete(). - */ - public function testDelete() - { - Session::prefix(null); - Session::set('sessionnamedel', 'sessionvalue'); - Session::delete('sessionnamedel'); - $this->assertEmpty($_SESSION['sessionnamedel']); - - Session::set('sessionnamedelarr.subname', 'sessionvalue'); - Session::delete('sessionnamedelarr.subname'); - $this->assertEmpty($_SESSION['sessionnamedelarr']['subname']); - - Session::set('sessionnamedelper', 'sessionvalue', 'think_'); - Session::delete('sessionnamedelper', 'think_'); - $this->assertEmpty($_SESSION['think_']['sessionnamedelper']); - - Session::set('sessionnamedelperarr.subname', 'sessionvalue', 'think_'); - Session::delete('sessionnamedelperarr.subname', 'think_'); - $this->assertEmpty($_SESSION['think_']['sessionnamedelperarr']['subname']); - } - - /** - * @covers think\Session::clear - * - * @todo Implement testClear(). - */ - public function testClear() - { - Session::prefix(null); - - Session::set('sessionnameclsper', 'sessionvalue1', 'think_'); - Session::clear('think_'); - $this->assertNull($_SESSION['think_']); - - Session::set('sessionnameclsper', 'sessionvalue1', 'think_'); - Session::clear(); - $this->assertEmpty($_SESSION); - } - - /** - * @covers think\Session::has - * - * @todo Implement testHas(). - */ - public function testHas() - { - Session::prefix(null); - Session::set('sessionnamehas', 'sessionvalue'); - $this->assertTrue(Session::has('sessionnamehas')); - - Session::set('sessionnamehasarr.subname', 'sessionvalue'); - $this->assertTrue(Session::has('sessionnamehasarr.subname')); - - Session::set('sessionnamehasper', 'sessionvalue', 'think_'); - $this->assertTrue(Session::has('sessionnamehasper', 'think_')); - - Session::set('sessionnamehasarrper.subname', 'sessionvalue', 'think_'); - $this->assertTrue(Session::has('sessionnamehasarrper.subname', 'think_')); - } - - /** - * @covers think\Session::pause - * - * @todo Implement testPause(). - */ - public function testPause() - { - Session::pause(); - } - - /** - * @covers think\Session::start - * - * @todo Implement testStart(). - */ - public function testStart() - { - Session::start(); - } - - /** - * @covers think\Session::destroy - * - * @todo Implement testDestroy(). - */ - public function testDestroy() - { - Session::set('sessionnamedestroy', 'sessionvalue'); - Session::destroy(); - $this->assertEmpty($_SESSION['sessionnamedestroy']); - } -} diff --git a/thinkphp/tests/thinkphp/library/think/template/driver/.gitignore b/thinkphp/tests/thinkphp/library/think/template/driver/.gitignore deleted file mode 100644 index c96a04f0..00000000 --- a/thinkphp/tests/thinkphp/library/think/template/driver/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore \ No newline at end of file diff --git a/thinkphp/tests/thinkphp/library/think/template/taglib/cxTest.php b/thinkphp/tests/thinkphp/library/think/template/taglib/cxTest.php deleted file mode 100644 index 8aee392f..00000000 --- a/thinkphp/tests/thinkphp/library/think/template/taglib/cxTest.php +++ /dev/null @@ -1,575 +0,0 @@ - -// +---------------------------------------------------------------------- - -/** - * 模板测试 - * @author Haotong Lin - */ - -namespace tests\thinkphp\library\think\tempplate\taglib; - -use think\Template; -use think\template\taglib\Cx; - -class cxTest extends \PHPUnit_Framework_TestCase -{ - public function testPhp() - { - $template = new template(); - $cx = new Cx($template); - - $content = << -EOF; - $cx->parseTag($content); - $this->assertEquals($content, $data); - } - - public function testVolist() - { - $template = new template(); - $cx = new Cx($template); - - $content = <<\$vo): \$mod = (\$key % 2 );++\$key;?> - - -EOF; - $cx->parseTag($content); - $this->assertEquals($data, $content); - - $content = <<display($content, ['list' => [1, 2, 3, 4, 5]]); - $this->expectOutputString('234'); - } - - public function testForeach() - { - $template = new template(); - $cx = new Cx($template); - - $content = <<\$val} - -{/foreach} -EOF; - $data = <<\$val): ?> - - -EOF; - $cx->parseTag($content); - $this->assertEquals($content, $data); - - $content = <<\$val): ?> - - -EOF; - $cx->parseTag($content); - $this->assertEquals($content, $data); - - $content = <<display($content); - $this->expectOutputString('234'); - } - - public function testIf() - { - $template = new template(); - $cx = new Cx($template); - - $content = << -one - -two - -default - -EOF; - $cx->parseTag($content); - $this->assertEquals($content, $data); - } - - public function testSwitch() - { - $template = new template(); - $cx = new Cx($template); - - $content = << - -a - - -b - - -d - - -default - -EOF; - $cx->parseTag($content); - $this->assertEquals($content, $data); - } - - public function testCompare() - { - $template = new template(); - $cx = new Cx($template); - - $content = << -default - -EOF; - $cx->parseTag($content); - $this->assertEquals($content, $data); - - $content = << -default - -EOF; - $cx->parseTag($content); - $this->assertEquals($content, $data); - - $content = << -default - -EOF; - $cx->parseTag($content); - $this->assertEquals($content, $data); - - $content = << -default - -EOF; - $cx->parseTag($content); - $this->assertEquals($content, $data); - - $content = << '0'): ?> -default - -EOF; - $cx->parseTag($content); - $this->assertEquals($content, $data); - - $content = <<= '0'): ?> -default - -EOF; - $cx->parseTag($content); - $this->assertEquals($content, $data); - - $content = << -default - -EOF; - $cx->parseTag($content); - $this->assertEquals($content, $data); - - $content = << -default - -EOF; - $cx->parseTag($content); - $this->assertEquals($content, $data); - - $content = << -default - -EOF; - $cx->parseTag($content); - $this->assertEquals($content, $data); - - $content = << -default - -EOF; - $cx->parseTag($content); - $this->assertEquals($content, $data); - - } - - public function testRange() - { - $template = new template(); - $cx = new Cx($template); - - $content = << -default - -EOF; - $cx->parseTag($content); - $this->assertEquals($content, $data); - - $content = << -default - -EOF; - $cx->parseTag($content); - $this->assertEquals($content, $data); - - $content = <<display($content); - $this->expectOutputString('yesno'); - } - - public function testPresent() - { - $template = new template(); - $cx = new Cx($template); - - $content = << -default - -EOF; - $cx->parseTag($content); - $this->assertEquals($content, $data); - - $content = << -default - -EOF; - $cx->parseTag($content); - $this->assertEquals($content, $data); - } - - public function testEmpty() - { - $template = new template(); - $cx = new Cx($template); - - $content = <<isEmpty())): ?> -default - -EOF; - $cx->parseTag($content); - $this->assertEquals($content, $data); - - $content = <<isEmpty()))): ?> -default - -EOF; - $cx->parseTag($content); - $this->assertEquals($content, $data); - } - - public function testDefined() - { - $template = new template(); - $cx = new Cx($template); - - $content = << -default - -EOF; - $cx->parseTag($content); - $this->assertEquals($content, $data); - - $content = << -default - -EOF; - $cx->parseTag($content); - $this->assertEquals($content, $data); - } - - public function testImport() - { - $template = new template(); - $cx = new Cx($template); - - $content = << -EOF; - $cx->parseTag($content); - $this->assertEquals($content, $data); - - $content = << -EOF; - $cx->parseTag($content); - $this->assertEquals($content, $data); - - $content = << -EOF; - $cx->parseTag($content); - $this->assertEquals($content, $data); - } - - public function testAssign() - { - $template = new template(); - $cx = new Cx($template); - - $content = << -EOF; - $cx->parseTag($content); - $this->assertEquals($content, $data); - - $content = << -EOF; - $cx->parseTag($content); - $this->assertEquals($content, $data); - } - - public function testDefine() - { - $template = new template(); - $cx = new Cx($template); - - $content = << -EOF; - $cx->parseTag($content); - $this->assertEquals($content, $data); - - $content = << -EOF; - $cx->parseTag($content); - $this->assertEquals($content, $data); - } - - public function testFor() - { - $template = new template(); - - $content = <<display($content); - $this->expectOutputString('123456789'); - } - public function testUrl() - { - $template = new template(); - $content = <<display($content); - $this->expectOutputString(\think\Url::build('Index/index')); - } - - public function testFunction() - { - $template = new template(); - $data = [ - 'list' => ['language' => 'php', 'version' => ['5.4', '5.5']], - 'a' => '[', - 'b' => ']', - ]; - - $content = <<\$val} -{if is_array(\$val)} -{~\$func(\$val)} -{else} -{if !is_numeric(\$key)} -{\$key.':'.\$val.','} -{else} -{\$a.\$val.\$b} -{/if} -{/if} -{/foreach} -{/function} -EOF; - $template->display($content, $data); - $this->expectOutputString("language:php,[5.4][5.5]"); - } -} diff --git a/thinkphp/tests/thinkphp/library/think/templateTest.php b/thinkphp/tests/thinkphp/library/think/templateTest.php deleted file mode 100644 index 27e49dbb..00000000 --- a/thinkphp/tests/thinkphp/library/think/templateTest.php +++ /dev/null @@ -1,414 +0,0 @@ - -// +---------------------------------------------------------------------- - -/** - * 模板测试 - * @author oldrind - */ - -namespace tests\thinkphp\library\think; - -use think\Template; - -class templateTest extends \PHPUnit_Framework_TestCase -{ - public function testVar() - { - $template = new Template(); - - $content = << -EOF; - - $template->parse($content); - $this->assertEquals($data, $content); - - $content = << -EOF; - - $template->parse($content); - $this->assertEquals($data, $content); - - $content = << -EOF; - - $template->parse($content); - $this->assertEquals($data, $content); - - $content = << -EOF; - - $template->parse($content); - $this->assertEquals($data, $content); - - $content = << -EOF; - - $template->parse($content); - $this->assertEquals($data, $content); - - $content = << -EOF; - - $template->parse($content); - $this->assertEquals($data, $content); - - $content = << -EOF; - - $template->parse($content); - $this->assertEquals($data, $content); - - $content = << -EOF; - - $template->parse($content); - $this->assertEquals($data, $content); - - $content = << -EOF; - - $template->parse($content); - $this->assertEquals($data, $content); - - $content = << -EOF; - - $template->parse($content); - $this->assertEquals($data, $content); - - $content = << -EOF; - - $template->parse($content); - $this->assertEquals($data, $content); - - $content = << -EOF; - - $template->parse($content); - $this->assertEquals($data, $content); - - $content = <<parse($content); - $this->assertEquals($data, $content); - - $content = <<parse($content); - $this->assertEquals($data, $content); - - } - - public function testVarFunction() - { - $template = new Template(); - - $content = << -EOF; - - $template->parse($content); - $this->assertEquals($data, $content); - - $content = << -EOF; - - $template->parse($content); - $this->assertEquals($data, $content); - - $content = << - -EOF; - - $template->parse($content); - $this->assertEquals($data, $content); - } - - public function testVarIdentify() - { - $config['tpl_begin'] = '<#'; - $config['tpl_end'] = '#>'; - $config['tpl_var_identify'] = ''; - $template = new Template($config); - - $content = << -EOF; - $data = <<a)) ? (is_array(\$info)?\$info['a']:\$info->a) : 'test'; ?> -EOF; - - $template->parse($content); - $this->assertEquals($data, $content); - - $content = << -EOF; - $data = <<a)) echo 'test'; ?> -EOF; - - $template->parse($content); - $this->assertEquals($data, $content); - - $content = << -EOF; - $data = <<a)==(is_array(\$info)?\$info['b']:\$info->b)) echo 'test'; ?> -EOF; - - $template->parse($content); - $this->assertEquals($data, $content); - - $content = << -EOF; - $data = <<a) ?: 'test')?'yes':'no'; ?> -EOF; - $template->parse($content); - $this->assertEquals($data, $content); - - $template2 = new Template(); - $template2->tpl_var_identify = 'obj'; - $content = <<b)?'yes':'no'; ?> -EOF; - $template2->parse($content); - $this->assertEquals($data, $content); - } - - public function testThinkVar() - { - $config['tpl_begin'] = '{'; - $config['tpl_end'] = '}'; - $template = new Template($config); - - $_SERVER['SERVER_NAME'] = 'server_name'; - $_GET['action'] = 'action'; - $_POST['action'] = 'action'; - $_COOKIE['name'] = 'name'; - $_SESSION['action'] = ['name' => 'name']; - define('SITE_NAME', 'site_name'); - - $content = << -{\$Think.GET.action}
-{\$Think.POST.action}
-{\$Think.COOKIE.action}
-{\$Think.COOKIE.action.name}
-{\$Think.SESSION.action}
-{\$Think.SESSION.action.name}
-{\$Think.ENV.OS}
-{\$Think.REQUEST.action}
-{\$Think.CONST.SITE_NAME}
-{\$Think.LANG.action}
-{\$Think.CONFIG.action.name}
-{\$Think.NOW}
-{\$Think.VERSION}
-{\$Think.LDELIM}
-{\$Think.RDELIM}
-{\$Think.SITE_NAME}
-{\$Think.SITE.URL} -EOF; - $data = <<server('SERVER_NAME'); ?>
-get('action'); ?>
-post('action'); ?>
-
-
-
-
-env('OS'); ?>
-request('action'); ?>
-
-
-
-
-
-
-
-
- -EOF; - $template->parse($content); - $this->assertEquals($data, $content); - } - - public function testFetch() - { - $template = new Template(); - $template->assign('name', 'name'); - $config = [ - 'strip_space' => true, - 'view_path' => dirname(__FILE__) . DS, - 'cache_id' => '__CACHE_ID__', - 'display_cache' => true, - ]; - $data = ['name' => 'value']; - $template->layout('layout')->fetch('display', $data, $config); - $this->expectOutputString('value'); - } - - public function testDisplay() - { - $config['view_path'] = dirname(__FILE__) . DS; - $config['view_suffix'] = '.html'; - $config['layout_on'] = true; - $config['layout_name'] = 'layout'; - $template = new Template($config); - $files = ['extend' => 'extend', 'include' => 'include']; - $template->assign('files', $files); - $template->assign('user', ['name' => 'name', 'account' => 100]); - $template->assign('message', 'message'); - $template->assign('info', ['value' => 'value']); - - $content = << -header -
- -value: - -main - - - side - - -value: - message{\$message} - - - mainbody - - - - {\$name} - - php code
- -EOF; - $template->display($content); - $this->expectOutputString($content2); -// $template->parse($content); - // var_dump($content); - } - - public function testVarAssign() - { - $template = new Template(); - $template->assign('name', 'value'); - $value = $template->get('name'); - $this->assertEquals('value', $value); - } - - public function testVarGet() - { - $template = new Template(); - $data = ['a' => 'a', 'b' => 'b']; - $template->assign($data); - $this->assertEquals($data, $template->get()); - } - - public function testIsCache() - { - $template = new Template(['cache_id' => '__CACHE_ID__', 'display_cache' => true]); - $this->assertTrue($template->isCache('__CACHE_ID__')); - $template->display_cache = false; - $this->assertTrue(!$template->isCache('__CACHE_ID__')); - } -} diff --git a/thinkphp/tests/thinkphp/library/think/urlTest.php b/thinkphp/tests/thinkphp/library/think/urlTest.php deleted file mode 100644 index 1cb64084..00000000 --- a/thinkphp/tests/thinkphp/library/think/urlTest.php +++ /dev/null @@ -1,127 +0,0 @@ - -// +---------------------------------------------------------------------- - -/** - * Url测试 - * @author liu21st - */ - -namespace tests\thinkphp\library\think; - -use think\Config; -use think\Route; -use think\Url; - -class urlTest extends \PHPUnit_Framework_TestCase -{ - - public function setUp() - { - Route::rules(['get' => [], - 'post' => [], - 'put' => [], - 'delete' => [], - 'patch' => [], - 'head' => [], - 'options' => [], - '*' => [], - 'alias' => [], - 'domain' => [], - 'pattern' => [], - 'name' => []]); - Route::name([]); - } - - public function testBuildModule() - { - - Route::get('blog/:name', 'index/blog'); - Route::get('blog/:id', 'index/blog'); - Config::set('pathinfo_depr', '/'); - Config::set('url_html_suffix', ''); - - $this->assertEquals('/blog/thinkphp', Url::build('index/blog?name=thinkphp')); - $this->assertEquals('/blog/thinkphp.html', Url::build('index/blog', 'name=thinkphp', 'html')); - $this->assertEquals('/blog/10', Url::build('index/blog?id=10')); - $this->assertEquals('/blog/10.html', Url::build('index/blog', 'id=10', 'html')); - - Route::get('item-', 'blog/item', [], ['name' => '\w+', 'id' => '\d+']); - $this->assertEquals('/item-thinkphp', Url::build('blog/item?name=thinkphp')); - $this->assertEquals('/item-thinkphp2016', Url::build('blog/item?name=thinkphp&id=2016')); - } - - public function testBuildController() - { - Config::set('url_html_suffix', ''); - Route::get('blog/:id', '@index/blog/read'); - $this->assertEquals('/blog/10.html', Url::build('@index/blog/read', 'id=10', 'html')); - - Route::get('foo/bar', '@foo/bar/index'); - $this->assertEquals('/foo/bar', Url::build('@foo/bar/index')); - - Route::get('foo/bar/baz', '@foo/bar.BAZ/index'); - $this->assertEquals('/foo/bar/baz', Url::build('@foo/bar.BAZ/index')); - } - - public function testBuildMethod() - { - Route::get('blog/:id', '\app\index\controller\blog@read'); - $this->assertEquals('/blog/10.html', Url::build('\app\index\controller\blog@read', 'id=10', 'html')); - } - - public function testBuildRoute() - { - Route::get('blog/:id', 'index/blog'); - Config::set('url_html_suffix', 'shtml'); - $this->assertNotEquals('/blog/10.html', Url::build('/blog/10')); - $this->assertEquals('/blog/10.shtml', Url::build('/blog/10')); - } - - public function testBuildNameRoute() - { - Route::get(['name', 'blog/:id'], 'index/blog'); - $this->assertEquals([['blog/:id', ['id' => 1], null, null]], Route::name('name')); - Config::set('url_html_suffix', 'shtml'); - $this->assertEquals('/blog/10.shtml', Url::build('name?id=10')); - } - - public function testBuildAnchor() - { - Route::get('blog/:id', 'index/blog'); - Config::set('url_html_suffix', 'shtml'); - $this->assertEquals('/blog/10.shtml#detail', Url::build('index/blog#detail', 'id=10')); - - Config::set('url_common_param', true); - $this->assertEquals('/blog/10.shtml?foo=bar#detail', Url::build('index/blog#detail', "id=10&foo=bar")); - } - - public function testBuildDomain() - { - Config::set('url_domain_deploy', true); - Route::domain('subdomain.thinkphp.cn', 'admin'); - $this->assertEquals('http://subdomain.thinkphp.cn/blog/10.shtml', Url::build('/blog/10')); - Route::domain('subdomain.thinkphp.cn', [ - 'hello/:name' => 'index/hello', - ]); - $this->assertEquals('http://subdomain.thinkphp.cn/hello/thinkphp.shtml', Url::build('index/hello?name=thinkphp')); - } - - public function testRoot() - { - Config::set('url_domain_deploy', false); - Config::set('url_common_param', false); - Url::root('/index.php'); - Route::get('blog/:id', 'index/blog/read'); - Config::set('url_html_suffix', 'shtml'); - $this->assertEquals('/index.php/blog/10/name/thinkphp.shtml', Url::build('index/blog/read?id=10&name=thinkphp')); - - } -} diff --git a/thinkphp/tests/thinkphp/library/think/validateTest.php b/thinkphp/tests/thinkphp/library/think/validateTest.php deleted file mode 100644 index 081a6f2b..00000000 --- a/thinkphp/tests/thinkphp/library/think/validateTest.php +++ /dev/null @@ -1,200 +0,0 @@ - -// +---------------------------------------------------------------------- - -/** - * Validate类测试 - */ - -namespace tests\thinkphp\library\think; - -use think\File; -use think\Validate; - -class validateTest extends \PHPUnit_Framework_TestCase -{ - - public function testCheck() - { - $rule = [ - 'name' => 'require|max:25', - 'age' => 'number|between:1,120', - 'email' => 'email', - ]; - $msg = [ - 'name.require' => '名称必须', - 'name.max' => '名称最多不能超过25个字符', - 'age.number' => '年龄必须是数字', - 'age.between' => '年龄只能在1-120之间', - 'email' => '邮箱格式错误', - ]; - $data = [ - 'name' => 'thinkphp', - 'age' => 10, - 'email' => 'thinkphp@qq.com', - ]; - $validate = new Validate($rule, $msg); - $result = $validate->check($data); - $this->assertEquals(true, $result); - } - - public function testRule() - { - $rule = [ - 'name' => 'require|method:get|alphaNum|max:25|expire:2016-1-1,2026-1-1', - 'account' => 'requireIf:name,thinkphp|alphaDash|min:4|length:4,30', - 'age' => 'number|between:1,120', - 'email' => 'requireWith:name|email', - 'host' => 'activeUrl|activeUrl:A', - 'url' => 'url', - 'ip' => 'ip|ip:ipv4', - 'score' => 'float|gt:60|notBetween:90,100|notIn:70,80|lt:100|elt:100|egt:60', - 'status' => 'integer|in:0,1,2', - 'begin_time' => 'after:2016-3-18', - 'end_time' => 'before:2016-10-01', - 'info' => 'require|array|length:4|max:5|min:2', - 'info.name' => 'require|length:8|alpha|same:thinkphp', - 'value' => 'same:100|different:status', - 'bool' => 'boolean', - 'title' => 'chsAlpha', - 'city' => 'chs', - 'nickname' => 'chsDash', - 'aliasname' => 'chsAlphaNum', - 'file' => 'file|fileSize:20480', - 'image' => 'image|fileMime:image/png|image:80,80,png', - 'test' => 'test', - ]; - $data = [ - 'name' => 'thinkphp', - 'account' => 'liuchen', - 'age' => 10, - 'email' => 'thinkphp@qq.com', - 'host' => 'thinkphp.cn', - 'url' => 'http://thinkphp.cn/topic', - 'ip' => '114.34.54.5', - 'score' => '89.15', - 'status' => 1, - 'begin_time' => '2016-3-20', - 'end_time' => '2016-5-1', - 'info' => [1, 2, 3, 'name' => 'thinkphp'], - 'zip' => '200000', - 'date' => '16-3-8', - 'ok' => 'yes', - 'value' => 100, - 'bool' => true, - 'title' => '流年ThinkPHP', - 'city' => '上海', - 'nickname' => '流年ThinkPHP_2016', - 'aliasname' => '流年Think2016', - 'file' => new File(THINK_PATH . 'base.php'), - 'image' => new File(THINK_PATH . 'logo.png'), - 'test' => 'test', - ]; - $validate = new Validate($rule); - $validate->extend('test', function ($value) {return 'test' == $value ? true : false;}); - $validate->rule('zip', '/^\d{6}$/'); - $validate->rule([ - 'ok' => 'require|accepted', - 'date' => 'date|dateFormat:y-m-d', - ]); - $result = $validate->batch()->check($data); - $this->assertEquals(true, $result); - } - - public function testMsg() - { - $validate = new Validate(); - $validate->message('name.require', '名称必须'); - $validate->message([ - 'name.require' => '名称必须', - 'name.max' => '名称最多不能超过25个字符', - 'age.number' => '年龄必须是数字', - 'age.between' => '年龄只能在1-120之间', - 'email' => '邮箱格式错误', - ]); - } - - public function testMake() - { - $rule = [ - 'name' => 'require|max:25', - 'age' => 'number|between:1,120', - 'email' => 'email', - ]; - $msg = [ - 'name.require' => '名称必须', - 'name.max' => '名称最多不能超过25个字符', - 'age.number' => '年龄必须是数字', - 'age.between' => '年龄只能在1-120之间', - 'email' => '邮箱格式错误', - ]; - $validate = Validate::make($rule, $msg); - } - - public function testExtend() - { - $validate = new Validate(['name' => 'check:1']); - $validate->extend('check', function ($value, $rule) {return $rule == $value ? true : false;}); - $validate->extend(['check' => function ($value, $rule) {return $rule == $value ? true : false;}]); - $data = ['name' => 1]; - $result = $validate->check($data); - $this->assertEquals(true, $result); - } - - public function testScene() - { - $rule = [ - 'name' => 'require|max:25', - 'age' => 'number|between:1,120', - 'email' => 'email', - ]; - $msg = [ - 'name.require' => '名称必须', - 'name.max' => '名称最多不能超过25个字符', - 'age.number' => '年龄必须是数字', - 'age.between' => '年龄只能在1-120之间', - 'email' => '邮箱格式错误', - ]; - $data = [ - 'name' => 'thinkphp', - 'age' => 10, - 'email' => 'thinkphp@qq.com', - ]; - $validate = new Validate($rule); - $validate->scene(['edit' => ['name', 'age']]); - $validate->scene('edit', ['name', 'age']); - $validate->scene('edit'); - $result = $validate->check($data); - $this->assertEquals(true, $result); - } - - public function testSetTypeMsg() - { - $rule = [ - 'name|名称' => 'require|max:25', - 'age' => 'number|between:1,120', - 'email' => 'email', - ['sex', 'in:1,2', '性别错误'], - ]; - $data = [ - 'name' => '', - 'age' => 10, - 'email' => 'thinkphp@qq.com', - 'sex' => '3', - ]; - $validate = new Validate($rule); - $validate->setTypeMsg('require', ':attribute必须'); - $validate->setTypeMsg(['require' => ':attribute必须']); - $result = $validate->batch()->check($data); - $this->assertFalse($result); - $this->assertEquals(['name' => '名称必须', 'sex' => '性别错误'], $validate->getError()); - } - -} diff --git a/thinkphp/tests/thinkphp/library/think/view/driver/.gitignore b/thinkphp/tests/thinkphp/library/think/view/driver/.gitignore deleted file mode 100644 index c96a04f0..00000000 --- a/thinkphp/tests/thinkphp/library/think/view/driver/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore \ No newline at end of file diff --git a/thinkphp/tests/thinkphp/library/think/view/theme/index/template.html b/thinkphp/tests/thinkphp/library/think/view/theme/index/template.html deleted file mode 100644 index 5f4548be..00000000 --- a/thinkphp/tests/thinkphp/library/think/view/theme/index/template.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - Document - - - - - diff --git a/thinkphp/tests/thinkphp/library/think/viewTest.php b/thinkphp/tests/thinkphp/library/think/viewTest.php deleted file mode 100644 index 5bb7de16..00000000 --- a/thinkphp/tests/thinkphp/library/think/viewTest.php +++ /dev/null @@ -1,76 +0,0 @@ - -// +---------------------------------------------------------------------- - -/** - * view测试 - * @author mahuan - */ - -namespace tests\thinkphp\library\think; - -class viewTest extends \PHPUnit_Framework_TestCase -{ - - /** - * 句柄测试 - * @return mixed - * @access public - */ - public function testGetInstance() - { - \think\Cookie::get('a'); - $view_instance = \think\View::instance(); - $this->assertInstanceOf('\think\view', $view_instance, 'instance方法返回错误'); - } - - /** - * 测试变量赋值 - * @return mixed - * @access public - */ - public function testAssign() - { - $view_instance = \think\View::instance(); - $view_instance->key = 'value'; - $this->assertTrue(isset($view_instance->key)); - $this->assertEquals('value', $view_instance->key); - $data = $view_instance->assign(array('key' => 'value')); - $data = $view_instance->assign('key2', 'value2'); - //测试私有属性 - $expect_data = array('key' => 'value', 'key2' => 'value2'); - $this->assertAttributeEquals($expect_data, 'data', $view_instance); - } - - /** - * 测试引擎设置 - * @return mixed - * @access public - */ - public function testEngine() - { - $view_instance = \think\View::instance(); - $data = $view_instance->engine('php'); - $data = $view_instance->engine(['type' => 'php', 'view_path' => '', 'view_suffix' => '.php', 'view_depr' => DS]); - $php_engine = new \think\view\driver\Php(['view_path' => '', 'view_suffix' => '.php', 'view_depr' => DS]); - $this->assertAttributeEquals($php_engine, 'engine', $view_instance); - //测试模板引擎驱动 - $data = $view_instance->engine(['type' => 'think', 'view_path' => '', 'view_suffix' => '.html', 'view_depr' => DS]); - $think_engine = new \think\view\driver\Think(['view_path' => '', 'view_suffix' => '.html', 'view_depr' => DS]); - $this->assertAttributeEquals($think_engine, 'engine', $view_instance); - } - - public function testReplace() - { - $view_instance = \think\View::instance(); - $view_instance->replace('string', 'replace')->display('string'); - } - -} diff --git a/thinkphp/tests/thinkphp/library/traits/controller/.gitignore b/thinkphp/tests/thinkphp/library/traits/controller/.gitignore deleted file mode 100644 index c96a04f0..00000000 --- a/thinkphp/tests/thinkphp/library/traits/controller/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore \ No newline at end of file diff --git a/thinkphp/tests/thinkphp/library/traits/model/.gitignore b/thinkphp/tests/thinkphp/library/traits/model/.gitignore deleted file mode 100644 index c96a04f0..00000000 --- a/thinkphp/tests/thinkphp/library/traits/model/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore \ No newline at end of file diff --git a/thinkphp/tpl/dispatch_jump.tpl b/thinkphp/tpl/dispatch_jump.tpl index 18ee01bd..583376bb 100644 --- a/thinkphp/tpl/dispatch_jump.tpl +++ b/thinkphp/tpl/dispatch_jump.tpl @@ -2,6 +2,7 @@ + 跳转提示 ",rE:!0,sL:["css","xml"]}},{cN:"tag",b:"|$)",e:">",k:{name:"script"},c:[r],starts:{e:"",rE:!0,sL:["actionscript","javascript","handlebars","xml"]}},{cN:"meta",v:[{b:/<\?xml/,e:/\?>/,r:10},{b:/<\?\w+/,e:/\?>/}]},{cN:"tag",b:"",c:[{cN:"name",b:/[^\/><\s]+/,r:0},r]}]}}),e.registerLanguage("asciidoc",function(e){return{aliases:["adoc"],c:[e.C("^/{4,}\\n","\\n/{4,}$",{r:10}),e.C("^//","$",{r:0}),{cN:"title",b:"^\\.\\w.*$"},{b:"^[=\\*]{4,}\\n",e:"\\n^[=\\*]{4,}$",r:10},{cN:"section",r:10,v:[{b:"^(={1,5}) .+?( \\1)?$"},{b:"^[^\\[\\]\\n]+?\\n[=\\-~\\^\\+]{2,}$"}]},{cN:"meta",b:"^:.+?:",e:"\\s",eE:!0,r:10},{cN:"meta",b:"^\\[.+?\\]$",r:0},{cN:"quote",b:"^_{4,}\\n",e:"\\n_{4,}$",r:10},{cN:"code",b:"^[\\-\\.]{4,}\\n",e:"\\n[\\-\\.]{4,}$",r:10},{b:"^\\+{4,}\\n",e:"\\n\\+{4,}$",c:[{b:"<",e:">",sL:"xml",r:0}],r:10},{cN:"bullet",b:"^(\\*+|\\-+|\\.+|[^\\n]+?::)\\s+"},{cN:"symbol",b:"^(NOTE|TIP|IMPORTANT|WARNING|CAUTION):\\s+",r:10},{cN:"strong",b:"\\B\\*(?![\\*\\s])",e:"(\\n{2}|\\*)",c:[{b:"\\\\*\\w",r:0}]},{cN:"emphasis",b:"\\B'(?!['\\s])",e:"(\\n{2}|')",c:[{b:"\\\\'\\w",r:0}],r:0},{cN:"emphasis",b:"_(?![_\\s])",e:"(\\n{2}|_)",r:0},{cN:"string",v:[{b:"``.+?''"},{b:"`.+?'"}]},{cN:"code",b:"(`.+?`|\\+.+?\\+)",r:0},{cN:"code",b:"^[ \\t]",e:"$",r:0},{b:"^'{3,}[ \\t]*$",r:10},{b:"(link:)?(http|https|ftp|file|irc|image:?):\\S+\\[.*?\\]",rB:!0,c:[{b:"(link|image:?):",r:0},{cN:"link",b:"\\w",e:"[^\\[]+",r:0},{cN:"string",b:"\\[",e:"\\]",eB:!0,eE:!0,r:0}],r:10}]}}),e.registerLanguage("aspectj",function(e){var t="false synchronized int abstract float private char boolean static null if const for true while long throw strictfp finally protected import native final return void enum else extends implements break transient new catch instanceof byte super volatile case assert short package default double public try this switch continue throws privileged aspectOf adviceexecution proceed cflowbelow cflow initialization preinitialization staticinitialization withincode target within execution getWithinTypeName handler thisJoinPoint thisJoinPointStaticPart thisEnclosingJoinPointStaticPart declare parents warning error soft precedence thisAspectInstance",r="get set args call";return{k:t,i:/<\/|#/,c:[e.C("/\\*\\*","\\*/",{r:0,c:[{b:/\w+@/,r:0},{cN:"doctag",b:"@[A-Za-z]+"}]}),e.CLCM,e.CBCM,e.ASM,e.QSM,{cN:"class",bK:"aspect",e:/[{;=]/,eE:!0,i:/[:;"\[\]]/,c:[{bK:"extends implements pertypewithin perthis pertarget percflowbelow percflow issingleton"},e.UTM,{b:/\([^\)]*/,e:/[)]+/,k:t+" "+r,eE:!1}]},{cN:"class",bK:"class interface",e:/[{;=]/,eE:!0,r:0,k:"class interface",i:/[:"\[\]]/,c:[{bK:"extends implements"},e.UTM]},{bK:"pointcut after before around throwing returning",e:/[)]/,eE:!1,i:/["\[\]]/,c:[{b:e.UIR+"\\s*\\(",rB:!0,c:[e.UTM]}]},{b:/[:]/,rB:!0,e:/[{;]/,r:0,eE:!1,k:t,i:/["\[\]]/,c:[{b:e.UIR+"\\s*\\(",k:t+" "+r,r:0},e.QSM]},{bK:"new throw",r:0},{cN:"function",b:/\w+ +\w+(\.)?\w+\s*\([^\)]*\)\s*((throws)[\w\s,]+)?[\{;]/,rB:!0,e:/[{;=]/,k:t,eE:!0,c:[{b:e.UIR+"\\s*\\(",rB:!0,r:0,c:[e.UTM]},{cN:"params",b:/\(/,e:/\)/,r:0,k:t,c:[e.ASM,e.QSM,e.CNM,e.CBCM]},e.CLCM,e.CBCM]},e.CNM,{cN:"meta",b:"@[A-Za-z]+"}]}}),e.registerLanguage("autohotkey",function(e){var t={b:"`[\\s\\S]"};return{cI:!0,aliases:["ahk"],k:{keyword:"Break Continue Critical Exit ExitApp Gosub Goto New OnExit Pause return SetBatchLines SetTimer Suspend Thread Throw Until ahk_id ahk_class ahk_pid ahk_exe ahk_group",literal:"A|0 true false NOT AND OR",built_in:"ComSpec Clipboard ClipboardAll ErrorLevel"},c:[{cN:"built_in",b:"A_[a-zA-Z0-9]+"},t,e.inherit(e.QSM,{c:[t]}),e.C(";","$",{r:0}),e.CBCM,{cN:"number",b:e.NR,r:0},{cN:"subst",b:"%(?=[a-zA-Z0-9#_$@])",e:"%",i:"[^a-zA-Z0-9#_$@]"},{cN:"built_in",b:"^\\s*\\w+\\s*,"},{cN:"meta",b:"^\\s*#w+",e:"$",r:0},{cN:"symbol",c:[t],v:[{b:'^[^\\n";]+::(?!=)'},{b:'^[^\\n";]+:(?!=)',r:0}]},{b:",\\s*,"}]}}),e.registerLanguage("autoit",function(e){var t="ByRef Case Const ContinueCase ContinueLoop Default Dim Do Else ElseIf EndFunc EndIf EndSelect EndSwitch EndWith Enum Exit ExitLoop For Func Global If In Local Next ReDim Return Select Static Step Switch Then To Until Volatile WEnd While With",r="True False And Null Not Or",a="Abs ACos AdlibRegister AdlibUnRegister Asc AscW ASin Assign ATan AutoItSetOption AutoItWinGetTitle AutoItWinSetTitle Beep Binary BinaryLen BinaryMid BinaryToString BitAND BitNOT BitOR BitRotate BitShift BitXOR BlockInput Break Call CDTray Ceiling Chr ChrW ClipGet ClipPut ConsoleRead ConsoleWrite ConsoleWriteError ControlClick ControlCommand ControlDisable ControlEnable ControlFocus ControlGetFocus ControlGetHandle ControlGetPos ControlGetText ControlHide ControlListView ControlMove ControlSend ControlSetText ControlShow ControlTreeView Cos Dec DirCopy DirCreate DirGetSize DirMove DirRemove DllCall DllCallAddress DllCallbackFree DllCallbackGetPtr DllCallbackRegister DllClose DllOpen DllStructCreate DllStructGetData DllStructGetPtr DllStructGetSize DllStructSetData DriveGetDrive DriveGetFileSystem DriveGetLabel DriveGetSerial DriveGetType DriveMapAdd DriveMapDel DriveMapGet DriveSetLabel DriveSpaceFree DriveSpaceTotal DriveStatus EnvGet EnvSet EnvUpdate Eval Execute Exp FileChangeDir FileClose FileCopy FileCreateNTFSLink FileCreateShortcut FileDelete FileExists FileFindFirstFile FileFindNextFile FileFlush FileGetAttrib FileGetEncoding FileGetLongName FileGetPos FileGetShortcut FileGetShortName FileGetSize FileGetTime FileGetVersion FileInstall FileMove FileOpen FileOpenDialog FileRead FileReadLine FileReadToArray FileRecycle FileRecycleEmpty FileSaveDialog FileSelectFolder FileSetAttrib FileSetEnd FileSetPos FileSetTime FileWrite FileWriteLine Floor FtpSetProxy FuncName GUICreate GUICtrlCreateAvi GUICtrlCreateButton GUICtrlCreateCheckbox GUICtrlCreateCombo GUICtrlCreateContextMenu GUICtrlCreateDate GUICtrlCreateDummy GUICtrlCreateEdit GUICtrlCreateGraphic GUICtrlCreateGroup GUICtrlCreateIcon GUICtrlCreateInput GUICtrlCreateLabel GUICtrlCreateList GUICtrlCreateListView GUICtrlCreateListViewItem GUICtrlCreateMenu GUICtrlCreateMenuItem GUICtrlCreateMonthCal GUICtrlCreateObj GUICtrlCreatePic GUICtrlCreateProgress GUICtrlCreateRadio GUICtrlCreateSlider GUICtrlCreateTab GUICtrlCreateTabItem GUICtrlCreateTreeView GUICtrlCreateTreeViewItem GUICtrlCreateUpdown GUICtrlDelete GUICtrlGetHandle GUICtrlGetState GUICtrlRead GUICtrlRecvMsg GUICtrlRegisterListViewSort GUICtrlSendMsg GUICtrlSendToDummy GUICtrlSetBkColor GUICtrlSetColor GUICtrlSetCursor GUICtrlSetData GUICtrlSetDefBkColor GUICtrlSetDefColor GUICtrlSetFont GUICtrlSetGraphic GUICtrlSetImage GUICtrlSetLimit GUICtrlSetOnEvent GUICtrlSetPos GUICtrlSetResizing GUICtrlSetState GUICtrlSetStyle GUICtrlSetTip GUIDelete GUIGetCursorInfo GUIGetMsg GUIGetStyle GUIRegisterMsg GUISetAccelerators GUISetBkColor GUISetCoord GUISetCursor GUISetFont GUISetHelp GUISetIcon GUISetOnEvent GUISetState GUISetStyle GUIStartGroup GUISwitch Hex HotKeySet HttpSetProxy HttpSetUserAgent HWnd InetClose InetGet InetGetInfo InetGetSize InetRead IniDelete IniRead IniReadSection IniReadSectionNames IniRenameSection IniWrite IniWriteSection InputBox Int IsAdmin IsArray IsBinary IsBool IsDeclared IsDllStruct IsFloat IsFunc IsHWnd IsInt IsKeyword IsNumber IsObj IsPtr IsString Log MemGetStats Mod MouseClick MouseClickDrag MouseDown MouseGetCursor MouseGetPos MouseMove MouseUp MouseWheel MsgBox Number ObjCreate ObjCreateInterface ObjEvent ObjGet ObjName OnAutoItExitRegister OnAutoItExitUnRegister Ping PixelChecksum PixelGetColor PixelSearch ProcessClose ProcessExists ProcessGetStats ProcessList ProcessSetPriority ProcessWait ProcessWaitClose ProgressOff ProgressOn ProgressSet Ptr Random RegDelete RegEnumKey RegEnumVal RegRead RegWrite Round Run RunAs RunAsWait RunWait Send SendKeepActive SetError SetExtended ShellExecute ShellExecuteWait Shutdown Sin Sleep SoundPlay SoundSetWaveVolume SplashImageOn SplashOff SplashTextOn Sqrt SRandom StatusbarGetText StderrRead StdinWrite StdioClose StdoutRead String StringAddCR StringCompare StringFormat StringFromASCIIArray StringInStr StringIsAlNum StringIsAlpha StringIsASCII StringIsDigit StringIsFloat StringIsInt StringIsLower StringIsSpace StringIsUpper StringIsXDigit StringLeft StringLen StringLower StringMid StringRegExp StringRegExpReplace StringReplace StringReverse StringRight StringSplit StringStripCR StringStripWS StringToASCIIArray StringToBinary StringTrimLeft StringTrimRight StringUpper Tan TCPAccept TCPCloseSocket TCPConnect TCPListen TCPNameToIP TCPRecv TCPSend TCPShutdown, UDPShutdown TCPStartup, UDPStartup TimerDiff TimerInit ToolTip TrayCreateItem TrayCreateMenu TrayGetMsg TrayItemDelete TrayItemGetHandle TrayItemGetState TrayItemGetText TrayItemSetOnEvent TrayItemSetState TrayItemSetText TraySetClick TraySetIcon TraySetOnEvent TraySetPauseIcon TraySetState TraySetToolTip TrayTip UBound UDPBind UDPCloseSocket UDPOpen UDPRecv UDPSend VarGetType WinActivate WinActive WinClose WinExists WinFlash WinGetCaretPos WinGetClassList WinGetClientSize WinGetHandle WinGetPos WinGetProcess WinGetState WinGetText WinGetTitle WinKill WinList WinMenuSelectItem WinMinimizeAll WinMinimizeAllUndo WinMove WinSetOnTop WinSetState WinSetTitle WinSetTrans WinWait",i={v:[e.C(";","$",{r:0}),e.C("#cs","#ce"),e.C("#comments-start","#comments-end")]},n={b:"\\$[A-z0-9_]+"},o={cN:"string",v:[{b:/"/,e:/"/,c:[{b:/""/,r:0}]},{b:/'/,e:/'/,c:[{b:/''/,r:0}]}]},s={v:[e.BNM,e.CNM]},l={cN:"meta",b:"#",e:"$",k:{"meta-keyword":"comments include include-once NoTrayIcon OnAutoItStartRegister pragma compile RequireAdmin"},c:[{b:/\\\n/,r:0},{bK:"include",k:{"meta-keyword":"include"},e:"$",c:[o,{cN:"meta-string",v:[{b:"<",e:">"},{b:/"/,e:/"/,c:[{b:/""/,r:0}]},{b:/'/,e:/'/,c:[{b:/''/,r:0}]}]}]},o,i]},c={cN:"symbol",b:"@[A-z0-9_]+"},d={cN:"function",bK:"Func",e:"$",i:"\\$|\\[|%",c:[e.UTM,{cN:"params",b:"\\(",e:"\\)",c:[n,o,s]}]};return{cI:!0,i:/\/\*/,k:{keyword:t,built_in:a,literal:r},c:[i,n,o,s,l,c,d]}}),e.registerLanguage("avrasm",function(e){return{cI:!0,l:"\\.?"+e.IR,k:{keyword:"adc add adiw and andi asr bclr bld brbc brbs brcc brcs break breq brge brhc brhs brid brie brlo brlt brmi brne brpl brsh brtc brts brvc brvs bset bst call cbi cbr clc clh cli cln clr cls clt clv clz com cp cpc cpi cpse dec eicall eijmp elpm eor fmul fmuls fmulsu icall ijmp in inc jmp ld ldd ldi lds lpm lsl lsr mov movw mul muls mulsu neg nop or ori out pop push rcall ret reti rjmp rol ror sbc sbr sbrc sbrs sec seh sbi sbci sbic sbis sbiw sei sen ser ses set sev sez sleep spm st std sts sub subi swap tst wdr",built_in:"r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 r13 r14 r15 r16 r17 r18 r19 r20 r21 r22 r23 r24 r25 r26 r27 r28 r29 r30 r31 x|0 xh xl y|0 yh yl z|0 zh zl ucsr1c udr1 ucsr1a ucsr1b ubrr1l ubrr1h ucsr0c ubrr0h tccr3c tccr3a tccr3b tcnt3h tcnt3l ocr3ah ocr3al ocr3bh ocr3bl ocr3ch ocr3cl icr3h icr3l etimsk etifr tccr1c ocr1ch ocr1cl twcr twdr twar twsr twbr osccal xmcra xmcrb eicra spmcsr spmcr portg ddrg ping portf ddrf sreg sph spl xdiv rampz eicrb eimsk gimsk gicr eifr gifr timsk tifr mcucr mcucsr tccr0 tcnt0 ocr0 assr tccr1a tccr1b tcnt1h tcnt1l ocr1ah ocr1al ocr1bh ocr1bl icr1h icr1l tccr2 tcnt2 ocr2 ocdr wdtcr sfior eearh eearl eedr eecr porta ddra pina portb ddrb pinb portc ddrc pinc portd ddrd pind spdr spsr spcr udr0 ucsr0a ucsr0b ubrr0l acsr admux adcsr adch adcl porte ddre pine pinf",meta:".byte .cseg .db .def .device .dseg .dw .endmacro .equ .eseg .exit .include .list .listmac .macro .nolist .org .set"},c:[e.CBCM,e.C(";","$",{r:0}),e.CNM,e.BNM,{cN:"number",b:"\\b(\\$[a-zA-Z0-9]+|0o[0-7]+)"},e.QSM,{cN:"string",b:"'",e:"[^\\\\]'",i:"[^\\\\][^']"},{cN:"symbol",b:"^[A-Za-z0-9_.$]+:"},{cN:"meta",b:"#",e:"$"},{cN:"subst",b:"@[0-9]+"}]}}),e.registerLanguage("awk",function(e){var t={cN:"variable",v:[{b:/\$[\w\d#@][\w\d_]*/},{b:/\$\{(.*?)}/}]},r="BEGIN END if else while do for in break continue delete next nextfile function func exit|10",a={cN:"string",c:[e.BE],v:[{b:/(u|b)?r?'''/,e:/'''/,r:10},{b:/(u|b)?r?"""/,e:/"""/,r:10},{b:/(u|r|ur)'/,e:/'/,r:10},{b:/(u|r|ur)"/,e:/"/,r:10},{b:/(b|br)'/,e:/'/},{b:/(b|br)"/,e:/"/},e.ASM,e.QSM]};return{k:{keyword:r},c:[t,a,e.RM,e.HCM,e.NM]}}),e.registerLanguage("axapta",function(e){return{k:"false int abstract private char boolean static null if for true while long throw finally protected final return void enum else break new catch byte super case short default double public try this switch continue reverse firstfast firstonly forupdate nofetch sum avg minof maxof count order group by asc desc index hint like dispaly edit client server ttsbegin ttscommit str real date container anytype common div mod",c:[e.CLCM,e.CBCM,e.ASM,e.QSM,e.CNM,{cN:"meta",b:"#",e:"$"},{cN:"class",bK:"class interface",e:"{",eE:!0,i:":",c:[{bK:"extends implements"},e.UTM]}]}}),e.registerLanguage("bash",function(e){var t={cN:"variable",v:[{b:/\$[\w\d#@][\w\d_]*/},{b:/\$\{(.*?)}/}]},r={cN:"string",b:/"/,e:/"/,c:[e.BE,t,{cN:"variable",b:/\$\(/,e:/\)/,c:[e.BE]}]},a={cN:"string",b:/'/,e:/'/};return{aliases:["sh","zsh"],l:/\b-?[a-z\._]+\b/,k:{keyword:"if then else elif fi for while in do done case esac function",literal:"true false",built_in:"break cd continue eval exec exit export getopts hash pwd readonly return shift test times trap umask unset alias bind builtin caller command declare echo enable help let local logout mapfile printf read readarray source type typeset ulimit unalias set shopt autoload bg bindkey bye cap chdir clone comparguments compcall compctl compdescribe compfiles compgroups compquote comptags comptry compvalues dirs disable disown echotc echoti emulate fc fg float functions getcap getln history integer jobs kill limit log noglob popd print pushd pushln rehash sched setcap setopt stat suspend ttyctl unfunction unhash unlimit unsetopt vared wait whence where which zcompile zformat zftp zle zmodload zparseopts zprof zpty zregexparse zsocket zstyle ztcp",_:"-ne -eq -lt -gt -f -d -e -s -l -a"},c:[{cN:"meta",b:/^#![^\n]+sh\s*$/,r:10},{cN:"function",b:/\w[\w\d_]*\s*\(\s*\)\s*\{/,rB:!0,c:[e.inherit(e.TM,{b:/\w[\w\d_]*/})],r:0},e.HCM,r,a,t]}}),e.registerLanguage("basic",function(e){return{cI:!0,i:"^.",l:"[a-zA-Z][a-zA-Z0-9_$%!#]*",k:{keyword:"ABS ASC AND ATN AUTO|0 BEEP BLOAD|10 BSAVE|10 CALL CALLS CDBL CHAIN CHDIR CHR$|10 CINT CIRCLE CLEAR CLOSE CLS COLOR COM COMMON CONT COS CSNG CSRLIN CVD CVI CVS DATA DATE$ DEFDBL DEFINT DEFSNG DEFSTR DEF|0 SEG USR DELETE DIM DRAW EDIT END ENVIRON ENVIRON$ EOF EQV ERASE ERDEV ERDEV$ ERL ERR ERROR EXP FIELD FILES FIX FOR|0 FRE GET GOSUB|10 GOTO HEX$ IF|0 THEN ELSE|0 INKEY$ INP INPUT INPUT# INPUT$ INSTR IMP INT IOCTL IOCTL$ KEY ON OFF LIST KILL LEFT$ LEN LET LINE LLIST LOAD LOC LOCATE LOF LOG LPRINT USING LSET MERGE MID$ MKDIR MKD$ MKI$ MKS$ MOD NAME NEW NEXT NOISE NOT OCT$ ON OR PEN PLAY STRIG OPEN OPTION BASE OUT PAINT PALETTE PCOPY PEEK PMAP POINT POKE POS PRINT PRINT] PSET PRESET PUT RANDOMIZE READ REM RENUM RESET|0 RESTORE RESUME RETURN|0 RIGHT$ RMDIR RND RSET RUN SAVE SCREEN SGN SHELL SIN SOUND SPACE$ SPC SQR STEP STICK STOP STR$ STRING$ SWAP SYSTEM TAB TAN TIME$ TIMER TROFF TRON TO USR VAL VARPTR VARPTR$ VIEW WAIT WHILE WEND WIDTH WINDOW WRITE XOR" -},c:[e.QSM,e.C("REM","$",{r:10}),e.C("'","$",{r:0}),{cN:"symbol",b:"^[0-9]+ ",r:10},{cN:"number",b:"\\b([0-9]+[0-9edED.]*[#!]?)",r:0},{cN:"number",b:"(&[hH][0-9a-fA-F]{1,4})"},{cN:"number",b:"(&[oO][0-7]{1,6})"}]}}),e.registerLanguage("bnf",function(e){return{c:[{cN:"attribute",b://},{b:/::=/,starts:{e:/$/,c:[{b://},e.CLCM,e.CBCM,e.ASM,e.QSM]}}]}}),e.registerLanguage("brainfuck",function(e){var t={cN:"literal",b:"[\\+\\-]",r:0};return{aliases:["bf"],c:[e.C("[^\\[\\]\\.,\\+\\-<> \r\n]","[\\[\\]\\.,\\+\\-<> \r\n]",{rE:!0,r:0}),{cN:"title",b:"[\\[\\]]",r:0},{cN:"string",b:"[\\.,]",r:0},{b:/\+\+|\-\-/,rB:!0,c:[t]},t]}}),e.registerLanguage("cal",function(e){var t="div mod in and or not xor asserterror begin case do downto else end exit for if of repeat then to until while with var",r="false true",a=[e.CLCM,e.C(/\{/,/\}/,{r:0}),e.C(/\(\*/,/\*\)/,{r:10})],i={cN:"string",b:/'/,e:/'/,c:[{b:/''/}]},n={cN:"string",b:/(#\d+)+/},o={cN:"number",b:"\\b\\d+(\\.\\d+)?(DT|D|T)",r:0},s={cN:"string",b:'"',e:'"'},l={cN:"function",bK:"procedure",e:/[:;]/,k:"procedure|10",c:[e.TM,{cN:"params",b:/\(/,e:/\)/,k:t,c:[i,n]}].concat(a)},c={cN:"class",b:"OBJECT (Table|Form|Report|Dataport|Codeunit|XMLport|MenuSuite|Page|Query) (\\d+) ([^\\r\\n]+)",rB:!0,c:[e.TM,l]};return{cI:!0,k:{keyword:t,literal:r},i:/\/\*/,c:[i,n,o,s,e.NM,c,l]}}),e.registerLanguage("capnproto",function(e){return{aliases:["capnp"],k:{keyword:"struct enum interface union group import using const annotation extends in of on as with from fixed",built_in:"Void Bool Int8 Int16 Int32 Int64 UInt8 UInt16 UInt32 UInt64 Float32 Float64 Text Data AnyPointer AnyStruct Capability List",literal:"true false"},c:[e.QSM,e.NM,e.HCM,{cN:"meta",b:/@0x[\w\d]{16};/,i:/\n/},{cN:"symbol",b:/@\d+\b/},{cN:"class",bK:"struct enum",e:/\{/,i:/\n/,c:[e.inherit(e.TM,{starts:{eW:!0,eE:!0}})]},{cN:"class",bK:"interface",e:/\{/,i:/\n/,c:[e.inherit(e.TM,{starts:{eW:!0,eE:!0}})]}]}}),e.registerLanguage("ceylon",function(e){var t="assembly module package import alias class interface object given value assign void function new of extends satisfies abstracts in out return break continue throw assert dynamic if else switch case for while try catch finally then let this outer super is exists nonempty",r="shared abstract formal default actual variable late native deprecatedfinal sealed annotation suppressWarnings small",a="doc by license see throws tagged",i={cN:"subst",eB:!0,eE:!0,b:/``/,e:/``/,k:t,r:10},n=[{cN:"string",b:'"""',e:'"""',r:10},{cN:"string",b:'"',e:'"',c:[i]},{cN:"string",b:"'",e:"'"},{cN:"number",b:"#[0-9a-fA-F_]+|\\$[01_]+|[0-9_]+(?:\\.[0-9_](?:[eE][+-]?\\d+)?)?[kMGTPmunpf]?",r:0}];return i.c=n,{k:{keyword:t+" "+r,meta:a},i:"\\$[^01]|#[^0-9a-fA-F]",c:[e.CLCM,e.C("/\\*","\\*/",{c:["self"]}),{cN:"meta",b:'@[a-z]\\w*(?:\\:"[^"]*")?'}].concat(n)}}),e.registerLanguage("clean",function(e){return{aliases:["clean","icl","dcl"],k:{keyword:"if let in with where case of class instance otherwise implementation definition system module from import qualified as special code inline foreign export ccall stdcall generic derive infix infixl infixr",literal:"True False"},c:[e.CLCM,e.CBCM,e.ASM,e.QSM,e.CNM,{b:"->|<-[|:]?|::|#!?|>>=|\\{\\||\\|\\}|:==|=:|\\.\\.|<>|`"}]}}),e.registerLanguage("clojure",function(e){var t={"builtin-name":"def defonce cond apply if-not if-let if not not= = < > <= >= == + / * - rem quot neg? pos? delay? symbol? keyword? true? false? integer? empty? coll? list? set? ifn? fn? associative? sequential? sorted? counted? reversible? number? decimal? class? distinct? isa? float? rational? reduced? ratio? odd? even? char? seq? vector? string? map? nil? contains? zero? instance? not-every? not-any? libspec? -> ->> .. . inc compare do dotimes mapcat take remove take-while drop letfn drop-last take-last drop-while while intern condp case reduced cycle split-at split-with repeat replicate iterate range merge zipmap declare line-seq sort comparator sort-by dorun doall nthnext nthrest partition eval doseq await await-for let agent atom send send-off release-pending-sends add-watch mapv filterv remove-watch agent-error restart-agent set-error-handler error-handler set-error-mode! error-mode shutdown-agents quote var fn loop recur throw try monitor-enter monitor-exit defmacro defn defn- macroexpand macroexpand-1 for dosync and or when when-not when-let comp juxt partial sequence memoize constantly complement identity assert peek pop doto proxy defstruct first rest cons defprotocol cast coll deftype defrecord last butlast sigs reify second ffirst fnext nfirst nnext defmulti defmethod meta with-meta ns in-ns create-ns import refer keys select-keys vals key val rseq name namespace promise into transient persistent! conj! assoc! dissoc! pop! disj! use class type num float double short byte boolean bigint biginteger bigdec print-method print-dup throw-if printf format load compile get-in update-in pr pr-on newline flush read slurp read-line subvec with-open memfn time re-find re-groups rand-int rand mod locking assert-valid-fdecl alias resolve ref deref refset swap! reset! set-validator! compare-and-set! alter-meta! reset-meta! commute get-validator alter ref-set ref-history-count ref-min-history ref-max-history ensure sync io! new next conj set! to-array future future-call into-array aset gen-class reduce map filter find empty hash-map hash-set sorted-map sorted-map-by sorted-set sorted-set-by vec vector seq flatten reverse assoc dissoc list disj get union difference intersection extend extend-type extend-protocol int nth delay count concat chunk chunk-buffer chunk-append chunk-first chunk-rest max min dec unchecked-inc-int unchecked-inc unchecked-dec-inc unchecked-dec unchecked-negate unchecked-add-int unchecked-add unchecked-subtract-int unchecked-subtract chunk-next chunk-cons chunked-seq? prn vary-meta lazy-seq spread list* str find-keyword keyword symbol gensym force rationalize"},r="a-zA-Z_\\-!.?+*=<>&#'",a="["+r+"]["+r+"0-9/;:]*",i="[-+]?\\d+(\\.\\d+)?",n={b:a,r:0},o={cN:"number",b:i,r:0},s=e.inherit(e.QSM,{i:null}),l=e.C(";","$",{r:0}),c={cN:"literal",b:/\b(true|false|nil)\b/},d={b:"[\\[\\{]",e:"[\\]\\}]"},p={cN:"comment",b:"\\^"+a},m=e.C("\\^\\{","\\}"),u={cN:"symbol",b:"[:]{1,2}"+a},b={b:"\\(",e:"\\)"},g={eW:!0,r:0},f={k:t,l:a,cN:"name",b:a,starts:g},_=[b,s,p,m,l,u,d,o,c,n];return b.c=[e.C("comment",""),f,g],g.c=_,d.c=_,m.c=[d],{aliases:["clj"],i:/\S/,c:[b,s,p,m,l,u,d,o,c]}}),e.registerLanguage("clojure-repl",function(e){return{c:[{cN:"meta",b:/^([\w.-]+|\s*#_)=>/,starts:{e:/$/,sL:"clojure"}}]}}),e.registerLanguage("cmake",function(e){return{aliases:["cmake.in"],cI:!0,k:{keyword:"add_custom_command add_custom_target add_definitions add_dependencies add_executable add_library add_subdirectory add_test aux_source_directory break build_command cmake_minimum_required cmake_policy configure_file create_test_sourcelist define_property else elseif enable_language enable_testing endforeach endfunction endif endmacro endwhile execute_process export find_file find_library find_package find_path find_program fltk_wrap_ui foreach function get_cmake_property get_directory_property get_filename_component get_property get_source_file_property get_target_property get_test_property if include include_directories include_external_msproject include_regular_expression install link_directories load_cache load_command macro mark_as_advanced message option output_required_files project qt_wrap_cpp qt_wrap_ui remove_definitions return separate_arguments set set_directory_properties set_property set_source_files_properties set_target_properties set_tests_properties site_name source_group string target_link_libraries try_compile try_run unset variable_watch while build_name exec_program export_library_dependencies install_files install_programs install_targets link_libraries make_directory remove subdir_depends subdirs use_mangled_mesa utility_source variable_requires write_file qt5_use_modules qt5_use_package qt5_wrap_cpp on off true false and or equal less greater strless strgreater strequal matches"},c:[{cN:"variable",b:"\\${",e:"}"},e.HCM,e.QSM,e.NM]}}),e.registerLanguage("coffeescript",function(e){var t={keyword:"in if for while finally new do return else break catch instanceof throw try this switch continue typeof delete debugger super yield import export from as default await then unless until loop of by when and or is isnt not",literal:"true false null undefined yes no on off",built_in:"npm require console print module global window document"},r="[A-Za-z$_][0-9A-Za-z$_]*",a={cN:"subst",b:/#\{/,e:/}/,k:t},i=[e.BNM,e.inherit(e.CNM,{starts:{e:"(\\s*/)?",r:0}}),{cN:"string",v:[{b:/'''/,e:/'''/,c:[e.BE]},{b:/'/,e:/'/,c:[e.BE]},{b:/"""/,e:/"""/,c:[e.BE,a]},{b:/"/,e:/"/,c:[e.BE,a]}]},{cN:"regexp",v:[{b:"///",e:"///",c:[a,e.HCM]},{b:"//[gim]*",r:0},{b:/\/(?![ *])(\\\/|.)*?\/[gim]*(?=\W|$)/}]},{b:"@"+r},{sL:"javascript",eB:!0,eE:!0,v:[{b:"```",e:"```"},{b:"`",e:"`"}]}];a.c=i;var n=e.inherit(e.TM,{b:r}),o="(\\(.*\\))?\\s*\\B[-=]>",s={cN:"params",b:"\\([^\\(]",rB:!0,c:[{b:/\(/,e:/\)/,k:t,c:["self"].concat(i)}]};return{aliases:["coffee","cson","iced"],k:t,i:/\/\*/,c:i.concat([e.C("###","###"),e.HCM,{cN:"function",b:"^\\s*"+r+"\\s*=\\s*"+o,e:"[-=]>",rB:!0,c:[n,s]},{b:/[:\(,=]\s*/,r:0,c:[{cN:"function",b:o,e:"[-=]>",rB:!0,c:[s]}]},{cN:"class",bK:"class",e:"$",i:/[:="\[\]]/,c:[{bK:"extends",eW:!0,i:/[:="\[\]]/,c:[n]},n]},{b:r+":",e:":",rB:!0,rE:!0,r:0}])}}),e.registerLanguage("coq",function(e){return{k:{keyword:"_ as at cofix else end exists exists2 fix for forall fun if IF in let match mod Prop return Set then Type using where with Abort About Add Admit Admitted All Arguments Assumptions Axiom Back BackTo Backtrack Bind Blacklist Canonical Cd Check Class Classes Close Coercion Coercions CoFixpoint CoInductive Collection Combined Compute Conjecture Conjectures Constant constr Constraint Constructors Context Corollary CreateHintDb Cut Declare Defined Definition Delimit Dependencies DependentDerive Drop eauto End Equality Eval Example Existential Existentials Existing Export exporting Extern Extract Extraction Fact Field Fields File Fixpoint Focus for From Function Functional Generalizable Global Goal Grab Grammar Graph Guarded Heap Hint HintDb Hints Hypotheses Hypothesis ident Identity If Immediate Implicit Import Include Inductive Infix Info Initial Inline Inspect Instance Instances Intro Intros Inversion Inversion_clear Language Left Lemma Let Libraries Library Load LoadPath Local Locate Ltac ML Mode Module Modules Monomorphic Morphism Next NoInline Notation Obligation Obligations Opaque Open Optimize Options Parameter Parameters Parametric Path Paths pattern Polymorphic Preterm Print Printing Program Projections Proof Proposition Pwd Qed Quit Rec Record Recursive Redirect Relation Remark Remove Require Reserved Reset Resolve Restart Rewrite Right Ring Rings Save Scheme Scope Scopes Script Search SearchAbout SearchHead SearchPattern SearchRewrite Section Separate Set Setoid Show Solve Sorted Step Strategies Strategy Structure SubClass Table Tables Tactic Term Test Theorem Time Timeout Transparent Type Typeclasses Types Undelimit Undo Unfocus Unfocused Unfold Universe Universes Unset Unshelve using Variable Variables Variant Verbose Visibility where with",built_in:"abstract absurd admit after apply as assert assumption at auto autorewrite autounfold before bottom btauto by case case_eq cbn cbv change classical_left classical_right clear clearbody cofix compare compute congruence constr_eq constructor contradict contradiction cut cutrewrite cycle decide decompose dependent destruct destruction dintuition discriminate discrR do double dtauto eapply eassumption eauto ecase econstructor edestruct ediscriminate eelim eexact eexists einduction einjection eleft elim elimtype enough equality erewrite eright esimplify_eq esplit evar exact exactly_once exfalso exists f_equal fail field field_simplify field_simplify_eq first firstorder fix fold fourier functional generalize generalizing gfail give_up has_evar hnf idtac in induction injection instantiate intro intro_pattern intros intuition inversion inversion_clear is_evar is_var lapply lazy left lia lra move native_compute nia nsatz omega once pattern pose progress proof psatz quote record red refine reflexivity remember rename repeat replace revert revgoals rewrite rewrite_strat right ring ring_simplify rtauto set setoid_reflexivity setoid_replace setoid_rewrite setoid_symmetry setoid_transitivity shelve shelve_unifiable simpl simple simplify_eq solve specialize split split_Rabs split_Rmult stepl stepr subst sum swap symmetry tactic tauto time timeout top transitivity trivial try tryif unfold unify until using vm_compute with"},c:[e.QSM,e.C("\\(\\*","\\*\\)"),e.CNM,{cN:"type",eB:!0,b:"\\|\\s*",e:"\\w+"},{b:/[-=]>/}]}}),e.registerLanguage("cos",function(e){var t={cN:"string",v:[{b:'"',e:'"',c:[{b:'""',r:0}]}]},r={cN:"number",b:"\\b(\\d+(\\.\\d*)?|\\.\\d+)",r:0},a="property parameter class classmethod clientmethod extends as break catch close continue do d|0 else elseif for goto halt hang h|0 if job j|0 kill k|0 lock l|0 merge new open quit q|0 read r|0 return set s|0 tcommit throw trollback try tstart use view while write w|0 xecute x|0 zkill znspace zn ztrap zwrite zw zzdump zzwrite print zbreak zinsert zload zprint zremove zsave zzprint mv mvcall mvcrt mvdim mvprint zquit zsync ascii";return{cI:!0,aliases:["cos","cls"],k:a,c:[r,t,e.CLCM,e.CBCM,{cN:"comment",b:/;/,e:"$",r:0},{cN:"built_in",b:/(?:\$\$?|\.\.)\^?[a-zA-Z]+/},{cN:"built_in",b:/\$\$\$[a-zA-Z]+/},{cN:"built_in",b:/%[a-z]+(?:\.[a-z]+)*/},{cN:"symbol",b:/\^%?[a-zA-Z][\w]*/},{cN:"keyword",b:/##class|##super|#define|#dim/},{b:/&sql\(/,e:/\)/,eB:!0,eE:!0,sL:"sql"},{b:/&(js|jscript|javascript)/,eB:!0,eE:!0,sL:"javascript"},{b:/&html<\s*\s*>/,sL:"xml"}]}}),e.registerLanguage("crmsh",function(e){var t="primitive rsc_template",r="group clone ms master location colocation order fencing_topology rsc_ticket acl_target acl_group user role tag xml",a="property rsc_defaults op_defaults",i="params meta operations op rule attributes utilization",n="read write deny defined not_defined in_range date spec in ref reference attribute type xpath version and or lt gt tag lte gte eq ne \\",o="number string",s="Master Started Slave Stopped start promote demote stop monitor true false";return{aliases:["crm","pcmk"],cI:!0,k:{keyword:i+" "+n+" "+o,literal:s},c:[e.HCM,{bK:"node",starts:{e:"\\s*([\\w_-]+:)?",starts:{cN:"title",e:"\\s*[\\$\\w_][\\w_-]*"}}},{bK:t,starts:{cN:"title",e:"\\s*[\\$\\w_][\\w_-]*",starts:{e:"\\s*@?[\\w_][\\w_\\.:-]*"}}},{b:"\\b("+r.split(" ").join("|")+")\\s+",k:r,starts:{cN:"title",e:"[\\$\\w_][\\w_-]*"}},{bK:a,starts:{cN:"title",e:"\\s*([\\w_-]+:)?"}},e.QSM,{cN:"meta",b:"(ocf|systemd|service|lsb):[\\w_:-]+",r:0},{cN:"number",b:"\\b\\d+(\\.\\d+)?(ms|s|h|m)?",r:0},{cN:"literal",b:"[-]?(infinity|inf)",r:0},{cN:"attr",b:/([A-Za-z\$_\#][\w_-]+)=/,r:0},{cN:"tag",b:"",r:0}]}}),e.registerLanguage("crystal",function(e){function t(e,t){var r=[{b:e,e:t}];return r[0].c=r,r}var r="(_[uif](8|16|32|64))?",a="[a-zA-Z_]\\w*[!?=]?",i="!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",n="[a-zA-Z_]\\w*[!?=]?|[-+~]\\@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\][=?]?",o={keyword:"abstract alias as as? asm begin break case class def do else elsif end ensure enum extend for fun if include instance_sizeof is_a? lib macro module next nil? of out pointerof private protected rescue responds_to? return require select self sizeof struct super then type typeof union uninitialized unless until when while with yield __DIR__ __END_LINE__ __FILE__ __LINE__",literal:"false nil true"},s={cN:"subst",b:"#{",e:"}",k:o},l={cN:"template-variable",v:[{b:"\\{\\{",e:"\\}\\}"},{b:"\\{%",e:"%\\}"}],k:o},c={cN:"string",c:[e.BE,s],v:[{b:/'/,e:/'/},{b:/"/,e:/"/},{b:/`/,e:/`/},{b:"%w?\\(",e:"\\)",c:t("\\(","\\)")},{b:"%w?\\[",e:"\\]",c:t("\\[","\\]")},{b:"%w?{",e:"}",c:t("{","}")},{b:"%w?<",e:">",c:t("<",">")},{b:"%w?/",e:"/"},{b:"%w?%",e:"%"},{b:"%w?-",e:"-"},{b:"%w?\\|",e:"\\|"},{b:/<<-\w+$/,e:/^\s*\w+$/}],r:0},d={cN:"string",v:[{b:"%q\\(",e:"\\)",c:t("\\(","\\)")},{b:"%q\\[",e:"\\]",c:t("\\[","\\]")},{b:"%q{",e:"}",c:t("{","}")},{b:"%q<",e:">",c:t("<",">")},{b:"%q/",e:"/"},{b:"%q%",e:"%"},{b:"%q-",e:"-"},{b:"%q\\|",e:"\\|"},{b:/<<-'\w+'$/,e:/^\s*\w+$/}],r:0},p={b:"("+i+")\\s*",c:[{cN:"regexp",c:[e.BE,s],v:[{b:"//[a-z]*",r:0},{b:"/",e:"/[a-z]*"},{b:"%r\\(",e:"\\)",c:t("\\(","\\)")},{b:"%r\\[",e:"\\]",c:t("\\[","\\]")},{b:"%r{",e:"}",c:t("{","}")},{b:"%r<",e:">",c:t("<",">")},{b:"%r/",e:"/"},{b:"%r%",e:"%"},{b:"%r-",e:"-"},{b:"%r\\|",e:"\\|"}]}],r:0},m={cN:"regexp",c:[e.BE,s],v:[{b:"%r\\(",e:"\\)",c:t("\\(","\\)")},{b:"%r\\[",e:"\\]",c:t("\\[","\\]")},{b:"%r{",e:"}",c:t("{","}")},{b:"%r<",e:">",c:t("<",">")},{b:"%r/",e:"/"},{b:"%r%",e:"%"},{b:"%r-",e:"-"},{b:"%r\\|",e:"\\|"}],r:0},u={cN:"meta",b:"@\\[",e:"\\]",c:[e.inherit(e.QSM,{cN:"meta-string"})]},b=[l,c,d,p,m,u,e.HCM,{cN:"class",bK:"class module struct",e:"$|;",i:/=/,c:[e.HCM,e.inherit(e.TM,{b:"[A-Za-z_]\\w*(::\\w+)*(\\?|\\!)?"}),{b:"<"}]},{cN:"class",bK:"lib enum union",e:"$|;",i:/=/,c:[e.HCM,e.inherit(e.TM,{b:"[A-Za-z_]\\w*(::\\w+)*(\\?|\\!)?"})],r:10},{cN:"function",bK:"def",e:/\B\b/,c:[e.inherit(e.TM,{b:n,endsParent:!0})]},{cN:"function",bK:"fun macro",e:/\B\b/,c:[e.inherit(e.TM,{b:n,endsParent:!0})],r:5},{cN:"symbol",b:e.UIR+"(\\!|\\?)?:",r:0},{cN:"symbol",b:":",c:[c,{b:n}],r:0},{cN:"number",v:[{b:"\\b0b([01_]*[01])"+r},{b:"\\b0o([0-7_]*[0-7])"+r},{b:"\\b0x([A-Fa-f0-9_]*[A-Fa-f0-9])"+r},{b:"\\b(([0-9][0-9_]*[0-9]|[0-9])(\\.[0-9_]*[0-9])?([eE][+-]?[0-9_]*[0-9])?)"+r}],r:0}];return s.c=b,l.c=b.slice(1),{aliases:["cr"],l:a,k:o,c:b}}),e.registerLanguage("cs",function(e){var t={keyword:"abstract as base bool break byte case catch char checked const continue decimal default delegate do double enum event explicit extern finally fixed float for foreach goto if implicit in int interface internal is lock long nameof object operator out override params private protected public readonly ref sbyte sealed short sizeof stackalloc static string struct switch this try typeof uint ulong unchecked unsafe ushort using virtual void volatile while add alias ascending async await by descending dynamic equals from get global group into join let on orderby partial remove select set value var where yield",literal:"null false true"},r={cN:"string",b:'@"',e:'"',c:[{b:'""'}]},a=e.inherit(r,{i:/\n/}),i={cN:"subst",b:"{",e:"}",k:t},n=e.inherit(i,{i:/\n/}),o={cN:"string",b:/\$"/,e:'"',i:/\n/,c:[{b:"{{"},{b:"}}"},e.BE,n]},s={cN:"string",b:/\$@"/,e:'"',c:[{b:"{{"},{b:"}}"},{b:'""'},i]},l=e.inherit(s,{i:/\n/,c:[{b:"{{"},{b:"}}"},{b:'""'},n]});i.c=[s,o,r,e.ASM,e.QSM,e.CNM,e.CBCM],n.c=[l,o,a,e.ASM,e.QSM,e.CNM,e.inherit(e.CBCM,{i:/\n/})];var c={v:[s,o,r,e.ASM,e.QSM]},d=e.IR+"(<"+e.IR+"(\\s*,\\s*"+e.IR+")*>)?(\\[\\])?";return{aliases:["csharp"],k:t,i:/::/,c:[e.C("///","$",{rB:!0,c:[{cN:"doctag",v:[{b:"///",r:0},{b:""},{b:""}]}]}),e.CLCM,e.CBCM,{cN:"meta",b:"#",e:"$",k:{"meta-keyword":"if else elif endif define undef warning error line region endregion pragma checksum"}},c,e.CNM,{bK:"class interface",e:/[{;=]/,i:/[^\s:]/,c:[e.TM,e.CLCM,e.CBCM]},{bK:"namespace",e:/[{;=]/,i:/[^\s:]/,c:[e.inherit(e.TM,{b:"[a-zA-Z](\\.?\\w)*"}),e.CLCM,e.CBCM]},{cN:"meta",b:"^\\s*\\[",eB:!0,e:"\\]",eE:!0,c:[{cN:"meta-string",b:/"/,e:/"/}]},{bK:"new return throw await else",r:0},{cN:"function",b:"("+d+"\\s+)+"+e.IR+"\\s*\\(",rB:!0,e:/[{;=]/,eE:!0,k:t,c:[{b:e.IR+"\\s*\\(",rB:!0,c:[e.TM],r:0},{cN:"params",b:/\(/,e:/\)/,eB:!0,eE:!0,k:t,r:0,c:[c,e.CNM,e.CBCM]},e.CLCM,e.CBCM]}]}}),e.registerLanguage("csp",function(e){return{cI:!1,l:"[a-zA-Z][a-zA-Z0-9_-]*",k:{keyword:"base-uri child-src connect-src default-src font-src form-action frame-ancestors frame-src img-src media-src object-src plugin-types report-uri sandbox script-src style-src"},c:[{cN:"string",b:"'",e:"'"},{cN:"attribute",b:"^Content",e:":",eE:!0}]}}),e.registerLanguage("css",function(e){var t="[a-zA-Z-][a-zA-Z0-9_-]*",r={b:/[A-Z\_\.\-]+\s*:/,rB:!0,e:";",eW:!0,c:[{cN:"attribute",b:/\S/,e:":",eE:!0,starts:{eW:!0,eE:!0,c:[{b:/[\w-]+\(/,rB:!0,c:[{cN:"built_in",b:/[\w-]+/},{b:/\(/,e:/\)/,c:[e.ASM,e.QSM]}]},e.CSSNM,e.QSM,e.ASM,e.CBCM,{cN:"number",b:"#[0-9A-Fa-f]+"},{cN:"meta",b:"!important"}]}}]};return{cI:!0,i:/[=\/|'\$]/,c:[e.CBCM,{cN:"selector-id",b:/#[A-Za-z0-9_-]+/},{cN:"selector-class",b:/\.[A-Za-z0-9_-]+/},{cN:"selector-attr",b:/\[/,e:/\]/,i:"$"},{cN:"selector-pseudo",b:/:(:)?[a-zA-Z0-9\_\-\+\(\)"'.]+/},{b:"@(font-face|page)",l:"[a-z-]+",k:"font-face page"},{b:"@",e:"[{;]",i:/:/,c:[{cN:"keyword",b:/\w+/},{b:/\s/,eW:!0,eE:!0,r:0,c:[e.ASM,e.QSM,e.CSSNM]}]},{cN:"selector-tag",b:t,r:0},{b:"{",e:"}",i:/\S/,c:[e.CBCM,r]}]}}),e.registerLanguage("d",function(e){var t={keyword:"abstract alias align asm assert auto body break byte case cast catch class const continue debug default delete deprecated do else enum export extern final finally for foreach foreach_reverse|10 goto if immutable import in inout int interface invariant is lazy macro mixin module new nothrow out override package pragma private protected public pure ref return scope shared static struct super switch synchronized template this throw try typedef typeid typeof union unittest version void volatile while with __FILE__ __LINE__ __gshared|10 __thread __traits __DATE__ __EOF__ __TIME__ __TIMESTAMP__ __VENDOR__ __VERSION__",built_in:"bool cdouble cent cfloat char creal dchar delegate double dstring float function idouble ifloat ireal long real short string ubyte ucent uint ulong ushort wchar wstring",literal:"false null true"},r="(0|[1-9][\\d_]*)",a="(0|[1-9][\\d_]*|\\d[\\d_]*|[\\d_]+?\\d)",i="0[bB][01_]+",n="([\\da-fA-F][\\da-fA-F_]*|_[\\da-fA-F][\\da-fA-F_]*)",o="0[xX]"+n,s="([eE][+-]?"+a+")",l="("+a+"(\\.\\d*|"+s+")|\\d+\\."+a+a+"|\\."+r+s+"?)",c="(0[xX]("+n+"\\."+n+"|\\.?"+n+")[pP][+-]?"+a+")",d="("+r+"|"+i+"|"+o+")",p="("+c+"|"+l+")",m="\\\\(['\"\\?\\\\abfnrtv]|u[\\dA-Fa-f]{4}|[0-7]{1,3}|x[\\dA-Fa-f]{2}|U[\\dA-Fa-f]{8})|&[a-zA-Z\\d]{2,};",u={cN:"number",b:"\\b"+d+"(L|u|U|Lu|LU|uL|UL)?",r:0},b={cN:"number",b:"\\b("+p+"([fF]|L|i|[fF]i|Li)?|"+d+"(i|[fF]i|Li))",r:0},g={cN:"string",b:"'("+m+"|.)",e:"'",i:"."},f={b:m,r:0},_={cN:"string",b:'"',c:[f],e:'"[cwd]?'},h={cN:"string",b:'[rq]"',e:'"[cwd]?',r:5},v={cN:"string",b:"`",e:"`[cwd]?"},y={cN:"string",b:'x"[\\da-fA-F\\s\\n\\r]*"[cwd]?',r:10},S={cN:"string",b:'q"\\{',e:'\\}"'},C={cN:"meta",b:"^#!",e:"$",r:5},x={cN:"meta",b:"#(line)",e:"$",r:5},E={cN:"keyword",b:"@[a-zA-Z_][a-zA-Z_\\d]*"},N=e.C("\\/\\+","\\+\\/",{c:["self"],r:10});return{l:e.UIR,k:t,c:[e.CLCM,e.CBCM,N,y,_,h,v,S,b,u,g,C,x,E]}}),e.registerLanguage("markdown",function(e){return{aliases:["md","mkdown","mkd"],c:[{cN:"section",v:[{b:"^#{1,6}",e:"$"},{b:"^.+?\\n[=-]{2,}$"}]},{b:"<",e:">",sL:"xml",r:0},{cN:"bullet",b:"^([*+-]|(\\d+\\.))\\s+"},{cN:"strong",b:"[*_]{2}.+?[*_]{2}"},{cN:"emphasis",v:[{b:"\\*.+?\\*"},{b:"_.+?_",r:0}]},{cN:"quote",b:"^>\\s+",e:"$"},{cN:"code",v:[{b:"^```w*s*$",e:"^```s*$"},{b:"`.+?`"},{b:"^( {4}| )",e:"$",r:0}]},{b:"^[-\\*]{3,}",e:"$"},{b:"\\[.+?\\][\\(\\[].*?[\\)\\]]",rB:!0,c:[{cN:"string",b:"\\[",e:"\\]",eB:!0,rE:!0,r:0},{cN:"link",b:"\\]\\(",e:"\\)",eB:!0,eE:!0},{cN:"symbol",b:"\\]\\[",e:"\\]",eB:!0,eE:!0}],r:10},{b:/^\[[^\n]+\]:/,rB:!0,c:[{cN:"symbol",b:/\[/,e:/\]/,eB:!0,eE:!0},{cN:"link",b:/:\s*/,e:/$/,eB:!0}]}]}}),e.registerLanguage("dart",function(e){var t={cN:"subst",b:"\\$\\{",e:"}",k:"true false null this is new super"},r={cN:"string",v:[{b:"r'''",e:"'''"},{b:'r"""',e:'"""'},{b:"r'",e:"'",i:"\\n"},{b:'r"',e:'"',i:"\\n"},{b:"'''",e:"'''",c:[e.BE,t]},{b:'"""',e:'"""',c:[e.BE,t]},{b:"'",e:"'",i:"\\n",c:[e.BE,t]},{b:'"',e:'"',i:"\\n",c:[e.BE,t]}]};t.c=[e.CNM,r];var a={keyword:"assert async await break case catch class const continue default do else enum extends false final finally for if in is new null rethrow return super switch sync this throw true try var void while with yield abstract as dynamic export external factory get implements import library operator part set static typedef",built_in:"print Comparable DateTime Duration Function Iterable Iterator List Map Match Null Object Pattern RegExp Set Stopwatch String StringBuffer StringSink Symbol Type Uri bool double int num document window querySelector querySelectorAll Element ElementList"};return{k:a,c:[r,e.C("/\\*\\*","\\*/",{sL:"markdown"}),e.C("///","$",{sL:"markdown"}),e.CLCM,e.CBCM,{cN:"class",bK:"class interface",e:"{",eE:!0,c:[{bK:"extends implements"},e.UTM]},e.CNM,{cN:"meta",b:"@[A-Za-z]+"},{b:"=>"}]}}),e.registerLanguage("delphi",function(e){var t="exports register file shl array record property for mod while set ally label uses raise not stored class safecall var interface or private static exit index inherited to else stdcall override shr asm far resourcestring finalization packed virtual out and protected library do xorwrite goto near function end div overload object unit begin string on inline repeat until destructor write message program with read initialization except default nil if case cdecl in downto threadvar of try pascal const external constructor type public then implementation finally published procedure absolute reintroduce operator as is abstract alias assembler bitpacked break continue cppdecl cvar enumerator experimental platform deprecated unimplemented dynamic export far16 forward generic helper implements interrupt iochecks local name nodefault noreturn nostackframe oldfpccall otherwise saveregisters softfloat specialize strict unaligned varargs ",r=[e.CLCM,e.C(/\{/,/\}/,{r:0}),e.C(/\(\*/,/\*\)/,{r:10})],a={cN:"meta",v:[{b:/\{\$/,e:/\}/},{b:/\(\*\$/,e:/\*\)/}]},i={cN:"string",b:/'/,e:/'/,c:[{b:/''/}]},n={cN:"string",b:/(#\d+)+/},o={b:e.IR+"\\s*=\\s*class\\s*\\(",rB:!0,c:[e.TM]},s={cN:"function",bK:"function constructor destructor procedure",e:/[:;]/,k:"function constructor|10 destructor|10 procedure|10",c:[e.TM,{cN:"params",b:/\(/,e:/\)/,k:t,c:[i,n,a].concat(r)},a].concat(r)};return{aliases:["dpr","dfm","pas","pascal","freepascal","lazarus","lpr","lfm"],cI:!0,k:t,i:/"|\$[G-Zg-z]|\/\*|<\/|\|/,c:[i,n,e.NM,o,s,a].concat(r)}}),e.registerLanguage("diff",function(e){return{aliases:["patch"],c:[{cN:"meta",r:10,v:[{b:/^@@ +\-\d+,\d+ +\+\d+,\d+ +@@$/},{b:/^\*\*\* +\d+,\d+ +\*\*\*\*$/},{b:/^\-\-\- +\d+,\d+ +\-\-\-\-$/}]},{cN:"comment",v:[{b:/Index: /,e:/$/},{b:/={3,}/,e:/$/},{b:/^\-{3}/,e:/$/},{b:/^\*{3} /,e:/$/},{b:/^\+{3}/,e:/$/},{b:/\*{5}/,e:/\*{5}$/}]},{cN:"addition",b:"^\\+",e:"$"},{cN:"deletion",b:"^\\-",e:"$"},{cN:"addition",b:"^\\!",e:"$"}]}}),e.registerLanguage("django",function(e){var t={b:/\|[A-Za-z]+:?/,k:{name:"truncatewords removetags linebreaksbr yesno get_digit timesince random striptags filesizeformat escape linebreaks length_is ljust rjust cut urlize fix_ampersands title floatformat capfirst pprint divisibleby add make_list unordered_list urlencode timeuntil urlizetrunc wordcount stringformat linenumbers slice date dictsort dictsortreversed default_if_none pluralize lower join center default truncatewords_html upper length phone2numeric wordwrap time addslashes slugify first escapejs force_escape iriencode last safe safeseq truncatechars localize unlocalize localtime utc timezone"},c:[e.QSM,e.ASM]};return{aliases:["jinja"],cI:!0,sL:"xml",c:[e.C(/\{%\s*comment\s*%}/,/\{%\s*endcomment\s*%}/),e.C(/\{#/,/#}/),{cN:"template-tag",b:/\{%/,e:/%}/,c:[{cN:"name",b:/\w+/,k:{name:"comment endcomment load templatetag ifchanged endifchanged if endif firstof for endfor ifnotequal endifnotequal widthratio extends include spaceless endspaceless regroup ifequal endifequal ssi now with cycle url filter endfilter debug block endblock else autoescape endautoescape csrf_token empty elif endwith static trans blocktrans endblocktrans get_static_prefix get_media_prefix plural get_current_language language get_available_languages get_current_language_bidi get_language_info get_language_info_list localize endlocalize localtime endlocaltime timezone endtimezone get_current_timezone verbatim"},starts:{eW:!0,k:"in by as",c:[t],r:0}}]},{cN:"template-variable",b:/\{\{/,e:/}}/,c:[t]}]}}),e.registerLanguage("dns",function(e){return{aliases:["bind","zone"],k:{keyword:"IN A AAAA AFSDB APL CAA CDNSKEY CDS CERT CNAME DHCID DLV DNAME DNSKEY DS HIP IPSECKEY KEY KX LOC MX NAPTR NS NSEC NSEC3 NSEC3PARAM PTR RRSIG RP SIG SOA SRV SSHFP TA TKEY TLSA TSIG TXT"},c:[e.C(";","$",{r:0}),{cN:"meta",b:/^\$(TTL|GENERATE|INCLUDE|ORIGIN)\b/},{cN:"number",b:"((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:)))\\b"},{cN:"number",b:"((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]).){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\b"},e.inherit(e.NM,{b:/\b\d+[dhwm]?/})]}}),e.registerLanguage("dockerfile",function(e){return{aliases:["docker"],cI:!0,k:"from maintainer expose env arg user onbuild stopsignal",c:[e.HCM,e.ASM,e.QSM,e.NM,{bK:"run cmd entrypoint volume add copy workdir label healthcheck shell",starts:{e:/[^\\]\n/,sL:"bash"}}],i:"", -i:"\\n"}]},t,e.CLCM,e.CBCM]},i={cN:"variable",b:"\\&[a-z\\d_]*\\b"},n={cN:"meta-keyword",b:"/[a-z][a-z\\d-]*/"},o={cN:"symbol",b:"^\\s*[a-zA-Z_][a-zA-Z\\d_]*:"},s={cN:"params",b:"<",e:">",c:[r,i]},l={cN:"class",b:/[a-zA-Z_][a-zA-Z\d_@]*\s{/,e:/[{;=]/,rB:!0,eE:!0},c={cN:"class",b:"/\\s*{",e:"};",r:10,c:[i,n,o,l,s,e.CLCM,e.CBCM,r,t]};return{k:"",c:[c,i,n,o,l,s,e.CLCM,e.CBCM,r,t,a,{b:e.IR+"::",k:""}]}}),e.registerLanguage("dust",function(e){var t="if eq ne lt lte gt gte select default math sep";return{aliases:["dst"],cI:!0,sL:"xml",c:[{cN:"template-tag",b:/\{[#\/]/,e:/\}/,i:/;/,c:[{cN:"name",b:/[a-zA-Z\.-]+/,starts:{eW:!0,r:0,c:[e.QSM]}}]},{cN:"template-variable",b:/\{/,e:/\}/,i:/;/,k:t}]}}),e.registerLanguage("ebnf",function(e){var t=e.C(/\(\*/,/\*\)/),r={cN:"attribute",b:/^[ ]*[a-zA-Z][a-zA-Z-]*([\s-]+[a-zA-Z][a-zA-Z]*)*/},a={cN:"meta",b:/\?.*\?/},i={b:/=/,e:/;/,c:[t,a,e.ASM,e.QSM]};return{i:/\S/,c:[t,r,i]}}),e.registerLanguage("elixir",function(e){var t="[a-zA-Z_][a-zA-Z0-9_]*(\\!|\\?)?",r="[a-zA-Z_]\\w*[!?=]?|[-+~]\\@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?",a="and false then defined module in return redo retry end for true self when next until do begin unless nil break not case cond alias while ensure or include use alias fn quote",i={cN:"subst",b:"#\\{",e:"}",l:t,k:a},n={cN:"string",c:[e.BE,i],v:[{b:/'/,e:/'/},{b:/"/,e:/"/}]},o={cN:"function",bK:"def defp defmacro",e:/\B\b/,c:[e.inherit(e.TM,{b:t,endsParent:!0})]},s=e.inherit(o,{cN:"class",bK:"defimpl defmodule defprotocol defrecord",e:/\bdo\b|$|;/}),l=[n,e.HCM,s,o,{cN:"symbol",b:":(?!\\s)",c:[n,{b:r}],r:0},{cN:"symbol",b:t+":",r:0},{cN:"number",b:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",r:0},{cN:"variable",b:"(\\$\\W)|((\\$|\\@\\@?)(\\w+))"},{b:"->"},{b:"("+e.RSR+")\\s*",c:[e.HCM,{cN:"regexp",i:"\\n",c:[e.BE,i],v:[{b:"/",e:"/[a-z]*"},{b:"%r\\[",e:"\\][a-z]*"}]}],r:0}];return i.c=l,{l:t,k:a,c:l}}),e.registerLanguage("elm",function(e){var t={v:[e.C("--","$"),e.C("{-","-}",{c:["self"]})]},r={cN:"type",b:"\\b[A-Z][\\w']*",r:0},a={b:"\\(",e:"\\)",i:'"',c:[{cN:"type",b:"\\b[A-Z][\\w]*(\\((\\.\\.|,|\\w+)\\))?"},t]},i={b:"{",e:"}",c:a.c};return{k:"let in if then else case of where module import exposing type alias as infix infixl infixr port effect command subscription",c:[{bK:"port effect module",e:"exposing",k:"port effect module where command subscription exposing",c:[a,t],i:"\\W\\.|;"},{b:"import",e:"$",k:"import as exposing",c:[a,t],i:"\\W\\.|;"},{b:"type",e:"$",k:"type alias",c:[r,a,i,t]},{bK:"infix infixl infixr",e:"$",c:[e.CNM,t]},{b:"port",e:"$",k:"port",c:[t]},e.QSM,e.CNM,r,e.inherit(e.TM,{b:"^[_a-z][\\w']*"}),t,{b:"->|<-"}],i:/;/}}),e.registerLanguage("ruby",function(e){var t="[a-zA-Z_]\\w*[!?=]?|[-+~]\\@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?",r={keyword:"and then defined module in return redo if BEGIN retry end for self when next until do begin unless END rescue else break undef not super class case require yield alias while ensure elsif or include attr_reader attr_writer attr_accessor",literal:"true false nil"},a={cN:"doctag",b:"@[A-Za-z]+"},i={b:"#<",e:">"},n=[e.C("#","$",{c:[a]}),e.C("^\\=begin","^\\=end",{c:[a],r:10}),e.C("^__END__","\\n$")],o={cN:"subst",b:"#\\{",e:"}",k:r},s={cN:"string",c:[e.BE,o],v:[{b:/'/,e:/'/},{b:/"/,e:/"/},{b:/`/,e:/`/},{b:"%[qQwWx]?\\(",e:"\\)"},{b:"%[qQwWx]?\\[",e:"\\]"},{b:"%[qQwWx]?{",e:"}"},{b:"%[qQwWx]?<",e:">"},{b:"%[qQwWx]?/",e:"/"},{b:"%[qQwWx]?%",e:"%"},{b:"%[qQwWx]?-",e:"-"},{b:"%[qQwWx]?\\|",e:"\\|"},{b:/\B\?(\\\d{1,3}|\\x[A-Fa-f0-9]{1,2}|\\u[A-Fa-f0-9]{4}|\\?\S)\b/},{b:/<<(-?)\w+$/,e:/^\s*\w+$/}]},l={cN:"params",b:"\\(",e:"\\)",endsParent:!0,k:r},c=[s,i,{cN:"class",bK:"class module",e:"$|;",i:/=/,c:[e.inherit(e.TM,{b:"[A-Za-z_]\\w*(::\\w+)*(\\?|\\!)?"}),{b:"<\\s*",c:[{b:"("+e.IR+"::)?"+e.IR}]}].concat(n)},{cN:"function",bK:"def",e:"$|;",c:[e.inherit(e.TM,{b:t}),l].concat(n)},{b:e.IR+"::"},{cN:"symbol",b:e.UIR+"(\\!|\\?)?:",r:0},{cN:"symbol",b:":(?!\\s)",c:[s,{b:t}],r:0},{cN:"number",b:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",r:0},{b:"(\\$\\W)|((\\$|\\@\\@?)(\\w+))"},{cN:"params",b:/\|/,e:/\|/,k:r},{b:"("+e.RSR+"|unless)\\s*",k:"unless",c:[i,{cN:"regexp",c:[e.BE,o],i:/\n/,v:[{b:"/",e:"/[a-z]*"},{b:"%r{",e:"}[a-z]*"},{b:"%r\\(",e:"\\)[a-z]*"},{b:"%r!",e:"![a-z]*"},{b:"%r\\[",e:"\\][a-z]*"}]}].concat(n),r:0}].concat(n);o.c=c,l.c=c;var d="[>?]>",p="[\\w#]+\\(\\w+\\):\\d+:\\d+>",m="(\\w+-)?\\d+\\.\\d+\\.\\d(p\\d+)?[^>]+>",u=[{b:/^\s*=>/,starts:{e:"$",c:c}},{cN:"meta",b:"^("+d+"|"+p+"|"+m+")",starts:{e:"$",c:c}}];return{aliases:["rb","gemspec","podspec","thor","irb"],k:r,i:/\/\*/,c:n.concat(u).concat(c)}}),e.registerLanguage("erb",function(e){return{sL:"xml",c:[e.C("<%#","%>"),{b:"<%[%=-]?",e:"[%-]?%>",sL:"ruby",eB:!0,eE:!0}]}}),e.registerLanguage("erlang-repl",function(e){return{k:{built_in:"spawn spawn_link self",keyword:"after and andalso|10 band begin bnot bor bsl bsr bxor case catch cond div end fun if let not of or orelse|10 query receive rem try when xor"},c:[{cN:"meta",b:"^[0-9]+> ",r:10},e.C("%","$"),{cN:"number",b:"\\b(\\d+#[a-fA-F0-9]+|\\d+(\\.\\d+)?([eE][-+]?\\d+)?)",r:0},e.ASM,e.QSM,{b:"\\?(::)?([A-Z]\\w*(::)?)+"},{b:"->"},{b:"ok"},{b:"!"},{b:"(\\b[a-z'][a-zA-Z0-9_']*:[a-z'][a-zA-Z0-9_']*)|(\\b[a-z'][a-zA-Z0-9_']*)",r:0},{b:"[A-Z][a-zA-Z0-9_']*",r:0}]}}),e.registerLanguage("erlang",function(e){var t="[a-z'][a-zA-Z0-9_']*",r="("+t+":"+t+"|"+t+")",a={keyword:"after and andalso|10 band begin bnot bor bsl bzr bxor case catch cond div end fun if let not of orelse|10 query receive rem try when xor",literal:"false true"},i=e.C("%","$"),n={cN:"number",b:"\\b(\\d+#[a-fA-F0-9]+|\\d+(\\.\\d+)?([eE][-+]?\\d+)?)",r:0},o={b:"fun\\s+"+t+"/\\d+"},s={b:r+"\\(",e:"\\)",rB:!0,r:0,c:[{b:r,r:0},{b:"\\(",e:"\\)",eW:!0,rE:!0,r:0}]},l={b:"{",e:"}",r:0},c={b:"\\b_([A-Z][A-Za-z0-9_]*)?",r:0},d={b:"[A-Z][a-zA-Z0-9_]*",r:0},p={b:"#"+e.UIR,r:0,rB:!0,c:[{b:"#"+e.UIR,r:0},{b:"{",e:"}",r:0}]},m={bK:"fun receive if try case",e:"end",k:a};m.c=[i,o,e.inherit(e.ASM,{cN:""}),m,s,e.QSM,n,l,c,d,p];var u=[i,o,m,s,e.QSM,n,l,c,d,p];s.c[1].c=u,l.c=u,p.c[1].c=u;var b={cN:"params",b:"\\(",e:"\\)",c:u};return{aliases:["erl"],k:a,i:"(",rB:!0,i:"\\(|#|//|/\\*|\\\\|:|;",c:[b,e.inherit(e.TM,{b:t})],starts:{e:";|\\.",k:a,c:u}},i,{b:"^-",e:"\\.",r:0,eE:!0,rB:!0,l:"-"+e.IR,k:"-module -record -undef -export -ifdef -ifndef -author -copyright -doc -vsn -import -include -include_lib -compile -define -else -endif -file -behaviour -behavior -spec",c:[b]},n,e.QSM,p,c,d,l,{b:/\.$/}]}}),e.registerLanguage("excel",function(e){return{aliases:["xlsx","xls"],cI:!0,l:/[a-zA-Z][\w\.]*/,k:{built_in:"ABS ACCRINT ACCRINTM ACOS ACOSH ACOT ACOTH AGGREGATE ADDRESS AMORDEGRC AMORLINC AND ARABIC AREAS ASC ASIN ASINH ATAN ATAN2 ATANH AVEDEV AVERAGE AVERAGEA AVERAGEIF AVERAGEIFS BAHTTEXT BASE BESSELI BESSELJ BESSELK BESSELY BETADIST BETA.DIST BETAINV BETA.INV BIN2DEC BIN2HEX BIN2OCT BINOMDIST BINOM.DIST BINOM.DIST.RANGE BINOM.INV BITAND BITLSHIFT BITOR BITRSHIFT BITXOR CALL CEILING CEILING.MATH CEILING.PRECISE CELL CHAR CHIDIST CHIINV CHITEST CHISQ.DIST CHISQ.DIST.RT CHISQ.INV CHISQ.INV.RT CHISQ.TEST CHOOSE CLEAN CODE COLUMN COLUMNS COMBIN COMBINA COMPLEX CONCAT CONCATENATE CONFIDENCE CONFIDENCE.NORM CONFIDENCE.T CONVERT CORREL COS COSH COT COTH COUNT COUNTA COUNTBLANK COUNTIF COUNTIFS COUPDAYBS COUPDAYS COUPDAYSNC COUPNCD COUPNUM COUPPCD COVAR COVARIANCE.P COVARIANCE.S CRITBINOM CSC CSCH CUBEKPIMEMBER CUBEMEMBER CUBEMEMBERPROPERTY CUBERANKEDMEMBER CUBESET CUBESETCOUNT CUBEVALUE CUMIPMT CUMPRINC DATE DATEDIF DATEVALUE DAVERAGE DAY DAYS DAYS360 DB DBCS DCOUNT DCOUNTA DDB DEC2BIN DEC2HEX DEC2OCT DECIMAL DEGREES DELTA DEVSQ DGET DISC DMAX DMIN DOLLAR DOLLARDE DOLLARFR DPRODUCT DSTDEV DSTDEVP DSUM DURATION DVAR DVARP EDATE EFFECT ENCODEURL EOMONTH ERF ERF.PRECISE ERFC ERFC.PRECISE ERROR.TYPE EUROCONVERT EVEN EXACT EXP EXPON.DIST EXPONDIST FACT FACTDOUBLE FALSE|0 F.DIST FDIST F.DIST.RT FILTERXML FIND FINDB F.INV F.INV.RT FINV FISHER FISHERINV FIXED FLOOR FLOOR.MATH FLOOR.PRECISE FORECAST FORECAST.ETS FORECAST.ETS.CONFINT FORECAST.ETS.SEASONALITY FORECAST.ETS.STAT FORECAST.LINEAR FORMULATEXT FREQUENCY F.TEST FTEST FV FVSCHEDULE GAMMA GAMMA.DIST GAMMADIST GAMMA.INV GAMMAINV GAMMALN GAMMALN.PRECISE GAUSS GCD GEOMEAN GESTEP GETPIVOTDATA GROWTH HARMEAN HEX2BIN HEX2DEC HEX2OCT HLOOKUP HOUR HYPERLINK HYPGEOM.DIST HYPGEOMDIST IF|0 IFERROR IFNA IFS IMABS IMAGINARY IMARGUMENT IMCONJUGATE IMCOS IMCOSH IMCOT IMCSC IMCSCH IMDIV IMEXP IMLN IMLOG10 IMLOG2 IMPOWER IMPRODUCT IMREAL IMSEC IMSECH IMSIN IMSINH IMSQRT IMSUB IMSUM IMTAN INDEX INDIRECT INFO INT INTERCEPT INTRATE IPMT IRR ISBLANK ISERR ISERROR ISEVEN ISFORMULA ISLOGICAL ISNA ISNONTEXT ISNUMBER ISODD ISREF ISTEXT ISO.CEILING ISOWEEKNUM ISPMT JIS KURT LARGE LCM LEFT LEFTB LEN LENB LINEST LN LOG LOG10 LOGEST LOGINV LOGNORM.DIST LOGNORMDIST LOGNORM.INV LOOKUP LOWER MATCH MAX MAXA MAXIFS MDETERM MDURATION MEDIAN MID MIDBs MIN MINIFS MINA MINUTE MINVERSE MIRR MMULT MOD MODE MODE.MULT MODE.SNGL MONTH MROUND MULTINOMIAL MUNIT N NA NEGBINOM.DIST NEGBINOMDIST NETWORKDAYS NETWORKDAYS.INTL NOMINAL NORM.DIST NORMDIST NORMINV NORM.INV NORM.S.DIST NORMSDIST NORM.S.INV NORMSINV NOT NOW NPER NPV NUMBERVALUE OCT2BIN OCT2DEC OCT2HEX ODD ODDFPRICE ODDFYIELD ODDLPRICE ODDLYIELD OFFSET OR PDURATION PEARSON PERCENTILE.EXC PERCENTILE.INC PERCENTILE PERCENTRANK.EXC PERCENTRANK.INC PERCENTRANK PERMUT PERMUTATIONA PHI PHONETIC PI PMT POISSON.DIST POISSON POWER PPMT PRICE PRICEDISC PRICEMAT PROB PRODUCT PROPER PV QUARTILE QUARTILE.EXC QUARTILE.INC QUOTIENT RADIANS RAND RANDBETWEEN RANK.AVG RANK.EQ RANK RATE RECEIVED REGISTER.ID REPLACE REPLACEB REPT RIGHT RIGHTB ROMAN ROUND ROUNDDOWN ROUNDUP ROW ROWS RRI RSQ RTD SEARCH SEARCHB SEC SECH SECOND SERIESSUM SHEET SHEETS SIGN SIN SINH SKEW SKEW.P SLN SLOPE SMALL SQL.REQUEST SQRT SQRTPI STANDARDIZE STDEV STDEV.P STDEV.S STDEVA STDEVP STDEVPA STEYX SUBSTITUTE SUBTOTAL SUM SUMIF SUMIFS SUMPRODUCT SUMSQ SUMX2MY2 SUMX2PY2 SUMXMY2 SWITCH SYD T TAN TANH TBILLEQ TBILLPRICE TBILLYIELD T.DIST T.DIST.2T T.DIST.RT TDIST TEXT TEXTJOIN TIME TIMEVALUE T.INV T.INV.2T TINV TODAY TRANSPOSE TREND TRIM TRIMMEAN TRUE|0 TRUNC T.TEST TTEST TYPE UNICHAR UNICODE UPPER VALUE VAR VAR.P VAR.S VARA VARP VARPA VDB VLOOKUP WEBSERVICE WEEKDAY WEEKNUM WEIBULL WEIBULL.DIST WORKDAY WORKDAY.INTL XIRR XNPV XOR YEAR YEARFRAC YIELD YIELDDISC YIELDMAT Z.TEST ZTEST"},c:[{b:/^=/,e:/[^=]/,rE:!0,i:/=/,r:10},{cN:"symbol",b:/\b[A-Z]{1,2}\d+\b/,e:/[^\d]/,eE:!0,r:0},{cN:"symbol",b:/[A-Z]{0,2}\d*:[A-Z]{0,2}\d*/,r:0},e.BE,e.QSM,{cN:"number",b:e.NR+"(%)?",r:0},e.C(/\bN\(/,/\)/,{eB:!0,eE:!0,i:/\n/})]}}),e.registerLanguage("fix",function(e){return{c:[{b:/[^\u2401\u0001]+/,e:/[\u2401\u0001]/,eE:!0,rB:!0,rE:!1,c:[{b:/([^\u2401\u0001=]+)/,e:/=([^\u2401\u0001=]+)/,rE:!0,rB:!1,cN:"attr"},{b:/=/,e:/([\u2401\u0001])/,eE:!0,eB:!0,cN:"string"}]}],cI:!0}}),e.registerLanguage("flix",function(e){var t={cN:"string",b:/'(.|\\[xXuU][a-zA-Z0-9]+)'/},r={cN:"string",v:[{b:'"',e:'"'}]},a={cN:"title",b:/[^0-9\n\t "'(),.`{}\[\]:;][^\n\t "'(),.`{}\[\]:;]+|[^0-9\n\t "'(),.`{}\[\]:;=]/},i={cN:"function",bK:"def",e:/[:={\[(\n;]/,eE:!0,c:[a]};return{k:{literal:"true false",keyword:"case class def else enum if impl import in lat rel index let match namespace switch type yield with"},c:[e.CLCM,e.CBCM,t,r,i,e.CNM]}}),e.registerLanguage("fortran",function(e){var t={cN:"params",b:"\\(",e:"\\)"},r={literal:".False. .True.",keyword:"kind do while private call intrinsic where elsewhere type endtype endmodule endselect endinterface end enddo endif if forall endforall only contains default return stop then public subroutine|10 function program .and. .or. .not. .le. .eq. .ge. .gt. .lt. goto save else use module select case access blank direct exist file fmt form formatted iostat name named nextrec number opened rec recl sequential status unformatted unit continue format pause cycle exit c_null_char c_alert c_backspace c_form_feed flush wait decimal round iomsg synchronous nopass non_overridable pass protected volatile abstract extends import non_intrinsic value deferred generic final enumerator class associate bind enum c_int c_short c_long c_long_long c_signed_char c_size_t c_int8_t c_int16_t c_int32_t c_int64_t c_int_least8_t c_int_least16_t c_int_least32_t c_int_least64_t c_int_fast8_t c_int_fast16_t c_int_fast32_t c_int_fast64_t c_intmax_t C_intptr_t c_float c_double c_long_double c_float_complex c_double_complex c_long_double_complex c_bool c_char c_null_ptr c_null_funptr c_new_line c_carriage_return c_horizontal_tab c_vertical_tab iso_c_binding c_loc c_funloc c_associated c_f_pointer c_ptr c_funptr iso_fortran_env character_storage_size error_unit file_storage_size input_unit iostat_end iostat_eor numeric_storage_size output_unit c_f_procpointer ieee_arithmetic ieee_support_underflow_control ieee_get_underflow_mode ieee_set_underflow_mode newunit contiguous recursive pad position action delim readwrite eor advance nml interface procedure namelist include sequence elemental pure integer real character complex logical dimension allocatable|10 parameter external implicit|10 none double precision assign intent optional pointer target in out common equivalence data",built_in:"alog alog10 amax0 amax1 amin0 amin1 amod cabs ccos cexp clog csin csqrt dabs dacos dasin datan datan2 dcos dcosh ddim dexp dint dlog dlog10 dmax1 dmin1 dmod dnint dsign dsin dsinh dsqrt dtan dtanh float iabs idim idint idnint ifix isign max0 max1 min0 min1 sngl algama cdabs cdcos cdexp cdlog cdsin cdsqrt cqabs cqcos cqexp cqlog cqsin cqsqrt dcmplx dconjg derf derfc dfloat dgamma dimag dlgama iqint qabs qacos qasin qatan qatan2 qcmplx qconjg qcos qcosh qdim qerf qerfc qexp qgamma qimag qlgama qlog qlog10 qmax1 qmin1 qmod qnint qsign qsin qsinh qsqrt qtan qtanh abs acos aimag aint anint asin atan atan2 char cmplx conjg cos cosh exp ichar index int log log10 max min nint sign sin sinh sqrt tan tanh print write dim lge lgt lle llt mod nullify allocate deallocate adjustl adjustr all allocated any associated bit_size btest ceiling count cshift date_and_time digits dot_product eoshift epsilon exponent floor fraction huge iand ibclr ibits ibset ieor ior ishft ishftc lbound len_trim matmul maxexponent maxloc maxval merge minexponent minloc minval modulo mvbits nearest pack present product radix random_number random_seed range repeat reshape rrspacing scale scan selected_int_kind selected_real_kind set_exponent shape size spacing spread sum system_clock tiny transpose trim ubound unpack verify achar iachar transfer dble entry dprod cpu_time command_argument_count get_command get_command_argument get_environment_variable is_iostat_end ieee_arithmetic ieee_support_underflow_control ieee_get_underflow_mode ieee_set_underflow_mode is_iostat_eor move_alloc new_line selected_char_kind same_type_as extends_type_ofacosh asinh atanh bessel_j0 bessel_j1 bessel_jn bessel_y0 bessel_y1 bessel_yn erf erfc erfc_scaled gamma log_gamma hypot norm2 atomic_define atomic_ref execute_command_line leadz trailz storage_size merge_bits bge bgt ble blt dshiftl dshiftr findloc iall iany iparity image_index lcobound ucobound maskl maskr num_images parity popcnt poppar shifta shiftl shiftr this_image"};return{cI:!0,aliases:["f90","f95"],k:r,i:/\/\*/,c:[e.inherit(e.ASM,{cN:"string",r:0}),e.inherit(e.QSM,{cN:"string",r:0}),{cN:"function",bK:"subroutine function program",i:"[${=\\n]",c:[e.UTM,t]},e.C("!","$",{r:0}),{cN:"number",b:"(?=\\b|\\+|\\-|\\.)(?=\\.\\d|\\d)(?:\\d+)?(?:\\.?\\d*)(?:[de][+-]?\\d+)?\\b\\.?",r:0}]}}),e.registerLanguage("fsharp",function(e){var t={b:"<",e:">",c:[e.inherit(e.TM,{b:/'[a-zA-Z0-9_]+/})]};return{aliases:["fs"],k:"abstract and as assert base begin class default delegate do done downcast downto elif else end exception extern false finally for fun function global if in inherit inline interface internal lazy let match member module mutable namespace new null of open or override private public rec return sig static struct then to true try type upcast use val void when while with yield",i:/\/\*/,c:[{cN:"keyword",b:/\b(yield|return|let|do)!/},{cN:"string",b:'@"',e:'"',c:[{b:'""'}]},{cN:"string",b:'"""',e:'"""'},e.C("\\(\\*","\\*\\)"),{cN:"class",bK:"type",e:"\\(|=|$",eE:!0,c:[e.UTM,t]},{cN:"meta",b:"\\[<",e:">\\]",r:10},{cN:"symbol",b:"\\B('[A-Za-z])\\b",c:[e.BE]},e.CLCM,e.inherit(e.QSM,{i:null}),e.CNM]}}),e.registerLanguage("gams",function(e){var t={keyword:"abort acronym acronyms alias all and assign binary card diag display else eq file files for free ge gt if integer le loop lt maximizing minimizing model models ne negative no not option options or ord positive prod put putpage puttl repeat sameas semicont semiint smax smin solve sos1 sos2 sum system table then until using while xor yes",literal:"eps inf na","built-in":"abs arccos arcsin arctan arctan2 Beta betaReg binomial ceil centropy cos cosh cvPower div div0 eDist entropy errorf execSeed exp fact floor frac gamma gammaReg log logBeta logGamma log10 log2 mapVal max min mod ncpCM ncpF ncpVUpow ncpVUsin normal pi poly power randBinomial randLinear randTriangle round rPower sigmoid sign signPower sin sinh slexp sllog10 slrec sqexp sqlog10 sqr sqrec sqrt tan tanh trunc uniform uniformInt vcPower bool_and bool_eqv bool_imp bool_not bool_or bool_xor ifThen rel_eq rel_ge rel_gt rel_le rel_lt rel_ne gday gdow ghour gleap gmillisec gminute gmonth gsecond gyear jdate jnow jstart jtime errorLevel execError gamsRelease gamsVersion handleCollect handleDelete handleStatus handleSubmit heapFree heapLimit heapSize jobHandle jobKill jobStatus jobTerminate licenseLevel licenseStatus maxExecError sleep timeClose timeComp timeElapsed timeExec timeStart"},r={cN:"params",b:/\(/,e:/\)/,eB:!0,eE:!0},a={cN:"symbol",v:[{b:/\=[lgenxc]=/},{b:/\$/}]},i={cN:"comment",v:[{b:"'",e:"'"},{b:'"',e:'"'}],i:"\\n",c:[e.BE]},n={b:"/",e:"/",k:t,c:[i,e.CLCM,e.CBCM,e.QSM,e.ASM,e.CNM]},o={b:/[a-z][a-z0-9_]*(\([a-z0-9_, ]*\))?[ \t]+/,eB:!0,e:"$",eW:!0,c:[i,n,{cN:"comment",b:/([ ]*[a-z0-9&#*=?@>\\<:\-,()$\[\]_.{}!+%^]+)+/,r:0}]};return{aliases:["gms"],cI:!0,k:t,c:[e.C(/^\$ontext/,/^\$offtext/),{cN:"meta",b:"^\\$[a-z0-9]+",e:"$",rB:!0,c:[{cN:"meta-keyword",b:"^\\$[a-z0-9]+"}]},e.C("^\\*","$"),e.CLCM,e.CBCM,e.QSM,e.ASM,{bK:"set sets parameter parameters variable variables scalar scalars equation equations",e:";",c:[e.C("^\\*","$"),e.CLCM,e.CBCM,e.QSM,e.ASM,n,o]},{bK:"table",e:";",rB:!0,c:[{bK:"table",e:"$",c:[o]},e.C("^\\*","$"),e.CLCM,e.CBCM,e.QSM,e.ASM,e.CNM]},{cN:"function",b:/^[a-z][a-z0-9_,\-+' ()$]+\.{2}/,rB:!0,c:[{cN:"title",b:/^[a-z0-9_]+/},r,a]},e.CNM,a]}}),e.registerLanguage("gauss",function(e){var t={keyword:"and bool break call callexe checkinterrupt clear clearg closeall cls comlog compile continue create debug declare delete disable dlibrary dllcall do dos ed edit else elseif enable end endfor endif endp endo errorlog errorlogat expr external fn for format goto gosub graph if keyword let lib library line load loadarray loadexe loadf loadk loadm loadp loads loadx local locate loopnextindex lprint lpwidth lshow matrix msym ndpclex new not open or output outwidth plot plotsym pop prcsn print printdos proc push retp return rndcon rndmod rndmult rndseed run save saveall screen scroll setarray show sparse stop string struct system trace trap threadfor threadendfor threadbegin threadjoin threadstat threadend until use while winprint",built_in:"abs acf aconcat aeye amax amean AmericanBinomCall AmericanBinomCall_Greeks AmericanBinomCall_ImpVol AmericanBinomPut AmericanBinomPut_Greeks AmericanBinomPut_ImpVol AmericanBSCall AmericanBSCall_Greeks AmericanBSCall_ImpVol AmericanBSPut AmericanBSPut_Greeks AmericanBSPut_ImpVol amin amult annotationGetDefaults annotationSetBkd annotationSetFont annotationSetLineColor annotationSetLineStyle annotationSetLineThickness annualTradingDays arccos arcsin areshape arrayalloc arrayindex arrayinit arraytomat asciiload asclabel astd astds asum atan atan2 atranspose axmargin balance band bandchol bandcholsol bandltsol bandrv bandsolpd bar base10 begwind besselj bessely beta box boxcox cdfBeta cdfBetaInv cdfBinomial cdfBinomialInv cdfBvn cdfBvn2 cdfBvn2e cdfCauchy cdfCauchyInv cdfChic cdfChii cdfChinc cdfChincInv cdfExp cdfExpInv cdfFc cdfFnc cdfFncInv cdfGam cdfGenPareto cdfHyperGeo cdfLaplace cdfLaplaceInv cdfLogistic cdfLogisticInv cdfmControlCreate cdfMvn cdfMvn2e cdfMvnce cdfMvne cdfMvt2e cdfMvtce cdfMvte cdfN cdfN2 cdfNc cdfNegBinomial cdfNegBinomialInv cdfNi cdfPoisson cdfPoissonInv cdfRayleigh cdfRayleighInv cdfTc cdfTci cdfTnc cdfTvn cdfWeibull cdfWeibullInv cdir ceil ChangeDir chdir chiBarSquare chol choldn cholsol cholup chrs close code cols colsf combinate combinated complex con cond conj cons ConScore contour conv convertsatostr convertstrtosa corrm corrms corrvc corrx corrxs cos cosh counts countwts crossprd crout croutp csrcol csrlin csvReadM csvReadSA cumprodc cumsumc curve cvtos datacreate datacreatecomplex datalist dataload dataloop dataopen datasave date datestr datestring datestrymd dayinyr dayofweek dbAddDatabase dbClose dbCommit dbCreateQuery dbExecQuery dbGetConnectOptions dbGetDatabaseName dbGetDriverName dbGetDrivers dbGetHostName dbGetLastErrorNum dbGetLastErrorText dbGetNumericalPrecPolicy dbGetPassword dbGetPort dbGetTableHeaders dbGetTables dbGetUserName dbHasFeature dbIsDriverAvailable dbIsOpen dbIsOpenError dbOpen dbQueryBindValue dbQueryClear dbQueryCols dbQueryExecPrepared dbQueryFetchAllM dbQueryFetchAllSA dbQueryFetchOneM dbQueryFetchOneSA dbQueryFinish dbQueryGetBoundValue dbQueryGetBoundValues dbQueryGetField dbQueryGetLastErrorNum dbQueryGetLastErrorText dbQueryGetLastInsertID dbQueryGetLastQuery dbQueryGetPosition dbQueryIsActive dbQueryIsForwardOnly dbQueryIsNull dbQueryIsSelect dbQueryIsValid dbQueryPrepare dbQueryRows dbQuerySeek dbQuerySeekFirst dbQuerySeekLast dbQuerySeekNext dbQuerySeekPrevious dbQuerySetForwardOnly dbRemoveDatabase dbRollback dbSetConnectOptions dbSetDatabaseName dbSetHostName dbSetNumericalPrecPolicy dbSetPort dbSetUserName dbTransaction DeleteFile delif delrows denseToSp denseToSpRE denToZero design det detl dfft dffti diag diagrv digamma doswin DOSWinCloseall DOSWinOpen dotfeq dotfeqmt dotfge dotfgemt dotfgt dotfgtmt dotfle dotflemt dotflt dotfltmt dotfne dotfnemt draw drop dsCreate dstat dstatmt dstatmtControlCreate dtdate dtday dttime dttodtv dttostr dttoutc dtvnormal dtvtodt dtvtoutc dummy dummybr dummydn eig eigh eighv eigv elapsedTradingDays endwind envget eof eqSolve eqSolvemt eqSolvemtControlCreate eqSolvemtOutCreate eqSolveset erf erfc erfccplx erfcplx error etdays ethsec etstr EuropeanBinomCall EuropeanBinomCall_Greeks EuropeanBinomCall_ImpVol EuropeanBinomPut EuropeanBinomPut_Greeks EuropeanBinomPut_ImpVol EuropeanBSCall EuropeanBSCall_Greeks EuropeanBSCall_ImpVol EuropeanBSPut EuropeanBSPut_Greeks EuropeanBSPut_ImpVol exctsmpl exec execbg exp extern eye fcheckerr fclearerr feq feqmt fflush fft ffti fftm fftmi fftn fge fgemt fgets fgetsa fgetsat fgetst fgt fgtmt fileinfo filesa fle flemt floor flt fltmt fmod fne fnemt fonts fopen formatcv formatnv fputs fputst fseek fstrerror ftell ftocv ftos ftostrC gamma gammacplx gammaii gausset gdaAppend gdaCreate gdaDStat gdaDStatMat gdaGetIndex gdaGetName gdaGetNames gdaGetOrders gdaGetType gdaGetTypes gdaGetVarInfo gdaIsCplx gdaLoad gdaPack gdaRead gdaReadByIndex gdaReadSome gdaReadSparse gdaReadStruct gdaReportVarInfo gdaSave gdaUpdate gdaUpdateAndPack gdaVars gdaWrite gdaWrite32 gdaWriteSome getarray getdims getf getGAUSShome getmatrix getmatrix4D getname getnamef getNextTradingDay getNextWeekDay getnr getorders getpath getPreviousTradingDay getPreviousWeekDay getRow getscalar3D getscalar4D getTrRow getwind glm gradcplx gradMT gradMTm gradMTT gradMTTm gradp graphprt graphset hasimag header headermt hess hessMT hessMTg hessMTgw hessMTm hessMTmw hessMTT hessMTTg hessMTTgw hessMTTm hessMTw hessp hist histf histp hsec imag indcv indexcat indices indices2 indicesf indicesfn indnv indsav integrate1d integrateControlCreate intgrat2 intgrat3 inthp1 inthp2 inthp3 inthp4 inthpControlCreate intquad1 intquad2 intquad3 intrleav intrleavsa intrsect intsimp inv invpd invswp iscplx iscplxf isden isinfnanmiss ismiss key keyav keyw lag lag1 lagn lapEighb lapEighi lapEighvb lapEighvi lapgEig lapgEigh lapgEighv lapgEigv lapgSchur lapgSvdcst lapgSvds lapgSvdst lapSvdcusv lapSvds lapSvdusv ldlp ldlsol linSolve listwise ln lncdfbvn lncdfbvn2 lncdfmvn lncdfn lncdfn2 lncdfnc lnfact lngammacplx lnpdfmvn lnpdfmvt lnpdfn lnpdft loadd loadstruct loadwind loess loessmt loessmtControlCreate log loglog logx logy lower lowmat lowmat1 ltrisol lu lusol machEpsilon make makevars makewind margin matalloc matinit mattoarray maxbytes maxc maxindc maxv maxvec mbesselei mbesselei0 mbesselei1 mbesseli mbesseli0 mbesseli1 meanc median mergeby mergevar minc minindc minv miss missex missrv moment momentd movingave movingaveExpwgt movingaveWgt nextindex nextn nextnevn nextwind ntos null null1 numCombinations ols olsmt olsmtControlCreate olsqr olsqr2 olsqrmt ones optn optnevn orth outtyp pacf packedToSp packr parse pause pdfCauchy pdfChi pdfExp pdfGenPareto pdfHyperGeo pdfLaplace pdfLogistic pdfn pdfPoisson pdfRayleigh pdfWeibull pi pinv pinvmt plotAddArrow plotAddBar plotAddBox plotAddHist plotAddHistF plotAddHistP plotAddPolar plotAddScatter plotAddShape plotAddTextbox plotAddTS plotAddXY plotArea plotBar plotBox plotClearLayout plotContour plotCustomLayout plotGetDefaults plotHist plotHistF plotHistP plotLayout plotLogLog plotLogX plotLogY plotOpenWindow plotPolar plotSave plotScatter plotSetAxesPen plotSetBar plotSetBarFill plotSetBarStacked plotSetBkdColor plotSetFill plotSetGrid plotSetLegend plotSetLineColor plotSetLineStyle plotSetLineSymbol plotSetLineThickness plotSetNewWindow plotSetTitle plotSetWhichYAxis plotSetXAxisShow plotSetXLabel plotSetXRange plotSetXTicInterval plotSetXTicLabel plotSetYAxisShow plotSetYLabel plotSetYRange plotSetZAxisShow plotSetZLabel plotSurface plotTS plotXY polar polychar polyeval polygamma polyint polymake polymat polymroot polymult polyroot pqgwin previousindex princomp printfm printfmt prodc psi putarray putf putvals pvCreate pvGetIndex pvGetParNames pvGetParVector pvLength pvList pvPack pvPacki pvPackm pvPackmi pvPacks pvPacksi pvPacksm pvPacksmi pvPutParVector pvTest pvUnpack QNewton QNewtonmt QNewtonmtControlCreate QNewtonmtOutCreate QNewtonSet QProg QProgmt QProgmtInCreate qqr qqre qqrep qr qre qrep qrsol qrtsol qtyr qtyre qtyrep quantile quantiled qyr qyre qyrep qz rank rankindx readr real reclassify reclassifyCuts recode recserar recsercp recserrc rerun rescale reshape rets rev rfft rffti rfftip rfftn rfftnp rfftp rndBernoulli rndBeta rndBinomial rndCauchy rndChiSquare rndCon rndCreateState rndExp rndGamma rndGeo rndGumbel rndHyperGeo rndi rndKMbeta rndKMgam rndKMi rndKMn rndKMnb rndKMp rndKMu rndKMvm rndLaplace rndLCbeta rndLCgam rndLCi rndLCn rndLCnb rndLCp rndLCu rndLCvm rndLogNorm rndMTu rndMVn rndMVt rndn rndnb rndNegBinomial rndp rndPoisson rndRayleigh rndStateSkip rndu rndvm rndWeibull rndWishart rotater round rows rowsf rref sampleData satostrC saved saveStruct savewind scale scale3d scalerr scalinfnanmiss scalmiss schtoc schur searchsourcepath seekr select selif seqa seqm setdif setdifsa setvars setvwrmode setwind shell shiftr sin singleindex sinh sleep solpd sortc sortcc sortd sorthc sorthcc sortind sortindc sortmc sortr sortrc spBiconjGradSol spChol spConjGradSol spCreate spDenseSubmat spDiagRvMat spEigv spEye spLDL spline spLU spNumNZE spOnes spreadSheetReadM spreadSheetReadSA spreadSheetWrite spScale spSubmat spToDense spTrTDense spTScalar spZeros sqpSolve sqpSolveMT sqpSolveMTControlCreate sqpSolveMTlagrangeCreate sqpSolveMToutCreate sqpSolveSet sqrt statements stdc stdsc stocv stof strcombine strindx strlen strput strrindx strsect strsplit strsplitPad strtodt strtof strtofcplx strtriml strtrimr strtrunc strtruncl strtruncpad strtruncr submat subscat substute subvec sumc sumr surface svd svd1 svd2 svdcusv svds svdusv sysstate tab tan tanh tempname threadBegin threadEnd threadEndFor threadFor threadJoin threadStat time timedt timestr timeutc title tkf2eps tkf2ps tocart todaydt toeplitz token topolar trapchk trigamma trimr trunc type typecv typef union unionsa uniqindx uniqindxsa unique uniquesa upmat upmat1 upper utctodt utctodtv utrisol vals varCovMS varCovXS varget vargetl varmall varmares varput varputl vartypef vcm vcms vcx vcxs vec vech vecr vector vget view viewxyz vlist vnamecv volume vput vread vtypecv wait waitc walkindex where window writer xlabel xlsGetSheetCount xlsGetSheetSize xlsGetSheetTypes xlsMakeRange xlsReadM xlsReadSA xlsWrite xlsWriteM xlsWriteSA xpnd xtics xy xyz ylabel ytics zeros zeta zlabel ztics cdfEmpirical dot h5create h5open h5read h5readAttribute h5write h5writeAttribute ldl plotAddErrorBar plotAddSurface plotCDFEmpirical plotSetColormap plotSetContourLabels plotSetLegendFont plotSetTextInterpreter plotSetXTicCount plotSetYTicCount plotSetZLevels powerm strjoin strtrim sylvester",literal:"DB_AFTER_LAST_ROW DB_ALL_TABLES DB_BATCH_OPERATIONS DB_BEFORE_FIRST_ROW DB_BLOB DB_EVENT_NOTIFICATIONS DB_FINISH_QUERY DB_HIGH_PRECISION DB_LAST_INSERT_ID DB_LOW_PRECISION_DOUBLE DB_LOW_PRECISION_INT32 DB_LOW_PRECISION_INT64 DB_LOW_PRECISION_NUMBERS DB_MULTIPLE_RESULT_SETS DB_NAMED_PLACEHOLDERS DB_POSITIONAL_PLACEHOLDERS DB_PREPARED_QUERIES DB_QUERY_SIZE DB_SIMPLE_LOCKING DB_SYSTEM_TABLES DB_TABLES DB_TRANSACTIONS DB_UNICODE DB_VIEWS"},r={cN:"meta",b:"#",e:"$",k:{"meta-keyword":"define definecs|10 undef ifdef ifndef iflight ifdllcall ifmac ifos2win ifunix else endif lineson linesoff srcfile srcline"},c:[{b:/\\\n/,r:0},{bK:"include",e:"$",k:{"meta-keyword":"include"},c:[{cN:"meta-string",b:'"',e:'"',i:"\\n"}]},e.CLCM,e.CBCM]},a=e.UIR+"\\s*\\(?",i=[{cN:"params",b:/\(/,e:/\)/,k:t,r:0,c:[e.CNM,e.CLCM,e.CBCM]}];return{aliases:["gss"],cI:!0,k:t,i:"(\\{[%#]|[%#]\\})",c:[e.CNM,e.CLCM,e.CBCM,e.C("@","@"),r,{cN:"string",b:'"',e:'"',c:[e.BE]},{cN:"function",bK:"proc keyword",e:";",eE:!0,k:t,c:[{b:a,rB:!0,c:[e.UTM],r:0},e.CNM,e.CLCM,e.CBCM,r].concat(i)},{cN:"function",bK:"fn",e:";",eE:!0,k:t,c:[{b:a+e.IR+"\\)?\\s*\\=\\s*",rB:!0,c:[e.UTM],r:0},e.CNM,e.CLCM,e.CBCM].concat(i)},{cN:"function",b:"\\bexternal (proc|keyword|fn)\\s+",e:";",eE:!0,k:t,c:[{b:a,rB:!0,c:[e.UTM],r:0},e.CLCM,e.CBCM]},{cN:"function",b:"\\bexternal (matrix|string|array|sparse matrix|struct "+e.IR+")\\s+",e:";",eE:!0,k:t,c:[e.CLCM,e.CBCM]}]}}),e.registerLanguage("gcode",function(e){var t="[A-Z_][A-Z0-9_.]*",r="\\%",a="IF DO WHILE ENDWHILE CALL ENDIF SUB ENDSUB GOTO REPEAT ENDREPEAT EQ LT GT NE GE LE OR XOR",i={cN:"meta",b:"([O])([0-9]+)"},n=[e.CLCM,e.CBCM,e.C(/\(/,/\)/),e.inherit(e.CNM,{b:"([-+]?([0-9]*\\.?[0-9]+\\.?))|"+e.CNR}),e.inherit(e.ASM,{i:null}),e.inherit(e.QSM,{i:null}),{cN:"name",b:"([G])([0-9]+\\.?[0-9]?)"},{cN:"name",b:"([M])([0-9]+\\.?[0-9]?)"},{cN:"attr",b:"(VC|VS|#)",e:"(\\d+)"},{cN:"attr",b:"(VZOFX|VZOFY|VZOFZ)"},{cN:"built_in",b:"(ATAN|ABS|ACOS|ASIN|SIN|COS|EXP|FIX|FUP|ROUND|LN|TAN)(\\[)",e:"([-+]?([0-9]*\\.?[0-9]+\\.?))(\\])"},{cN:"symbol",v:[{b:"N",e:"\\d+",i:"\\W"}]}];return{aliases:["nc"],cI:!0,l:t,k:a,c:[{cN:"meta",b:r},i].concat(n)}}),e.registerLanguage("gherkin",function(e){return{aliases:["feature"],k:"Feature Background Ability Business Need Scenario Scenarios Scenario Outline Scenario Template Examples Given And Then But When",c:[{cN:"symbol",b:"\\*",r:0},{cN:"meta",b:"@[^@\\s]+"},{b:"\\|",e:"\\|\\w*$",c:[{cN:"string",b:"[^|]+"}]},{cN:"variable",b:"<",e:">"},e.HCM,{cN:"string",b:'"""',e:'"""'},e.QSM]}}),e.registerLanguage("glsl",function(e){return{k:{keyword:"break continue discard do else for if return while switch case default attribute binding buffer ccw centroid centroid varying coherent column_major const cw depth_any depth_greater depth_less depth_unchanged early_fragment_tests equal_spacing flat fractional_even_spacing fractional_odd_spacing highp in index inout invariant invocations isolines layout line_strip lines lines_adjacency local_size_x local_size_y local_size_z location lowp max_vertices mediump noperspective offset origin_upper_left out packed patch pixel_center_integer point_mode points precise precision quads r11f_g11f_b10f r16 r16_snorm r16f r16i r16ui r32f r32i r32ui r8 r8_snorm r8i r8ui readonly restrict rg16 rg16_snorm rg16f rg16i rg16ui rg32f rg32i rg32ui rg8 rg8_snorm rg8i rg8ui rgb10_a2 rgb10_a2ui rgba16 rgba16_snorm rgba16f rgba16i rgba16ui rgba32f rgba32i rgba32ui rgba8 rgba8_snorm rgba8i rgba8ui row_major sample shared smooth std140 std430 stream triangle_strip triangles triangles_adjacency uniform varying vertices volatile writeonly", -type:"atomic_uint bool bvec2 bvec3 bvec4 dmat2 dmat2x2 dmat2x3 dmat2x4 dmat3 dmat3x2 dmat3x3 dmat3x4 dmat4 dmat4x2 dmat4x3 dmat4x4 double dvec2 dvec3 dvec4 float iimage1D iimage1DArray iimage2D iimage2DArray iimage2DMS iimage2DMSArray iimage2DRect iimage3D iimageBufferiimageCube iimageCubeArray image1D image1DArray image2D image2DArray image2DMS image2DMSArray image2DRect image3D imageBuffer imageCube imageCubeArray int isampler1D isampler1DArray isampler2D isampler2DArray isampler2DMS isampler2DMSArray isampler2DRect isampler3D isamplerBuffer isamplerCube isamplerCubeArray ivec2 ivec3 ivec4 mat2 mat2x2 mat2x3 mat2x4 mat3 mat3x2 mat3x3 mat3x4 mat4 mat4x2 mat4x3 mat4x4 sampler1D sampler1DArray sampler1DArrayShadow sampler1DShadow sampler2D sampler2DArray sampler2DArrayShadow sampler2DMS sampler2DMSArray sampler2DRect sampler2DRectShadow sampler2DShadow sampler3D samplerBuffer samplerCube samplerCubeArray samplerCubeArrayShadow samplerCubeShadow image1D uimage1DArray uimage2D uimage2DArray uimage2DMS uimage2DMSArray uimage2DRect uimage3D uimageBuffer uimageCube uimageCubeArray uint usampler1D usampler1DArray usampler2D usampler2DArray usampler2DMS usampler2DMSArray usampler2DRect usampler3D samplerBuffer usamplerCube usamplerCubeArray uvec2 uvec3 uvec4 vec2 vec3 vec4 void",built_in:"gl_MaxAtomicCounterBindings gl_MaxAtomicCounterBufferSize gl_MaxClipDistances gl_MaxClipPlanes gl_MaxCombinedAtomicCounterBuffers gl_MaxCombinedAtomicCounters gl_MaxCombinedImageUniforms gl_MaxCombinedImageUnitsAndFragmentOutputs gl_MaxCombinedTextureImageUnits gl_MaxComputeAtomicCounterBuffers gl_MaxComputeAtomicCounters gl_MaxComputeImageUniforms gl_MaxComputeTextureImageUnits gl_MaxComputeUniformComponents gl_MaxComputeWorkGroupCount gl_MaxComputeWorkGroupSize gl_MaxDrawBuffers gl_MaxFragmentAtomicCounterBuffers gl_MaxFragmentAtomicCounters gl_MaxFragmentImageUniforms gl_MaxFragmentInputComponents gl_MaxFragmentInputVectors gl_MaxFragmentUniformComponents gl_MaxFragmentUniformVectors gl_MaxGeometryAtomicCounterBuffers gl_MaxGeometryAtomicCounters gl_MaxGeometryImageUniforms gl_MaxGeometryInputComponents gl_MaxGeometryOutputComponents gl_MaxGeometryOutputVertices gl_MaxGeometryTextureImageUnits gl_MaxGeometryTotalOutputComponents gl_MaxGeometryUniformComponents gl_MaxGeometryVaryingComponents gl_MaxImageSamples gl_MaxImageUnits gl_MaxLights gl_MaxPatchVertices gl_MaxProgramTexelOffset gl_MaxTessControlAtomicCounterBuffers gl_MaxTessControlAtomicCounters gl_MaxTessControlImageUniforms gl_MaxTessControlInputComponents gl_MaxTessControlOutputComponents gl_MaxTessControlTextureImageUnits gl_MaxTessControlTotalOutputComponents gl_MaxTessControlUniformComponents gl_MaxTessEvaluationAtomicCounterBuffers gl_MaxTessEvaluationAtomicCounters gl_MaxTessEvaluationImageUniforms gl_MaxTessEvaluationInputComponents gl_MaxTessEvaluationOutputComponents gl_MaxTessEvaluationTextureImageUnits gl_MaxTessEvaluationUniformComponents gl_MaxTessGenLevel gl_MaxTessPatchComponents gl_MaxTextureCoords gl_MaxTextureImageUnits gl_MaxTextureUnits gl_MaxVaryingComponents gl_MaxVaryingFloats gl_MaxVaryingVectors gl_MaxVertexAtomicCounterBuffers gl_MaxVertexAtomicCounters gl_MaxVertexAttribs gl_MaxVertexImageUniforms gl_MaxVertexOutputComponents gl_MaxVertexOutputVectors gl_MaxVertexTextureImageUnits gl_MaxVertexUniformComponents gl_MaxVertexUniformVectors gl_MaxViewports gl_MinProgramTexelOffset gl_BackColor gl_BackLightModelProduct gl_BackLightProduct gl_BackMaterial gl_BackSecondaryColor gl_ClipDistance gl_ClipPlane gl_ClipVertex gl_Color gl_DepthRange gl_EyePlaneQ gl_EyePlaneR gl_EyePlaneS gl_EyePlaneT gl_Fog gl_FogCoord gl_FogFragCoord gl_FragColor gl_FragCoord gl_FragData gl_FragDepth gl_FrontColor gl_FrontFacing gl_FrontLightModelProduct gl_FrontLightProduct gl_FrontMaterial gl_FrontSecondaryColor gl_GlobalInvocationID gl_InstanceID gl_InvocationID gl_Layer gl_LightModel gl_LightSource gl_LocalInvocationID gl_LocalInvocationIndex gl_ModelViewMatrix gl_ModelViewMatrixInverse gl_ModelViewMatrixInverseTranspose gl_ModelViewMatrixTranspose gl_ModelViewProjectionMatrix gl_ModelViewProjectionMatrixInverse gl_ModelViewProjectionMatrixInverseTranspose gl_ModelViewProjectionMatrixTranspose gl_MultiTexCoord0 gl_MultiTexCoord1 gl_MultiTexCoord2 gl_MultiTexCoord3 gl_MultiTexCoord4 gl_MultiTexCoord5 gl_MultiTexCoord6 gl_MultiTexCoord7 gl_Normal gl_NormalMatrix gl_NormalScale gl_NumSamples gl_NumWorkGroups gl_ObjectPlaneQ gl_ObjectPlaneR gl_ObjectPlaneS gl_ObjectPlaneT gl_PatchVerticesIn gl_Point gl_PointCoord gl_PointSize gl_Position gl_PrimitiveID gl_PrimitiveIDIn gl_ProjectionMatrix gl_ProjectionMatrixInverse gl_ProjectionMatrixInverseTranspose gl_ProjectionMatrixTranspose gl_SampleID gl_SampleMask gl_SampleMaskIn gl_SamplePosition gl_SecondaryColor gl_TessCoord gl_TessLevelInner gl_TessLevelOuter gl_TexCoord gl_TextureEnvColor gl_TextureMatrix gl_TextureMatrixInverse gl_TextureMatrixInverseTranspose gl_TextureMatrixTranspose gl_Vertex gl_VertexID gl_ViewportIndex gl_WorkGroupID gl_WorkGroupSize gl_in gl_out EmitStreamVertex EmitVertex EndPrimitive EndStreamPrimitive abs acos acosh all any asin asinh atan atanh atomicAdd atomicAnd atomicCompSwap atomicCounter atomicCounterDecrement atomicCounterIncrement atomicExchange atomicMax atomicMin atomicOr atomicXor barrier bitCount bitfieldExtract bitfieldInsert bitfieldReverse ceil clamp cos cosh cross dFdx dFdy degrees determinant distance dot equal exp exp2 faceforward findLSB findMSB floatBitsToInt floatBitsToUint floor fma fract frexp ftransform fwidth greaterThan greaterThanEqual groupMemoryBarrier imageAtomicAdd imageAtomicAnd imageAtomicCompSwap imageAtomicExchange imageAtomicMax imageAtomicMin imageAtomicOr imageAtomicXor imageLoad imageSize imageStore imulExtended intBitsToFloat interpolateAtCentroid interpolateAtOffset interpolateAtSample inverse inversesqrt isinf isnan ldexp length lessThan lessThanEqual log log2 matrixCompMult max memoryBarrier memoryBarrierAtomicCounter memoryBarrierBuffer memoryBarrierImage memoryBarrierShared min mix mod modf noise1 noise2 noise3 noise4 normalize not notEqual outerProduct packDouble2x32 packHalf2x16 packSnorm2x16 packSnorm4x8 packUnorm2x16 packUnorm4x8 pow radians reflect refract round roundEven shadow1D shadow1DLod shadow1DProj shadow1DProjLod shadow2D shadow2DLod shadow2DProj shadow2DProjLod sign sin sinh smoothstep sqrt step tan tanh texelFetch texelFetchOffset texture texture1D texture1DLod texture1DProj texture1DProjLod texture2D texture2DLod texture2DProj texture2DProjLod texture3D texture3DLod texture3DProj texture3DProjLod textureCube textureCubeLod textureGather textureGatherOffset textureGatherOffsets textureGrad textureGradOffset textureLod textureLodOffset textureOffset textureProj textureProjGrad textureProjGradOffset textureProjLod textureProjLodOffset textureProjOffset textureQueryLevels textureQueryLod textureSize transpose trunc uaddCarry uintBitsToFloat umulExtended unpackDouble2x32 unpackHalf2x16 unpackSnorm2x16 unpackSnorm4x8 unpackUnorm2x16 unpackUnorm4x8 usubBorrow",literal:"true false"},i:'"',c:[e.CLCM,e.CBCM,e.CNM,{cN:"meta",b:"#",e:"$"}]}}),e.registerLanguage("go",function(e){var t={keyword:"break default func interface select case map struct chan else goto package switch const fallthrough if range type continue for import return var go defer bool byte complex64 complex128 float32 float64 int8 int16 int32 int64 string uint8 uint16 uint32 uint64 int uint uintptr rune",literal:"true false iota nil",built_in:"append cap close complex copy imag len make new panic print println real recover delete"};return{aliases:["golang"],k:t,i:"",e:",\\s+",rB:!0,eW:!0,c:[{cN:"attr",b:":\\w+"},e.ASM,e.QSM,{b:"\\w+",r:0}]}]},{b:"\\(\\s*",e:"\\s*\\)",eE:!0,c:[{b:"\\w+\\s*=",e:"\\s+",rB:!0,eW:!0,c:[{cN:"attr",b:"\\w+",r:0},e.ASM,e.QSM,{b:"\\w+",r:0}]}]}]},{b:"^\\s*[=~]\\s*"},{b:"#{",starts:{e:"}",sL:"ruby"}}]}}),e.registerLanguage("handlebars",function(e){var t={"builtin-name":"each in with if else unless bindattr action collection debugger log outlet template unbound view yield"};return{aliases:["hbs","html.hbs","html.handlebars"],cI:!0,sL:"xml",c:[e.C("{{!(--)?","(--)?}}"),{cN:"template-tag",b:/\{\{[#\/]/,e:/\}\}/,c:[{cN:"name",b:/[a-zA-Z\.-]+/,k:t,starts:{eW:!0,r:0,c:[e.QSM]}}]},{cN:"template-variable",b:/\{\{/,e:/\}\}/,k:t}]}}),e.registerLanguage("haskell",function(e){var t={v:[e.C("--","$"),e.C("{-","-}",{c:["self"]})]},r={cN:"meta",b:"{-#",e:"#-}"},a={cN:"meta",b:"^#",e:"$"},i={cN:"type",b:"\\b[A-Z][\\w']*",r:0},n={b:"\\(",e:"\\)",i:'"',c:[r,a,{cN:"type",b:"\\b[A-Z][\\w]*(\\((\\.\\.|,|\\w+)\\))?"},e.inherit(e.TM,{b:"[_a-z][\\w']*"}),t]},o={b:"{",e:"}",c:n.c};return{aliases:["hs"],k:"let in if then else case of where do module import hiding qualified type data newtype deriving class instance as default infix infixl infixr foreign export ccall stdcall cplusplus jvm dotnet safe unsafe family forall mdo proc rec",c:[{bK:"module",e:"where",k:"module where",c:[n,t],i:"\\W\\.|;"},{b:"\\bimport\\b",e:"$",k:"import qualified as hiding",c:[n,t],i:"\\W\\.|;"},{cN:"class",b:"^(\\s*)?(class|instance)\\b",e:"where",k:"class family instance where",c:[i,n,t]},{cN:"class",b:"\\b(data|(new)?type)\\b",e:"$",k:"data family type newtype deriving",c:[r,i,n,o,t]},{bK:"default",e:"$",c:[i,n,t]},{bK:"infix infixl infixr",e:"$",c:[e.CNM,t]},{b:"\\bforeign\\b",e:"$",k:"foreign import export ccall stdcall cplusplus jvm dotnet safe unsafe",c:[i,e.QSM,t]},{cN:"meta",b:"#!\\/usr\\/bin\\/env runhaskell",e:"$"},r,a,e.QSM,e.CNM,i,e.inherit(e.TM,{b:"^[_a-z][\\w']*"}),t,{b:"->|<-"}]}}),e.registerLanguage("haxe",function(e){var t="Int Float String Bool Dynamic Void Array ";return{aliases:["hx"],k:{keyword:"break case cast catch continue default do dynamic else enum extern for function here if import in inline never new override package private get set public return static super switch this throw trace try typedef untyped using var while "+t,built_in:"trace this",literal:"true false null _"},c:[{cN:"string",b:"'",e:"'",c:[e.BE,{cN:"subst",b:"\\$\\{",e:"\\}"},{cN:"subst",b:"\\$",e:"\\W}"}]},e.QSM,e.CLCM,e.CBCM,e.CNM,{cN:"meta",b:"@:",e:"$"},{cN:"meta",b:"#",e:"$",k:{"meta-keyword":"if else elseif end error"}},{cN:"type",b:":[ ]*",e:"[^A-Za-z0-9_ \\->]",eB:!0,eE:!0,r:0},{cN:"type",b:":[ ]*",e:"\\W",eB:!0,eE:!0},{cN:"type",b:"new *",e:"\\W",eB:!0,eE:!0},{cN:"class",bK:"enum",e:"\\{",c:[e.TM]},{cN:"class",bK:"abstract",e:"[\\{$]",c:[{cN:"type",b:"\\(",e:"\\)",eB:!0,eE:!0},{cN:"type",b:"from +",e:"\\W",eB:!0,eE:!0},{cN:"type",b:"to +",e:"\\W",eB:!0,eE:!0},e.TM],k:{keyword:"abstract from to"}},{cN:"class",b:"\\b(class|interface) +",e:"[\\{$]",eE:!0,k:"class interface",c:[{cN:"keyword",b:"\\b(extends|implements) +",k:"extends implements",c:[{cN:"type",b:e.IR,r:0}]},e.TM]},{cN:"function",bK:"function",e:"\\(",eE:!0,i:"\\S",c:[e.TM]}],i:/<\//}}),e.registerLanguage("hsp",function(e){return{cI:!0,l:/[\w\._]+/,k:"goto gosub return break repeat loop continue wait await dim sdim foreach dimtype dup dupptr end stop newmod delmod mref run exgoto on mcall assert logmes newlab resume yield onexit onerror onkey onclick oncmd exist delete mkdir chdir dirlist bload bsave bcopy memfile if else poke wpoke lpoke getstr chdpm memexpand memcpy memset notesel noteadd notedel noteload notesave randomize noteunsel noteget split strrep setease button chgdisp exec dialog mmload mmplay mmstop mci pset pget syscolor mes print title pos circle cls font sysfont objsize picload color palcolor palette redraw width gsel gcopy gzoom gmode bmpsave hsvcolor getkey listbox chkbox combox input mesbox buffer screen bgscr mouse objsel groll line clrobj boxf objprm objmode stick grect grotate gsquare gradf objimage objskip objenable celload celdiv celput newcom querycom delcom cnvstow comres axobj winobj sendmsg comevent comevarg sarrayconv callfunc cnvwtos comevdisp libptr system hspstat hspver stat cnt err strsize looplev sublev iparam wparam lparam refstr refdval int rnd strlen length length2 length3 length4 vartype gettime peek wpeek lpeek varptr varuse noteinfo instr abs limit getease str strmid strf getpath strtrim sin cos tan atan sqrt double absf expf logf limitf powf geteasef mousex mousey mousew hwnd hinstance hdc ginfo objinfo dirinfo sysinfo thismod __hspver__ __hsp30__ __date__ __time__ __line__ __file__ _debug __hspdef__ and or xor not screen_normal screen_palette screen_hide screen_fixedsize screen_tool screen_frame gmode_gdi gmode_mem gmode_rgb0 gmode_alpha gmode_rgb0alpha gmode_add gmode_sub gmode_pixela ginfo_mx ginfo_my ginfo_act ginfo_sel ginfo_wx1 ginfo_wy1 ginfo_wx2 ginfo_wy2 ginfo_vx ginfo_vy ginfo_sizex ginfo_sizey ginfo_winx ginfo_winy ginfo_mesx ginfo_mesy ginfo_r ginfo_g ginfo_b ginfo_paluse ginfo_dispx ginfo_dispy ginfo_cx ginfo_cy ginfo_intid ginfo_newid ginfo_sx ginfo_sy objinfo_mode objinfo_bmscr objinfo_hwnd notemax notesize dir_cur dir_exe dir_win dir_sys dir_cmdline dir_desktop dir_mydoc dir_tv font_normal font_bold font_italic font_underline font_strikeout font_antialias objmode_normal objmode_guifont objmode_usefont gsquare_grad msgothic msmincho do until while wend for next _break _continue switch case default swbreak swend ddim ldim alloc m_pi rad2deg deg2rad ease_linear ease_quad_in ease_quad_out ease_quad_inout ease_cubic_in ease_cubic_out ease_cubic_inout ease_quartic_in ease_quartic_out ease_quartic_inout ease_bounce_in ease_bounce_out ease_bounce_inout ease_shake_in ease_shake_out ease_shake_inout ease_loop",c:[e.CLCM,e.CBCM,e.QSM,e.ASM,{cN:"string",b:'{"',e:'"}',c:[e.BE]},e.C(";","$",{r:0}),{cN:"meta",b:"#",e:"$",k:{"meta-keyword":"addion cfunc cmd cmpopt comfunc const defcfunc deffunc define else endif enum epack func global if ifdef ifndef include modcfunc modfunc modinit modterm module pack packopt regcmd runtime undef usecom uselib"},c:[e.inherit(e.QSM,{cN:"meta-string"}),e.NM,e.CNM,e.CLCM,e.CBCM]},{cN:"symbol",b:"^\\*(\\w+|@)"},e.NM,e.CNM]}}),e.registerLanguage("htmlbars",function(e){var t="action collection component concat debugger each each-in else get hash if input link-to loc log mut outlet partial query-params render textarea unbound unless with yield view",r={i:/\}\}/,b:/[a-zA-Z0-9_]+=/,rB:!0,r:0,c:[{cN:"attr",b:/[a-zA-Z0-9_]+/}]},a=({i:/\}\}/,b:/\)/,e:/\)/,c:[{b:/[a-zA-Z\.\-]+/,k:{built_in:t},starts:{eW:!0,r:0,c:[e.QSM]}}]},{eW:!0,r:0,k:{keyword:"as",built_in:t},c:[e.QSM,r,e.NM]});return{cI:!0,sL:"xml",c:[e.C("{{!(--)?","(--)?}}"),{cN:"template-tag",b:/\{\{[#\/]/,e:/\}\}/,c:[{cN:"name",b:/[a-zA-Z\.\-]+/,k:{"builtin-name":t},starts:a}]},{cN:"template-variable",b:/\{\{[a-zA-Z][a-zA-Z\-]+/,e:/\}\}/,k:{keyword:"as",built_in:t},c:[e.QSM]}]}}),e.registerLanguage("http",function(e){var t="HTTP/[0-9\\.]+";return{aliases:["https"],i:"\\S",c:[{b:"^"+t,e:"$",c:[{cN:"number",b:"\\b\\d{3}\\b"}]},{b:"^[A-Z]+ (.*?) "+t+"$",rB:!0,e:"$",c:[{cN:"string",b:" ",e:" ",eB:!0,eE:!0},{b:t},{cN:"keyword",b:"[A-Z]+"}]},{cN:"attribute",b:"^\\w",e:": ",eE:!0,i:"\\n|\\s|=",starts:{e:"$",r:0}},{b:"\\n\\n",starts:{sL:[],eW:!0}}]}}),e.registerLanguage("hy",function(e){var t={"builtin-name":"!= % %= & &= * ** **= *= *map + += , --build-class-- --import-- -= . / // //= /= < << <<= <= = > >= >> >>= @ @= ^ ^= abs accumulate all and any ap-compose ap-dotimes ap-each ap-each-while ap-filter ap-first ap-if ap-last ap-map ap-map-when ap-pipe ap-reduce ap-reject apply as-> ascii assert assoc bin break butlast callable calling-module-name car case cdr chain chr coll? combinations compile compress cond cons cons? continue count curry cut cycle dec def default-method defclass defmacro defmacro-alias defmacro/g! defmain defmethod defmulti defn defn-alias defnc defnr defreader defseq del delattr delete-route dict-comp dir disassemble dispatch-reader-macro distinct divmod do doto drop drop-last drop-while empty? end-sequence eval eval-and-compile eval-when-compile even? every? except exec filter first flatten float? fn fnc fnr for for* format fraction genexpr gensym get getattr global globals group-by hasattr hash hex id identity if if* if-not if-python2 import in inc input instance? integer integer-char? integer? interleave interpose is is-coll is-cons is-empty is-even is-every is-float is-instance is-integer is-integer-char is-iterable is-iterator is-keyword is-neg is-none is-not is-numeric is-odd is-pos is-string is-symbol is-zero isinstance islice issubclass iter iterable? iterate iterator? keyword keyword? lambda last len let lif lif-not list* list-comp locals loop macro-error macroexpand macroexpand-1 macroexpand-all map max merge-with method-decorator min multi-decorator multicombinations name neg? next none? nonlocal not not-in not? nth numeric? oct odd? open or ord partition permutations pos? post-route postwalk pow prewalk print product profile/calls profile/cpu put-route quasiquote quote raise range read read-str recursive-replace reduce remove repeat repeatedly repr require rest round route route-with-methods rwm second seq set-comp setattr setv some sorted string string? sum switch symbol? take take-nth take-while tee try unless unquote unquote-splicing vars walk when while with with* with-decorator with-gensyms xi xor yield yield-from zero? zip zip-longest | |= ~"},r="a-zA-Z_\\-!.?+*=<>&#'",a="["+r+"]["+r+"0-9/;:]*",i="[-+]?\\d+(\\.\\d+)?",n={cN:"meta",b:"^#!",e:"$"},o={b:a,r:0},s={cN:"number",b:i,r:0},l=e.inherit(e.QSM,{i:null}),c=e.C(";","$",{r:0}),d={cN:"literal",b:/\b([Tt]rue|[Ff]alse|nil|None)\b/},p={b:"[\\[\\{]",e:"[\\]\\}]"},m={cN:"comment",b:"\\^"+a},u=e.C("\\^\\{","\\}"),b={cN:"symbol",b:"[:]{1,2}"+a},g={b:"\\(",e:"\\)"},f={eW:!0,r:0},_={k:t,l:a,cN:"name",b:a,starts:f},h=[g,l,m,u,c,b,p,s,d,o];return g.c=[e.C("comment",""),_,f],f.c=h,p.c=h,{aliases:["hylang"],i:/\S/,c:[n,g,l,m,u,c,b,p,s,d]}}),e.registerLanguage("inform7",function(e){var t="\\[",r="\\]";return{aliases:["i7"],cI:!0,k:{keyword:"thing room person man woman animal container supporter backdrop door scenery open closed locked inside gender is are say understand kind of rule"},c:[{cN:"string",b:'"',e:'"',r:0,c:[{cN:"subst",b:t,e:r}]},{cN:"section",b:/^(Volume|Book|Part|Chapter|Section|Table)\b/,e:"$"},{b:/^(Check|Carry out|Report|Instead of|To|Rule|When|Before|After)\b/,e:":",c:[{b:"\\(This",e:"\\)"}]},{cN:"comment",b:t,e:r,c:["self"]}]}}),e.registerLanguage("ini",function(e){var t={cN:"string",c:[e.BE],v:[{b:"'''",e:"'''",r:10},{b:'"""',e:'"""',r:10},{b:'"',e:'"'},{b:"'",e:"'"}]};return{aliases:["toml"],cI:!0,i:/\S/,c:[e.C(";","$"),e.HCM,{cN:"section",b:/^\s*\[+/,e:/\]+/},{b:/^[a-z0-9\[\]_-]+\s*=\s*/,e:"$",rB:!0,c:[{cN:"attr",b:/[a-z0-9\[\]_-]+/},{b:/=/,eW:!0,r:0,c:[{cN:"literal",b:/\bon|off|true|false|yes|no\b/},{cN:"variable",v:[{b:/\$[\w\d"][\w\d_]*/},{b:/\$\{(.*?)}/}]},t,{cN:"number",b:/([\+\-]+)?[\d]+_[\d_]+/},e.NM]}]}]}}),e.registerLanguage("irpf90",function(e){var t={cN:"params",b:"\\(",e:"\\)"},r={literal:".False. .True.",keyword:"kind do while private call intrinsic where elsewhere type endtype endmodule endselect endinterface end enddo endif if forall endforall only contains default return stop then public subroutine|10 function program .and. .or. .not. .le. .eq. .ge. .gt. .lt. goto save else use module select case access blank direct exist file fmt form formatted iostat name named nextrec number opened rec recl sequential status unformatted unit continue format pause cycle exit c_null_char c_alert c_backspace c_form_feed flush wait decimal round iomsg synchronous nopass non_overridable pass protected volatile abstract extends import non_intrinsic value deferred generic final enumerator class associate bind enum c_int c_short c_long c_long_long c_signed_char c_size_t c_int8_t c_int16_t c_int32_t c_int64_t c_int_least8_t c_int_least16_t c_int_least32_t c_int_least64_t c_int_fast8_t c_int_fast16_t c_int_fast32_t c_int_fast64_t c_intmax_t C_intptr_t c_float c_double c_long_double c_float_complex c_double_complex c_long_double_complex c_bool c_char c_null_ptr c_null_funptr c_new_line c_carriage_return c_horizontal_tab c_vertical_tab iso_c_binding c_loc c_funloc c_associated c_f_pointer c_ptr c_funptr iso_fortran_env character_storage_size error_unit file_storage_size input_unit iostat_end iostat_eor numeric_storage_size output_unit c_f_procpointer ieee_arithmetic ieee_support_underflow_control ieee_get_underflow_mode ieee_set_underflow_mode newunit contiguous recursive pad position action delim readwrite eor advance nml interface procedure namelist include sequence elemental pure integer real character complex logical dimension allocatable|10 parameter external implicit|10 none double precision assign intent optional pointer target in out common equivalence data begin_provider &begin_provider end_provider begin_shell end_shell begin_template end_template subst assert touch soft_touch provide no_dep free irp_if irp_else irp_endif irp_write irp_read",built_in:"alog alog10 amax0 amax1 amin0 amin1 amod cabs ccos cexp clog csin csqrt dabs dacos dasin datan datan2 dcos dcosh ddim dexp dint dlog dlog10 dmax1 dmin1 dmod dnint dsign dsin dsinh dsqrt dtan dtanh float iabs idim idint idnint ifix isign max0 max1 min0 min1 sngl algama cdabs cdcos cdexp cdlog cdsin cdsqrt cqabs cqcos cqexp cqlog cqsin cqsqrt dcmplx dconjg derf derfc dfloat dgamma dimag dlgama iqint qabs qacos qasin qatan qatan2 qcmplx qconjg qcos qcosh qdim qerf qerfc qexp qgamma qimag qlgama qlog qlog10 qmax1 qmin1 qmod qnint qsign qsin qsinh qsqrt qtan qtanh abs acos aimag aint anint asin atan atan2 char cmplx conjg cos cosh exp ichar index int log log10 max min nint sign sin sinh sqrt tan tanh print write dim lge lgt lle llt mod nullify allocate deallocate adjustl adjustr all allocated any associated bit_size btest ceiling count cshift date_and_time digits dot_product eoshift epsilon exponent floor fraction huge iand ibclr ibits ibset ieor ior ishft ishftc lbound len_trim matmul maxexponent maxloc maxval merge minexponent minloc minval modulo mvbits nearest pack present product radix random_number random_seed range repeat reshape rrspacing scale scan selected_int_kind selected_real_kind set_exponent shape size spacing spread sum system_clock tiny transpose trim ubound unpack verify achar iachar transfer dble entry dprod cpu_time command_argument_count get_command get_command_argument get_environment_variable is_iostat_end ieee_arithmetic ieee_support_underflow_control ieee_get_underflow_mode ieee_set_underflow_mode is_iostat_eor move_alloc new_line selected_char_kind same_type_as extends_type_ofacosh asinh atanh bessel_j0 bessel_j1 bessel_jn bessel_y0 bessel_y1 bessel_yn erf erfc erfc_scaled gamma log_gamma hypot norm2 atomic_define atomic_ref execute_command_line leadz trailz storage_size merge_bits bge bgt ble blt dshiftl dshiftr findloc iall iany iparity image_index lcobound ucobound maskl maskr num_images parity popcnt poppar shifta shiftl shiftr this_image IRP_ALIGN irp_here"};return{cI:!0,k:r,i:/\/\*/,c:[e.inherit(e.ASM,{cN:"string",r:0}),e.inherit(e.QSM,{cN:"string",r:0}),{cN:"function",bK:"subroutine function program",i:"[${=\\n]",c:[e.UTM,t]},e.C("!","$",{r:0}),e.C("begin_doc","end_doc",{r:10}),{cN:"number",b:"(?=\\b|\\+|\\-|\\.)(?=\\.\\d|\\d)(?:\\d+)?(?:\\.?\\d*)(?:[de][+-]?\\d+)?\\b\\.?",r:0}]}}),e.registerLanguage("java",function(e){var t="[À-ʸa-zA-Z_$][À-ʸa-zA-Z_$0-9]*",r=t+"(<"+t+"(\\s*,\\s*"+t+")*>)?",a="false synchronized int abstract float private char boolean static null if const for true while long strictfp finally protected import native final void enum else break transient catch instanceof byte super volatile case assert short package default double public try this switch continue throws protected public private module requires exports do",i="\\b(0[bB]([01]+[01_]+[01]+|[01]+)|0[xX]([a-fA-F0-9]+[a-fA-F0-9_]+[a-fA-F0-9]+|[a-fA-F0-9]+)|(([\\d]+[\\d_]+[\\d]+|[\\d]+)(\\.([\\d]+[\\d_]+[\\d]+|[\\d]+))?|\\.([\\d]+[\\d_]+[\\d]+|[\\d]+))([eE][-+]?\\d+)?)[lLfF]?",n={cN:"number",b:i,r:0};return{aliases:["jsp"],k:a,i:/<\/|#/,c:[e.C("/\\*\\*","\\*/",{r:0,c:[{b:/\w+@/,r:0},{cN:"doctag",b:"@[A-Za-z]+"}]}),e.CLCM,e.CBCM,e.ASM,e.QSM,{cN:"class",bK:"class interface",e:/[{;=]/,eE:!0,k:"class interface",i:/[:"\[\]]/,c:[{bK:"extends implements"},e.UTM]},{bK:"new throw return else",r:0},{cN:"function",b:"("+r+"\\s+)+"+e.UIR+"\\s*\\(",rB:!0,e:/[{;=]/,eE:!0,k:a,c:[{b:e.UIR+"\\s*\\(",rB:!0,r:0,c:[e.UTM]},{cN:"params",b:/\(/,e:/\)/,k:a,r:0,c:[e.ASM,e.QSM,e.CNM,e.CBCM]},e.CLCM,e.CBCM]},n,{cN:"meta",b:"@[A-Za-z]+"}]}}),e.registerLanguage("javascript",function(e){var t="[A-Za-z$_][0-9A-Za-z$_]*",r={keyword:"in of if for while finally var new function do return void else break catch instanceof with throw case default try this switch continue typeof delete let yield const export super debugger as async await static import from as",literal:"true false null undefined NaN Infinity",built_in:"eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Error EvalError InternalError RangeError ReferenceError StopIteration SyntaxError TypeError URIError Number Math Date String RegExp Array Float32Array Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require module console window document Symbol Set Map WeakSet WeakMap Proxy Reflect Promise"},a={cN:"number",v:[{b:"\\b(0[bB][01]+)"},{b:"\\b(0[oO][0-7]+)"},{b:e.CNR}],r:0},i={cN:"subst",b:"\\$\\{",e:"\\}",k:r,c:[]},n={cN:"string",b:"`",e:"`",c:[e.BE,i]};i.c=[e.ASM,e.QSM,n,a,e.RM];var o=i.c.concat([e.CBCM,e.CLCM]);return{aliases:["js","jsx"],k:r,c:[{cN:"meta",r:10,b:/^\s*['"]use (strict|asm)['"]/},{cN:"meta",b:/^#!/,e:/$/},e.ASM,e.QSM,n,e.CLCM,e.CBCM,a,{b:/[{,]\s*/,r:0,c:[{b:t+"\\s*:",rB:!0,r:0,c:[{cN:"attr",b:t,r:0}]}]},{b:"("+e.RSR+"|\\b(case|return|throw)\\b)\\s*",k:"return throw case",c:[e.CLCM,e.CBCM,e.RM,{cN:"function",b:"(\\(.*?\\)|"+t+")\\s*=>",rB:!0,e:"\\s*=>",c:[{cN:"params",v:[{b:t},{b:/\(\s*\)/},{b:/\(/,e:/\)/,eB:!0,eE:!0,k:r,c:o}]}]},{b://,sL:"xml",c:[{b:/<\w+\s*\/>/,skip:!0},{b:/<\w+/,e:/(\/\w+|\w+\/)>/,skip:!0,c:[{b:/<\w+\s*\/>/,skip:!0},"self"]}]}],r:0},{cN:"function",bK:"function",e:/\{/,eE:!0,c:[e.inherit(e.TM,{b:t}),{cN:"params",b:/\(/,e:/\)/,eB:!0,eE:!0,c:o}],i:/\[|%/},{b:/\$[(.]/},e.METHOD_GUARD,{cN:"class",bK:"class",e:/[{;=]/,eE:!0,i:/[:"\[\]]/,c:[{bK:"extends"},e.UTM]},{bK:"constructor",e:/\{/,eE:!0}],i:/#(?!!)/}}),e.registerLanguage("jboss-cli",function(e){var t={b:/[\w-]+ *=/,rB:!0,r:0,c:[{cN:"attr",b:/[\w-]+/}]},r={cN:"params",b:/\(/,e:/\)/,c:[t],r:0},a={cN:"function",b:/:[\w\-.]+/,r:0},i={cN:"string",b:/\B(([\/.])[\w\-.\/=]+)+/},n={cN:"params",b:/--[\w\-=\/]+/};return{aliases:["wildfly-cli"],l:"[a-z-]+",k:{keyword:"alias batch cd clear command connect connection-factory connection-info data-source deploy deployment-info deployment-overlay echo echo-dmr help history if jdbc-driver-info jms-queue|20 jms-topic|20 ls patch pwd quit read-attribute read-operation reload rollout-plan run-batch set shutdown try unalias undeploy unset version xa-data-source",literal:"true false"},c:[e.HCM,e.QSM,n,a,i,r]}}),e.registerLanguage("json",function(e){var t={literal:"true false null"},r=[e.QSM,e.CNM],a={e:",",eW:!0,eE:!0,c:r,k:t},i={b:"{",e:"}",c:[{cN:"attr",b:/"/,e:/"/,c:[e.BE],i:"\\n"},e.inherit(a,{b:/:/})],i:"\\S"},n={b:"\\[",e:"\\]",c:[e.inherit(a)],i:"\\S"};return r.splice(r.length,0,i,n),{c:r,k:t,i:"\\S"}}),e.registerLanguage("julia",function(e){var t={keyword:"in isa where baremodule begin break catch ccall const continue do else elseif end export false finally for function global if import importall let local macro module quote return true try using while type immutable abstract bitstype typealias ",literal:"true false ARGS C_NULL DevNull ENDIAN_BOM ENV I Inf Inf16 Inf32 Inf64 InsertionSort JULIA_HOME LOAD_PATH MergeSort NaN NaN16 NaN32 NaN64 PROGRAM_FILE QuickSort RoundDown RoundFromZero RoundNearest RoundNearestTiesAway RoundNearestTiesUp RoundToZero RoundUp STDERR STDIN STDOUT VERSION catalan e|0 eu|0 eulergamma golden im nothing pi γ π φ ",built_in:"ANY AbstractArray AbstractChannel AbstractFloat AbstractMatrix AbstractRNG AbstractSerializer AbstractSet AbstractSparseArray AbstractSparseMatrix AbstractSparseVector AbstractString AbstractUnitRange AbstractVecOrMat AbstractVector Any ArgumentError Array AssertionError Associative Base64DecodePipe Base64EncodePipe Bidiagonal BigFloat BigInt BitArray BitMatrix BitVector Bool BoundsError BufferStream CachingPool CapturedException CartesianIndex CartesianRange Cchar Cdouble Cfloat Channel Char Cint Cintmax_t Clong Clonglong ClusterManager Cmd CodeInfo Colon Complex Complex128 Complex32 Complex64 CompositeException Condition ConjArray ConjMatrix ConjVector Cptrdiff_t Cshort Csize_t Cssize_t Cstring Cuchar Cuint Cuintmax_t Culong Culonglong Cushort Cwchar_t Cwstring DataType Date DateFormat DateTime DenseArray DenseMatrix DenseVecOrMat DenseVector Diagonal Dict DimensionMismatch Dims DirectIndexString Display DivideError DomainError EOFError EachLine Enum Enumerate ErrorException Exception ExponentialBackOff Expr Factorization FileMonitor Float16 Float32 Float64 Function Future GlobalRef GotoNode HTML Hermitian IO IOBuffer IOContext IOStream IPAddr IPv4 IPv6 IndexCartesian IndexLinear IndexStyle InexactError InitError Int Int128 Int16 Int32 Int64 Int8 IntSet Integer InterruptException InvalidStateException Irrational KeyError LabelNode LinSpace LineNumberNode LoadError LowerTriangular MIME Matrix MersenneTwister Method MethodError MethodTable Module NTuple NewvarNode NullException Nullable Number ObjectIdDict OrdinalRange OutOfMemoryError OverflowError Pair ParseError PartialQuickSort PermutedDimsArray Pipe PollingFileWatcher ProcessExitedException Ptr QuoteNode RandomDevice Range RangeIndex Rational RawFD ReadOnlyMemoryError Real ReentrantLock Ref Regex RegexMatch RemoteChannel RemoteException RevString RoundingMode RowVector SSAValue SegmentationFault SerializationState Set SharedArray SharedMatrix SharedVector Signed SimpleVector Slot SlotNumber SparseMatrixCSC SparseVector StackFrame StackOverflowError StackTrace StepRange StepRangeLen StridedArray StridedMatrix StridedVecOrMat StridedVector String SubArray SubString SymTridiagonal Symbol Symmetric SystemError TCPSocket Task Text TextDisplay Timer Tridiagonal Tuple Type TypeError TypeMapEntry TypeMapLevel TypeName TypeVar TypedSlot UDPSocket UInt UInt128 UInt16 UInt32 UInt64 UInt8 UndefRefError UndefVarError UnicodeError UniformScaling Union UnionAll UnitRange Unsigned UpperTriangular Val Vararg VecElement VecOrMat Vector VersionNumber Void WeakKeyDict WeakRef WorkerConfig WorkerPool " -},r="[A-Za-z_\\u00A1-\\uFFFF][A-Za-z_0-9\\u00A1-\\uFFFF]*",a={l:r,k:t,i:/<\//},i={cN:"number",b:/(\b0x[\d_]*(\.[\d_]*)?|0x\.\d[\d_]*)p[-+]?\d+|\b0[box][a-fA-F0-9][a-fA-F0-9_]*|(\b\d[\d_]*(\.[\d_]*)?|\.\d[\d_]*)([eEfF][-+]?\d+)?/,r:0},n={cN:"string",b:/'(.|\\[xXuU][a-zA-Z0-9]+)'/},o={cN:"subst",b:/\$\(/,e:/\)/,k:t},s={cN:"variable",b:"\\$"+r},l={cN:"string",c:[e.BE,o,s],v:[{b:/\w*"""/,e:/"""\w*/,r:10},{b:/\w*"/,e:/"\w*/}]},c={cN:"string",c:[e.BE,o,s],b:"`",e:"`"},d={cN:"meta",b:"@"+r},p={cN:"comment",v:[{b:"#=",e:"=#",r:10},{b:"#",e:"$"}]};return a.c=[i,n,l,c,d,p,e.HCM,{cN:"keyword",b:"\\b(((abstract|primitive)\\s+)type|(mutable\\s+)?struct)\\b"},{b:/<:/}],o.c=a.c,a}),e.registerLanguage("julia-repl",function(e){return{c:[{cN:"meta",b:/^julia>/,r:10,starts:{e:/^(?![ ]{6})/,sL:"julia"},aliases:["jldoctest"]}]}}),e.registerLanguage("kotlin",function(e){var t={keyword:"abstract as val var vararg get set class object open private protected public noinline crossinline dynamic final enum if else do while for when throw try catch finally import package is in fun override companion reified inline lateinit initinterface annotation data sealed internal infix operator out by constructor super trait volatile transient native default",built_in:"Byte Short Char Int Long Boolean Float Double Void Unit Nothing",literal:"true false null"},r={cN:"keyword",b:/\b(break|continue|return|this)\b/,starts:{c:[{cN:"symbol",b:/@\w+/}]}},a={cN:"symbol",b:e.UIR+"@"},i={cN:"subst",b:"\\${",e:"}",c:[e.ASM,e.CNM]},n={cN:"variable",b:"\\$"+e.UIR},o={cN:"string",v:[{b:'"""',e:'"""',c:[n,i]},{b:"'",e:"'",i:/\n/,c:[e.BE]},{b:'"',e:'"',i:/\n/,c:[e.BE,n,i]}]},s={cN:"meta",b:"@(?:file|property|field|get|set|receiver|param|setparam|delegate)\\s*:(?:\\s*"+e.UIR+")?"},l={cN:"meta",b:"@"+e.UIR,c:[{b:/\(/,e:/\)/,c:[e.inherit(o,{cN:"meta-string"})]}]};return{k:t,c:[e.C("/\\*\\*","\\*/",{r:0,c:[{cN:"doctag",b:"@[A-Za-z]+"}]}),e.CLCM,e.CBCM,r,a,s,l,{cN:"function",bK:"fun",e:"[(]|$",rB:!0,eE:!0,k:t,i:/fun\s+(<.*>)?[^\s\(]+(\s+[^\s\(]+)\s*=/,r:5,c:[{b:e.UIR+"\\s*\\(",rB:!0,r:0,c:[e.UTM]},{cN:"type",b://,k:"reified",r:0},{cN:"params",b:/\(/,e:/\)/,endsParent:!0,k:t,r:0,c:[{b:/:/,e:/[=,\/]/,eW:!0,c:[{cN:"type",b:e.UIR},e.CLCM,e.CBCM],r:0},e.CLCM,e.CBCM,s,l,o,e.CNM]},e.CBCM]},{cN:"class",bK:"class interface trait",e:/[:\{(]|$/,eE:!0,i:"extends implements",c:[{bK:"public protected internal private constructor"},e.UTM,{cN:"type",b://,eB:!0,eE:!0,r:0},{cN:"type",b:/[,:]\s*/,e:/[<\(,]|$/,eB:!0,rE:!0},s,l]},o,{cN:"meta",b:"^#!/usr/bin/env",e:"$",i:"\n"},e.CNM]}}),e.registerLanguage("lasso",function(e){var t="[a-zA-Z_][\\w.]*",r="<\\?(lasso(script)?|=)",a="\\]|\\?>",i={literal:"true false none minimal full all void and or not bw nbw ew new cn ncn lt lte gt gte eq neq rx nrx ft",built_in:"array date decimal duration integer map pair string tag xml null boolean bytes keyword list locale queue set stack staticarray local var variable global data self inherited currentcapture givenblock",keyword:"cache database_names database_schemanames database_tablenames define_tag define_type email_batch encode_set html_comment handle handle_error header if inline iterate ljax_target link link_currentaction link_currentgroup link_currentrecord link_detail link_firstgroup link_firstrecord link_lastgroup link_lastrecord link_nextgroup link_nextrecord link_prevgroup link_prevrecord log loop namespace_using output_none portal private protect records referer referrer repeating resultset rows search_args search_arguments select sort_args sort_arguments thread_atomic value_list while abort case else fail_if fail_ifnot fail if_empty if_false if_null if_true loop_abort loop_continue loop_count params params_up return return_value run_children soap_definetag soap_lastrequest soap_lastresponse tag_name ascending average by define descending do equals frozen group handle_failure import in into join let match max min on order parent protected provide public require returnhome skip split_thread sum take thread to trait type where with yield yieldhome"},n=e.C("",{r:0}),o={cN:"meta",b:"\\[noprocess\\]",starts:{e:"\\[/noprocess\\]",rE:!0,c:[n]}},s={cN:"meta",b:"\\[/noprocess|"+r},l={cN:"symbol",b:"'"+t+"'"},c=[e.CLCM,e.CBCM,e.inherit(e.CNM,{b:e.CNR+"|(-?infinity|NaN)\\b"}),e.inherit(e.ASM,{i:null}),e.inherit(e.QSM,{i:null}),{cN:"string",b:"`",e:"`"},{v:[{b:"[#$]"+t},{b:"#",e:"\\d+",i:"\\W"}]},{cN:"type",b:"::\\s*",e:t,i:"\\W"},{cN:"params",v:[{b:"-(?!infinity)"+t,r:0},{b:"(\\.\\.\\.)"}]},{b:/(->|\.)\s*/,r:0,c:[l]},{cN:"class",bK:"define",rE:!0,e:"\\(|=>",c:[e.inherit(e.TM,{b:t+"(=(?!>))?|[-+*/%](?!>)"})]}];return{aliases:["ls","lassoscript"],cI:!0,l:t+"|&[lg]t;",k:i,c:[{cN:"meta",b:a,r:0,starts:{e:"\\[|"+r,rE:!0,r:0,c:[n]}},o,s,{cN:"meta",b:"\\[no_square_brackets",starts:{e:"\\[/no_square_brackets\\]",l:t+"|&[lg]t;",k:i,c:[{cN:"meta",b:a,r:0,starts:{e:"\\[noprocess\\]|"+r,rE:!0,c:[n]}},o,s].concat(c)}},{cN:"meta",b:"\\[",r:0},{cN:"meta",b:"^#!",e:"lasso9$",r:10}].concat(c)}}),e.registerLanguage("ldif",function(e){return{c:[{cN:"attribute",b:"^dn",e:": ",eE:!0,starts:{e:"$",r:0},r:10},{cN:"attribute",b:"^\\w",e:": ",eE:!0,starts:{e:"$",r:0}},{cN:"literal",b:"^-",e:"$"},e.HCM]}}),e.registerLanguage("leaf",function(e){return{c:[{cN:"function",b:"#+[A-Za-z_0-9]*\\(",e:" {",rB:!0,eE:!0,c:[{cN:"keyword",b:"#+"},{cN:"title",b:"[A-Za-z_][A-Za-z_0-9]*"},{cN:"params",b:"\\(",e:"\\)",endsParent:!0,c:[{cN:"string",b:'"',e:'"'},{cN:"variable",b:"[A-Za-z_][A-Za-z_0-9]*"}]}]}]}}),e.registerLanguage("less",function(e){var t="[\\w-]+",r="("+t+"|@{"+t+"})",a=[],i=[],n=function(e){return{cN:"string",b:"~?"+e+".*?"+e}},o=function(e,t,r){return{cN:e,b:t,r:r}},s={b:"\\(",e:"\\)",c:i,r:0};i.push(e.CLCM,e.CBCM,n("'"),n('"'),e.CSSNM,{b:"(url|data-uri)\\(",starts:{cN:"string",e:"[\\)\\n]",eE:!0}},o("number","#[0-9A-Fa-f]+\\b"),s,o("variable","@@?"+t,10),o("variable","@{"+t+"}"),o("built_in","~?`[^`]*?`"),{cN:"attribute",b:t+"\\s*:",e:":",rB:!0,eE:!0},{cN:"meta",b:"!important"});var l=i.concat({b:"{",e:"}",c:a}),c={bK:"when",eW:!0,c:[{bK:"and not"}].concat(i)},d={b:r+"\\s*:",rB:!0,e:"[;}]",r:0,c:[{cN:"attribute",b:r,e:":",eE:!0,starts:{eW:!0,i:"[<=$]",r:0,c:i}}]},p={cN:"keyword",b:"@(import|media|charset|font-face|(-[a-z]+-)?keyframes|supports|document|namespace|page|viewport|host)\\b",starts:{e:"[;{}]",rE:!0,c:i,r:0}},m={cN:"variable",v:[{b:"@"+t+"\\s*:",r:15},{b:"@"+t}],starts:{e:"[;}]",rE:!0,c:l}},u={v:[{b:"[\\.#:&\\[>]",e:"[;{}]"},{b:r,e:"{"}],rB:!0,rE:!0,i:"[<='$\"]",r:0,c:[e.CLCM,e.CBCM,c,o("keyword","all\\b"),o("variable","@{"+t+"}"),o("selector-tag",r+"%?",0),o("selector-id","#"+r),o("selector-class","\\."+r,0),o("selector-tag","&",0),{cN:"selector-attr",b:"\\[",e:"\\]"},{cN:"selector-pseudo",b:/:(:)?[a-zA-Z0-9\_\-\+\(\)"'.]+/},{b:"\\(",e:"\\)",c:l},{b:"!important"}]};return a.push(e.CLCM,e.CBCM,p,m,d,u),{cI:!0,i:"[=>'/<($\"]",c:a}}),e.registerLanguage("lisp",function(e){var t="[a-zA-Z_\\-\\+\\*\\/\\<\\=\\>\\&\\#][a-zA-Z0-9_\\-\\+\\*\\/\\<\\=\\>\\&\\#!]*",r="\\|[^]*?\\|",a="(\\-|\\+)?\\d+(\\.\\d+|\\/\\d+)?((d|e|f|l|s|D|E|F|L|S)(\\+|\\-)?\\d+)?",i={cN:"meta",b:"^#!",e:"$"},n={cN:"literal",b:"\\b(t{1}|nil)\\b"},o={cN:"number",v:[{b:a,r:0},{b:"#(b|B)[0-1]+(/[0-1]+)?"},{b:"#(o|O)[0-7]+(/[0-7]+)?"},{b:"#(x|X)[0-9a-fA-F]+(/[0-9a-fA-F]+)?"},{b:"#(c|C)\\("+a+" +"+a,e:"\\)"}]},s=e.inherit(e.QSM,{i:null}),l=e.C(";","$",{r:0}),c={b:"\\*",e:"\\*"},d={cN:"symbol",b:"[:&]"+t},p={b:t,r:0},m={b:r},u={b:"\\(",e:"\\)",c:["self",n,s,o,p]},b={c:[o,s,c,d,u,p],v:[{b:"['`]\\(",e:"\\)"},{b:"\\(quote ",e:"\\)",k:{name:"quote"}},{b:"'"+r}]},g={v:[{b:"'"+t},{b:"#'"+t+"(::"+t+")*"}]},f={b:"\\(\\s*",e:"\\)"},_={eW:!0,r:0};return f.c=[{cN:"name",v:[{b:t},{b:r}]},_],_.c=[b,g,f,n,o,s,l,c,d,m,p],{i:/\S/,c:[o,i,n,s,l,b,g,f,p]}}),e.registerLanguage("livecodeserver",function(e){var t={b:"\\b[gtps][A-Z]+[A-Za-z0-9_\\-]*\\b|\\$_[A-Z]+",r:0},r=[e.CBCM,e.HCM,e.C("--","$"),e.C("[^:]//","$")],a=e.inherit(e.TM,{v:[{b:"\\b_*rig[A-Z]+[A-Za-z0-9_\\-]*"},{b:"\\b_[a-z0-9\\-]+"}]}),i=e.inherit(e.TM,{b:"\\b([A-Za-z0-9_\\-]+)\\b"});return{cI:!1,k:{keyword:"$_COOKIE $_FILES $_GET $_GET_BINARY $_GET_RAW $_POST $_POST_BINARY $_POST_RAW $_SESSION $_SERVER codepoint codepoints segment segments codeunit codeunits sentence sentences trueWord trueWords paragraph after byte bytes english the until http forever descending using line real8 with seventh for stdout finally element word words fourth before black ninth sixth characters chars stderr uInt1 uInt1s uInt2 uInt2s stdin string lines relative rel any fifth items from middle mid at else of catch then third it file milliseconds seconds second secs sec int1 int1s int4 int4s internet int2 int2s normal text item last long detailed effective uInt4 uInt4s repeat end repeat URL in try into switch to words https token binfile each tenth as ticks tick system real4 by dateItems without char character ascending eighth whole dateTime numeric short first ftp integer abbreviated abbr abbrev private case while if div mod wrap and or bitAnd bitNot bitOr bitXor among not in a an within contains ends with begins the keys of keys",literal:"SIX TEN FORMFEED NINE ZERO NONE SPACE FOUR FALSE COLON CRLF PI COMMA ENDOFFILE EOF EIGHT FIVE QUOTE EMPTY ONE TRUE RETURN CR LINEFEED RIGHT BACKSLASH NULL SEVEN TAB THREE TWO six ten formfeed nine zero none space four false colon crlf pi comma endoffile eof eight five quote empty one true return cr linefeed right backslash null seven tab three two RIVERSION RISTATE FILE_READ_MODE FILE_WRITE_MODE FILE_WRITE_MODE DIR_WRITE_MODE FILE_READ_UMASK FILE_WRITE_UMASK DIR_READ_UMASK DIR_WRITE_UMASK",built_in:"put abs acos aliasReference annuity arrayDecode arrayEncode asin atan atan2 average avg avgDev base64Decode base64Encode baseConvert binaryDecode binaryEncode byteOffset byteToNum cachedURL cachedURLs charToNum cipherNames codepointOffset codepointProperty codepointToNum codeunitOffset commandNames compound compress constantNames cos date dateFormat decompress directories diskSpace DNSServers exp exp1 exp2 exp10 extents files flushEvents folders format functionNames geometricMean global globals hasMemory harmonicMean hostAddress hostAddressToName hostName hostNameToAddress isNumber ISOToMac itemOffset keys len length libURLErrorData libUrlFormData libURLftpCommand libURLLastHTTPHeaders libURLLastRHHeaders libUrlMultipartFormAddPart libUrlMultipartFormData libURLVersion lineOffset ln ln1 localNames log log2 log10 longFilePath lower macToISO matchChunk matchText matrixMultiply max md5Digest median merge millisec millisecs millisecond milliseconds min monthNames nativeCharToNum normalizeText num number numToByte numToChar numToCodepoint numToNativeChar offset open openfiles openProcesses openProcessIDs openSockets paragraphOffset paramCount param params peerAddress pendingMessages platform popStdDev populationStandardDeviation populationVariance popVariance processID random randomBytes replaceText result revCreateXMLTree revCreateXMLTreeFromFile revCurrentRecord revCurrentRecordIsFirst revCurrentRecordIsLast revDatabaseColumnCount revDatabaseColumnIsNull revDatabaseColumnLengths revDatabaseColumnNames revDatabaseColumnNamed revDatabaseColumnNumbered revDatabaseColumnTypes revDatabaseConnectResult revDatabaseCursors revDatabaseID revDatabaseTableNames revDatabaseType revDataFromQuery revdb_closeCursor revdb_columnbynumber revdb_columncount revdb_columnisnull revdb_columnlengths revdb_columnnames revdb_columntypes revdb_commit revdb_connect revdb_connections revdb_connectionerr revdb_currentrecord revdb_cursorconnection revdb_cursorerr revdb_cursors revdb_dbtype revdb_disconnect revdb_execute revdb_iseof revdb_isbof revdb_movefirst revdb_movelast revdb_movenext revdb_moveprev revdb_query revdb_querylist revdb_recordcount revdb_rollback revdb_tablenames revGetDatabaseDriverPath revNumberOfRecords revOpenDatabase revOpenDatabases revQueryDatabase revQueryDatabaseBlob revQueryResult revQueryIsAtStart revQueryIsAtEnd revUnixFromMacPath revXMLAttribute revXMLAttributes revXMLAttributeValues revXMLChildContents revXMLChildNames revXMLCreateTreeFromFileWithNamespaces revXMLCreateTreeWithNamespaces revXMLDataFromXPathQuery revXMLEvaluateXPath revXMLFirstChild revXMLMatchingNode revXMLNextSibling revXMLNodeContents revXMLNumberOfChildren revXMLParent revXMLPreviousSibling revXMLRootNode revXMLRPC_CreateRequest revXMLRPC_Documents revXMLRPC_Error revXMLRPC_GetHost revXMLRPC_GetMethod revXMLRPC_GetParam revXMLText revXMLRPC_Execute revXMLRPC_GetParamCount revXMLRPC_GetParamNode revXMLRPC_GetParamType revXMLRPC_GetPath revXMLRPC_GetPort revXMLRPC_GetProtocol revXMLRPC_GetRequest revXMLRPC_GetResponse revXMLRPC_GetSocket revXMLTree revXMLTrees revXMLValidateDTD revZipDescribeItem revZipEnumerateItems revZipOpenArchives round sampVariance sec secs seconds sentenceOffset sha1Digest shell shortFilePath sin specialFolderPath sqrt standardDeviation statRound stdDev sum sysError systemVersion tan tempName textDecode textEncode tick ticks time to tokenOffset toLower toUpper transpose truewordOffset trunc uniDecode uniEncode upper URLDecode URLEncode URLStatus uuid value variableNames variance version waitDepth weekdayNames wordOffset xsltApplyStylesheet xsltApplyStylesheetFromFile xsltLoadStylesheet xsltLoadStylesheetFromFile add breakpoint cancel clear local variable file word line folder directory URL close socket process combine constant convert create new alias folder directory decrypt delete variable word line folder directory URL dispatch divide do encrypt filter get include intersect kill libURLDownloadToFile libURLFollowHttpRedirects libURLftpUpload libURLftpUploadFile libURLresetAll libUrlSetAuthCallback libURLSetCustomHTTPHeaders libUrlSetExpect100 libURLSetFTPListCommand libURLSetFTPMode libURLSetFTPStopTime libURLSetStatusCallback load multiply socket prepare process post seek rel relative read from process rename replace require resetAll resolve revAddXMLNode revAppendXML revCloseCursor revCloseDatabase revCommitDatabase revCopyFile revCopyFolder revCopyXMLNode revDeleteFolder revDeleteXMLNode revDeleteAllXMLTrees revDeleteXMLTree revExecuteSQL revGoURL revInsertXMLNode revMoveFolder revMoveToFirstRecord revMoveToLastRecord revMoveToNextRecord revMoveToPreviousRecord revMoveToRecord revMoveXMLNode revPutIntoXMLNode revRollBackDatabase revSetDatabaseDriverPath revSetXMLAttribute revXMLRPC_AddParam revXMLRPC_DeleteAllDocuments revXMLAddDTD revXMLRPC_Free revXMLRPC_FreeAll revXMLRPC_DeleteDocument revXMLRPC_DeleteParam revXMLRPC_SetHost revXMLRPC_SetMethod revXMLRPC_SetPort revXMLRPC_SetProtocol revXMLRPC_SetSocket revZipAddItemWithData revZipAddItemWithFile revZipAddUncompressedItemWithData revZipAddUncompressedItemWithFile revZipCancel revZipCloseArchive revZipDeleteItem revZipExtractItemToFile revZipExtractItemToVariable revZipSetProgressCallback revZipRenameItem revZipReplaceItemWithData revZipReplaceItemWithFile revZipOpenArchive send set sort split start stop subtract union unload wait write"},c:[t,{cN:"keyword",b:"\\bend\\sif\\b"},{cN:"function",bK:"function",e:"$",c:[t,i,e.ASM,e.QSM,e.BNM,e.CNM,a]},{cN:"function",b:"\\bend\\s+",e:"$",k:"end",c:[i,a],r:0},{bK:"command on",e:"$",c:[t,i,e.ASM,e.QSM,e.BNM,e.CNM,a]},{cN:"meta",v:[{b:"<\\?(rev|lc|livecode)",r:10},{b:"<\\?"},{b:"\\?>"}]},e.ASM,e.QSM,e.BNM,e.CNM,a].concat(r),i:";$|^\\[|^=|&|{"}}),e.registerLanguage("livescript",function(e){var t={keyword:"in if for while finally new do return else break catch instanceof throw try this switch continue typeof delete debugger case default function var with then unless until loop of by when and or is isnt not it that otherwise from to til fallthrough super case default function var void const let enum export import native __hasProp __extends __slice __bind __indexOf",literal:"true false null undefined yes no on off it that void",built_in:"npm require console print module global window document"},r="[A-Za-z$_](?:-[0-9A-Za-z$_]|[0-9A-Za-z$_])*",a=e.inherit(e.TM,{b:r}),i={cN:"subst",b:/#\{/,e:/}/,k:t},n={cN:"subst",b:/#[A-Za-z$_]/,e:/(?:\-[0-9A-Za-z$_]|[0-9A-Za-z$_])*/,k:t},o=[e.BNM,{cN:"number",b:"(\\b0[xX][a-fA-F0-9_]+)|(\\b\\d(\\d|_\\d)*(\\.(\\d(\\d|_\\d)*)?)?(_*[eE]([-+]\\d(_\\d|\\d)*)?)?[_a-z]*)",r:0,starts:{e:"(\\s*/)?",r:0}},{cN:"string",v:[{b:/'''/,e:/'''/,c:[e.BE]},{b:/'/,e:/'/,c:[e.BE]},{b:/"""/,e:/"""/,c:[e.BE,i,n]},{b:/"/,e:/"/,c:[e.BE,i,n]},{b:/\\/,e:/(\s|$)/,eE:!0}]},{cN:"regexp",v:[{b:"//",e:"//[gim]*",c:[i,e.HCM]},{b:/\/(?![ *])(\\\/|.)*?\/[gim]*(?=\W|$)/}]},{b:"@"+r},{b:"``",e:"``",eB:!0,eE:!0,sL:"javascript"}];i.c=o;var s={cN:"params",b:"\\(",rB:!0,c:[{b:/\(/,e:/\)/,k:t,c:["self"].concat(o)}]};return{aliases:["ls"],k:t,i:/\/\*/,c:o.concat([e.C("\\/\\*","\\*\\/"),e.HCM,{cN:"function",c:[a,s],rB:!0,v:[{b:"("+r+"\\s*(?:=|:=)\\s*)?(\\(.*\\))?\\s*\\B\\->\\*?",e:"\\->\\*?"},{b:"("+r+"\\s*(?:=|:=)\\s*)?!?(\\(.*\\))?\\s*\\B[-~]{1,2}>\\*?",e:"[-~]{1,2}>\\*?"},{b:"("+r+"\\s*(?:=|:=)\\s*)?(\\(.*\\))?\\s*\\B!?[-~]{1,2}>\\*?",e:"!?[-~]{1,2}>\\*?"}]},{cN:"class",bK:"class",e:"$",i:/[:="\[\]]/,c:[{bK:"extends",eW:!0,i:/[:="\[\]]/,c:[a]},a]},{b:r+":",e:":",rB:!0,rE:!0,r:0}])}}),e.registerLanguage("llvm",function(e){var t="([-a-zA-Z$._][\\w\\-$.]*)";return{k:"begin end true false declare define global constant private linker_private internal available_externally linkonce linkonce_odr weak weak_odr appending dllimport dllexport common default hidden protected extern_weak external thread_local zeroinitializer undef null to tail target triple datalayout volatile nuw nsw nnan ninf nsz arcp fast exact inbounds align addrspace section alias module asm sideeffect gc dbg linker_private_weak attributes blockaddress initialexec localdynamic localexec prefix unnamed_addr ccc fastcc coldcc x86_stdcallcc x86_fastcallcc arm_apcscc arm_aapcscc arm_aapcs_vfpcc ptx_device ptx_kernel intel_ocl_bicc msp430_intrcc spir_func spir_kernel x86_64_sysvcc x86_64_win64cc x86_thiscallcc cc c signext zeroext inreg sret nounwind noreturn noalias nocapture byval nest readnone readonly inlinehint noinline alwaysinline optsize ssp sspreq noredzone noimplicitfloat naked builtin cold nobuiltin noduplicate nonlazybind optnone returns_twice sanitize_address sanitize_memory sanitize_thread sspstrong uwtable returned type opaque eq ne slt sgt sle sge ult ugt ule uge oeq one olt ogt ole oge ord uno ueq une x acq_rel acquire alignstack atomic catch cleanup filter inteldialect max min monotonic nand personality release seq_cst singlethread umax umin unordered xchg add fadd sub fsub mul fmul udiv sdiv fdiv urem srem frem shl lshr ashr and or xor icmp fcmp phi call trunc zext sext fptrunc fpext uitofp sitofp fptoui fptosi inttoptr ptrtoint bitcast addrspacecast select va_arg ret br switch invoke unwind unreachable indirectbr landingpad resume malloc alloca free load store getelementptr extractelement insertelement shufflevector getresult extractvalue insertvalue atomicrmw cmpxchg fence argmemonly double",c:[{cN:"keyword",b:"i\\d+"},e.C(";","\\n",{r:0}),e.QSM,{cN:"string",v:[{b:'"',e:'[^\\\\]"'}],r:0},{cN:"title",v:[{b:"@"+t},{b:"@\\d+"},{b:"!"+t},{b:"!\\d+"+t}]},{cN:"symbol",v:[{b:"%"+t},{b:"%\\d+"},{b:"#\\d+"}]},{cN:"number",v:[{b:"0[xX][a-fA-F0-9]+"},{b:"-?\\d+(?:[.]\\d+)?(?:[eE][-+]?\\d+(?:[.]\\d+)?)?"}],r:0}]}}),e.registerLanguage("lsl",function(e){var t={cN:"subst",b:/\\[tn"\\]/},r={cN:"string",b:'"',e:'"',c:[t]},a={cN:"number",b:e.CNR},i={cN:"literal",v:[{b:"\\b(?:PI|TWO_PI|PI_BY_TWO|DEG_TO_RAD|RAD_TO_DEG|SQRT2)\\b"},{b:"\\b(?:XP_ERROR_(?:EXPERIENCES_DISABLED|EXPERIENCE_(?:DISABLED|SUSPENDED)|INVALID_(?:EXPERIENCE|PARAMETERS)|KEY_NOT_FOUND|MATURITY_EXCEEDED|NONE|NOT_(?:FOUND|PERMITTED(?:_LAND)?)|NO_EXPERIENCE|QUOTA_EXCEEDED|RETRY_UPDATE|STORAGE_EXCEPTION|STORE_DISABLED|THROTTLED|UNKNOWN_ERROR)|JSON_APPEND|STATUS_(?:PHYSICS|ROTATE_[XYZ]|PHANTOM|SANDBOX|BLOCK_GRAB(?:_OBJECT)?|(?:DIE|RETURN)_AT_EDGE|CAST_SHADOWS|OK|MALFORMED_PARAMS|TYPE_MISMATCH|BOUNDS_ERROR|NOT_(?:FOUND|SUPPORTED)|INTERNAL_ERROR|WHITELIST_FAILED)|AGENT(?:_(?:BY_(?:LEGACY_|USER)NAME|FLYING|ATTACHMENTS|SCRIPTED|MOUSELOOK|SITTING|ON_OBJECT|AWAY|WALKING|IN_AIR|TYPING|CROUCHING|BUSY|ALWAYS_RUN|AUTOPILOT|LIST_(?:PARCEL(?:_OWNER)?|REGION)))?|CAMERA_(?:PITCH|DISTANCE|BEHINDNESS_(?:ANGLE|LAG)|(?:FOCUS|POSITION)(?:_(?:THRESHOLD|LOCKED|LAG))?|FOCUS_OFFSET|ACTIVE)|ANIM_ON|LOOP|REVERSE|PING_PONG|SMOOTH|ROTATE|SCALE|ALL_SIDES|LINK_(?:ROOT|SET|ALL_(?:OTHERS|CHILDREN)|THIS)|ACTIVE|PASS(?:IVE|_(?:ALWAYS|IF_NOT_HANDLED|NEVER))|SCRIPTED|CONTROL_(?:FWD|BACK|(?:ROT_)?(?:LEFT|RIGHT)|UP|DOWN|(?:ML_)?LBUTTON)|PERMISSION_(?:RETURN_OBJECTS|DEBIT|OVERRIDE_ANIMATIONS|SILENT_ESTATE_MANAGEMENT|TAKE_CONTROLS|TRIGGER_ANIMATION|ATTACH|CHANGE_LINKS|(?:CONTROL|TRACK)_CAMERA|TELEPORT)|INVENTORY_(?:TEXTURE|SOUND|OBJECT|SCRIPT|LANDMARK|CLOTHING|NOTECARD|BODYPART|ANIMATION|GESTURE|ALL|NONE)|CHANGED_(?:INVENTORY|COLOR|SHAPE|SCALE|TEXTURE|LINK|ALLOWED_DROP|OWNER|REGION(?:_START)?|TELEPORT|MEDIA)|OBJECT_(?:CLICK_ACTION|HOVER_HEIGHT|LAST_OWNER_ID|(?:PHYSICS|SERVER|STREAMING)_COST|UNKNOWN_DETAIL|CHARACTER_TIME|PHANTOM|PHYSICS|TEMP_ON_REZ|NAME|DESC|POS|PRIM_(?:COUNT|EQUIVALENCE)|RETURN_(?:PARCEL(?:_OWNER)?|REGION)|REZZER_KEY|ROO?T|VELOCITY|OMEGA|OWNER|GROUP|CREATOR|ATTACHED_POINT|RENDER_WEIGHT|(?:BODY_SHAPE|PATHFINDING)_TYPE|(?:RUNNING|TOTAL)_SCRIPT_COUNT|TOTAL_INVENTORY_COUNT|SCRIPT_(?:MEMORY|TIME))|TYPE_(?:INTEGER|FLOAT|STRING|KEY|VECTOR|ROTATION|INVALID)|(?:DEBUG|PUBLIC)_CHANNEL|ATTACH_(?:AVATAR_CENTER|CHEST|HEAD|BACK|PELVIS|MOUTH|CHIN|NECK|NOSE|BELLY|[LR](?:SHOULDER|HAND|FOOT|EAR|EYE|[UL](?:ARM|LEG)|HIP)|(?:LEFT|RIGHT)_PEC|HUD_(?:CENTER_[12]|TOP_(?:RIGHT|CENTER|LEFT)|BOTTOM(?:_(?:RIGHT|LEFT))?)|[LR]HAND_RING1|TAIL_(?:BASE|TIP)|[LR]WING|FACE_(?:JAW|[LR]EAR|[LR]EYE|TOUNGE)|GROIN|HIND_[LR]FOOT)|LAND_(?:LEVEL|RAISE|LOWER|SMOOTH|NOISE|REVERT)|DATA_(?:ONLINE|NAME|BORN|SIM_(?:POS|STATUS|RATING)|PAYINFO)|PAYMENT_INFO_(?:ON_FILE|USED)|REMOTE_DATA_(?:CHANNEL|REQUEST|REPLY)|PSYS_(?:PART_(?:BF_(?:ZERO|ONE(?:_MINUS_(?:DEST_COLOR|SOURCE_(ALPHA|COLOR)))?|DEST_COLOR|SOURCE_(ALPHA|COLOR))|BLEND_FUNC_(DEST|SOURCE)|FLAGS|(?:START|END)_(?:COLOR|ALPHA|SCALE|GLOW)|MAX_AGE|(?:RIBBON|WIND|INTERP_(?:COLOR|SCALE)|BOUNCE|FOLLOW_(?:SRC|VELOCITY)|TARGET_(?:POS|LINEAR)|EMISSIVE)_MASK)|SRC_(?:MAX_AGE|PATTERN|ANGLE_(?:BEGIN|END)|BURST_(?:RATE|PART_COUNT|RADIUS|SPEED_(?:MIN|MAX))|ACCEL|TEXTURE|TARGET_KEY|OMEGA|PATTERN_(?:DROP|EXPLODE|ANGLE(?:_CONE(?:_EMPTY)?)?)))|VEHICLE_(?:REFERENCE_FRAME|TYPE_(?:NONE|SLED|CAR|BOAT|AIRPLANE|BALLOON)|(?:LINEAR|ANGULAR)_(?:FRICTION_TIMESCALE|MOTOR_DIRECTION)|LINEAR_MOTOR_OFFSET|HOVER_(?:HEIGHT|EFFICIENCY|TIMESCALE)|BUOYANCY|(?:LINEAR|ANGULAR)_(?:DEFLECTION_(?:EFFICIENCY|TIMESCALE)|MOTOR_(?:DECAY_)?TIMESCALE)|VERTICAL_ATTRACTION_(?:EFFICIENCY|TIMESCALE)|BANKING_(?:EFFICIENCY|MIX|TIMESCALE)|FLAG_(?:NO_DEFLECTION_UP|LIMIT_(?:ROLL_ONLY|MOTOR_UP)|HOVER_(?:(?:WATER|TERRAIN|UP)_ONLY|GLOBAL_HEIGHT)|MOUSELOOK_(?:STEER|BANK)|CAMERA_DECOUPLED))|PRIM_(?:ALPHA_MODE(?:_(?:BLEND|EMISSIVE|MASK|NONE))?|NORMAL|SPECULAR|TYPE(?:_(?:BOX|CYLINDER|PRISM|SPHERE|TORUS|TUBE|RING|SCULPT))?|HOLE_(?:DEFAULT|CIRCLE|SQUARE|TRIANGLE)|MATERIAL(?:_(?:STONE|METAL|GLASS|WOOD|FLESH|PLASTIC|RUBBER))?|SHINY_(?:NONE|LOW|MEDIUM|HIGH)|BUMP_(?:NONE|BRIGHT|DARK|WOOD|BARK|BRICKS|CHECKER|CONCRETE|TILE|STONE|DISKS|GRAVEL|BLOBS|SIDING|LARGETILE|STUCCO|SUCTION|WEAVE)|TEXGEN_(?:DEFAULT|PLANAR)|SCULPT_(?:TYPE_(?:SPHERE|TORUS|PLANE|CYLINDER|MASK)|FLAG_(?:MIRROR|INVERT))|PHYSICS(?:_(?:SHAPE_(?:CONVEX|NONE|PRIM|TYPE)))?|(?:POS|ROT)_LOCAL|SLICE|TEXT|FLEXIBLE|POINT_LIGHT|TEMP_ON_REZ|PHANTOM|POSITION|SIZE|ROTATION|TEXTURE|NAME|OMEGA|DESC|LINK_TARGET|COLOR|BUMP_SHINY|FULLBRIGHT|TEXGEN|GLOW|MEDIA_(?:ALT_IMAGE_ENABLE|CONTROLS|(?:CURRENT|HOME)_URL|AUTO_(?:LOOP|PLAY|SCALE|ZOOM)|FIRST_CLICK_INTERACT|(?:WIDTH|HEIGHT)_PIXELS|WHITELIST(?:_ENABLE)?|PERMS_(?:INTERACT|CONTROL)|PARAM_MAX|CONTROLS_(?:STANDARD|MINI)|PERM_(?:NONE|OWNER|GROUP|ANYONE)|MAX_(?:URL_LENGTH|WHITELIST_(?:SIZE|COUNT)|(?:WIDTH|HEIGHT)_PIXELS)))|MASK_(?:BASE|OWNER|GROUP|EVERYONE|NEXT)|PERM_(?:TRANSFER|MODIFY|COPY|MOVE|ALL)|PARCEL_(?:MEDIA_COMMAND_(?:STOP|PAUSE|PLAY|LOOP|TEXTURE|URL|TIME|AGENT|UNLOAD|AUTO_ALIGN|TYPE|SIZE|DESC|LOOP_SET)|FLAG_(?:ALLOW_(?:FLY|(?:GROUP_)?SCRIPTS|LANDMARK|TERRAFORM|DAMAGE|CREATE_(?:GROUP_)?OBJECTS)|USE_(?:ACCESS_(?:GROUP|LIST)|BAN_LIST|LAND_PASS_LIST)|LOCAL_SOUND_ONLY|RESTRICT_PUSHOBJECT|ALLOW_(?:GROUP|ALL)_OBJECT_ENTRY)|COUNT_(?:TOTAL|OWNER|GROUP|OTHER|SELECTED|TEMP)|DETAILS_(?:NAME|DESC|OWNER|GROUP|AREA|ID|SEE_AVATARS))|LIST_STAT_(?:MAX|MIN|MEAN|MEDIAN|STD_DEV|SUM(?:_SQUARES)?|NUM_COUNT|GEOMETRIC_MEAN|RANGE)|PAY_(?:HIDE|DEFAULT)|REGION_FLAG_(?:ALLOW_DAMAGE|FIXED_SUN|BLOCK_TERRAFORM|SANDBOX|DISABLE_(?:COLLISIONS|PHYSICS)|BLOCK_FLY|ALLOW_DIRECT_TELEPORT|RESTRICT_PUSHOBJECT)|HTTP_(?:METHOD|MIMETYPE|BODY_(?:MAXLENGTH|TRUNCATED)|CUSTOM_HEADER|PRAGMA_NO_CACHE|VERBOSE_THROTTLE|VERIFY_CERT)|STRING_(?:TRIM(?:_(?:HEAD|TAIL))?)|CLICK_ACTION_(?:NONE|TOUCH|SIT|BUY|PAY|OPEN(?:_MEDIA)?|PLAY|ZOOM)|TOUCH_INVALID_FACE|PROFILE_(?:NONE|SCRIPT_MEMORY)|RC_(?:DATA_FLAGS|DETECT_PHANTOM|GET_(?:LINK_NUM|NORMAL|ROOT_KEY)|MAX_HITS|REJECT_(?:TYPES|AGENTS|(?:NON)?PHYSICAL|LAND))|RCERR_(?:CAST_TIME_EXCEEDED|SIM_PERF_LOW|UNKNOWN)|ESTATE_ACCESS_(?:ALLOWED_(?:AGENT|GROUP)_(?:ADD|REMOVE)|BANNED_AGENT_(?:ADD|REMOVE))|DENSITY|FRICTION|RESTITUTION|GRAVITY_MULTIPLIER|KFM_(?:COMMAND|CMD_(?:PLAY|STOP|PAUSE)|MODE|FORWARD|LOOP|PING_PONG|REVERSE|DATA|ROTATION|TRANSLATION)|ERR_(?:GENERIC|PARCEL_PERMISSIONS|MALFORMED_PARAMS|RUNTIME_PERMISSIONS|THROTTLED)|CHARACTER_(?:CMD_(?:(?:SMOOTH_)?STOP|JUMP)|DESIRED_(?:TURN_)?SPEED|RADIUS|STAY_WITHIN_PARCEL|LENGTH|ORIENTATION|ACCOUNT_FOR_SKIPPED_FRAMES|AVOIDANCE_MODE|TYPE(?:_(?:[ABCD]|NONE))?|MAX_(?:DECEL|TURN_RADIUS|(?:ACCEL|SPEED)))|PURSUIT_(?:OFFSET|FUZZ_FACTOR|GOAL_TOLERANCE|INTERCEPT)|REQUIRE_LINE_OF_SIGHT|FORCE_DIRECT_PATH|VERTICAL|HORIZONTAL|AVOID_(?:CHARACTERS|DYNAMIC_OBSTACLES|NONE)|PU_(?:EVADE_(?:HIDDEN|SPOTTED)|FAILURE_(?:DYNAMIC_PATHFINDING_DISABLED|INVALID_(?:GOAL|START)|NO_(?:NAVMESH|VALID_DESTINATION)|OTHER|TARGET_GONE|(?:PARCEL_)?UNREACHABLE)|(?:GOAL|SLOWDOWN_DISTANCE)_REACHED)|TRAVERSAL_TYPE(?:_(?:FAST|NONE|SLOW))?|CONTENT_TYPE_(?:ATOM|FORM|HTML|JSON|LLSD|RSS|TEXT|XHTML|XML)|GCNP_(?:RADIUS|STATIC)|(?:PATROL|WANDER)_PAUSE_AT_WAYPOINTS|OPT_(?:AVATAR|CHARACTER|EXCLUSION_VOLUME|LEGACY_LINKSET|MATERIAL_VOLUME|OTHER|STATIC_OBSTACLE|WALKABLE)|SIM_STAT_PCT_CHARS_STEPPED)\\b"},{b:"\\b(?:FALSE|TRUE)\\b"},{b:"\\b(?:ZERO_ROTATION)\\b"},{b:"\\b(?:EOF|JSON_(?:ARRAY|DELETE|FALSE|INVALID|NULL|NUMBER|OBJECT|STRING|TRUE)|NULL_KEY|TEXTURE_(?:BLANK|DEFAULT|MEDIA|PLYWOOD|TRANSPARENT)|URL_REQUEST_(?:GRANTED|DENIED))\\b"},{b:"\\b(?:ZERO_VECTOR|TOUCH_INVALID_(?:TEXCOORD|VECTOR))\\b"}]},n={cN:"built_in",b:"\\b(?:ll(?:AgentInExperience|(?:Create|DataSize|Delete|KeyCount|Keys|Read|Update)KeyValue|GetExperience(?:Details|ErrorMessage)|ReturnObjectsBy(?:ID|Owner)|Json(?:2List|[GS]etValue|ValueType)|Sin|Cos|Tan|Atan2|Sqrt|Pow|Abs|Fabs|Frand|Floor|Ceil|Round|Vec(?:Mag|Norm|Dist)|Rot(?:Between|2(?:Euler|Fwd|Left|Up))|(?:Euler|Axes)2Rot|Whisper|(?:Region|Owner)?Say|Shout|Listen(?:Control|Remove)?|Sensor(?:Repeat|Remove)?|Detected(?:Name|Key|Owner|Type|Pos|Vel|Grab|Rot|Group|LinkNumber)|Die|Ground|Wind|(?:[GS]et)(?:AnimationOverride|MemoryLimit|PrimMediaParams|ParcelMusicURL|Object(?:Desc|Name)|PhysicsMaterial|Status|Scale|Color|Alpha|Texture|Pos|Rot|Force|Torque)|ResetAnimationOverride|(?:Scale|Offset|Rotate)Texture|(?:Rot)?Target(?:Remove)?|(?:Stop)?MoveToTarget|Apply(?:Rotational)?Impulse|Set(?:KeyframedMotion|ContentType|RegionPos|(?:Angular)?Velocity|Buoyancy|HoverHeight|ForceAndTorque|TimerEvent|ScriptState|Damage|TextureAnim|Sound(?:Queueing|Radius)|Vehicle(?:Type|(?:Float|Vector|Rotation)Param)|(?:Touch|Sit)?Text|Camera(?:Eye|At)Offset|PrimitiveParams|ClickAction|Link(?:Alpha|Color|PrimitiveParams(?:Fast)?|Texture(?:Anim)?|Camera|Media)|RemoteScriptAccessPin|PayPrice|LocalRot)|ScaleByFactor|Get(?:(?:Max|Min)ScaleFactor|ClosestNavPoint|StaticPath|SimStats|Env|PrimitiveParams|Link(?:PrimitiveParams|Number(?:OfSides)?|Key|Name|Media)|HTTPHeader|FreeURLs|Object(?:Details|PermMask|PrimCount)|Parcel(?:MaxPrims|Details|Prim(?:Count|Owners))|Attached(?:List)?|(?:SPMax|Free|Used)Memory|Region(?:Name|TimeDilation|FPS|Corner|AgentCount)|Root(?:Position|Rotation)|UnixTime|(?:Parcel|Region)Flags|(?:Wall|GMT)clock|SimulatorHostname|BoundingBox|GeometricCenter|Creator|NumberOf(?:Prims|NotecardLines|Sides)|Animation(?:List)?|(?:Camera|Local)(?:Pos|Rot)|Vel|Accel|Omega|Time(?:stamp|OfDay)|(?:Object|CenterOf)?Mass|MassMKS|Energy|Owner|(?:Owner)?Key|SunDirection|Texture(?:Offset|Scale|Rot)|Inventory(?:Number|Name|Key|Type|Creator|PermMask)|Permissions(?:Key)?|StartParameter|List(?:Length|EntryType)|Date|Agent(?:Size|Info|Language|List)|LandOwnerAt|NotecardLine|Script(?:Name|State))|(?:Get|Reset|GetAndReset)Time|PlaySound(?:Slave)?|LoopSound(?:Master|Slave)?|(?:Trigger|Stop|Preload)Sound|(?:(?:Get|Delete)Sub|Insert)String|To(?:Upper|Lower)|Give(?:InventoryList|Money)|RezObject|(?:Stop)?LookAt|Sleep|CollisionFilter|(?:Take|Release)Controls|DetachFromAvatar|AttachToAvatar(?:Temp)?|InstantMessage|(?:GetNext)?Email|StopHover|MinEventDelay|RotLookAt|String(?:Length|Trim)|(?:Start|Stop)Animation|TargetOmega|Request(?:Experience)?Permissions|(?:Create|Break)Link|BreakAllLinks|(?:Give|Remove)Inventory|Water|PassTouches|Request(?:Agent|Inventory)Data|TeleportAgent(?:Home|GlobalCoords)?|ModifyLand|CollisionSound|ResetScript|MessageLinked|PushObject|PassCollisions|AxisAngle2Rot|Rot2(?:Axis|Angle)|A(?:cos|sin)|AngleBetween|AllowInventoryDrop|SubStringIndex|List2(?:CSV|Integer|Json|Float|String|Key|Vector|Rot|List(?:Strided)?)|DeleteSubList|List(?:Statistics|Sort|Randomize|(?:Insert|Find|Replace)List)|EdgeOfWorld|AdjustSoundVolume|Key2Name|TriggerSoundLimited|EjectFromLand|(?:CSV|ParseString)2List|OverMyLand|SameGroup|UnSit|Ground(?:Slope|Normal|Contour)|GroundRepel|(?:Set|Remove)VehicleFlags|(?:AvatarOn)?(?:Link)?SitTarget|Script(?:Danger|Profiler)|Dialog|VolumeDetect|ResetOtherScript|RemoteLoadScriptPin|(?:Open|Close)RemoteDataChannel|SendRemoteData|RemoteDataReply|(?:Integer|String)ToBase64|XorBase64|Log(?:10)?|Base64To(?:String|Integer)|ParseStringKeepNulls|RezAtRoot|RequestSimulatorData|ForceMouselook|(?:Load|Release|(?:E|Une)scape)URL|ParcelMedia(?:CommandList|Query)|ModPow|MapDestination|(?:RemoveFrom|AddTo|Reset)Land(?:Pass|Ban)List|(?:Set|Clear)CameraParams|HTTP(?:Request|Response)|TextBox|DetectedTouch(?:UV|Face|Pos|(?:N|Bin)ormal|ST)|(?:MD5|SHA1|DumpList2)String|Request(?:Secure)?URL|Clear(?:Prim|Link)Media|(?:Link)?ParticleSystem|(?:Get|Request)(?:Username|DisplayName)|RegionSayTo|CastRay|GenerateKey|TransferLindenDollars|ManageEstateAccess|(?:Create|Delete)Character|ExecCharacterCmd|Evade|FleeFrom|NavigateTo|PatrolPoints|Pursue|UpdateCharacter|WanderWithin))\\b"};return{i:":",c:[r,{cN:"comment",v:[e.C("//","$"),e.C("/\\*","\\*/")]},a,{cN:"section",v:[{b:"\\b(?:state|default)\\b"},{b:"\\b(?:state_(?:entry|exit)|touch(?:_(?:start|end))?|(?:land_)?collision(?:_(?:start|end))?|timer|listen|(?:no_)?sensor|control|(?:not_)?at_(?:rot_)?target|money|email|experience_permissions(?:_denied)?|run_time_permissions|changed|attach|dataserver|moving_(?:start|end)|link_message|(?:on|object)_rez|remote_data|http_re(?:sponse|quest)|path_update|transaction_result)\\b"}]},n,i,{cN:"type",b:"\\b(?:integer|float|string|key|vector|quaternion|rotation|list)\\b"}]}}),e.registerLanguage("lua",function(e){var t="\\[=*\\[",r="\\]=*\\]",a={b:t,e:r,c:["self"]},i=[e.C("--(?!"+t+")","$"),e.C("--"+t,r,{c:[a],r:10})];return{l:e.UIR,k:{literal:"true false nil",keyword:"and break do else elseif end for goto if in local not or repeat return then until while",built_in:"_G _ENV _VERSION __index __newindex __mode __call __metatable __tostring __len __gc __add __sub __mul __div __mod __pow __concat __unm __eq __lt __le assert collectgarbage dofile error getfenv getmetatable ipairs load loadfile loadstringmodule next pairs pcall print rawequal rawget rawset require select setfenvsetmetatable tonumber tostring type unpack xpcall arg selfcoroutine resume yield status wrap create running debug getupvalue debug sethook getmetatable gethook setmetatable setlocal traceback setfenv getinfo setupvalue getlocal getregistry getfenv io lines write close flush open output type read stderr stdin input stdout popen tmpfile math log max acos huge ldexp pi cos tanh pow deg tan cosh sinh random randomseed frexp ceil floor rad abs sqrt modf asin min mod fmod log10 atan2 exp sin atan os exit setlocale date getenv difftime remove time clock tmpname rename execute package preload loadlib loaded loaders cpath config path seeall string sub upper len gfind rep find match char dump gmatch reverse byte format gsub lower table setn insert getn foreachi maxn foreach concat sort remove" -},c:i.concat([{cN:"function",bK:"function",e:"\\)",c:[e.inherit(e.TM,{b:"([_a-zA-Z]\\w*\\.)*([_a-zA-Z]\\w*:)?[_a-zA-Z]\\w*"}),{cN:"params",b:"\\(",eW:!0,c:i}].concat(i)},e.CNM,e.ASM,e.QSM,{cN:"string",b:t,e:r,c:[a],r:5}])}}),e.registerLanguage("makefile",function(e){var t={cN:"variable",v:[{b:"\\$\\("+e.UIR+"\\)",c:[e.BE]},{b:/\$[@%"},{b:"<=",r:0},{b:"=>",r:0},{b:"/\\\\"},{b:"\\\\/"}]},l={cN:"built_in",v:[{b:":-\\|-->"},{b:"=",r:0}]};return{aliases:["m","moo"],k:t,c:[s,l,r,e.CBCM,a,e.NM,i,n,{b:/:-/}]}}),e.registerLanguage("mipsasm",function(e){return{cI:!0,aliases:["mips"],l:"\\.?"+e.IR,k:{meta:".2byte .4byte .align .ascii .asciz .balign .byte .code .data .else .end .endif .endm .endr .equ .err .exitm .extern .global .hword .if .ifdef .ifndef .include .irp .long .macro .rept .req .section .set .skip .space .text .word .ltorg ",built_in:"$0 $1 $2 $3 $4 $5 $6 $7 $8 $9 $10 $11 $12 $13 $14 $15 $16 $17 $18 $19 $20 $21 $22 $23 $24 $25 $26 $27 $28 $29 $30 $31 zero at v0 v1 a0 a1 a2 a3 a4 a5 a6 a7 t0 t1 t2 t3 t4 t5 t6 t7 t8 t9 s0 s1 s2 s3 s4 s5 s6 s7 s8 k0 k1 gp sp fp ra $f0 $f1 $f2 $f2 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15 $f16 $f17 $f18 $f19 $f20 $f21 $f22 $f23 $f24 $f25 $f26 $f27 $f28 $f29 $f30 $f31 Context Random EntryLo0 EntryLo1 Context PageMask Wired EntryHi HWREna BadVAddr Count Compare SR IntCtl SRSCtl SRSMap Cause EPC PRId EBase Config Config1 Config2 Config3 LLAddr Debug DEPC DESAVE CacheErr ECC ErrorEPC TagLo DataLo TagHi DataHi WatchLo WatchHi PerfCtl PerfCnt "},c:[{cN:"keyword",b:"\\b(addi?u?|andi?|b(al)?|beql?|bgez(al)?l?|bgtzl?|blezl?|bltz(al)?l?|bnel?|cl[oz]|divu?|ext|ins|j(al)?|jalr(.hb)?|jr(.hb)?|lbu?|lhu?|ll|lui|lw[lr]?|maddu?|mfhi|mflo|movn|movz|move|msubu?|mthi|mtlo|mul|multu?|nop|nor|ori?|rotrv?|sb|sc|se[bh]|sh|sllv?|slti?u?|srav?|srlv?|subu?|sw[lr]?|xori?|wsbh|abs.[sd]|add.[sd]|alnv.ps|bc1[ft]l?|c.(s?f|un|u?eq|[ou]lt|[ou]le|ngle?|seq|l[et]|ng[et]).[sd]|(ceil|floor|round|trunc).[lw].[sd]|cfc1|cvt.d.[lsw]|cvt.l.[dsw]|cvt.ps.s|cvt.s.[dlw]|cvt.s.p[lu]|cvt.w.[dls]|div.[ds]|ldx?c1|luxc1|lwx?c1|madd.[sd]|mfc1|mov[fntz]?.[ds]|msub.[sd]|mth?c1|mul.[ds]|neg.[ds]|nmadd.[ds]|nmsub.[ds]|p[lu][lu].ps|recip.fmt|r?sqrt.[ds]|sdx?c1|sub.[ds]|suxc1|swx?c1|break|cache|d?eret|[de]i|ehb|mfc0|mtc0|pause|prefx?|rdhwr|rdpgpr|sdbbp|ssnop|synci?|syscall|teqi?|tgei?u?|tlb(p|r|w[ir])|tlti?u?|tnei?|wait|wrpgpr)",e:"\\s"},e.C("[;#]","$"),e.CBCM,e.QSM,{cN:"string",b:"'",e:"[^\\\\]'",r:0},{cN:"title",b:"\\|",e:"\\|",i:"\\n",r:0},{cN:"number",v:[{b:"0x[0-9a-f]+"},{b:"\\b-?\\d+"}],r:0},{cN:"symbol",v:[{b:"^\\s*[a-z_\\.\\$][a-z0-9_\\.\\$]+:"},{b:"^\\s*[0-9]+:"},{b:"[0-9]+[bf]"}],r:0}],i:"/"}}),e.registerLanguage("mizar",function(e){return{k:"environ vocabularies notations constructors definitions registrations theorems schemes requirements begin end definition registration cluster existence pred func defpred deffunc theorem proof let take assume then thus hence ex for st holds consider reconsider such that and in provided of as from be being by means equals implies iff redefine define now not or attr is mode suppose per cases set thesis contradiction scheme reserve struct correctness compatibility coherence symmetry assymetry reflexivity irreflexivity connectedness uniqueness commutativity idempotence involutiveness projectivity",c:[e.C("::","$")]}}),e.registerLanguage("perl",function(e){var t="getpwent getservent quotemeta msgrcv scalar kill dbmclose undef lc ma syswrite tr send umask sysopen shmwrite vec qx utime local oct semctl localtime readpipe do return format read sprintf dbmopen pop getpgrp not getpwnam rewinddir qqfileno qw endprotoent wait sethostent bless s|0 opendir continue each sleep endgrent shutdown dump chomp connect getsockname die socketpair close flock exists index shmgetsub for endpwent redo lstat msgctl setpgrp abs exit select print ref gethostbyaddr unshift fcntl syscall goto getnetbyaddr join gmtime symlink semget splice x|0 getpeername recv log setsockopt cos last reverse gethostbyname getgrnam study formline endhostent times chop length gethostent getnetent pack getprotoent getservbyname rand mkdir pos chmod y|0 substr endnetent printf next open msgsnd readdir use unlink getsockopt getpriority rindex wantarray hex system getservbyport endservent int chr untie rmdir prototype tell listen fork shmread ucfirst setprotoent else sysseek link getgrgid shmctl waitpid unpack getnetbyname reset chdir grep split require caller lcfirst until warn while values shift telldir getpwuid my getprotobynumber delete and sort uc defined srand accept package seekdir getprotobyname semop our rename seek if q|0 chroot sysread setpwent no crypt getc chown sqrt write setnetent setpriority foreach tie sin msgget map stat getlogin unless elsif truncate exec keys glob tied closedirioctl socket readlink eval xor readline binmode setservent eof ord bind alarm pipe atan2 getgrent exp time push setgrent gt lt or ne m|0 break given say state when",r={cN:"subst",b:"[$@]\\{",e:"\\}",k:t},a={b:"->{",e:"}"},i={v:[{b:/\$\d/},{b:/[\$%@](\^\w\b|#\w+(::\w+)*|{\w+}|\w+(::\w*)*)/},{b:/[\$%@][^\s\w{]/,r:0}]},n=[e.BE,r,i],o=[i,e.HCM,e.C("^\\=\\w","\\=cut",{eW:!0}),a,{cN:"string",c:n,v:[{b:"q[qwxr]?\\s*\\(",e:"\\)",r:5},{b:"q[qwxr]?\\s*\\[",e:"\\]",r:5},{b:"q[qwxr]?\\s*\\{",e:"\\}",r:5},{b:"q[qwxr]?\\s*\\|",e:"\\|",r:5},{b:"q[qwxr]?\\s*\\<",e:"\\>",r:5},{b:"qw\\s+q",e:"q",r:5},{b:"'",e:"'",c:[e.BE]},{b:'"',e:'"'},{b:"`",e:"`",c:[e.BE]},{b:"{\\w+}",c:[],r:0},{b:"-?\\w+\\s*\\=\\>",c:[],r:0}]},{cN:"number",b:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",r:0},{b:"(\\/\\/|"+e.RSR+"|\\b(split|return|print|reverse|grep)\\b)\\s*",k:"split return print reverse grep",r:0,c:[e.HCM,{cN:"regexp",b:"(s|tr|y)/(\\\\.|[^/])*/(\\\\.|[^/])*/[a-z]*",r:10},{cN:"regexp",b:"(m|qr)?/",e:"/[a-z]*",c:[e.BE],r:0}]},{cN:"function",bK:"sub",e:"(\\s*\\(.*?\\))?[;{]",eE:!0,r:5,c:[e.TM]},{b:"-\\w\\b",r:0},{b:"^__DATA__$",e:"^__END__$",sL:"mojolicious",c:[{b:"^@@.*",e:"$",cN:"comment"}]}];return r.c=o,a.c=o,{aliases:["pl","pm"],l:/[\w\.]+/,k:t,c:o}}),e.registerLanguage("mojolicious",function(e){return{sL:"xml",c:[{cN:"meta",b:"^__(END|DATA)__$"},{b:"^\\s*%{1,2}={0,2}",e:"$",sL:"perl"},{b:"<%{1,2}={0,2}",e:"={0,1}%>",sL:"perl",eB:!0,eE:!0}]}}),e.registerLanguage("monkey",function(e){var t={cN:"number",r:0,v:[{b:"[$][a-fA-F0-9]+"},e.NM]};return{cI:!0,k:{keyword:"public private property continue exit extern new try catch eachin not abstract final select case default const local global field end if then else elseif endif while wend repeat until forever for to step next return module inline throw import",built_in:"DebugLog DebugStop Error Print ACos ACosr ASin ASinr ATan ATan2 ATan2r ATanr Abs Abs Ceil Clamp Clamp Cos Cosr Exp Floor Log Max Max Min Min Pow Sgn Sgn Sin Sinr Sqrt Tan Tanr Seed PI HALFPI TWOPI",literal:"true false null and or shl shr mod"},i:/\/\*/,c:[e.C("#rem","#end"),e.C("'","$",{r:0}),{cN:"function",bK:"function method",e:"[(=:]|$",i:/\n/,c:[e.UTM]},{cN:"class",bK:"class interface",e:"$",c:[{bK:"extends implements"},e.UTM]},{cN:"built_in",b:"\\b(self|super)\\b"},{cN:"meta",b:"\\s*#",e:"$",k:{"meta-keyword":"if else elseif endif end then"}},{cN:"meta",b:"^\\s*strict\\b"},{bK:"alias",e:"=",c:[e.UTM]},e.QSM,t]}}),e.registerLanguage("moonscript",function(e){var t={keyword:"if then not for in while do return else elseif break continue switch and or unless when class extends super local import export from using",literal:"true false nil",built_in:"_G _VERSION assert collectgarbage dofile error getfenv getmetatable ipairs load loadfile loadstring module next pairs pcall print rawequal rawget rawset require select setfenv setmetatable tonumber tostring type unpack xpcall coroutine debug io math os package string table"},r="[A-Za-z$_][0-9A-Za-z$_]*",a={cN:"subst",b:/#\{/,e:/}/,k:t},i=[e.inherit(e.CNM,{starts:{e:"(\\s*/)?",r:0}}),{cN:"string",v:[{b:/'/,e:/'/,c:[e.BE]},{b:/"/,e:/"/,c:[e.BE,a]}]},{cN:"built_in",b:"@__"+e.IR},{b:"@"+e.IR},{b:e.IR+"\\\\"+e.IR}];a.c=i;var n=e.inherit(e.TM,{b:r}),o="(\\(.*\\))?\\s*\\B[-=]>",s={cN:"params",b:"\\([^\\(]",rB:!0,c:[{b:/\(/,e:/\)/,k:t,c:["self"].concat(i)}]};return{aliases:["moon"],k:t,i:/\/\*/,c:i.concat([e.C("--","$"),{cN:"function",b:"^\\s*"+r+"\\s*=\\s*"+o,e:"[-=]>",rB:!0,c:[n,s]},{b:/[\(,:=]\s*/,r:0,c:[{cN:"function",b:o,e:"[-=]>",rB:!0,c:[s]}]},{cN:"class",bK:"class",e:"$",i:/[:="\[\]]/,c:[{bK:"extends",eW:!0,i:/[:="\[\]]/,c:[n]},n]},{cN:"name",b:r+":",e:":",rB:!0,rE:!0,r:0}])}}),e.registerLanguage("n1ql",function(e){return{cI:!0,c:[{bK:"build create index delete drop explain infer|10 insert merge prepare select update upsert|10",e:/;/,eW:!0,k:{keyword:"all alter analyze and any array as asc begin between binary boolean break bucket build by call case cast cluster collate collection commit connect continue correlate cover create database dataset datastore declare decrement delete derived desc describe distinct do drop each element else end every except exclude execute exists explain fetch first flatten for force from function grant group gsi having if ignore ilike in include increment index infer inline inner insert intersect into is join key keys keyspace known last left let letting like limit lsm map mapping matched materialized merge minus namespace nest not number object offset on option or order outer over parse partition password path pool prepare primary private privilege procedure public raw realm reduce rename return returning revoke right role rollback satisfies schema select self semi set show some start statistics string system then to transaction trigger truncate under union unique unknown unnest unset update upsert use user using validate value valued values via view when where while with within work xor",literal:"true false null missing|5",built_in:"array_agg array_append array_concat array_contains array_count array_distinct array_ifnull array_length array_max array_min array_position array_prepend array_put array_range array_remove array_repeat array_replace array_reverse array_sort array_sum avg count max min sum greatest least ifmissing ifmissingornull ifnull missingif nullif ifinf ifnan ifnanorinf naninf neginfif posinfif clock_millis clock_str date_add_millis date_add_str date_diff_millis date_diff_str date_part_millis date_part_str date_trunc_millis date_trunc_str duration_to_str millis str_to_millis millis_to_str millis_to_utc millis_to_zone_name now_millis now_str str_to_duration str_to_utc str_to_zone_name decode_json encode_json encoded_size poly_length base64 base64_encode base64_decode meta uuid abs acos asin atan atan2 ceil cos degrees e exp ln log floor pi power radians random round sign sin sqrt tan trunc object_length object_names object_pairs object_inner_pairs object_values object_inner_values object_add object_put object_remove object_unwrap regexp_contains regexp_like regexp_position regexp_replace contains initcap length lower ltrim position repeat replace rtrim split substr title trim upper isarray isatom isboolean isnumber isobject isstring type toarray toatom toboolean tonumber toobject tostring"},c:[{cN:"string",b:"'",e:"'",c:[e.BE],r:0},{cN:"string",b:'"',e:'"',c:[e.BE],r:0},{cN:"symbol",b:"`",e:"`",c:[e.BE],r:2},e.CNM,e.CBCM]},e.CBCM]}}),e.registerLanguage("nginx",function(e){var t={cN:"variable",v:[{b:/\$\d+/},{b:/\$\{/,e:/}/},{b:"[\\$\\@]"+e.UIR}]},r={eW:!0,l:"[a-z/_]+",k:{literal:"on off yes no true false none blocked debug info notice warn error crit select break last permanent redirect kqueue rtsig epoll poll /dev/poll"},r:0,i:"=>",c:[e.HCM,{cN:"string",c:[e.BE,t],v:[{b:/"/,e:/"/},{b:/'/,e:/'/}]},{b:"([a-z]+):/",e:"\\s",eW:!0,eE:!0,c:[t]},{cN:"regexp",c:[e.BE,t],v:[{b:"\\s\\^",e:"\\s|{|;",rE:!0},{b:"~\\*?\\s+",e:"\\s|{|;",rE:!0},{b:"\\*(\\.[a-z\\-]+)+"},{b:"([a-z\\-]+\\.)+\\*"}]},{cN:"number",b:"\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}(:\\d{1,5})?\\b"},{cN:"number",b:"\\b\\d+[kKmMgGdshdwy]*\\b",r:0},t]};return{aliases:["nginxconf"],c:[e.HCM,{b:e.UIR+"\\s+{",rB:!0,e:"{",c:[{cN:"section",b:e.UIR}],r:0},{b:e.UIR+"\\s",e:";|{",rB:!0,c:[{cN:"attribute",b:e.UIR,starts:r}],r:0}],i:"[^\\s\\}]"}}),e.registerLanguage("nimrod",function(e){return{aliases:["nim"],k:{keyword:"addr and as asm bind block break case cast const continue converter discard distinct div do elif else end enum except export finally for from generic if import in include interface is isnot iterator let macro method mixin mod nil not notin object of or out proc ptr raise ref return shl shr static template try tuple type using var when while with without xor yield",literal:"shared guarded stdin stdout stderr result true false",built_in:"int int8 int16 int32 int64 uint uint8 uint16 uint32 uint64 float float32 float64 bool char string cstring pointer expr stmt void auto any range array openarray varargs seq set clong culong cchar cschar cshort cint csize clonglong cfloat cdouble clongdouble cuchar cushort cuint culonglong cstringarray semistatic"},c:[{cN:"meta",b:/{\./,e:/\.}/,r:10},{cN:"string",b:/[a-zA-Z]\w*"/,e:/"/,c:[{b:/""/}]},{cN:"string",b:/([a-zA-Z]\w*)?"""/,e:/"""/},e.QSM,{cN:"type",b:/\b[A-Z]\w+\b/,r:0},{cN:"number",r:0,v:[{b:/\b(0[xX][0-9a-fA-F][_0-9a-fA-F]*)('?[iIuU](8|16|32|64))?/},{b:/\b(0o[0-7][_0-7]*)('?[iIuUfF](8|16|32|64))?/},{b:/\b(0(b|B)[01][_01]*)('?[iIuUfF](8|16|32|64))?/},{b:/\b(\d[_\d]*)('?[iIuUfF](8|16|32|64))?/}]},e.HCM]}}),e.registerLanguage("nix",function(e){var t={keyword:"rec with let in inherit assert if else then",literal:"true false or and null",built_in:"import abort baseNameOf dirOf isNull builtins map removeAttrs throw toString derivation"},r={cN:"subst",b:/\$\{/,e:/}/,k:t},a={b:/[a-zA-Z0-9-_]+(\s*=)/,rB:!0,r:0,c:[{cN:"attr",b:/\S+/}]},i={cN:"string",c:[r],v:[{b:"''",e:"''"},{b:'"',e:'"'}]},n=[e.NM,e.HCM,e.CBCM,i,a];return r.c=n,{aliases:["nixos"],k:t,c:n}}),e.registerLanguage("nsis",function(e){var t={cN:"variable",b:/\$(ADMINTOOLS|APPDATA|CDBURN_AREA|CMDLINE|COMMONFILES32|COMMONFILES64|COMMONFILES|COOKIES|DESKTOP|DOCUMENTS|EXEDIR|EXEFILE|EXEPATH|FAVORITES|FONTS|HISTORY|HWNDPARENT|INSTDIR|INTERNET_CACHE|LANGUAGE|LOCALAPPDATA|MUSIC|NETHOOD|OUTDIR|PICTURES|PLUGINSDIR|PRINTHOOD|PROFILE|PROGRAMFILES32|PROGRAMFILES64|PROGRAMFILES|QUICKLAUNCH|RECENT|RESOURCES_LOCALIZED|RESOURCES|SENDTO|SMPROGRAMS|SMSTARTUP|STARTMENU|SYSDIR|TEMP|TEMPLATES|VIDEOS|WINDIR)/},r={cN:"variable",b:/\$+{[\w\.:-]+}/},a={cN:"variable",b:/\$+\w+/,i:/\(\){}/},i={cN:"variable",b:/\$+\([\w\^\.:-]+\)/},n={cN:"params",b:"(ARCHIVE|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_OFFLINE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_TEMPORARY|HKCR|HKCU|HKDD|HKEY_CLASSES_ROOT|HKEY_CURRENT_CONFIG|HKEY_CURRENT_USER|HKEY_DYN_DATA|HKEY_LOCAL_MACHINE|HKEY_PERFORMANCE_DATA|HKEY_USERS|HKLM|HKPD|HKU|IDABORT|IDCANCEL|IDIGNORE|IDNO|IDOK|IDRETRY|IDYES|MB_ABORTRETRYIGNORE|MB_DEFBUTTON1|MB_DEFBUTTON2|MB_DEFBUTTON3|MB_DEFBUTTON4|MB_ICONEXCLAMATION|MB_ICONINFORMATION|MB_ICONQUESTION|MB_ICONSTOP|MB_OK|MB_OKCANCEL|MB_RETRYCANCEL|MB_RIGHT|MB_RTLREADING|MB_SETFOREGROUND|MB_TOPMOST|MB_USERICON|MB_YESNO|NORMAL|OFFLINE|READONLY|SHCTX|SHELL_CONTEXT|SYSTEM|TEMPORARY)"},o={cN:"keyword",b:/\!(addincludedir|addplugindir|appendfile|cd|define|delfile|echo|else|endif|error|execute|finalize|getdllversionsystem|ifdef|ifmacrodef|ifmacrondef|ifndef|if|include|insertmacro|macroend|macro|makensis|packhdr|searchparse|searchreplace|tempfile|undef|verbose|warning)/},s={cN:"subst",b:/\$(\\[nrt]|\$)/},l={cN:"class",b:/\w+\:\:\w+/},c={cN:"string",v:[{b:'"',e:'"'},{b:"'",e:"'"},{b:"`",e:"`"}],i:/\n/,c:[s,t,r,a,i]};return{cI:!1,k:{keyword:"Abort AddBrandingImage AddSize AllowRootDirInstall AllowSkipFiles AutoCloseWindow BGFont BGGradient BrandingText BringToFront Call CallInstDLL Caption ChangeUI CheckBitmap ClearErrors CompletedText ComponentText CopyFiles CRCCheck CreateDirectory CreateFont CreateShortCut Delete DeleteINISec DeleteINIStr DeleteRegKey DeleteRegValue DetailPrint DetailsButtonText DirText DirVar DirVerify EnableWindow EnumRegKey EnumRegValue Exch Exec ExecShell ExecWait ExpandEnvStrings File FileBufSize FileClose FileErrorText FileOpen FileRead FileReadByte FileReadUTF16LE FileReadWord FileSeek FileWrite FileWriteByte FileWriteUTF16LE FileWriteWord FindClose FindFirst FindNext FindWindow FlushINI FunctionEnd GetCurInstType GetCurrentAddress GetDlgItem GetDLLVersion GetDLLVersionLocal GetErrorLevel GetFileTime GetFileTimeLocal GetFullPathName GetFunctionAddress GetInstDirError GetLabelAddress GetTempFileName Goto HideWindow Icon IfAbort IfErrors IfFileExists IfRebootFlag IfSilent InitPluginsDir InstallButtonText InstallColors InstallDir InstallDirRegKey InstProgressFlags InstType InstTypeGetText InstTypeSetText IntCmp IntCmpU IntFmt IntOp IsWindow LangString LicenseBkColor LicenseData LicenseForceSelection LicenseLangString LicenseText LoadLanguageFile LockWindow LogSet LogText ManifestDPIAware ManifestSupportedOS MessageBox MiscButtonText Name Nop OutFile Page PageCallbacks PageExEnd Pop Push Quit ReadEnvStr ReadINIStr ReadRegDWORD ReadRegStr Reboot RegDLL Rename RequestExecutionLevel ReserveFile Return RMDir SearchPath SectionEnd SectionGetFlags SectionGetInstTypes SectionGetSize SectionGetText SectionGroupEnd SectionIn SectionSetFlags SectionSetInstTypes SectionSetSize SectionSetText SendMessage SetAutoClose SetBrandingImage SetCompress SetCompressor SetCompressorDictSize SetCtlColors SetCurInstType SetDatablockOptimize SetDateSave SetDetailsPrint SetDetailsView SetErrorLevel SetErrors SetFileAttributes SetFont SetOutPath SetOverwrite SetRebootFlag SetRegView SetShellVarContext SetSilent ShowInstDetails ShowUninstDetails ShowWindow SilentInstall SilentUnInstall Sleep SpaceTexts StrCmp StrCmpS StrCpy StrLen SubCaption Unicode UninstallButtonText UninstallCaption UninstallIcon UninstallSubCaption UninstallText UninstPage UnRegDLL Var VIAddVersionKey VIFileVersion VIProductVersion WindowIcon WriteINIStr WriteRegBin WriteRegDWORD WriteRegExpandStr WriteRegStr WriteUninstaller XPStyle",literal:"admin all auto both bottom bzip2 colored components current custom directory false force hide highest ifdiff ifnewer instfiles lastused leave left license listonly lzma nevershow none normal notset off on open print right show silent silentlog smooth textonly top true try un.components un.custom un.directory un.instfiles un.license uninstConfirm user Win10 Win7 Win8 WinVista zlib"},c:[e.HCM,e.CBCM,e.C(";","$",{r:0}),{cN:"function",bK:"Function PageEx Section SectionGroup",e:"$"},c,o,r,a,i,n,l,e.NM]}}),e.registerLanguage("objectivec",function(e){var t={cN:"built_in",b:"\\b(AV|CA|CF|CG|CI|CL|CM|CN|CT|MK|MP|MTK|MTL|NS|SCN|SK|UI|WK|XC)\\w+"},r={keyword:"int float while char export sizeof typedef const struct for union unsigned long volatile static bool mutable if do return goto void enum else break extern asm case short default double register explicit signed typename this switch continue wchar_t inline readonly assign readwrite self @synchronized id typeof nonatomic super unichar IBOutlet IBAction strong weak copy in out inout bycopy byref oneway __strong __weak __block __autoreleasing @private @protected @public @try @property @end @throw @catch @finally @autoreleasepool @synthesize @dynamic @selector @optional @required @encode @package @import @defs @compatibility_alias __bridge __bridge_transfer __bridge_retained __bridge_retain __covariant __contravariant __kindof _Nonnull _Nullable _Null_unspecified __FUNCTION__ __PRETTY_FUNCTION__ __attribute__ getter setter retain unsafe_unretained nonnull nullable null_unspecified null_resettable class instancetype NS_DESIGNATED_INITIALIZER NS_UNAVAILABLE NS_REQUIRES_SUPER NS_RETURNS_INNER_POINTER NS_INLINE NS_AVAILABLE NS_DEPRECATED NS_ENUM NS_OPTIONS NS_SWIFT_UNAVAILABLE NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_END NS_REFINED_FOR_SWIFT NS_SWIFT_NAME NS_SWIFT_NOTHROW NS_DURING NS_HANDLER NS_ENDHANDLER NS_VALUERETURN NS_VOIDRETURN",literal:"false true FALSE TRUE nil YES NO NULL",built_in:"BOOL dispatch_once_t dispatch_queue_t dispatch_sync dispatch_async dispatch_once"},a=/[a-zA-Z@][a-zA-Z0-9_]*/,i="@interface @class @protocol @implementation";return{aliases:["mm","objc","obj-c"],k:r,l:a,i:""}]}]},{cN:"class",b:"("+i.split(" ").join("|")+")\\b",e:"({|$)",eE:!0,k:i,l:a,c:[e.UTM]},{b:"\\."+e.UIR,r:0}]}}),e.registerLanguage("ocaml",function(e){return{aliases:["ml"],k:{keyword:"and as assert asr begin class constraint do done downto else end exception external for fun function functor if in include inherit! inherit initializer land lazy let lor lsl lsr lxor match method!|10 method mod module mutable new object of open! open or private rec sig struct then to try type val! val virtual when while with parser value",built_in:"array bool bytes char exn|5 float int int32 int64 list lazy_t|5 nativeint|5 string unit in_channel out_channel ref",literal:"true false"},i:/\/\/|>>/,l:"[a-z_]\\w*!?",c:[{cN:"literal",b:"\\[(\\|\\|)?\\]|\\(\\)",r:0},e.C("\\(\\*","\\*\\)",{c:["self"]}),{cN:"symbol",b:"'[A-Za-z_](?!')[\\w']*"},{cN:"type",b:"`[A-Z][\\w']*"},{cN:"type",b:"\\b[A-Z][\\w']*",r:0},{b:"[a-z_]\\w*'[\\w']*",r:0},e.inherit(e.ASM,{cN:"string",r:0}),e.inherit(e.QSM,{i:null}),{cN:"number",b:"\\b(0[xX][a-fA-F0-9_]+[Lln]?|0[oO][0-7_]+[Lln]?|0[bB][01_]+[Lln]?|[0-9][0-9_]*([Lln]|(\\.[0-9_]*)?([eE][-+]?[0-9_]+)?)?)",r:0},{b:/[-=]>/}]}}),e.registerLanguage("openscad",function(e){var t={cN:"keyword",b:"\\$(f[asn]|t|vp[rtd]|children)"},r={cN:"literal",b:"false|true|PI|undef"},a={cN:"number",b:"\\b\\d+(\\.\\d+)?(e-?\\d+)?",r:0},i=e.inherit(e.QSM,{i:null}),n={cN:"meta",k:{"meta-keyword":"include use"},b:"include|use <",e:">"},o={cN:"params",b:"\\(",e:"\\)",c:["self",a,i,t,r]},s={b:"[*!#%]",r:0},l={cN:"function",bK:"module function",e:"\\=|\\{",c:[o,e.UTM]};return{aliases:["scad"],k:{keyword:"function module include use for intersection_for if else \\%",literal:"false true PI undef",built_in:"circle square polygon text sphere cube cylinder polyhedron translate rotate scale resize mirror multmatrix color offset hull minkowski union difference intersection abs sign sin cos tan acos asin atan atan2 floor round ceil ln log pow sqrt exp rands min max concat lookup str chr search version version_num norm cross parent_module echo import import_dxf dxf_linear_extrude linear_extrude rotate_extrude surface projection render children dxf_cross dxf_dim let assign"},c:[e.CLCM,e.CBCM,a,n,i,t,s,l]}}),e.registerLanguage("oxygene",function(e){var t="abstract add and array as asc aspect assembly async begin break block by case class concat const copy constructor continue create default delegate desc distinct div do downto dynamic each else empty end ensure enum equals event except exit extension external false final finalize finalizer finally flags for forward from function future global group has if implementation implements implies in index inherited inline interface into invariants is iterator join locked locking loop matching method mod module namespace nested new nil not notify nullable of old on operator or order out override parallel params partial pinned private procedure property protected public queryable raise read readonly record reintroduce remove repeat require result reverse sealed select self sequence set shl shr skip static step soft take then to true try tuple type union unit unsafe until uses using var virtual raises volatile where while with write xor yield await mapped deprecated stdcall cdecl pascal register safecall overload library platform reference packed strict published autoreleasepool selector strong weak unretained",r=e.C("{","}",{r:0}),a=e.C("\\(\\*","\\*\\)",{r:10}),i={cN:"string",b:"'",e:"'",c:[{b:"''"}]},n={cN:"string",b:"(#\\d+)+"},o={cN:"function",bK:"function constructor destructor procedure method",e:"[:;]",k:"function constructor|10 destructor|10 procedure|10 method|10",c:[e.TM,{cN:"params",b:"\\(",e:"\\)",k:t,c:[i,n]},r,a]};return{cI:!0,l:/\.?\w+/,k:t,i:'("|\\$[G-Zg-z]|\\/\\*||->)',c:[r,a,e.CLCM,i,n,e.NM,o,{cN:"class",b:"=\\bclass\\b",e:"end;",k:t,c:[i,n,r,a,e.CLCM,o]}]}}),e.registerLanguage("parser3",function(e){var t=e.C("{","}",{c:["self"]});return{sL:"xml",r:0,c:[e.C("^#","$"),e.C("\\^rem{","}",{r:10,c:[t]}),{cN:"meta",b:"^@(?:BASE|USE|CLASS|OPTIONS)$",r:10},{cN:"title",b:"@[\\w\\-]+\\[[\\w^;\\-]*\\](?:\\[[\\w^;\\-]*\\])?(?:.*)$"},{cN:"variable",b:"\\$\\{?[\\w\\-\\.\\:]+\\}?"},{cN:"keyword",b:"\\^[\\w\\-\\.\\:]+"},{cN:"number",b:"\\^#[0-9a-fA-F]+"},e.CNM]}}),e.registerLanguage("pf",function(e){var t={cN:"variable",b:/\$[\w\d#@][\w\d_]*/},r={cN:"variable",b:/<(?!\/)/,e:/>/};return{aliases:["pf.conf"],l:/[a-z0-9_<>-]+/,k:{built_in:"block match pass load anchor|5 antispoof|10 set table",keyword:"in out log quick on rdomain inet inet6 proto from port os to routeallow-opts divert-packet divert-reply divert-to flags group icmp-typeicmp6-type label once probability recieved-on rtable prio queuetos tag tagged user keep fragment for os dropaf-to|10 binat-to|10 nat-to|10 rdr-to|10 bitmask least-stats random round-robinsource-hash static-portdup-to reply-to route-toparent bandwidth default min max qlimitblock-policy debug fingerprints hostid limit loginterface optimizationreassemble ruleset-optimization basic none profile skip state-defaultsstate-policy timeoutconst counters persistno modulate synproxy state|5 floating if-bound no-sync pflow|10 sloppysource-track global rule max-src-nodes max-src-states max-src-connmax-src-conn-rate overload flushscrub|5 max-mss min-ttl no-df|10 random-id",literal:"all any no-route self urpf-failed egress|5 unknown"},c:[e.HCM,e.NM,e.QSM,t,r]}}),e.registerLanguage("php",function(e){var t={b:"\\$+[a-zA-Z_-ÿ][a-zA-Z0-9_-ÿ]*"},r={cN:"meta",b:/<\?(php)?|\?>/},a={cN:"string",c:[e.BE,r],v:[{b:'b"',e:'"'},{b:"b'",e:"'"},e.inherit(e.ASM,{i:null}),e.inherit(e.QSM,{i:null})]},i={v:[e.BNM,e.CNM]};return{aliases:["php3","php4","php5","php6"],cI:!0,k:"and include_once list abstract global private echo interface as static endswitch array null if endwhile or const for endforeach self var while isset public protected exit foreach throw elseif include __FILE__ empty require_once do xor return parent clone use __CLASS__ __LINE__ else break print eval new catch __METHOD__ case exception default die require __FUNCTION__ enddeclare final try switch continue endfor endif declare unset true false trait goto instanceof insteadof __DIR__ __NAMESPACE__ yield finally",c:[e.HCM,e.C("//","$",{c:[r]}),e.C("/\\*","\\*/",{c:[{cN:"doctag",b:"@[A-Za-z]+"}]}),e.C("__halt_compiler.+?;",!1,{eW:!0,k:"__halt_compiler",l:e.UIR}),{cN:"string",b:/<<<['"]?\w+['"]?$/,e:/^\w+;?$/,c:[e.BE,{cN:"subst",v:[{b:/\$\w+/},{b:/\{\$/,e:/\}/}]}]},r,{cN:"keyword",b:/\$this\b/},t,{b:/(::|->)+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/},{cN:"function",bK:"function",e:/[;{]/,eE:!0,i:"\\$|\\[|%",c:[e.UTM,{cN:"params",b:"\\(",e:"\\)",c:["self",t,e.CBCM,a,i]}]},{cN:"class",bK:"class interface",e:"{",eE:!0,i:/[:\(\$"]/,c:[{bK:"extends implements"},e.UTM]},{bK:"namespace",e:";",i:/[\.']/,c:[e.UTM]},{bK:"use",e:";",c:[e.UTM]},{b:"=>"},a,i]}}),e.registerLanguage("pony",function(e){var t={keyword:"actor addressof and as be break class compile_error compile_intrinsicconsume continue delegate digestof do else elseif embed end errorfor fun if ifdef in interface is isnt lambda let match new not objector primitive recover repeat return struct then trait try type until use var where while with xor",meta:"iso val tag trn box ref",literal:"this false true"},r={cN:"string",b:'"""',e:'"""',r:10},a={cN:"string",b:'"',e:'"',c:[e.BE]},i={cN:"string",b:"'",e:"'",c:[e.BE],r:0},n={cN:"type",b:"\\b_?[A-Z][\\w]*",r:0},o={b:e.IR+"'",r:0},s={cN:"class",bK:"class actor",e:"$",c:[e.TM,e.CLCM]},l={cN:"function",bK:"new fun",e:"=>",c:[e.TM,{b:/\(/,e:/\)/,c:[n,o,e.CNM,e.CBCM]},{b:/:/,eW:!0,c:[n]},e.CLCM]};return{k:t,c:[s,l,n,r,a,i,o,e.CNM,e.CLCM,e.CBCM]}}),e.registerLanguage("powershell",function(e){var t={b:"`[\\s\\S]",r:0},r={cN:"variable",v:[{b:/\$[\w\d][\w\d_:]*/}]},a={cN:"literal",b:/\$(null|true|false)\b/},i={cN:"string",v:[{b:/"/,e:/"/},{b:/@"/,e:/^"@/}],c:[t,r,{cN:"variable",b:/\$[A-z]/,e:/[^A-z]/}]},n={cN:"string",v:[{b:/'/,e:/'/},{b:/@'/,e:/^'@/}]},o={cN:"doctag",v:[{b:/\.(synopsis|description|example|inputs|outputs|notes|link|component|role|functionality)/},{b:/\.(parameter|forwardhelptargetname|forwardhelpcategory|remotehelprunspace|externalhelp)\s+\S+/}]},s=e.inherit(e.C(null,null),{v:[{b:/#/,e:/$/},{b:/<#/,e:/#>/}],c:[o]});return{aliases:["ps"],l:/-?[A-z\.\-]+/,cI:!0,k:{keyword:"if else foreach return function do while until elseif begin for trap data dynamicparam end break throw param continue finally in switch exit filter try process catch",built_in:"Add-Computer Add-Content Add-History Add-JobTrigger Add-Member Add-PSSnapin Add-Type Checkpoint-Computer Clear-Content Clear-EventLog Clear-History Clear-Host Clear-Item Clear-ItemProperty Clear-Variable Compare-Object Complete-Transaction Connect-PSSession Connect-WSMan Convert-Path ConvertFrom-Csv ConvertFrom-Json ConvertFrom-SecureString ConvertFrom-StringData ConvertTo-Csv ConvertTo-Html ConvertTo-Json ConvertTo-SecureString ConvertTo-Xml Copy-Item Copy-ItemProperty Debug-Process Disable-ComputerRestore Disable-JobTrigger Disable-PSBreakpoint Disable-PSRemoting Disable-PSSessionConfiguration Disable-WSManCredSSP Disconnect-PSSession Disconnect-WSMan Disable-ScheduledJob Enable-ComputerRestore Enable-JobTrigger Enable-PSBreakpoint Enable-PSRemoting Enable-PSSessionConfiguration Enable-ScheduledJob Enable-WSManCredSSP Enter-PSSession Exit-PSSession Export-Alias Export-Clixml Export-Console Export-Counter Export-Csv Export-FormatData Export-ModuleMember Export-PSSession ForEach-Object Format-Custom Format-List Format-Table Format-Wide Get-Acl Get-Alias Get-AuthenticodeSignature Get-ChildItem Get-Command Get-ComputerRestorePoint Get-Content Get-ControlPanelItem Get-Counter Get-Credential Get-Culture Get-Date Get-Event Get-EventLog Get-EventSubscriber Get-ExecutionPolicy Get-FormatData Get-Host Get-HotFix Get-Help Get-History Get-IseSnippet Get-Item Get-ItemProperty Get-Job Get-JobTrigger Get-Location Get-Member Get-Module Get-PfxCertificate Get-Process Get-PSBreakpoint Get-PSCallStack Get-PSDrive Get-PSProvider Get-PSSession Get-PSSessionConfiguration Get-PSSnapin Get-Random Get-ScheduledJob Get-ScheduledJobOption Get-Service Get-TraceSource Get-Transaction Get-TypeData Get-UICulture Get-Unique Get-Variable Get-Verb Get-WinEvent Get-WmiObject Get-WSManCredSSP Get-WSManInstance Group-Object Import-Alias Import-Clixml Import-Counter Import-Csv Import-IseSnippet Import-LocalizedData Import-PSSession Import-Module Invoke-AsWorkflow Invoke-Command Invoke-Expression Invoke-History Invoke-Item Invoke-RestMethod Invoke-WebRequest Invoke-WmiMethod Invoke-WSManAction Join-Path Limit-EventLog Measure-Command Measure-Object Move-Item Move-ItemProperty New-Alias New-Event New-EventLog New-IseSnippet New-Item New-ItemProperty New-JobTrigger New-Object New-Module New-ModuleManifest New-PSDrive New-PSSession New-PSSessionConfigurationFile New-PSSessionOption New-PSTransportOption New-PSWorkflowExecutionOption New-PSWorkflowSession New-ScheduledJobOption New-Service New-TimeSpan New-Variable New-WebServiceProxy New-WinEvent New-WSManInstance New-WSManSessionOption Out-Default Out-File Out-GridView Out-Host Out-Null Out-Printer Out-String Pop-Location Push-Location Read-Host Receive-Job Register-EngineEvent Register-ObjectEvent Register-PSSessionConfiguration Register-ScheduledJob Register-WmiEvent Remove-Computer Remove-Event Remove-EventLog Remove-Item Remove-ItemProperty Remove-Job Remove-JobTrigger Remove-Module Remove-PSBreakpoint Remove-PSDrive Remove-PSSession Remove-PSSnapin Remove-TypeData Remove-Variable Remove-WmiObject Remove-WSManInstance Rename-Computer Rename-Item Rename-ItemProperty Reset-ComputerMachinePassword Resolve-Path Restart-Computer Restart-Service Restore-Computer Resume-Job Resume-Service Save-Help Select-Object Select-String Select-Xml Send-MailMessage Set-Acl Set-Alias Set-AuthenticodeSignature Set-Content Set-Date Set-ExecutionPolicy Set-Item Set-ItemProperty Set-JobTrigger Set-Location Set-PSBreakpoint Set-PSDebug Set-PSSessionConfiguration Set-ScheduledJob Set-ScheduledJobOption Set-Service Set-StrictMode Set-TraceSource Set-Variable Set-WmiInstance Set-WSManInstance Set-WSManQuickConfig Show-Command Show-ControlPanelItem Show-EventLog Sort-Object Split-Path Start-Job Start-Process Start-Service Start-Sleep Start-Transaction Start-Transcript Stop-Computer Stop-Job Stop-Process Stop-Service Stop-Transcript Suspend-Job Suspend-Service Tee-Object Test-ComputerSecureChannel Test-Connection Test-ModuleManifest Test-Path Test-PSSessionConfigurationFile Trace-Command Unblock-File Undo-Transaction Unregister-Event Unregister-PSSessionConfiguration Unregister-ScheduledJob Update-FormatData Update-Help Update-List Update-TypeData Use-Transaction Wait-Event Wait-Job Wait-Process Where-Object Write-Debug Write-Error Write-EventLog Write-Host Write-Output Write-Progress Write-Verbose Write-Warning Add-MDTPersistentDrive Disable-MDTMonitorService Enable-MDTMonitorService Get-MDTDeploymentShareStatistics Get-MDTMonitorData Get-MDTOperatingSystemCatalog Get-MDTPersistentDrive Import-MDTApplication Import-MDTDriver Import-MDTOperatingSystem Import-MDTPackage Import-MDTTaskSequence New-MDTDatabase Remove-MDTMonitorData Remove-MDTPersistentDrive Restore-MDTPersistentDrive Set-MDTMonitorData Test-MDTDeploymentShare Test-MDTMonitorData Update-MDTDatabaseSchema Update-MDTDeploymentShare Update-MDTLinkedDS Update-MDTMedia Update-MDTMedia Add-VamtProductKey Export-VamtData Find-VamtManagedMachine Get-VamtConfirmationId Get-VamtProduct Get-VamtProductKey Import-VamtData Initialize-VamtData Install-VamtConfirmationId Install-VamtProductActivation Install-VamtProductKey Update-VamtProduct", -nomarkup:"-ne -eq -lt -gt -ge -le -not -like -notlike -match -notmatch -contains -notcontains -in -notin -replace"},c:[t,e.NM,i,n,a,r,s]}}),e.registerLanguage("processing",function(e){return{k:{keyword:"BufferedReader PVector PFont PImage PGraphics HashMap boolean byte char color double float int long String Array FloatDict FloatList IntDict IntList JSONArray JSONObject Object StringDict StringList Table TableRow XML false synchronized int abstract float private char boolean static null if const for true while long throw strictfp finally protected import native final return void enum else break transient new catch instanceof byte super volatile case assert short package default double public try this switch continue throws protected public private",literal:"P2D P3D HALF_PI PI QUARTER_PI TAU TWO_PI",title:"setup draw",built_in:"displayHeight displayWidth mouseY mouseX mousePressed pmouseX pmouseY key keyCode pixels focused frameCount frameRate height width size createGraphics beginDraw createShape loadShape PShape arc ellipse line point quad rect triangle bezier bezierDetail bezierPoint bezierTangent curve curveDetail curvePoint curveTangent curveTightness shape shapeMode beginContour beginShape bezierVertex curveVertex endContour endShape quadraticVertex vertex ellipseMode noSmooth rectMode smooth strokeCap strokeJoin strokeWeight mouseClicked mouseDragged mouseMoved mousePressed mouseReleased mouseWheel keyPressed keyPressedkeyReleased keyTyped print println save saveFrame day hour millis minute month second year background clear colorMode fill noFill noStroke stroke alpha blue brightness color green hue lerpColor red saturation modelX modelY modelZ screenX screenY screenZ ambient emissive shininess specular add createImage beginCamera camera endCamera frustum ortho perspective printCamera printProjection cursor frameRate noCursor exit loop noLoop popStyle pushStyle redraw binary boolean byte char float hex int str unbinary unhex join match matchAll nf nfc nfp nfs split splitTokens trim append arrayCopy concat expand reverse shorten sort splice subset box sphere sphereDetail createInput createReader loadBytes loadJSONArray loadJSONObject loadStrings loadTable loadXML open parseXML saveTable selectFolder selectInput beginRaw beginRecord createOutput createWriter endRaw endRecord PrintWritersaveBytes saveJSONArray saveJSONObject saveStream saveStrings saveXML selectOutput popMatrix printMatrix pushMatrix resetMatrix rotate rotateX rotateY rotateZ scale shearX shearY translate ambientLight directionalLight lightFalloff lights lightSpecular noLights normal pointLight spotLight image imageMode loadImage noTint requestImage tint texture textureMode textureWrap blend copy filter get loadPixels set updatePixels blendMode loadShader PShaderresetShader shader createFont loadFont text textFont textAlign textLeading textMode textSize textWidth textAscent textDescent abs ceil constrain dist exp floor lerp log mag map max min norm pow round sq sqrt acos asin atan atan2 cos degrees radians sin tan noise noiseDetail noiseSeed random randomGaussian randomSeed"},c:[e.CLCM,e.CBCM,e.ASM,e.QSM,e.CNM]}}),e.registerLanguage("profile",function(e){return{c:[e.CNM,{b:"[a-zA-Z_][\\da-zA-Z_]+\\.[\\da-zA-Z_]{1,3}",e:":",eE:!0},{b:"(ncalls|tottime|cumtime)",e:"$",k:"ncalls tottime|10 cumtime|10 filename",r:10},{b:"function calls",e:"$",c:[e.CNM],r:10},e.ASM,e.QSM,{cN:"string",b:"\\(",e:"\\)$",eB:!0,eE:!0,r:0}]}}),e.registerLanguage("prolog",function(e){var t={b:/[a-z][A-Za-z0-9_]*/,r:0},r={cN:"symbol",v:[{b:/[A-Z][a-zA-Z0-9_]*/},{b:/_[A-Za-z0-9_]*/}],r:0},a={b:/\(/,e:/\)/,r:0},i={b:/\[/,e:/\]/},n={cN:"comment",b:/%/,e:/$/,c:[e.PWM]},o={cN:"string",b:/`/,e:/`/,c:[e.BE]},s={cN:"string",b:/0\'(\\\'|.)/},l={cN:"string",b:/0\'\\s/},c={b:/:-/},d=[t,r,a,c,i,n,e.CBCM,e.QSM,e.ASM,o,s,l,e.CNM];return a.c=d,i.c=d,{c:d.concat([{b:/\.$/}])}}),e.registerLanguage("protobuf",function(e){return{k:{keyword:"package import option optional required repeated group",built_in:"double float int32 int64 uint32 uint64 sint32 sint64 fixed32 fixed64 sfixed32 sfixed64 bool string bytes",literal:"true false"},c:[e.QSM,e.NM,e.CLCM,{cN:"class",bK:"message enum service",e:/\{/,i:/\n/,c:[e.inherit(e.TM,{starts:{eW:!0,eE:!0}})]},{cN:"function",bK:"rpc",e:/;/,eE:!0,k:"rpc returns"},{b:/^\s*[A-Z_]+/,e:/\s*=/,eE:!0}]}}),e.registerLanguage("puppet",function(e){var t={keyword:"and case default else elsif false if in import enherits node or true undef unless main settings $string ",literal:"alias audit before loglevel noop require subscribe tag owner ensure group mode name|0 changes context force incl lens load_path onlyif provider returns root show_diff type_check en_address ip_address realname command environment hour monute month monthday special target weekday creates cwd ogoutput refresh refreshonly tries try_sleep umask backup checksum content ctime force ignore links mtime purge recurse recurselimit replace selinux_ignore_defaults selrange selrole seltype seluser source souirce_permissions sourceselect validate_cmd validate_replacement allowdupe attribute_membership auth_membership forcelocal gid ia_load_module members system host_aliases ip allowed_trunk_vlans description device_url duplex encapsulation etherchannel native_vlan speed principals allow_root auth_class auth_type authenticate_user k_of_n mechanisms rule session_owner shared options device fstype enable hasrestart directory present absent link atboot blockdevice device dump pass remounts poller_tag use message withpath adminfile allow_virtual allowcdrom category configfiles flavor install_options instance package_settings platform responsefile status uninstall_options vendor unless_system_user unless_uid binary control flags hasstatus manifest pattern restart running start stop allowdupe auths expiry gid groups home iterations key_membership keys managehome membership password password_max_age password_min_age profile_membership profiles project purge_ssh_keys role_membership roles salt shell uid baseurl cost descr enabled enablegroups exclude failovermethod gpgcheck gpgkey http_caching include includepkgs keepalive metadata_expire metalink mirrorlist priority protect proxy proxy_password proxy_username repo_gpgcheck s3_enabled skip_if_unavailable sslcacert sslclientcert sslclientkey sslverify mounted",built_in:"architecture augeasversion blockdevices boardmanufacturer boardproductname boardserialnumber cfkey dhcp_servers domain ec2_ ec2_userdata facterversion filesystems ldom fqdn gid hardwareisa hardwaremodel hostname id|0 interfaces ipaddress ipaddress_ ipaddress6 ipaddress6_ iphostnumber is_virtual kernel kernelmajversion kernelrelease kernelversion kernelrelease kernelversion lsbdistcodename lsbdistdescription lsbdistid lsbdistrelease lsbmajdistrelease lsbminordistrelease lsbrelease macaddress macaddress_ macosx_buildversion macosx_productname macosx_productversion macosx_productverson_major macosx_productversion_minor manufacturer memoryfree memorysize netmask metmask_ network_ operatingsystem operatingsystemmajrelease operatingsystemrelease osfamily partitions path physicalprocessorcount processor processorcount productname ps puppetversion rubysitedir rubyversion selinux selinux_config_mode selinux_config_policy selinux_current_mode selinux_current_mode selinux_enforced selinux_policyversion serialnumber sp_ sshdsakey sshecdsakey sshrsakey swapencrypted swapfree swapsize timezone type uniqueid uptime uptime_days uptime_hours uptime_seconds uuid virtual vlans xendomains zfs_version zonenae zones zpool_version"},r=e.C("#","$"),a="([A-Za-z_]|::)(\\w|::)*",i=e.inherit(e.TM,{b:a}),n={cN:"variable",b:"\\$"+a},o={cN:"string",c:[e.BE,n],v:[{b:/'/,e:/'/},{b:/"/,e:/"/}]};return{aliases:["pp"],c:[r,n,o,{bK:"class",e:"\\{|;",i:/=/,c:[i,r]},{bK:"define",e:/\{/,c:[{cN:"section",b:e.IR,endsParent:!0}]},{b:e.IR+"\\s+\\{",rB:!0,e:/\S/,c:[{cN:"keyword",b:e.IR},{b:/\{/,e:/\}/,k:t,r:0,c:[o,r,{b:"[a-zA-Z_]+\\s*=>",rB:!0,e:"=>",c:[{cN:"attr",b:e.IR}]},{cN:"number",b:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",r:0},n]}],r:0}]}}),e.registerLanguage("purebasic",function(e){var t={cN:"string",b:'(~)?"',e:'"',i:"\\n"},r={cN:"symbol",b:"#[a-zA-Z_]\\w*\\$?"};return{aliases:["pb","pbi"],k:"And As Break CallDebugger Case CompilerCase CompilerDefault CompilerElse CompilerEndIf CompilerEndSelect CompilerError CompilerIf CompilerSelect Continue Data DataSection EndDataSection Debug DebugLevel Default Define Dim DisableASM DisableDebugger DisableExplicit Else ElseIf EnableASM EnableDebugger EnableExplicit End EndEnumeration EndIf EndImport EndInterface EndMacro EndProcedure EndSelect EndStructure EndStructureUnion EndWith Enumeration Extends FakeReturn For Next ForEach ForEver Global Gosub Goto If Import ImportC IncludeBinary IncludeFile IncludePath Interface Macro NewList Not Or ProcedureReturn Protected Prototype PrototypeC Read ReDim Repeat Until Restore Return Select Shared Static Step Structure StructureUnion Swap To Wend While With XIncludeFile XOr Procedure ProcedureC ProcedureCDLL ProcedureDLL Declare DeclareC DeclareCDLL DeclareDLL",c:[e.C(";","$",{r:0}),{cN:"function",b:"\\b(Procedure|Declare)(C|CDLL|DLL)?\\b",e:"\\(",eE:!0,rB:!0,c:[{cN:"keyword",b:"(Procedure|Declare)(C|CDLL|DLL)?",eE:!0},{cN:"type",b:"\\.\\w*"},e.UTM]},t,r]}}),e.registerLanguage("python",function(e){var t={keyword:"and elif is global as in if from raise for except finally print import pass return exec else break not with class assert yield try while continue del or def lambda async await nonlocal|10 None True False",built_in:"Ellipsis NotImplemented"},r={cN:"meta",b:/^(>>>|\.\.\.) /},a={cN:"subst",b:/\{/,e:/\}/,k:t,i:/#/},i={cN:"string",c:[e.BE],v:[{b:/(u|b)?r?'''/,e:/'''/,c:[r],r:10},{b:/(u|b)?r?"""/,e:/"""/,c:[r],r:10},{b:/(fr|rf|f)'''/,e:/'''/,c:[r,a]},{b:/(fr|rf|f)"""/,e:/"""/,c:[r,a]},{b:/(u|r|ur)'/,e:/'/,r:10},{b:/(u|r|ur)"/,e:/"/,r:10},{b:/(b|br)'/,e:/'/},{b:/(b|br)"/,e:/"/},{b:/(fr|rf|f)'/,e:/'/,c:[a]},{b:/(fr|rf|f)"/,e:/"/,c:[a]},e.ASM,e.QSM]},n={cN:"number",r:0,v:[{b:e.BNR+"[lLjJ]?"},{b:"\\b(0o[0-7]+)[lLjJ]?"},{b:e.CNR+"[lLjJ]?"}]},o={cN:"params",b:/\(/,e:/\)/,c:["self",r,n,i]};return a.c=[i,n,r],{aliases:["py","gyp"],k:t,i:/(<\/|->|\?)|=>/,c:[r,n,i,e.HCM,{v:[{cN:"function",bK:"def"},{cN:"class",bK:"class"}],e:/:/,i:/[${=;\n,]/,c:[e.UTM,o,{b:/->/,eW:!0,k:"None"}]},{cN:"meta",b:/^[\t ]*@/,e:/$/},{b:/\b(print|exec)\(/}]}}),e.registerLanguage("q",function(e){var t={keyword:"do while select delete by update from",literal:"0b 1b",built_in:"neg not null string reciprocal floor ceiling signum mod xbar xlog and or each scan over prior mmu lsq inv md5 ltime gtime count first var dev med cov cor all any rand sums prds mins maxs fills deltas ratios avgs differ prev next rank reverse iasc idesc asc desc msum mcount mavg mdev xrank mmin mmax xprev rotate distinct group where flip type key til get value attr cut set upsert raze union inter except cross sv vs sublist enlist read0 read1 hopen hclose hdel hsym hcount peach system ltrim rtrim trim lower upper ssr view tables views cols xcols keys xkey xcol xasc xdesc fkeys meta lj aj aj0 ij pj asof uj ww wj wj1 fby xgroup ungroup ej save load rsave rload show csv parse eval min max avg wavg wsum sin cos tan sum",type:"`float `double int `timestamp `timespan `datetime `time `boolean `symbol `char `byte `short `long `real `month `date `minute `second `guid"};return{aliases:["k","kdb"],k:t,l:/(`?)[A-Za-z0-9_]+\b/,c:[e.CLCM,e.QSM,e.CNM]}}),e.registerLanguage("qml",function(e){var t={keyword:"in of on if for while finally var new function do return void else break catch instanceof with throw case default try this switch continue typeof delete let yield const export super debugger as async await import",literal:"true false null undefined NaN Infinity",built_in:"eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Error EvalError InternalError RangeError ReferenceError StopIteration SyntaxError TypeError URIError Number Math Date String RegExp Array Float32Array Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require module console window document Symbol Set Map WeakSet WeakMap Proxy Reflect Behavior bool color coordinate date double enumeration font geocircle georectangle geoshape int list matrix4x4 parent point quaternion real rect size string url variant vector2d vector3d vector4dPromise"},r="[a-zA-Z_][a-zA-Z0-9\\._]*",a={cN:"keyword",b:"\\bproperty\\b",starts:{cN:"string",e:"(:|=|;|,|//|/\\*|$)",rE:!0}},i={cN:"keyword",b:"\\bsignal\\b",starts:{cN:"string",e:"(\\(|:|=|;|,|//|/\\*|$)",rE:!0}},n={cN:"attribute",b:"\\bid\\s*:",starts:{cN:"string",e:r,rE:!1}},o={b:r+"\\s*:",rB:!0,c:[{cN:"attribute",b:r,e:"\\s*:",eE:!0,r:0}],r:0},s={b:r+"\\s*{",e:"{",rB:!0,r:0,c:[e.inherit(e.TM,{b:r})]};return{aliases:["qt"],cI:!1,k:t,c:[{cN:"meta",b:/^\s*['"]use (strict|asm)['"]/},e.ASM,e.QSM,{cN:"string",b:"`",e:"`",c:[e.BE,{cN:"subst",b:"\\$\\{",e:"\\}"}]},e.CLCM,e.CBCM,{cN:"number",v:[{b:"\\b(0[bB][01]+)"},{b:"\\b(0[oO][0-7]+)"},{b:e.CNR}],r:0},{b:"("+e.RSR+"|\\b(case|return|throw)\\b)\\s*",k:"return throw case",c:[e.CLCM,e.CBCM,e.RM,{b:/\s*[);\]]/,r:0,sL:"xml"}],r:0},i,a,{cN:"function",bK:"function",e:/\{/,eE:!0,c:[e.inherit(e.TM,{b:/[A-Za-z$_][0-9A-Za-z$_]*/}),{cN:"params",b:/\(/,e:/\)/,eB:!0,eE:!0,c:[e.CLCM,e.CBCM]}],i:/\[|%/},{b:"\\."+e.IR,r:0},n,o,s],i:/#/}}),e.registerLanguage("r",function(e){var t="([a-zA-Z]|\\.[a-zA-Z.])[a-zA-Z0-9._]*";return{c:[e.HCM,{b:t,l:t,k:{keyword:"function if in break next repeat else for return switch while try tryCatch stop warning require library attach detach source setMethod setGeneric setGroupGeneric setClass ...",literal:"NULL NA TRUE FALSE T F Inf NaN NA_integer_|10 NA_real_|10 NA_character_|10 NA_complex_|10"},r:0},{cN:"number",b:"0[xX][0-9a-fA-F]+[Li]?\\b",r:0},{cN:"number",b:"\\d+(?:[eE][+\\-]?\\d*)?L\\b",r:0},{cN:"number",b:"\\d+\\.(?!\\d)(?:i\\b)?",r:0},{cN:"number",b:"\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d*)?i?\\b",r:0},{cN:"number",b:"\\.\\d+(?:[eE][+\\-]?\\d*)?i?\\b",r:0},{b:"`",e:"`",r:0},{cN:"string",c:[e.BE],v:[{b:'"',e:'"'},{b:"'",e:"'"}]}]}}),e.registerLanguage("rib",function(e){return{k:"ArchiveRecord AreaLightSource Atmosphere Attribute AttributeBegin AttributeEnd Basis Begin Blobby Bound Clipping ClippingPlane Color ColorSamples ConcatTransform Cone CoordinateSystem CoordSysTransform CropWindow Curves Cylinder DepthOfField Detail DetailRange Disk Displacement Display End ErrorHandler Exposure Exterior Format FrameAspectRatio FrameBegin FrameEnd GeneralPolygon GeometricApproximation Geometry Hider Hyperboloid Identity Illuminate Imager Interior LightSource MakeCubeFaceEnvironment MakeLatLongEnvironment MakeShadow MakeTexture Matte MotionBegin MotionEnd NuPatch ObjectBegin ObjectEnd ObjectInstance Opacity Option Orientation Paraboloid Patch PatchMesh Perspective PixelFilter PixelSamples PixelVariance Points PointsGeneralPolygons PointsPolygons Polygon Procedural Projection Quantize ReadArchive RelativeDetail ReverseOrientation Rotate Scale ScreenWindow ShadingInterpolation ShadingRate Shutter Sides Skew SolidBegin SolidEnd Sphere SubdivisionMesh Surface TextureCoordinates Torus Transform TransformBegin TransformEnd TransformPoints Translate TrimCurve WorldBegin WorldEnd",i:"\]$/},{b:/<\//,e:/>/},{b:/^facet /,e:/\}/},{b:"^1\\.\\.(\\d+)$",e:/$/}],i:/./},e.C("^#","$"),s,l,o,{b:/[\w-]+\=([^\s\{\}\[\]\(\)]+)/,r:0,rB:!0,c:[{cN:"attribute",b:/[^=]+/},{b:/=/,eW:!0,r:0,c:[s,l,o,{cN:"literal",b:"\\b("+i.split(" ").join("|")+")\\b"},{b:/("[^"]*"|[^\s\{\}\[\]]+)/}]}]},{cN:"number",b:/\*[0-9a-fA-F]+/},{b:"\\b("+a.split(" ").join("|")+")([\\s[(]|])",rB:!0,c:[{cN:"builtin-name",b:/\w+/}]},{cN:"built_in",v:[{b:"(\\.\\./|/|\\s)(("+n.split(" ").join("|")+");?\\s)+",r:10},{b:/\.\./}]}]}}),e.registerLanguage("rsl",function(e){return{k:{keyword:"float color point normal vector matrix while for if do return else break extern continue",built_in:"abs acos ambient area asin atan atmosphere attribute calculatenormal ceil cellnoise clamp comp concat cos degrees depth Deriv diffuse distance Du Dv environment exp faceforward filterstep floor format fresnel incident length lightsource log match max min mod noise normalize ntransform opposite option phong pnoise pow printf ptlined radians random reflect refract renderinfo round setcomp setxcomp setycomp setzcomp shadow sign sin smoothstep specular specularbrdf spline sqrt step tan texture textureinfo trace transform vtransform xcomp ycomp zcomp"},i:""}]}}),e.registerLanguage("scala",function(e){var t={cN:"meta",b:"@[A-Za-z]+"},r={cN:"subst",v:[{b:"\\$[A-Za-z0-9_]+"},{b:"\\${",e:"}"}]},a={cN:"string",v:[{b:'"',e:'"',i:"\\n",c:[e.BE]},{b:'"""',e:'"""',r:10},{b:'[a-z]+"',e:'"',i:"\\n",c:[e.BE,r]},{cN:"string",b:'[a-z]+"""',e:'"""',c:[r],r:10}]},i={cN:"symbol",b:"'\\w[\\w\\d_]*(?!')"},n={cN:"type",b:"\\b[A-Z][A-Za-z0-9_]*",r:0},o={cN:"title",b:/[^0-9\n\t "'(),.`{}\[\]:;][^\n\t "'(),.`{}\[\]:;]+|[^0-9\n\t "'(),.`{}\[\]:;=]/,r:0},s={cN:"class",bK:"class object trait type",e:/[:={\[\n;]/,eE:!0,c:[{bK:"extends with",r:10},{b:/\[/,e:/\]/,eB:!0,eE:!0,r:0,c:[n]},{cN:"params",b:/\(/,e:/\)/,eB:!0,eE:!0,r:0,c:[n]},o]},l={cN:"function",bK:"def",e:/[:={\[(\n;]/,eE:!0,c:[o]};return{k:{literal:"true false null",keyword:"type yield lazy override def with val var sealed abstract private trait object if forSome for while throw finally protected extends import final return else break new catch super class case package default try this match continue throws implicit"},c:[e.CLCM,e.CBCM,a,i,n,l,s,e.CNM,t]}}),e.registerLanguage("scheme",function(e){var t="[^\\(\\)\\[\\]\\{\\}\",'`;#|\\\\\\s]+",r="(\\-|\\+)?\\d+([./]\\d+)?",a=r+"[+\\-]"+r+"i",i={"builtin-name":"case-lambda call/cc class define-class exit-handler field import inherit init-field interface let*-values let-values let/ec mixin opt-lambda override protect provide public rename require require-for-syntax syntax syntax-case syntax-error unit/sig unless when with-syntax and begin call-with-current-continuation call-with-input-file call-with-output-file case cond define define-syntax delay do dynamic-wind else for-each if lambda let let* let-syntax letrec letrec-syntax map or syntax-rules ' * + , ,@ - ... / ; < <= = => > >= ` abs acos angle append apply asin assoc assq assv atan boolean? caar cadr call-with-input-file call-with-output-file call-with-values car cdddar cddddr cdr ceiling char->integer char-alphabetic? char-ci<=? char-ci=? char-ci>? char-downcase char-lower-case? char-numeric? char-ready? char-upcase char-upper-case? char-whitespace? char<=? char=? char>? char? close-input-port close-output-port complex? cons cos current-input-port current-output-port denominator display eof-object? eq? equal? eqv? eval even? exact->inexact exact? exp expt floor force gcd imag-part inexact->exact inexact? input-port? integer->char integer? interaction-environment lcm length list list->string list->vector list-ref list-tail list? load log magnitude make-polar make-rectangular make-string make-vector max member memq memv min modulo negative? newline not null-environment null? number->string number? numerator odd? open-input-file open-output-file output-port? pair? peek-char port? positive? procedure? quasiquote quote quotient rational? rationalize read read-char real-part real? remainder reverse round scheme-report-environment set! set-car! set-cdr! sin sqrt string string->list string->number string->symbol string-append string-ci<=? string-ci=? string-ci>? string-copy string-fill! string-length string-ref string-set! string<=? string=? string>? string? substring symbol->string symbol? tan transcript-off transcript-on truncate values vector vector->list vector-fill! vector-length vector-ref vector-set! with-input-from-file with-output-to-file write write-char zero?"},n={cN:"meta",b:"^#!",e:"$"},o={cN:"literal",b:"(#t|#f|#\\\\"+t+"|#\\\\.)"},s={cN:"number",v:[{b:r,r:0},{b:a,r:0},{b:"#b[0-1]+(/[0-1]+)?"},{b:"#o[0-7]+(/[0-7]+)?"},{b:"#x[0-9a-f]+(/[0-9a-f]+)?"}]},l=e.QSM,c=[e.C(";","$",{r:0}),e.C("#\\|","\\|#")],d={b:t,r:0},p={cN:"symbol",b:"'"+t},m={eW:!0,r:0},u={v:[{b:/'/},{b:"`"}],c:[{b:"\\(",e:"\\)",c:["self",o,l,s,d,p]}]},b={cN:"name",b:t,l:t,k:i},g={b:/lambda/,eW:!0,rB:!0,c:[b,{b:/\(/,e:/\)/,endsParent:!0,c:[d]}]},f={v:[{b:"\\(",e:"\\)"},{b:"\\[",e:"\\]"}],c:[g,b,m]};return m.c=[o,s,l,d,p,u,f].concat(c),{i:/\S/,c:[n,s,l,p,u,f].concat(c)}}),e.registerLanguage("scilab",function(e){var t=[e.CNM,{cN:"string",b:"'|\"",e:"'|\"",c:[e.BE,{b:"''"}]}];return{aliases:["sci"],l:/%?\w+/,k:{keyword:"abort break case clear catch continue do elseif else endfunction end for function global if pause return resume select try then while",literal:"%f %F %t %T %pi %eps %inf %nan %e %i %z %s",built_in:"abs and acos asin atan ceil cd chdir clearglobal cosh cos cumprod deff disp error exec execstr exists exp eye gettext floor fprintf fread fsolve imag isdef isempty isinfisnan isvector lasterror length load linspace list listfiles log10 log2 log max min msprintf mclose mopen ones or pathconvert poly printf prod pwd rand real round sinh sin size gsort sprintf sqrt strcat strcmps tring sum system tanh tan type typename warning zeros matrix"},i:'("|#|/\\*|\\s+/\\w+)',c:[{cN:"function",bK:"function",e:"$",c:[e.UTM,{cN:"params",b:"\\(",e:"\\)"}]},{b:"[a-zA-Z_][a-zA-Z_0-9]*('+[\\.']*|[\\.']+)",e:"",r:0},{b:"\\[",e:"\\]'*[\\.']*",r:0,c:t},e.C("//","$")].concat(t)}}),e.registerLanguage("scss",function(e){var t="[a-zA-Z-][a-zA-Z0-9_-]*",r={cN:"variable",b:"(\\$"+t+")\\b"},a={cN:"number",b:"#[0-9A-Fa-f]+"};({cN:"attribute",b:"[A-Z\\_\\.\\-]+",e:":",eE:!0,i:"[^\\s]",starts:{eW:!0,eE:!0,c:[a,e.CSSNM,e.QSM,e.ASM,e.CBCM,{cN:"meta",b:"!important"}]}});return{cI:!0,i:"[=/|']",c:[e.CLCM,e.CBCM,{cN:"selector-id",b:"\\#[A-Za-z0-9_-]+",r:0},{cN:"selector-class",b:"\\.[A-Za-z0-9_-]+",r:0},{cN:"selector-attr",b:"\\[",e:"\\]",i:"$"},{cN:"selector-tag",b:"\\b(a|abbr|acronym|address|area|article|aside|audio|b|base|big|blockquote|body|br|button|canvas|caption|cite|code|col|colgroup|command|datalist|dd|del|details|dfn|div|dl|dt|em|embed|fieldset|figcaption|figure|footer|form|frame|frameset|(h[1-6])|head|header|hgroup|hr|html|i|iframe|img|input|ins|kbd|keygen|label|legend|li|link|map|mark|meta|meter|nav|noframes|noscript|object|ol|optgroup|option|output|p|param|pre|progress|q|rp|rt|ruby|samp|script|section|select|small|span|strike|strong|style|sub|sup|table|tbody|td|textarea|tfoot|th|thead|time|title|tr|tt|ul|var|video)\\b",r:0},{b:":(visited|valid|root|right|required|read-write|read-only|out-range|optional|only-of-type|only-child|nth-of-type|nth-last-of-type|nth-last-child|nth-child|not|link|left|last-of-type|last-child|lang|invalid|indeterminate|in-range|hover|focus|first-of-type|first-line|first-letter|first-child|first|enabled|empty|disabled|default|checked|before|after|active)"},{b:"::(after|before|choices|first-letter|first-line|repeat-index|repeat-item|selection|value)"},r,{cN:"attribute",b:"\\b(z-index|word-wrap|word-spacing|word-break|width|widows|white-space|visibility|vertical-align|unicode-bidi|transition-timing-function|transition-property|transition-duration|transition-delay|transition|transform-style|transform-origin|transform|top|text-underline-position|text-transform|text-shadow|text-rendering|text-overflow|text-indent|text-decoration-style|text-decoration-line|text-decoration-color|text-decoration|text-align-last|text-align|tab-size|table-layout|right|resize|quotes|position|pointer-events|perspective-origin|perspective|page-break-inside|page-break-before|page-break-after|padding-top|padding-right|padding-left|padding-bottom|padding|overflow-y|overflow-x|overflow-wrap|overflow|outline-width|outline-style|outline-offset|outline-color|outline|orphans|order|opacity|object-position|object-fit|normal|none|nav-up|nav-right|nav-left|nav-index|nav-down|min-width|min-height|max-width|max-height|mask|marks|margin-top|margin-right|margin-left|margin-bottom|margin|list-style-type|list-style-position|list-style-image|list-style|line-height|letter-spacing|left|justify-content|initial|inherit|ime-mode|image-orientation|image-resolution|image-rendering|icon|hyphens|height|font-weight|font-variant-ligatures|font-variant|font-style|font-stretch|font-size-adjust|font-size|font-language-override|font-kerning|font-feature-settings|font-family|font|float|flex-wrap|flex-shrink|flex-grow|flex-flow|flex-direction|flex-basis|flex|filter|empty-cells|display|direction|cursor|counter-reset|counter-increment|content|column-width|column-span|column-rule-width|column-rule-style|column-rule-color|column-rule|column-gap|column-fill|column-count|columns|color|clip-path|clip|clear|caption-side|break-inside|break-before|break-after|box-sizing|box-shadow|box-decoration-break|bottom|border-width|border-top-width|border-top-style|border-top-right-radius|border-top-left-radius|border-top-color|border-top|border-style|border-spacing|border-right-width|border-right-style|border-right-color|border-right|border-radius|border-left-width|border-left-style|border-left-color|border-left|border-image-width|border-image-source|border-image-slice|border-image-repeat|border-image-outset|border-image|border-color|border-collapse|border-bottom-width|border-bottom-style|border-bottom-right-radius|border-bottom-left-radius|border-bottom-color|border-bottom|border|background-size|background-repeat|background-position|background-origin|background-image|background-color|background-clip|background-attachment|background-blend-mode|background|backface-visibility|auto|animation-timing-function|animation-play-state|animation-name|animation-iteration-count|animation-fill-mode|animation-duration|animation-direction|animation-delay|animation|align-self|align-items|align-content)\\b", -i:"[^\\s]"},{b:"\\b(whitespace|wait|w-resize|visible|vertical-text|vertical-ideographic|uppercase|upper-roman|upper-alpha|underline|transparent|top|thin|thick|text|text-top|text-bottom|tb-rl|table-header-group|table-footer-group|sw-resize|super|strict|static|square|solid|small-caps|separate|se-resize|scroll|s-resize|rtl|row-resize|ridge|right|repeat|repeat-y|repeat-x|relative|progress|pointer|overline|outside|outset|oblique|nowrap|not-allowed|normal|none|nw-resize|no-repeat|no-drop|newspaper|ne-resize|n-resize|move|middle|medium|ltr|lr-tb|lowercase|lower-roman|lower-alpha|loose|list-item|line|line-through|line-edge|lighter|left|keep-all|justify|italic|inter-word|inter-ideograph|inside|inset|inline|inline-block|inherit|inactive|ideograph-space|ideograph-parenthesis|ideograph-numeric|ideograph-alpha|horizontal|hidden|help|hand|groove|fixed|ellipsis|e-resize|double|dotted|distribute|distribute-space|distribute-letter|distribute-all-lines|disc|disabled|default|decimal|dashed|crosshair|collapse|col-resize|circle|char|center|capitalize|break-word|break-all|bottom|both|bolder|bold|block|bidi-override|below|baseline|auto|always|all-scroll|absolute|table|table-cell)\\b"},{b:":",e:";",c:[r,a,e.CSSNM,e.QSM,e.ASM,{cN:"meta",b:"!important"}]},{b:"@",e:"[{;]",k:"mixin include extend for if else each while charset import debug media page content font-face namespace warn",c:[r,e.QSM,e.ASM,a,e.CSSNM,{b:"\\s[A-Za-z0-9_.-]+",r:0}]}]}}),e.registerLanguage("shell",function(e){return{aliases:["console"],c:[{cN:"meta",b:"^\\s{0,3}[\\w\\d\\[\\]()@-]*[>%$#]",starts:{e:"$",sL:"bash"}}]}}),e.registerLanguage("smali",function(e){var t=["add","and","cmp","cmpg","cmpl","const","div","double","float","goto","if","int","long","move","mul","neg","new","nop","not","or","rem","return","shl","shr","sput","sub","throw","ushr","xor"],r=["aget","aput","array","check","execute","fill","filled","goto/16","goto/32","iget","instance","invoke","iput","monitor","packed","sget","sparse"],a=["transient","constructor","abstract","final","synthetic","public","private","protected","static","bridge","system"];return{aliases:["smali"],c:[{cN:"string",b:'"',e:'"',r:0},e.C("#","$",{r:0}),{cN:"keyword",v:[{b:"\\s*\\.end\\s[a-zA-Z0-9]*"},{b:"^[ ]*\\.[a-zA-Z]*",r:0},{b:"\\s:[a-zA-Z_0-9]*",r:0},{b:"\\s("+a.join("|")+")"}]},{cN:"built_in",v:[{b:"\\s("+t.join("|")+")\\s"},{b:"\\s("+t.join("|")+")((\\-|/)[a-zA-Z0-9]+)+\\s",r:10},{b:"\\s("+r.join("|")+")((\\-|/)[a-zA-Z0-9]+)*\\s",r:10}]},{cN:"class",b:"L[^(;:\n]*;",r:0},{b:"[vp][0-9]+"}]}}),e.registerLanguage("smalltalk",function(e){var t="[a-z][a-zA-Z0-9_]*",r={cN:"string",b:"\\$.{1}"},a={cN:"symbol",b:"#"+e.UIR};return{aliases:["st"],k:"self super nil true false thisContext",c:[e.C('"','"'),e.ASM,{cN:"type",b:"\\b[A-Z][A-Za-z0-9_]*",r:0},{b:t+":",r:0},e.CNM,a,r,{b:"\\|[ ]*"+t+"([ ]+"+t+")*[ ]*\\|",rB:!0,e:/\|/,i:/\S/,c:[{b:"(\\|[ ]*)?"+t}]},{b:"\\#\\(",e:"\\)",c:[e.ASM,r,e.CNM,a]}]}}),e.registerLanguage("sml",function(e){return{aliases:["ml"],k:{keyword:"abstype and andalso as case datatype do else end eqtype exception fn fun functor handle if in include infix infixr let local nonfix of op open orelse raise rec sharing sig signature struct structure then type val with withtype where while",built_in:"array bool char exn int list option order real ref string substring vector unit word",literal:"true false NONE SOME LESS EQUAL GREATER nil"},i:/\/\/|>>/,l:"[a-z_]\\w*!?",c:[{cN:"literal",b:/\[(\|\|)?\]|\(\)/,r:0},e.C("\\(\\*","\\*\\)",{c:["self"]}),{cN:"symbol",b:"'[A-Za-z_](?!')[\\w']*"},{cN:"type",b:"`[A-Z][\\w']*"},{cN:"type",b:"\\b[A-Z][\\w']*",r:0},{b:"[a-z_]\\w*'[\\w']*"},e.inherit(e.ASM,{cN:"string",r:0}),e.inherit(e.QSM,{i:null}),{cN:"number",b:"\\b(0[xX][a-fA-F0-9_]+[Lln]?|0[oO][0-7_]+[Lln]?|0[bB][01_]+[Lln]?|[0-9][0-9_]*([Lln]|(\\.[0-9_]*)?([eE][-+]?[0-9_]+)?)?)",r:0},{b:/[-=]>/}]}}),e.registerLanguage("sqf",function(e){var t=e.getLanguage("cpp").exports,r={cN:"variable",b:/\b_+[a-zA-Z_]\w*/},a={cN:"title",b:/[a-zA-Z][a-zA-Z0-9]+_fnc_\w*/},i={cN:"string",v:[{b:'"',e:'"',c:[{b:'""',r:0}]},{b:"'",e:"'",c:[{b:"''",r:0}]}]};return{aliases:["sqf"],cI:!0,k:{keyword:"case catch default do else exit exitWith for forEach from if switch then throw to try waitUntil while with",built_in:"abs accTime acos action actionIDs actionKeys actionKeysImages actionKeysNames actionKeysNamesArray actionName actionParams activateAddons activatedAddons activateKey add3DENConnection add3DENEventHandler add3DENLayer addAction addBackpack addBackpackCargo addBackpackCargoGlobal addBackpackGlobal addCamShake addCuratorAddons addCuratorCameraArea addCuratorEditableObjects addCuratorEditingArea addCuratorPoints addEditorObject addEventHandler addGoggles addGroupIcon addHandgunItem addHeadgear addItem addItemCargo addItemCargoGlobal addItemPool addItemToBackpack addItemToUniform addItemToVest addLiveStats addMagazine addMagazineAmmoCargo addMagazineCargo addMagazineCargoGlobal addMagazineGlobal addMagazinePool addMagazines addMagazineTurret addMenu addMenuItem addMissionEventHandler addMPEventHandler addMusicEventHandler addOwnedMine addPlayerScores addPrimaryWeaponItem addPublicVariableEventHandler addRating addResources addScore addScoreSide addSecondaryWeaponItem addSwitchableUnit addTeamMember addToRemainsCollector addUniform addVehicle addVest addWaypoint addWeapon addWeaponCargo addWeaponCargoGlobal addWeaponGlobal addWeaponItem addWeaponPool addWeaponTurret agent agents AGLToASL aimedAtTarget aimPos airDensityRTD airportSide AISFinishHeal alive all3DENEntities allControls allCurators allCutLayers allDead allDeadMen allDisplays allGroups allMapMarkers allMines allMissionObjects allow3DMode allowCrewInImmobile allowCuratorLogicIgnoreAreas allowDamage allowDammage allowFileOperations allowFleeing allowGetIn allowSprint allPlayers allSites allTurrets allUnits allUnitsUAV allVariables ammo and animate animateDoor animateSource animationNames animationPhase animationSourcePhase animationState append apply armoryPoints arrayIntersect asin ASLToAGL ASLToATL assert assignAsCargo assignAsCargoIndex assignAsCommander assignAsDriver assignAsGunner assignAsTurret assignCurator assignedCargo assignedCommander assignedDriver assignedGunner assignedItems assignedTarget assignedTeam assignedVehicle assignedVehicleRole assignItem assignTeam assignToAirport atan atan2 atg ATLToASL attachedObject attachedObjects attachedTo attachObject attachTo attackEnabled backpack backpackCargo backpackContainer backpackItems backpackMagazines backpackSpaceFor behaviour benchmark binocular blufor boundingBox boundingBoxReal boundingCenter breakOut breakTo briefingName buildingExit buildingPos buttonAction buttonSetAction cadetMode call callExtension camCommand camCommit camCommitPrepared camCommitted camConstuctionSetParams camCreate camDestroy cameraEffect cameraEffectEnableHUD cameraInterest cameraOn cameraView campaignConfigFile camPreload camPreloaded camPrepareBank camPrepareDir camPrepareDive camPrepareFocus camPrepareFov camPrepareFovRange camPreparePos camPrepareRelPos camPrepareTarget camSetBank camSetDir camSetDive camSetFocus camSetFov camSetFovRange camSetPos camSetRelPos camSetTarget camTarget camUseNVG canAdd canAddItemToBackpack canAddItemToUniform canAddItemToVest cancelSimpleTaskDestination canFire canMove canSlingLoad canStand canSuspend canUnloadInCombat canVehicleCargo captive captiveNum cbChecked cbSetChecked ceil channelEnabled cheatsEnabled checkAIFeature checkVisibility civilian className clearAllItemsFromBackpack clearBackpackCargo clearBackpackCargoGlobal clearGroupIcons clearItemCargo clearItemCargoGlobal clearItemPool clearMagazineCargo clearMagazineCargoGlobal clearMagazinePool clearOverlay clearRadio clearWeaponCargo clearWeaponCargoGlobal clearWeaponPool clientOwner closeDialog closeDisplay closeOverlay collapseObjectTree collect3DENHistory combatMode commandArtilleryFire commandChat commander commandFire commandFollow commandFSM commandGetOut commandingMenu commandMove commandRadio commandStop commandSuppressiveFire commandTarget commandWatch comment commitOverlay compile compileFinal completedFSM composeText configClasses configFile configHierarchy configName configNull configProperties configSourceAddonList configSourceMod configSourceModList connectTerminalToUAV controlNull controlsGroupCtrl copyFromClipboard copyToClipboard copyWaypoints cos count countEnemy countFriendly countSide countType countUnknown create3DENComposition create3DENEntity createAgent createCenter createDialog createDiaryLink createDiaryRecord createDiarySubject createDisplay createGearDialog createGroup createGuardedPoint createLocation createMarker createMarkerLocal createMenu createMine createMissionDisplay createMPCampaignDisplay createSimpleObject createSimpleTask createSite createSoundSource createTask createTeam createTrigger createUnit createVehicle createVehicleCrew createVehicleLocal crew ctrlActivate ctrlAddEventHandler ctrlAngle ctrlAutoScrollDelay ctrlAutoScrollRewind ctrlAutoScrollSpeed ctrlChecked ctrlClassName ctrlCommit ctrlCommitted ctrlCreate ctrlDelete ctrlEnable ctrlEnabled ctrlFade ctrlHTMLLoaded ctrlIDC ctrlIDD ctrlMapAnimAdd ctrlMapAnimClear ctrlMapAnimCommit ctrlMapAnimDone ctrlMapCursor ctrlMapMouseOver ctrlMapScale ctrlMapScreenToWorld ctrlMapWorldToScreen ctrlModel ctrlModelDirAndUp ctrlModelScale ctrlParent ctrlParentControlsGroup ctrlPosition ctrlRemoveAllEventHandlers ctrlRemoveEventHandler ctrlScale ctrlSetActiveColor ctrlSetAngle ctrlSetAutoScrollDelay ctrlSetAutoScrollRewind ctrlSetAutoScrollSpeed ctrlSetBackgroundColor ctrlSetChecked ctrlSetEventHandler ctrlSetFade ctrlSetFocus ctrlSetFont ctrlSetFontH1 ctrlSetFontH1B ctrlSetFontH2 ctrlSetFontH2B ctrlSetFontH3 ctrlSetFontH3B ctrlSetFontH4 ctrlSetFontH4B ctrlSetFontH5 ctrlSetFontH5B ctrlSetFontH6 ctrlSetFontH6B ctrlSetFontHeight ctrlSetFontHeightH1 ctrlSetFontHeightH2 ctrlSetFontHeightH3 ctrlSetFontHeightH4 ctrlSetFontHeightH5 ctrlSetFontHeightH6 ctrlSetFontHeightSecondary ctrlSetFontP ctrlSetFontPB ctrlSetFontSecondary ctrlSetForegroundColor ctrlSetModel ctrlSetModelDirAndUp ctrlSetModelScale ctrlSetPosition ctrlSetScale ctrlSetStructuredText ctrlSetText ctrlSetTextColor ctrlSetTooltip ctrlSetTooltipColorBox ctrlSetTooltipColorShade ctrlSetTooltipColorText ctrlShow ctrlShown ctrlText ctrlTextHeight ctrlType ctrlVisible curatorAddons curatorCamera curatorCameraArea curatorCameraAreaCeiling curatorCoef curatorEditableObjects curatorEditingArea curatorEditingAreaType curatorMouseOver curatorPoints curatorRegisteredObjects curatorSelected curatorWaypointCost current3DENOperation currentChannel currentCommand currentMagazine currentMagazineDetail currentMagazineDetailTurret currentMagazineTurret currentMuzzle currentNamespace currentTask currentTasks currentThrowable currentVisionMode currentWaypoint currentWeapon currentWeaponMode currentWeaponTurret currentZeroing cursorObject cursorTarget customChat customRadio cutFadeOut cutObj cutRsc cutText damage date dateToNumber daytime deActivateKey debriefingText debugFSM debugLog deg delete3DENEntities deleteAt deleteCenter deleteCollection deleteEditorObject deleteGroup deleteIdentity deleteLocation deleteMarker deleteMarkerLocal deleteRange deleteResources deleteSite deleteStatus deleteTeam deleteVehicle deleteVehicleCrew deleteWaypoint detach detectedMines diag_activeMissionFSMs diag_activeScripts diag_activeSQFScripts diag_activeSQSScripts diag_captureFrame diag_captureSlowFrame diag_codePerformance diag_drawMode diag_enable diag_enabled diag_fps diag_fpsMin diag_frameNo diag_list diag_log diag_logSlowFrame diag_mergeConfigFile diag_recordTurretLimits diag_tickTime diag_toggle dialog diarySubjectExists didJIP didJIPOwner difficulty difficultyEnabled difficultyEnabledRTD difficultyOption direction directSay disableAI disableCollisionWith disableConversation disableDebriefingStats disableNVGEquipment disableRemoteSensors disableSerialization disableTIEquipment disableUAVConnectability disableUserInput displayAddEventHandler displayCtrl displayNull displayParent displayRemoveAllEventHandlers displayRemoveEventHandler displaySetEventHandler dissolveTeam distance distance2D distanceSqr distributionRegion do3DENAction doArtilleryFire doFire doFollow doFSM doGetOut doMove doorPhase doStop doSuppressiveFire doTarget doWatch drawArrow drawEllipse drawIcon drawIcon3D drawLine drawLine3D drawLink drawLocation drawPolygon drawRectangle driver drop east echo edit3DENMissionAttributes editObject editorSetEventHandler effectiveCommander emptyPositions enableAI enableAIFeature enableAimPrecision enableAttack enableAudioFeature enableCamShake enableCaustics enableChannel enableCollisionWith enableCopilot enableDebriefingStats enableDiagLegend enableEndDialog enableEngineArtillery enableEnvironment enableFatigue enableGunLights enableIRLasers enableMimics enablePersonTurret enableRadio enableReload enableRopeAttach enableSatNormalOnDetail enableSaving enableSentences enableSimulation enableSimulationGlobal enableStamina enableTeamSwitch enableUAVConnectability enableUAVWaypoints enableVehicleCargo endLoadingScreen endMission engineOn enginesIsOnRTD enginesRpmRTD enginesTorqueRTD entities estimatedEndServerTime estimatedTimeLeft evalObjectArgument everyBackpack everyContainer exec execEditorScript execFSM execVM exp expectedDestination exportJIPMessages eyeDirection eyePos face faction fadeMusic fadeRadio fadeSound fadeSpeech failMission fillWeaponsFromPool find findCover findDisplay findEditorObject findEmptyPosition findEmptyPositionReady findNearestEnemy finishMissionInit finite fire fireAtTarget firstBackpack flag flagOwner flagSide flagTexture fleeing floor flyInHeight flyInHeightASL fog fogForecast fogParams forceAddUniform forcedMap forceEnd forceMap forceRespawn forceSpeed forceWalk forceWeaponFire forceWeatherChange forEachMember forEachMemberAgent forEachMemberTeam format formation formationDirection formationLeader formationMembers formationPosition formationTask formatText formLeader freeLook fromEditor fuel fullCrew gearIDCAmmoCount gearSlotAmmoCount gearSlotData get3DENActionState get3DENAttribute get3DENCamera get3DENConnections get3DENEntity get3DENEntityID get3DENGrid get3DENIconsVisible get3DENLayerEntities get3DENLinesVisible get3DENMissionAttribute get3DENMouseOver get3DENSelected getAimingCoef getAllHitPointsDamage getAllOwnedMines getAmmoCargo getAnimAimPrecision getAnimSpeedCoef getArray getArtilleryAmmo getArtilleryComputerSettings getArtilleryETA getAssignedCuratorLogic getAssignedCuratorUnit getBackpackCargo getBleedingRemaining getBurningValue getCameraViewDirection getCargoIndex getCenterOfMass getClientState getClientStateNumber getConnectedUAV getCustomAimingCoef getDammage getDescription getDir getDirVisual getDLCs getEditorCamera getEditorMode getEditorObjectScope getElevationOffset getFatigue getFriend getFSMVariable getFuelCargo getGroupIcon getGroupIconParams getGroupIcons getHideFrom getHit getHitIndex getHitPointDamage getItemCargo getMagazineCargo getMarkerColor getMarkerPos getMarkerSize getMarkerType getMass getMissionConfig getMissionConfigValue getMissionDLCs getMissionLayerEntities getModelInfo getMousePosition getNumber getObjectArgument getObjectChildren getObjectDLC getObjectMaterials getObjectProxy getObjectTextures getObjectType getObjectViewDistance getOxygenRemaining getPersonUsedDLCs getPilotCameraDirection getPilotCameraPosition getPilotCameraRotation getPilotCameraTarget getPlayerChannel getPlayerScores getPlayerUID getPos getPosASL getPosASLVisual getPosASLW getPosATL getPosATLVisual getPosVisual getPosWorld getRelDir getRelPos getRemoteSensorsDisabled getRepairCargo getResolution getShadowDistance getShotParents getSlingLoad getSpeed getStamina getStatValue getSuppression getTerrainHeightASL getText getUnitLoadout getUnitTrait getVariable getVehicleCargo getWeaponCargo getWeaponSway getWPPos glanceAt globalChat globalRadio goggles goto group groupChat groupFromNetId groupIconSelectable groupIconsVisible groupId groupOwner groupRadio groupSelectedUnits groupSelectUnit grpNull gunner gusts halt handgunItems handgunMagazine handgunWeapon handsHit hasInterface hasPilotCamera hasWeapon hcAllGroups hcGroupParams hcLeader hcRemoveAllGroups hcRemoveGroup hcSelected hcSelectGroup hcSetGroup hcShowBar hcShownBar headgear hideBody hideObject hideObjectGlobal hideSelection hint hintC hintCadet hintSilent hmd hostMission htmlLoad HUDMovementLevels humidity image importAllGroups importance in inArea inAreaArray incapacitatedState independent inflame inflamed inGameUISetEventHandler inheritsFrom initAmbientLife inPolygon inputAction inRangeOfArtillery insertEditorObject intersect is3DEN is3DENMultiplayer isAbleToBreathe isAgent isArray isAutoHoverOn isAutonomous isAutotest isBleeding isBurning isClass isCollisionLightOn isCopilotEnabled isDedicated isDLCAvailable isEngineOn isEqualTo isEqualType isEqualTypeAll isEqualTypeAny isEqualTypeArray isEqualTypeParams isFilePatchingEnabled isFlashlightOn isFlatEmpty isForcedWalk isFormationLeader isHidden isInRemainsCollector isInstructorFigureEnabled isIRLaserOn isKeyActive isKindOf isLightOn isLocalized isManualFire isMarkedForCollection isMultiplayer isMultiplayerSolo isNil isNull isNumber isObjectHidden isObjectRTD isOnRoad isPipEnabled isPlayer isRealTime isRemoteExecuted isRemoteExecutedJIP isServer isShowing3DIcons isSprintAllowed isStaminaEnabled isSteamMission isStreamFriendlyUIEnabled isText isTouchingGround isTurnedOut isTutHintsEnabled isUAVConnectable isUAVConnected isUniformAllowed isVehicleCargo isWalking isWeaponDeployed isWeaponRested itemCargo items itemsWithMagazines join joinAs joinAsSilent joinSilent joinString kbAddDatabase kbAddDatabaseTargets kbAddTopic kbHasTopic kbReact kbRemoveTopic kbTell kbWasSaid keyImage keyName knowsAbout land landAt landResult language laserTarget lbAdd lbClear lbColor lbCurSel lbData lbDelete lbIsSelected lbPicture lbSelection lbSetColor lbSetCurSel lbSetData lbSetPicture lbSetPictureColor lbSetPictureColorDisabled lbSetPictureColorSelected lbSetSelectColor lbSetSelectColorRight lbSetSelected lbSetTooltip lbSetValue lbSize lbSort lbSortByValue lbText lbValue leader leaderboardDeInit leaderboardGetRows leaderboardInit leaveVehicle libraryCredits libraryDisclaimers lifeState lightAttachObject lightDetachObject lightIsOn lightnings limitSpeed linearConversion lineBreak lineIntersects lineIntersectsObjs lineIntersectsSurfaces lineIntersectsWith linkItem list listObjects ln lnbAddArray lnbAddColumn lnbAddRow lnbClear lnbColor lnbCurSelRow lnbData lnbDeleteColumn lnbDeleteRow lnbGetColumnsPosition lnbPicture lnbSetColor lnbSetColumnsPos lnbSetCurSelRow lnbSetData lnbSetPicture lnbSetText lnbSetValue lnbSize lnbText lnbValue load loadAbs loadBackpack loadFile loadGame loadIdentity loadMagazine loadOverlay loadStatus loadUniform loadVest local localize locationNull locationPosition lock lockCameraTo lockCargo lockDriver locked lockedCargo lockedDriver lockedTurret lockIdentity lockTurret lockWP log logEntities logNetwork logNetworkTerminate lookAt lookAtPos magazineCargo magazines magazinesAllTurrets magazinesAmmo magazinesAmmoCargo magazinesAmmoFull magazinesDetail magazinesDetailBackpack magazinesDetailUniform magazinesDetailVest magazinesTurret magazineTurretAmmo mapAnimAdd mapAnimClear mapAnimCommit mapAnimDone mapCenterOnCamera mapGridPosition markAsFinishedOnSteam markerAlpha markerBrush markerColor markerDir markerPos markerShape markerSize markerText markerType max members menuAction menuAdd menuChecked menuClear menuCollapse menuData menuDelete menuEnable menuEnabled menuExpand menuHover menuPicture menuSetAction menuSetCheck menuSetData menuSetPicture menuSetValue menuShortcut menuShortcutText menuSize menuSort menuText menuURL menuValue min mineActive mineDetectedBy missionConfigFile missionDifficulty missionName missionNamespace missionStart missionVersion mod modelToWorld modelToWorldVisual modParams moonIntensity moonPhase morale move move3DENCamera moveInAny moveInCargo moveInCommander moveInDriver moveInGunner moveInTurret moveObjectToEnd moveOut moveTime moveTo moveToCompleted moveToFailed musicVolume name nameSound nearEntities nearestBuilding nearestLocation nearestLocations nearestLocationWithDubbing nearestObject nearestObjects nearestTerrainObjects nearObjects nearObjectsReady nearRoads nearSupplies nearTargets needReload netId netObjNull newOverlay nextMenuItemIndex nextWeatherChange nMenuItems not numberToDate objectCurators objectFromNetId objectParent objNull objStatus onBriefingGroup onBriefingNotes onBriefingPlan onBriefingTeamSwitch onCommandModeChanged onDoubleClick onEachFrame onGroupIconClick onGroupIconOverEnter onGroupIconOverLeave onHCGroupSelectionChanged onMapSingleClick onPlayerConnected onPlayerDisconnected onPreloadFinished onPreloadStarted onShowNewObject onTeamSwitch openCuratorInterface openDLCPage openMap openYoutubeVideo opfor or orderGetIn overcast overcastForecast owner param params parseNumber parseText parsingNamespace particlesQuality pi pickWeaponPool pitch pixelGrid pixelGridBase pixelGridNoUIScale pixelH pixelW playableSlotsNumber playableUnits playAction playActionNow player playerRespawnTime playerSide playersNumber playGesture playMission playMove playMoveNow playMusic playScriptedMission playSound playSound3D position positionCameraToWorld posScreenToWorld posWorldToScreen ppEffectAdjust ppEffectCommit ppEffectCommitted ppEffectCreate ppEffectDestroy ppEffectEnable ppEffectEnabled ppEffectForceInNVG precision preloadCamera preloadObject preloadSound preloadTitleObj preloadTitleRsc preprocessFile preprocessFileLineNumbers primaryWeapon primaryWeaponItems primaryWeaponMagazine priority private processDiaryLink productVersion profileName profileNamespace profileNameSteam progressLoadingScreen progressPosition progressSetPosition publicVariable publicVariableClient publicVariableServer pushBack pushBackUnique putWeaponPool queryItemsPool queryMagazinePool queryWeaponPool rad radioChannelAdd radioChannelCreate radioChannelRemove radioChannelSetCallSign radioChannelSetLabel radioVolume rain rainbow random rank rankId rating rectangular registeredTasks registerTask reload reloadEnabled remoteControl remoteExec remoteExecCall remove3DENConnection remove3DENEventHandler remove3DENLayer removeAction removeAll3DENEventHandlers removeAllActions removeAllAssignedItems removeAllContainers removeAllCuratorAddons removeAllCuratorCameraAreas removeAllCuratorEditingAreas removeAllEventHandlers removeAllHandgunItems removeAllItems removeAllItemsWithMagazines removeAllMissionEventHandlers removeAllMPEventHandlers removeAllMusicEventHandlers removeAllOwnedMines removeAllPrimaryWeaponItems removeAllWeapons removeBackpack removeBackpackGlobal removeCuratorAddons removeCuratorCameraArea removeCuratorEditableObjects removeCuratorEditingArea removeDrawIcon removeDrawLinks removeEventHandler removeFromRemainsCollector removeGoggles removeGroupIcon removeHandgunItem removeHeadgear removeItem removeItemFromBackpack removeItemFromUniform removeItemFromVest removeItems removeMagazine removeMagazineGlobal removeMagazines removeMagazinesTurret removeMagazineTurret removeMenuItem removeMissionEventHandler removeMPEventHandler removeMusicEventHandler removeOwnedMine removePrimaryWeaponItem removeSecondaryWeaponItem removeSimpleTask removeSwitchableUnit removeTeamMember removeUniform removeVest removeWeapon removeWeaponGlobal removeWeaponTurret requiredVersion resetCamShake resetSubgroupDirection resistance resize resources respawnVehicle restartEditorCamera reveal revealMine reverse reversedMouseY roadAt roadsConnectedTo roleDescription ropeAttachedObjects ropeAttachedTo ropeAttachEnabled ropeAttachTo ropeCreate ropeCut ropeDestroy ropeDetach ropeEndPosition ropeLength ropes ropeUnwind ropeUnwound rotorsForcesRTD rotorsRpmRTD round runInitScript safeZoneH safeZoneW safeZoneWAbs safeZoneX safeZoneXAbs safeZoneY save3DENInventory saveGame saveIdentity saveJoysticks saveOverlay saveProfileNamespace saveStatus saveVar savingEnabled say say2D say3D scopeName score scoreSide screenshot screenToWorld scriptDone scriptName scriptNull scudState secondaryWeapon secondaryWeaponItems secondaryWeaponMagazine select selectBestPlaces selectDiarySubject selectedEditorObjects selectEditorObject selectionNames selectionPosition selectLeader selectMax selectMin selectNoPlayer selectPlayer selectRandom selectWeapon selectWeaponTurret sendAUMessage sendSimpleCommand sendTask sendTaskResult sendUDPMessage serverCommand serverCommandAvailable serverCommandExecutable serverName serverTime set set3DENAttribute set3DENAttributes set3DENGrid set3DENIconsVisible set3DENLayer set3DENLinesVisible set3DENMissionAttributes set3DENModelsVisible set3DENObjectType set3DENSelected setAccTime setAirportSide setAmmo setAmmoCargo setAnimSpeedCoef setAperture setApertureNew setArmoryPoints setAttributes setAutonomous setBehaviour setBleedingRemaining setCameraInterest setCamShakeDefParams setCamShakeParams setCamUseTi setCaptive setCenterOfMass setCollisionLight setCombatMode setCompassOscillation setCuratorCameraAreaCeiling setCuratorCoef setCuratorEditingAreaType setCuratorWaypointCost setCurrentChannel setCurrentTask setCurrentWaypoint setCustomAimCoef setDamage setDammage setDate setDebriefingText setDefaultCamera setDestination setDetailMapBlendPars setDir setDirection setDrawIcon setDropInterval setEditorMode setEditorObjectScope setEffectCondition setFace setFaceAnimation setFatigue setFlagOwner setFlagSide setFlagTexture setFog setFormation setFormationTask setFormDir setFriend setFromEditor setFSMVariable setFuel setFuelCargo setGroupIcon setGroupIconParams setGroupIconsSelectable setGroupIconsVisible setGroupId setGroupIdGlobal setGroupOwner setGusts setHideBehind setHit setHitIndex setHitPointDamage setHorizonParallaxCoef setHUDMovementLevels setIdentity setImportance setLeader setLightAmbient setLightAttenuation setLightBrightness setLightColor setLightDayLight setLightFlareMaxDistance setLightFlareSize setLightIntensity setLightnings setLightUseFlare setLocalWindParams setMagazineTurretAmmo setMarkerAlpha setMarkerAlphaLocal setMarkerBrush setMarkerBrushLocal setMarkerColor setMarkerColorLocal setMarkerDir setMarkerDirLocal setMarkerPos setMarkerPosLocal setMarkerShape setMarkerShapeLocal setMarkerSize setMarkerSizeLocal setMarkerText setMarkerTextLocal setMarkerType setMarkerTypeLocal setMass setMimic setMousePosition setMusicEffect setMusicEventHandler setName setNameSound setObjectArguments setObjectMaterial setObjectMaterialGlobal setObjectProxy setObjectTexture setObjectTextureGlobal setObjectViewDistance setOvercast setOwner setOxygenRemaining setParticleCircle setParticleClass setParticleFire setParticleParams setParticleRandom setPilotCameraDirection setPilotCameraRotation setPilotCameraTarget setPilotLight setPiPEffect setPitch setPlayable setPlayerRespawnTime setPos setPosASL setPosASL2 setPosASLW setPosATL setPosition setPosWorld setRadioMsg setRain setRainbow setRandomLip setRank setRectangular setRepairCargo setShadowDistance setShotParents setSide setSimpleTaskAlwaysVisible setSimpleTaskCustomData setSimpleTaskDescription setSimpleTaskDestination setSimpleTaskTarget setSimpleTaskType setSimulWeatherLayers setSize setSkill setSlingLoad setSoundEffect setSpeaker setSpeech setSpeedMode setStamina setStaminaScheme setStatValue setSuppression setSystemOfUnits setTargetAge setTaskResult setTaskState setTerrainGrid setText setTimeMultiplier setTitleEffect setTriggerActivation setTriggerArea setTriggerStatements setTriggerText setTriggerTimeout setTriggerType setType setUnconscious setUnitAbility setUnitLoadout setUnitPos setUnitPosWeak setUnitRank setUnitRecoilCoefficient setUnitTrait setUnloadInCombat setUserActionText setVariable setVectorDir setVectorDirAndUp setVectorUp setVehicleAmmo setVehicleAmmoDef setVehicleArmor setVehicleCargo setVehicleId setVehicleLock setVehiclePosition setVehicleTiPars setVehicleVarName setVelocity setVelocityTransformation setViewDistance setVisibleIfTreeCollapsed setWaves setWaypointBehaviour setWaypointCombatMode setWaypointCompletionRadius setWaypointDescription setWaypointForceBehaviour setWaypointFormation setWaypointHousePosition setWaypointLoiterRadius setWaypointLoiterType setWaypointName setWaypointPosition setWaypointScript setWaypointSpeed setWaypointStatements setWaypointTimeout setWaypointType setWaypointVisible setWeaponReloadingTime setWind setWindDir setWindForce setWindStr setWPPos show3DIcons showChat showCinemaBorder showCommandingMenu showCompass showCuratorCompass showGPS showHUD showLegend showMap shownArtilleryComputer shownChat shownCompass shownCuratorCompass showNewEditorObject shownGPS shownHUD shownMap shownPad shownRadio shownScoretable shownUAVFeed shownWarrant shownWatch showPad showRadio showScoretable showSubtitles showUAVFeed showWarrant showWatch showWaypoint showWaypoints side sideAmbientLife sideChat sideEmpty sideEnemy sideFriendly sideLogic sideRadio sideUnknown simpleTasks simulationEnabled simulCloudDensity simulCloudOcclusion simulInClouds simulWeatherSync sin size sizeOf skill skillFinal skipTime sleep sliderPosition sliderRange sliderSetPosition sliderSetRange sliderSetSpeed sliderSpeed slingLoadAssistantShown soldierMagazines someAmmo sort soundVolume spawn speaker speed speedMode splitString sqrt squadParams stance startLoadingScreen step stop stopEngineRTD stopped str sunOrMoon supportInfo suppressFor surfaceIsWater surfaceNormal surfaceType swimInDepth switchableUnits switchAction switchCamera switchGesture switchLight switchMove synchronizedObjects synchronizedTriggers synchronizedWaypoints synchronizeObjectsAdd synchronizeObjectsRemove synchronizeTrigger synchronizeWaypoint systemChat systemOfUnits tan targetKnowledge targetsAggregate targetsQuery taskAlwaysVisible taskChildren taskCompleted taskCustomData taskDescription taskDestination taskHint taskMarkerOffset taskNull taskParent taskResult taskState taskType teamMember teamMemberNull teamName teams teamSwitch teamSwitchEnabled teamType terminate terrainIntersect terrainIntersectASL text textLog textLogFormat tg time timeMultiplier titleCut titleFadeOut titleObj titleRsc titleText toArray toFixed toLower toString toUpper triggerActivated triggerActivation triggerArea triggerAttachedVehicle triggerAttachObject triggerAttachVehicle triggerStatements triggerText triggerTimeout triggerTimeoutCurrent triggerType turretLocal turretOwner turretUnit tvAdd tvClear tvCollapse tvCount tvCurSel tvData tvDelete tvExpand tvPicture tvSetCurSel tvSetData tvSetPicture tvSetPictureColor tvSetPictureColorDisabled tvSetPictureColorSelected tvSetPictureRight tvSetPictureRightColor tvSetPictureRightColorDisabled tvSetPictureRightColorSelected tvSetText tvSetTooltip tvSetValue tvSort tvSortByValue tvText tvTooltip tvValue type typeName typeOf UAVControl uiNamespace uiSleep unassignCurator unassignItem unassignTeam unassignVehicle underwater uniform uniformContainer uniformItems uniformMagazines unitAddons unitAimPosition unitAimPositionVisual unitBackpack unitIsUAV unitPos unitReady unitRecoilCoefficient units unitsBelowHeight unlinkItem unlockAchievement unregisterTask updateDrawIcon updateMenuItem updateObjectTree useAISteeringComponent useAudioTimeForMoves vectorAdd vectorCos vectorCrossProduct vectorDiff vectorDir vectorDirVisual vectorDistance vectorDistanceSqr vectorDotProduct vectorFromTo vectorMagnitude vectorMagnitudeSqr vectorMultiply vectorNormalized vectorUp vectorUpVisual vehicle vehicleCargoEnabled vehicleChat vehicleRadio vehicles vehicleVarName velocity velocityModelSpace verifySignature vest vestContainer vestItems vestMagazines viewDistance visibleCompass visibleGPS visibleMap visiblePosition visiblePositionASL visibleScoretable visibleWatch waves waypointAttachedObject waypointAttachedVehicle waypointAttachObject waypointAttachVehicle waypointBehaviour waypointCombatMode waypointCompletionRadius waypointDescription waypointForceBehaviour waypointFormation waypointHousePosition waypointLoiterRadius waypointLoiterType waypointName waypointPosition waypoints waypointScript waypointsEnabledUAV waypointShow waypointSpeed waypointStatements waypointTimeout waypointTimeoutCurrent waypointType waypointVisible weaponAccessories weaponAccessoriesCargo weaponCargo weaponDirection weaponInertia weaponLowered weapons weaponsItems weaponsItemsCargo weaponState weaponsTurret weightRTD west WFSideText wind", -literal:"true false nil"},c:[e.CLCM,e.CBCM,e.NM,r,a,i,t.preprocessor],i:/#/}}),e.registerLanguage("sql",function(e){var t=e.C("--","$");return{cI:!0,i:/[<>{}*#]/,c:[{bK:"begin end start commit rollback savepoint lock alter create drop rename call delete do handler insert load replace select truncate update set show pragma grant merge describe use explain help declare prepare execute deallocate release unlock purge reset change stop analyze cache flush optimize repair kill install uninstall checksum restore check backup revoke comment",e:/;/,eW:!0,l:/[\w\.]+/,k:{keyword:"abort abs absolute acc acce accep accept access accessed accessible account acos action activate add addtime admin administer advanced advise aes_decrypt aes_encrypt after agent aggregate ali alia alias allocate allow alter always analyze ancillary and any anydata anydataset anyschema anytype apply archive archived archivelog are as asc ascii asin assembly assertion associate asynchronous at atan atn2 attr attri attrib attribu attribut attribute attributes audit authenticated authentication authid authors auto autoallocate autodblink autoextend automatic availability avg backup badfile basicfile before begin beginning benchmark between bfile bfile_base big bigfile bin binary_double binary_float binlog bit_and bit_count bit_length bit_or bit_xor bitmap blob_base block blocksize body both bound buffer_cache buffer_pool build bulk by byte byteordermark bytes cache caching call calling cancel capacity cascade cascaded case cast catalog category ceil ceiling chain change changed char_base char_length character_length characters characterset charindex charset charsetform charsetid check checksum checksum_agg child choose chr chunk class cleanup clear client clob clob_base clone close cluster_id cluster_probability cluster_set clustering coalesce coercibility col collate collation collect colu colum column column_value columns columns_updated comment commit compact compatibility compiled complete composite_limit compound compress compute concat concat_ws concurrent confirm conn connec connect connect_by_iscycle connect_by_isleaf connect_by_root connect_time connection consider consistent constant constraint constraints constructor container content contents context contributors controlfile conv convert convert_tz corr corr_k corr_s corresponding corruption cos cost count count_big counted covar_pop covar_samp cpu_per_call cpu_per_session crc32 create creation critical cross cube cume_dist curdate current current_date current_time current_timestamp current_user cursor curtime customdatum cycle data database databases datafile datafiles datalength date_add date_cache date_format date_sub dateadd datediff datefromparts datename datepart datetime2fromparts day day_to_second dayname dayofmonth dayofweek dayofyear days db_role_change dbtimezone ddl deallocate declare decode decompose decrement decrypt deduplicate def defa defau defaul default defaults deferred defi defin define degrees delayed delegate delete delete_all delimited demand dense_rank depth dequeue des_decrypt des_encrypt des_key_file desc descr descri describ describe descriptor deterministic diagnostics difference dimension direct_load directory disable disable_all disallow disassociate discardfile disconnect diskgroup distinct distinctrow distribute distributed div do document domain dotnet double downgrade drop dumpfile duplicate duration each edition editionable editions element ellipsis else elsif elt empty enable enable_all enclosed encode encoding encrypt end end-exec endian enforced engine engines enqueue enterprise entityescaping eomonth error errors escaped evalname evaluate event eventdata events except exception exceptions exchange exclude excluding execu execut execute exempt exists exit exp expire explain export export_set extended extent external external_1 external_2 externally extract failed failed_login_attempts failover failure far fast feature_set feature_value fetch field fields file file_name_convert filesystem_like_logging final finish first first_value fixed flash_cache flashback floor flush following follows for forall force form forma format found found_rows freelist freelists freepools fresh from from_base64 from_days ftp full function general generated get get_format get_lock getdate getutcdate global global_name globally go goto grant grants greatest group group_concat group_id grouping grouping_id groups gtid_subtract guarantee guard handler hash hashkeys having hea head headi headin heading heap help hex hierarchy high high_priority hosts hour http id ident_current ident_incr ident_seed identified identity idle_time if ifnull ignore iif ilike ilm immediate import in include including increment index indexes indexing indextype indicator indices inet6_aton inet6_ntoa inet_aton inet_ntoa infile initial initialized initially initrans inmemory inner innodb input insert install instance instantiable instr interface interleaved intersect into invalidate invisible is is_free_lock is_ipv4 is_ipv4_compat is_not is_not_null is_used_lock isdate isnull isolation iterate java join json json_exists keep keep_duplicates key keys kill language large last last_day last_insert_id last_value lax lcase lead leading least leaves left len lenght length less level levels library like like2 like4 likec limit lines link list listagg little ln load load_file lob lobs local localtime localtimestamp locate locator lock locked log log10 log2 logfile logfiles logging logical logical_reads_per_call logoff logon logs long loop low low_priority lower lpad lrtrim ltrim main make_set makedate maketime managed management manual map mapping mask master master_pos_wait match matched materialized max maxextents maximize maxinstances maxlen maxlogfiles maxloghistory maxlogmembers maxsize maxtrans md5 measures median medium member memcompress memory merge microsecond mid migration min minextents minimum mining minus minute minvalue missing mod mode model modification modify module monitoring month months mount move movement multiset mutex name name_const names nan national native natural nav nchar nclob nested never new newline next nextval no no_write_to_binlog noarchivelog noaudit nobadfile nocheck nocompress nocopy nocycle nodelay nodiscardfile noentityescaping noguarantee nokeep nologfile nomapping nomaxvalue nominimize nominvalue nomonitoring none noneditionable nonschema noorder nopr nopro noprom nopromp noprompt norely noresetlogs noreverse normal norowdependencies noschemacheck noswitch not nothing notice notrim novalidate now nowait nth_value nullif nulls num numb numbe nvarchar nvarchar2 object ocicoll ocidate ocidatetime ociduration ociinterval ociloblocator ocinumber ociref ocirefcursor ocirowid ocistring ocitype oct octet_length of off offline offset oid oidindex old on online only opaque open operations operator optimal optimize option optionally or oracle oracle_date oradata ord ordaudio orddicom orddoc order ordimage ordinality ordvideo organization orlany orlvary out outer outfile outline output over overflow overriding package pad parallel parallel_enable parameters parent parse partial partition partitions pascal passing password password_grace_time password_lock_time password_reuse_max password_reuse_time password_verify_function patch path patindex pctincrease pctthreshold pctused pctversion percent percent_rank percentile_cont percentile_disc performance period period_add period_diff permanent physical pi pipe pipelined pivot pluggable plugin policy position post_transaction pow power pragma prebuilt precedes preceding precision prediction prediction_cost prediction_details prediction_probability prediction_set prepare present preserve prior priority private private_sga privileges procedural procedure procedure_analyze processlist profiles project prompt protection public publishingservername purge quarter query quick quiesce quota quotename radians raise rand range rank raw read reads readsize rebuild record records recover recovery recursive recycle redo reduced ref reference referenced references referencing refresh regexp_like register regr_avgx regr_avgy regr_count regr_intercept regr_r2 regr_slope regr_sxx regr_sxy reject rekey relational relative relaylog release release_lock relies_on relocate rely rem remainder rename repair repeat replace replicate replication required reset resetlogs resize resource respect restore restricted result result_cache resumable resume retention return returning returns reuse reverse revoke right rlike role roles rollback rolling rollup round row row_count rowdependencies rowid rownum rows rtrim rules safe salt sample save savepoint sb1 sb2 sb4 scan schema schemacheck scn scope scroll sdo_georaster sdo_topo_geometry search sec_to_time second section securefile security seed segment select self sequence sequential serializable server servererror session session_user sessions_per_user set sets settings sha sha1 sha2 share shared shared_pool short show shrink shutdown si_averagecolor si_colorhistogram si_featurelist si_positionalcolor si_stillimage si_texture siblings sid sign sin size size_t sizes skip slave sleep smalldatetimefromparts smallfile snapshot some soname sort soundex source space sparse spfile split sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_small_result sql_variant_property sqlcode sqldata sqlerror sqlname sqlstate sqrt square standalone standby start starting startup statement static statistics stats_binomial_test stats_crosstab stats_ks_test stats_mode stats_mw_test stats_one_way_anova stats_t_test_ stats_t_test_indep stats_t_test_one stats_t_test_paired stats_wsr_test status std stddev stddev_pop stddev_samp stdev stop storage store stored str str_to_date straight_join strcmp strict string struct stuff style subdate subpartition subpartitions substitutable substr substring subtime subtring_index subtype success sum suspend switch switchoffset switchover sync synchronous synonym sys sys_xmlagg sysasm sysaux sysdate sysdatetimeoffset sysdba sysoper system system_user sysutcdatetime table tables tablespace tan tdo template temporary terminated tertiary_weights test than then thread through tier ties time time_format time_zone timediff timefromparts timeout timestamp timestampadd timestampdiff timezone_abbr timezone_minute timezone_region to to_base64 to_date to_days to_seconds todatetimeoffset trace tracking transaction transactional translate translation treat trigger trigger_nestlevel triggers trim truncate try_cast try_convert try_parse type ub1 ub2 ub4 ucase unarchived unbounded uncompress under undo unhex unicode uniform uninstall union unique unix_timestamp unknown unlimited unlock unpivot unrecoverable unsafe unsigned until untrusted unusable unused update updated upgrade upped upper upsert url urowid usable usage use use_stored_outlines user user_data user_resources users using utc_date utc_timestamp uuid uuid_short validate validate_password_strength validation valist value values var var_samp varcharc vari varia variab variabl variable variables variance varp varraw varrawc varray verify version versions view virtual visible void wait wallet warning warnings week weekday weekofyear wellformed when whene whenev wheneve whenever where while whitespace with within without work wrapped xdb xml xmlagg xmlattributes xmlcast xmlcolattval xmlelement xmlexists xmlforest xmlindex xmlnamespaces xmlpi xmlquery xmlroot xmlschema xmlserialize xmltable xmltype xor year year_to_month years yearweek",literal:"true false null",built_in:"array bigint binary bit blob boolean char character date dec decimal float int int8 integer interval number numeric real record serial serial8 smallint text varchar varying void"},c:[{cN:"string",b:"'",e:"'",c:[e.BE,{b:"''"}]},{cN:"string",b:'"',e:'"',c:[e.BE,{b:'""'}]},{cN:"string",b:"`",e:"`",c:[e.BE]},e.CNM,e.CBCM,t]},e.CBCM,t]}}),e.registerLanguage("stan",function(e){return{c:[e.HCM,e.CLCM,e.CBCM,{b:e.UIR,l:e.UIR,k:{name:"for in while repeat until if then else",symbol:"bernoulli bernoulli_logit binomial binomial_logit beta_binomial hypergeometric categorical categorical_logit ordered_logistic neg_binomial neg_binomial_2 neg_binomial_2_log poisson poisson_log multinomial normal exp_mod_normal skew_normal student_t cauchy double_exponential logistic gumbel lognormal chi_square inv_chi_square scaled_inv_chi_square exponential inv_gamma weibull frechet rayleigh wiener pareto pareto_type_2 von_mises uniform multi_normal multi_normal_prec multi_normal_cholesky multi_gp multi_gp_cholesky multi_student_t gaussian_dlm_obs dirichlet lkj_corr lkj_corr_cholesky wishart inv_wishart","selector-tag":"int real vector simplex unit_vector ordered positive_ordered row_vector matrix cholesky_factor_corr cholesky_factor_cov corr_matrix cov_matrix",title:"functions model data parameters quantities transformed generated",literal:"true false"},r:0},{cN:"number",b:"0[xX][0-9a-fA-F]+[Li]?\\b",r:0},{cN:"number",b:"0[xX][0-9a-fA-F]+[Li]?\\b",r:0},{cN:"number",b:"\\d+(?:[eE][+\\-]?\\d*)?L\\b",r:0},{cN:"number",b:"\\d+\\.(?!\\d)(?:i\\b)?",r:0},{cN:"number",b:"\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d*)?i?\\b",r:0},{cN:"number",b:"\\.\\d+(?:[eE][+\\-]?\\d*)?i?\\b",r:0}]}}),e.registerLanguage("stata",function(e){return{aliases:["do","ado"],cI:!0,k:"if else in foreach for forv forva forval forvalu forvalue forvalues by bys bysort xi quietly qui capture about ac ac_7 acprplot acprplot_7 adjust ado adopath adoupdate alpha ameans an ano anov anova anova_estat anova_terms anovadef aorder ap app appe appen append arch arch_dr arch_estat arch_p archlm areg areg_p args arima arima_dr arima_estat arima_p as asmprobit asmprobit_estat asmprobit_lf asmprobit_mfx__dlg asmprobit_p ass asse asser assert avplot avplot_7 avplots avplots_7 bcskew0 bgodfrey binreg bip0_lf biplot bipp_lf bipr_lf bipr_p biprobit bitest bitesti bitowt blogit bmemsize boot bootsamp bootstrap bootstrap_8 boxco_l boxco_p boxcox boxcox_6 boxcox_p bprobit br break brier bro brow brows browse brr brrstat bs bs_7 bsampl_w bsample bsample_7 bsqreg bstat bstat_7 bstat_8 bstrap bstrap_7 ca ca_estat ca_p cabiplot camat canon canon_8 canon_8_p canon_estat canon_p cap caprojection capt captu captur capture cat cc cchart cchart_7 cci cd censobs_table centile cf char chdir checkdlgfiles checkestimationsample checkhlpfiles checksum chelp ci cii cl class classutil clear cli clis clist clo clog clog_lf clog_p clogi clogi_sw clogit clogit_lf clogit_p clogitp clogl_sw cloglog clonevar clslistarray cluster cluster_measures cluster_stop cluster_tree cluster_tree_8 clustermat cmdlog cnr cnre cnreg cnreg_p cnreg_sw cnsreg codebook collaps4 collapse colormult_nb colormult_nw compare compress conf confi confir confirm conren cons const constr constra constrai constrain constraint continue contract copy copyright copysource cor corc corr corr2data corr_anti corr_kmo corr_smc corre correl correla correlat correlate corrgram cou coun count cox cox_p cox_sw coxbase coxhaz coxvar cprplot cprplot_7 crc cret cretu cretur creturn cross cs cscript cscript_log csi ct ct_is ctset ctst_5 ctst_st cttost cumsp cumsp_7 cumul cusum cusum_7 cutil d|0 datasig datasign datasigna datasignat datasignatu datasignatur datasignature datetof db dbeta de dec deco decod decode deff des desc descr descri describ describe destring dfbeta dfgls dfuller di di_g dir dirstats dis discard disp disp_res disp_s displ displa display distinct do doe doed doedi doedit dotplot dotplot_7 dprobit drawnorm drop ds ds_util dstdize duplicates durbina dwstat dydx e|0 ed edi edit egen eivreg emdef en enc enco encod encode eq erase ereg ereg_lf ereg_p ereg_sw ereghet ereghet_glf ereghet_glf_sh ereghet_gp ereghet_ilf ereghet_ilf_sh ereghet_ip eret eretu eretur ereturn err erro error est est_cfexist est_cfname est_clickable est_expand est_hold est_table est_unhold est_unholdok estat estat_default estat_summ estat_vce_only esti estimates etodow etof etomdy ex exi exit expand expandcl fac fact facto factor factor_estat factor_p factor_pca_rotated factor_rotate factormat fcast fcast_compute fcast_graph fdades fdadesc fdadescr fdadescri fdadescrib fdadescribe fdasav fdasave fdause fh_st file open file read file close file filefilter fillin find_hlp_file findfile findit findit_7 fit fl fli flis flist for5_0 form forma format fpredict frac_154 frac_adj frac_chk frac_cox frac_ddp frac_dis frac_dv frac_in frac_mun frac_pp frac_pq frac_pv frac_wgt frac_xo fracgen fracplot fracplot_7 fracpoly fracpred fron_ex fron_hn fron_p fron_tn fron_tn2 frontier ftodate ftoe ftomdy ftowdate g|0 gamhet_glf gamhet_gp gamhet_ilf gamhet_ip gamma gamma_d2 gamma_p gamma_sw gammahet gdi_hexagon gdi_spokes ge gen gene gener genera generat generate genrank genstd genvmean gettoken gl gladder gladder_7 glim_l01 glim_l02 glim_l03 glim_l04 glim_l05 glim_l06 glim_l07 glim_l08 glim_l09 glim_l10 glim_l11 glim_l12 glim_lf glim_mu glim_nw1 glim_nw2 glim_nw3 glim_p glim_v1 glim_v2 glim_v3 glim_v4 glim_v5 glim_v6 glim_v7 glm glm_6 glm_p glm_sw glmpred glo glob globa global glogit glogit_8 glogit_p gmeans gnbre_lf gnbreg gnbreg_5 gnbreg_p gomp_lf gompe_sw gomper_p gompertz gompertzhet gomphet_glf gomphet_glf_sh gomphet_gp gomphet_ilf gomphet_ilf_sh gomphet_ip gphdot gphpen gphprint gprefs gprobi_p gprobit gprobit_8 gr gr7 gr_copy gr_current gr_db gr_describe gr_dir gr_draw gr_draw_replay gr_drop gr_edit gr_editviewopts gr_example gr_example2 gr_export gr_print gr_qscheme gr_query gr_read gr_rename gr_replay gr_save gr_set gr_setscheme gr_table gr_undo gr_use graph graph7 grebar greigen greigen_7 greigen_8 grmeanby grmeanby_7 gs_fileinfo gs_filetype gs_graphinfo gs_stat gsort gwood h|0 hadimvo hareg hausman haver he heck_d2 heckma_p heckman heckp_lf heckpr_p heckprob hel help hereg hetpr_lf hetpr_p hetprob hettest hexdump hilite hist hist_7 histogram hlogit hlu hmeans hotel hotelling hprobit hreg hsearch icd9 icd9_ff icd9p iis impute imtest inbase include inf infi infil infile infix inp inpu input ins insheet insp inspe inspec inspect integ inten intreg intreg_7 intreg_p intrg2_ll intrg_ll intrg_ll2 ipolate iqreg ir irf irf_create irfm iri is_svy is_svysum isid istdize ivprob_1_lf ivprob_lf ivprobit ivprobit_p ivreg ivreg_footnote ivtob_1_lf ivtob_lf ivtobit ivtobit_p jackknife jacknife jknife jknife_6 jknife_8 jkstat joinby kalarma1 kap kap_3 kapmeier kappa kapwgt kdensity kdensity_7 keep ksm ksmirnov ktau kwallis l|0 la lab labe label labelbook ladder levels levelsof leverage lfit lfit_p li lincom line linktest lis list lloghet_glf lloghet_glf_sh lloghet_gp lloghet_ilf lloghet_ilf_sh lloghet_ip llogi_sw llogis_p llogist llogistic llogistichet lnorm_lf lnorm_sw lnorma_p lnormal lnormalhet lnormhet_glf lnormhet_glf_sh lnormhet_gp lnormhet_ilf lnormhet_ilf_sh lnormhet_ip lnskew0 loadingplot loc loca local log logi logis_lf logistic logistic_p logit logit_estat logit_p loglogs logrank loneway lookfor lookup lowess lowess_7 lpredict lrecomp lroc lroc_7 lrtest ls lsens lsens_7 lsens_x lstat ltable ltable_7 ltriang lv lvr2plot lvr2plot_7 m|0 ma mac macr macro makecns man manova manova_estat manova_p manovatest mantel mark markin markout marksample mat mat_capp mat_order mat_put_rr mat_rapp mata mata_clear mata_describe mata_drop mata_matdescribe mata_matsave mata_matuse mata_memory mata_mlib mata_mosave mata_rename mata_which matalabel matcproc matlist matname matr matri matrix matrix_input__dlg matstrik mcc mcci md0_ md1_ md1debug_ md2_ md2debug_ mds mds_estat mds_p mdsconfig mdslong mdsmat mdsshepard mdytoe mdytof me_derd mean means median memory memsize meqparse mer merg merge mfp mfx mhelp mhodds minbound mixed_ll mixed_ll_reparm mkassert mkdir mkmat mkspline ml ml_5 ml_adjs ml_bhhhs ml_c_d ml_check ml_clear ml_cnt ml_debug ml_defd ml_e0 ml_e0_bfgs ml_e0_cycle ml_e0_dfp ml_e0i ml_e1 ml_e1_bfgs ml_e1_bhhh ml_e1_cycle ml_e1_dfp ml_e2 ml_e2_cycle ml_ebfg0 ml_ebfr0 ml_ebfr1 ml_ebh0q ml_ebhh0 ml_ebhr0 ml_ebr0i ml_ecr0i ml_edfp0 ml_edfr0 ml_edfr1 ml_edr0i ml_eds ml_eer0i ml_egr0i ml_elf ml_elf_bfgs ml_elf_bhhh ml_elf_cycle ml_elf_dfp ml_elfi ml_elfs ml_enr0i ml_enrr0 ml_erdu0 ml_erdu0_bfgs ml_erdu0_bhhh ml_erdu0_bhhhq ml_erdu0_cycle ml_erdu0_dfp ml_erdu0_nrbfgs ml_exde ml_footnote ml_geqnr ml_grad0 ml_graph ml_hbhhh ml_hd0 ml_hold ml_init ml_inv ml_log ml_max ml_mlout ml_mlout_8 ml_model ml_nb0 ml_opt ml_p ml_plot ml_query ml_rdgrd ml_repor ml_s_e ml_score ml_searc ml_technique ml_unhold mleval mlf_ mlmatbysum mlmatsum mlog mlogi mlogit mlogit_footnote mlogit_p mlopts mlsum mlvecsum mnl0_ mor more mov move mprobit mprobit_lf mprobit_p mrdu0_ mrdu1_ mvdecode mvencode mvreg mvreg_estat n|0 nbreg nbreg_al nbreg_lf nbreg_p nbreg_sw nestreg net newey newey_7 newey_p news nl nl_7 nl_9 nl_9_p nl_p nl_p_7 nlcom nlcom_p nlexp2 nlexp2_7 nlexp2a nlexp2a_7 nlexp3 nlexp3_7 nlgom3 nlgom3_7 nlgom4 nlgom4_7 nlinit nllog3 nllog3_7 nllog4 nllog4_7 nlog_rd nlogit nlogit_p nlogitgen nlogittree nlpred no nobreak noi nois noisi noisil noisily note notes notes_dlg nptrend numlabel numlist odbc old_ver olo olog ologi ologi_sw ologit ologit_p ologitp on one onew onewa oneway op_colnm op_comp op_diff op_inv op_str opr opro oprob oprob_sw oprobi oprobi_p oprobit oprobitp opts_exclusive order orthog orthpoly ou out outf outfi outfil outfile outs outsh outshe outshee outsheet ovtest pac pac_7 palette parse parse_dissim pause pca pca_8 pca_display pca_estat pca_p pca_rotate pcamat pchart pchart_7 pchi pchi_7 pcorr pctile pentium pergram pergram_7 permute permute_8 personal peto_st pkcollapse pkcross pkequiv pkexamine pkexamine_7 pkshape pksumm pksumm_7 pl plo plot plugin pnorm pnorm_7 poisgof poiss_lf poiss_sw poisso_p poisson poisson_estat post postclose postfile postutil pperron pr prais prais_e prais_e2 prais_p predict predictnl preserve print pro prob probi probit probit_estat probit_p proc_time procoverlay procrustes procrustes_estat procrustes_p profiler prog progr progra program prop proportion prtest prtesti pwcorr pwd q\\s qby qbys qchi qchi_7 qladder qladder_7 qnorm qnorm_7 qqplot qqplot_7 qreg qreg_c qreg_p qreg_sw qu quadchk quantile quantile_7 que quer query range ranksum ratio rchart rchart_7 rcof recast reclink recode reg reg3 reg3_p regdw regr regre regre_p2 regres regres_p regress regress_estat regriv_p remap ren rena renam rename renpfix repeat replace report reshape restore ret retu retur return rm rmdir robvar roccomp roccomp_7 roccomp_8 rocf_lf rocfit rocfit_8 rocgold rocplot rocplot_7 roctab roctab_7 rolling rologit rologit_p rot rota rotat rotate rotatemat rreg rreg_p ru run runtest rvfplot rvfplot_7 rvpplot rvpplot_7 sa safesum sample sampsi sav save savedresults saveold sc sca scal scala scalar scatter scm_mine sco scob_lf scob_p scobi_sw scobit scor score scoreplot scoreplot_help scree screeplot screeplot_help sdtest sdtesti se search separate seperate serrbar serrbar_7 serset set set_defaults sfrancia sh she shel shell shewhart shewhart_7 signestimationsample signrank signtest simul simul_7 simulate simulate_8 sktest sleep slogit slogit_d2 slogit_p smooth snapspan so sor sort spearman spikeplot spikeplot_7 spikeplt spline_x split sqreg sqreg_p sret sretu sretur sreturn ssc st st_ct st_hc st_hcd st_hcd_sh st_is st_issys st_note st_promo st_set st_show st_smpl st_subid stack statsby statsby_8 stbase stci stci_7 stcox stcox_estat stcox_fr stcox_fr_ll stcox_p stcox_sw stcoxkm stcoxkm_7 stcstat stcurv stcurve stcurve_7 stdes stem stepwise stereg stfill stgen stir stjoin stmc stmh stphplot stphplot_7 stphtest stphtest_7 stptime strate strate_7 streg streg_sw streset sts sts_7 stset stsplit stsum sttocc sttoct stvary stweib su suest suest_8 sum summ summa summar summari summariz summarize sunflower sureg survcurv survsum svar svar_p svmat svy svy_disp svy_dreg svy_est svy_est_7 svy_estat svy_get svy_gnbreg_p svy_head svy_header svy_heckman_p svy_heckprob_p svy_intreg_p svy_ivreg_p svy_logistic_p svy_logit_p svy_mlogit_p svy_nbreg_p svy_ologit_p svy_oprobit_p svy_poisson_p svy_probit_p svy_regress_p svy_sub svy_sub_7 svy_x svy_x_7 svy_x_p svydes svydes_8 svygen svygnbreg svyheckman svyheckprob svyintreg svyintreg_7 svyintrg svyivreg svylc svylog_p svylogit svymarkout svymarkout_8 svymean svymlog svymlogit svynbreg svyolog svyologit svyoprob svyoprobit svyopts svypois svypois_7 svypoisson svyprobit svyprobt svyprop svyprop_7 svyratio svyreg svyreg_p svyregress svyset svyset_7 svyset_8 svytab svytab_7 svytest svytotal sw sw_8 swcnreg swcox swereg swilk swlogis swlogit swologit swoprbt swpois swprobit swqreg swtobit swweib symmetry symmi symplot symplot_7 syntax sysdescribe sysdir sysuse szroeter ta tab tab1 tab2 tab_or tabd tabdi tabdis tabdisp tabi table tabodds tabodds_7 tabstat tabu tabul tabula tabulat tabulate te tempfile tempname tempvar tes test testnl testparm teststd tetrachoric time_it timer tis tob tobi tobit tobit_p tobit_sw token tokeni tokeniz tokenize tostring total translate translator transmap treat_ll treatr_p treatreg trim trnb_cons trnb_mean trpoiss_d2 trunc_ll truncr_p truncreg tsappend tset tsfill tsline tsline_ex tsreport tsrevar tsrline tsset tssmooth tsunab ttest ttesti tut_chk tut_wait tutorial tw tware_st two twoway twoway__fpfit_serset twoway__function_gen twoway__histogram_gen twoway__ipoint_serset twoway__ipoints_serset twoway__kdensity_gen twoway__lfit_serset twoway__normgen_gen twoway__pci_serset twoway__qfit_serset twoway__scatteri_serset twoway__sunflower_gen twoway_ksm_serset ty typ type typeof u|0 unab unabbrev unabcmd update us use uselabel var var_mkcompanion var_p varbasic varfcast vargranger varirf varirf_add varirf_cgraph varirf_create varirf_ctable varirf_describe varirf_dir varirf_drop varirf_erase varirf_graph varirf_ograph varirf_rename varirf_set varirf_table varlist varlmar varnorm varsoc varstable varstable_w varstable_w2 varwle vce vec vec_fevd vec_mkphi vec_p vec_p_w vecirf_create veclmar veclmar_w vecnorm vecnorm_w vecrank vecstable verinst vers versi versio version view viewsource vif vwls wdatetof webdescribe webseek webuse weib1_lf weib2_lf weib_lf weib_lf0 weibhet_glf weibhet_glf_sh weibhet_glfa weibhet_glfa_sh weibhet_gp weibhet_ilf weibhet_ilf_sh weibhet_ilfa weibhet_ilfa_sh weibhet_ip weibu_sw weibul_p weibull weibull_c weibull_s weibullhet wh whelp whi which whil while wilc_st wilcoxon win wind windo window winexec wntestb wntestb_7 wntestq xchart xchart_7 xcorr xcorr_7 xi xi_6 xmlsav xmlsave xmluse xpose xsh xshe xshel xshell xt_iis xt_tis xtab_p xtabond xtbin_p xtclog xtcloglog xtcloglog_8 xtcloglog_d2 xtcloglog_pa_p xtcloglog_re_p xtcnt_p xtcorr xtdata xtdes xtfront_p xtfrontier xtgee xtgee_elink xtgee_estat xtgee_makeivar xtgee_p xtgee_plink xtgls xtgls_p xthaus xthausman xtht_p xthtaylor xtile xtint_p xtintreg xtintreg_8 xtintreg_d2 xtintreg_p xtivp_1 xtivp_2 xtivreg xtline xtline_ex xtlogit xtlogit_8 xtlogit_d2 xtlogit_fe_p xtlogit_pa_p xtlogit_re_p xtmixed xtmixed_estat xtmixed_p xtnb_fe xtnb_lf xtnbreg xtnbreg_pa_p xtnbreg_refe_p xtpcse xtpcse_p xtpois xtpoisson xtpoisson_d2 xtpoisson_pa_p xtpoisson_refe_p xtpred xtprobit xtprobit_8 xtprobit_d2 xtprobit_re_p xtps_fe xtps_lf xtps_ren xtps_ren_8 xtrar_p xtrc xtrc_p xtrchh xtrefe_p xtreg xtreg_be xtreg_fe xtreg_ml xtreg_pa_p xtreg_re xtregar xtrere_p xtset xtsf_ll xtsf_llti xtsum xttab xttest0 xttobit xttobit_8 xttobit_p xttrans yx yxview__barlike_draw yxview_area_draw yxview_bar_draw yxview_dot_draw yxview_dropline_draw yxview_function_draw yxview_iarrow_draw yxview_ilabels_draw yxview_normal_draw yxview_pcarrow_draw yxview_pcbarrow_draw yxview_pccapsym_draw yxview_pcscatter_draw yxview_pcspike_draw yxview_rarea_draw yxview_rbar_draw yxview_rbarm_draw yxview_rcap_draw yxview_rcapsym_draw yxview_rconnected_draw yxview_rline_draw yxview_rscatter_draw yxview_rspike_draw yxview_spike_draw yxview_sunflower_draw zap_s zinb zinb_llf zinb_plf zip zip_llf zip_p zip_plf zt_ct_5 zt_hc_5 zt_hcd_5 zt_is_5 zt_iss_5 zt_sho_5 zt_smp_5 ztbase_5 ztcox_5 ztdes_5 ztereg_5 ztfill_5 ztgen_5 ztir_5 ztjoin_5 ztnb ztnb_p ztp ztp_p zts_5 ztset_5 ztspli_5 ztsum_5 zttoct_5 ztvary_5 ztweib_5",c:[{cN:"symbol",b:/`[a-zA-Z0-9_]+'/},{cN:"variable",b:/\$\{?[a-zA-Z0-9_]+\}?/},{cN:"string",v:[{b:'`"[^\r\n]*?"\''},{b:'"[^\r\n"]*"'}]},{cN:"built_in",v:[{b:"\\b(abs|acos|asin|atan|atan2|atanh|ceil|cloglog|comb|cos|digamma|exp|floor|invcloglog|invlogit|ln|lnfact|lnfactorial|lngamma|log|log10|max|min|mod|reldif|round|sign|sin|sqrt|sum|tan|tanh|trigamma|trunc|betaden|Binomial|binorm|binormal|chi2|chi2tail|dgammapda|dgammapdada|dgammapdadx|dgammapdx|dgammapdxdx|F|Fden|Ftail|gammaden|gammap|ibeta|invbinomial|invchi2|invchi2tail|invF|invFtail|invgammap|invibeta|invnchi2|invnFtail|invnibeta|invnorm|invnormal|invttail|nbetaden|nchi2|nFden|nFtail|nibeta|norm|normal|normalden|normd|npnchi2|tden|ttail|uniform|abbrev|char|index|indexnot|length|lower|ltrim|match|plural|proper|real|regexm|regexr|regexs|reverse|rtrim|string|strlen|strlower|strltrim|strmatch|strofreal|strpos|strproper|strreverse|strrtrim|strtrim|strupper|subinstr|subinword|substr|trim|upper|word|wordcount|_caller|autocode|byteorder|chop|clip|cond|e|epsdouble|epsfloat|group|inlist|inrange|irecode|matrix|maxbyte|maxdouble|maxfloat|maxint|maxlong|mi|minbyte|mindouble|minfloat|minint|minlong|missing|r|recode|replay|return|s|scalar|d|date|day|dow|doy|halfyear|mdy|month|quarter|week|year|d|daily|dofd|dofh|dofm|dofq|dofw|dofy|h|halfyearly|hofd|m|mofd|monthly|q|qofd|quarterly|tin|twithin|w|weekly|wofd|y|yearly|yh|ym|yofd|yq|yw|cholesky|colnumb|colsof|corr|det|diag|diag0cnt|el|get|hadamard|I|inv|invsym|issym|issymmetric|J|matmissing|matuniform|mreldif|nullmat|rownumb|rowsof|sweep|syminv|trace|vec|vecdiag)(?=\\(|$)"}]},e.C("^[ ]*\\*.*$",!1),e.CLCM,e.CBCM]}}),e.registerLanguage("step21",function(e){var t="[A-Z_][A-Z0-9_.]*",r={keyword:"HEADER ENDSEC DATA"},a={cN:"meta",b:"ISO-10303-21;",r:10},i={cN:"meta",b:"END-ISO-10303-21;",r:10};return{aliases:["p21","step","stp"],cI:!0,l:t,k:r,c:[a,i,e.CLCM,e.CBCM,e.C("/\\*\\*!","\\*/"),e.CNM,e.inherit(e.ASM,{i:null}),e.inherit(e.QSM,{i:null}),{cN:"string",b:"'",e:"'"},{cN:"symbol",v:[{b:"#",e:"\\d+",i:"\\W"}]}]}}),e.registerLanguage("stylus",function(e){var t={cN:"variable",b:"\\$"+e.IR},r={cN:"number",b:"#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})"},a=["charset","css","debug","extend","font-face","for","import","include","media","mixin","page","warn","while"],i=["after","before","first-letter","first-line","active","first-child","focus","hover","lang","link","visited"],n=["a","abbr","address","article","aside","audio","b","blockquote","body","button","canvas","caption","cite","code","dd","del","details","dfn","div","dl","dt","em","fieldset","figcaption","figure","footer","form","h1","h2","h3","h4","h5","h6","header","hgroup","html","i","iframe","img","input","ins","kbd","label","legend","li","mark","menu","nav","object","ol","p","q","quote","samp","section","span","strong","summary","sup","table","tbody","td","textarea","tfoot","th","thead","time","tr","ul","var","video"],o="[\\.\\s\\n\\[\\:,]",s=["align-content","align-items","align-self","animation","animation-delay","animation-direction","animation-duration","animation-fill-mode","animation-iteration-count","animation-name","animation-play-state","animation-timing-function","auto","backface-visibility","background","background-attachment","background-clip","background-color","background-image","background-origin","background-position","background-repeat","background-size","border","border-bottom","border-bottom-color","border-bottom-left-radius","border-bottom-right-radius","border-bottom-style","border-bottom-width","border-collapse","border-color","border-image","border-image-outset","border-image-repeat","border-image-slice","border-image-source","border-image-width","border-left","border-left-color","border-left-style","border-left-width","border-radius","border-right","border-right-color","border-right-style","border-right-width","border-spacing","border-style","border-top","border-top-color","border-top-left-radius","border-top-right-radius","border-top-style","border-top-width","border-width","bottom","box-decoration-break","box-shadow","box-sizing","break-after","break-before","break-inside","caption-side","clear","clip","clip-path","color","column-count","column-fill","column-gap","column-rule","column-rule-color","column-rule-style","column-rule-width","column-span","column-width","columns","content","counter-increment","counter-reset","cursor","direction","display","empty-cells","filter","flex","flex-basis","flex-direction","flex-flow","flex-grow","flex-shrink","flex-wrap","float","font","font-family","font-feature-settings","font-kerning","font-language-override","font-size","font-size-adjust","font-stretch","font-style","font-variant","font-variant-ligatures","font-weight","height","hyphens","icon","image-orientation","image-rendering","image-resolution","ime-mode","inherit","initial","justify-content","left","letter-spacing","line-height","list-style","list-style-image","list-style-position","list-style-type","margin","margin-bottom","margin-left","margin-right","margin-top","marks","mask","max-height","max-width","min-height","min-width","nav-down","nav-index","nav-left","nav-right","nav-up","none","normal","object-fit","object-position","opacity","order","orphans","outline","outline-color","outline-offset","outline-style","outline-width","overflow","overflow-wrap","overflow-x","overflow-y","padding","padding-bottom","padding-left","padding-right","padding-top","page-break-after","page-break-before","page-break-inside","perspective","perspective-origin","pointer-events","position","quotes","resize","right","tab-size","table-layout","text-align","text-align-last","text-decoration","text-decoration-color","text-decoration-line","text-decoration-style","text-indent","text-overflow","text-rendering","text-shadow","text-transform","text-underline-position","top","transform","transform-origin","transform-style","transition","transition-delay","transition-duration","transition-property","transition-timing-function","unicode-bidi","vertical-align","visibility","white-space","widows","width","word-break","word-spacing","word-wrap","z-index"],l=["\\?","(\\bReturn\\b)","(\\bEnd\\b)","(\\bend\\b)","(\\bdef\\b)",";","#\\s","\\*\\s","===\\s","\\|","%"]; -return{aliases:["styl"],cI:!1,k:"if else for in",i:"("+l.join("|")+")",c:[e.QSM,e.ASM,e.CLCM,e.CBCM,r,{b:"\\.[a-zA-Z][a-zA-Z0-9_-]*"+o,rB:!0,c:[{cN:"selector-class",b:"\\.[a-zA-Z][a-zA-Z0-9_-]*"}]},{b:"\\#[a-zA-Z][a-zA-Z0-9_-]*"+o,rB:!0,c:[{cN:"selector-id",b:"\\#[a-zA-Z][a-zA-Z0-9_-]*"}]},{b:"\\b("+n.join("|")+")"+o,rB:!0,c:[{cN:"selector-tag",b:"\\b[a-zA-Z][a-zA-Z0-9_-]*"}]},{b:"&?:?:\\b("+i.join("|")+")"+o},{b:"@("+a.join("|")+")\\b"},t,e.CSSNM,e.NM,{cN:"function",b:"^[a-zA-Z][a-zA-Z0-9_-]*\\(.*\\)",i:"[\\n]",rB:!0,c:[{cN:"title",b:"\\b[a-zA-Z][a-zA-Z0-9_-]*"},{cN:"params",b:/\(/,e:/\)/,c:[r,t,e.ASM,e.CSSNM,e.NM,e.QSM]}]},{cN:"attribute",b:"\\b("+s.reverse().join("|")+")\\b",starts:{e:/;|$/,c:[r,t,e.ASM,e.QSM,e.CSSNM,e.NM,e.CBCM],i:/\./,r:0}}]}}),e.registerLanguage("subunit",function(e){var t={cN:"string",b:"\\[\n(multipart)?",e:"\\]\n"},r={cN:"string",b:"\\d{4}-\\d{2}-\\d{2}(\\s+)\\d{2}:\\d{2}:\\d{2}.\\d+Z"},a={cN:"string",b:"(\\+|-)\\d+"},i={cN:"keyword",r:10,v:[{b:"^(test|testing|success|successful|failure|error|skip|xfail|uxsuccess)(:?)\\s+(test)?"},{b:"^progress(:?)(\\s+)?(pop|push)?"},{b:"^tags:"},{b:"^time:"}]};return{cI:!0,c:[t,r,a,i]}}),e.registerLanguage("swift",function(e){var t={keyword:"__COLUMN__ __FILE__ __FUNCTION__ __LINE__ as as! as? associativity break case catch class continue convenience default defer deinit didSet do dynamic dynamicType else enum extension fallthrough false fileprivate final for func get guard if import in indirect infix init inout internal is lazy left let mutating nil none nonmutating open operator optional override postfix precedence prefix private protocol Protocol public repeat required rethrows return right self Self set static struct subscript super switch throw throws true try try! try? Type typealias unowned var weak where while willSet",literal:"true false nil",built_in:"abs advance alignof alignofValue anyGenerator assert assertionFailure bridgeFromObjectiveC bridgeFromObjectiveCUnconditional bridgeToObjectiveC bridgeToObjectiveCUnconditional c contains count countElements countLeadingZeros debugPrint debugPrintln distance dropFirst dropLast dump encodeBitsAsWords enumerate equal fatalError filter find getBridgedObjectiveCType getVaList indices insertionSort isBridgedToObjectiveC isBridgedVerbatimToObjectiveC isUniquelyReferenced isUniquelyReferencedNonObjC join lazy lexicographicalCompare map max maxElement min minElement numericCast overlaps partition posix precondition preconditionFailure print println quickSort readLine reduce reflect reinterpretCast reverse roundUpToAlignment sizeof sizeofValue sort split startsWith stride strideof strideofValue swap toString transcode underestimateCount unsafeAddressOf unsafeBitCast unsafeDowncast unsafeUnwrap unsafeReflect withExtendedLifetime withObjectAtPlusZero withUnsafePointer withUnsafePointerToObject withUnsafeMutablePointer withUnsafeMutablePointers withUnsafePointer withUnsafePointers withVaList zip"},r={cN:"type",b:"\\b[A-Z][\\wÀ-ʸ']*",r:0},a=e.C("/\\*","\\*/",{c:["self"]}),i={cN:"subst",b:/\\\(/,e:"\\)",k:t,c:[]},n={cN:"number",b:"\\b([\\d_]+(\\.[\\deE_]+)?|0x[a-fA-F0-9_]+(\\.[a-fA-F0-9p_]+)?|0b[01_]+|0o[0-7_]+)\\b",r:0},o=e.inherit(e.QSM,{c:[i,e.BE]});return i.c=[n],{k:t,c:[o,e.CLCM,a,r,n,{cN:"function",bK:"func",e:"{",eE:!0,c:[e.inherit(e.TM,{b:/[A-Za-z$_][0-9A-Za-z$_]*/}),{b://},{cN:"params",b:/\(/,e:/\)/,endsParent:!0,k:t,c:["self",n,o,e.CBCM,{b:":"}],i:/["']/}],i:/\[|%/},{cN:"class",bK:"struct protocol class extension enum",k:t,e:"\\{",eE:!0,c:[e.inherit(e.TM,{b:/[A-Za-z$_][\u00C0-\u02B80-9A-Za-z$_]*/})]},{cN:"meta",b:"(@warn_unused_result|@exported|@lazy|@noescape|@NSCopying|@NSManaged|@objc|@convention|@required|@noreturn|@IBAction|@IBDesignable|@IBInspectable|@IBOutlet|@infix|@prefix|@postfix|@autoclosure|@testable|@available|@nonobjc|@NSApplicationMain|@UIApplicationMain)"},{bK:"import",e:/$/,c:[e.CLCM,a]}]}}),e.registerLanguage("taggerscript",function(e){var t={cN:"comment",b:/\$noop\(/,e:/\)/,c:[{b:/\(/,e:/\)/,c:["self",{b:/\\./}]}],r:10},r={cN:"keyword",b:/\$(?!noop)[a-zA-Z][_a-zA-Z0-9]*/,e:/\(/,eE:!0},a={cN:"variable",b:/%[_a-zA-Z0-9:]*/,e:"%"},i={cN:"symbol",b:/\\./};return{c:[t,r,a,i]}}),e.registerLanguage("yaml",function(e){var t="true false yes no null",r="^[ \\-]*",a="[a-zA-Z_][\\w\\-]*",i={cN:"attr",v:[{b:r+a+":"},{b:r+'"'+a+'":'},{b:r+"'"+a+"':"}]},n={cN:"template-variable",v:[{b:"{{",e:"}}"},{b:"%{",e:"}"}]},o={cN:"string",r:0,v:[{b:/'/,e:/'/},{b:/"/,e:/"/},{b:/\S+/}],c:[e.BE,n]};return{cI:!0,aliases:["yml","YAML","yaml"],c:[i,{cN:"meta",b:"^---s*$",r:10},{cN:"string",b:"[\\|>] *$",rE:!0,c:o.c,e:i.v[0].b},{b:"<%[%=-]?",e:"[%-]?%>",sL:"ruby",eB:!0,eE:!0,r:0},{cN:"type",b:"!!"+e.UIR},{cN:"meta",b:"&"+e.UIR+"$"},{cN:"meta",b:"\\*"+e.UIR+"$"},{cN:"bullet",b:"^ *-",r:0},e.HCM,{bK:t,k:{literal:t}},e.CNM,o]}}),e.registerLanguage("tap",function(e){return{cI:!0,c:[e.HCM,{cN:"meta",v:[{b:"^TAP version (\\d+)$"},{b:"^1\\.\\.(\\d+)$"}]},{b:"(s+)?---$",e:"\\.\\.\\.$",sL:"yaml",r:0},{cN:"number",b:" (\\d+) "},{cN:"symbol",v:[{b:"^ok"},{b:"^not ok"}]}]}}),e.registerLanguage("tcl",function(e){return{aliases:["tk"],k:"after append apply array auto_execok auto_import auto_load auto_mkindex auto_mkindex_old auto_qualify auto_reset bgerror binary break catch cd chan clock close concat continue dde dict encoding eof error eval exec exit expr fblocked fconfigure fcopy file fileevent filename flush for foreach format gets glob global history http if incr info interp join lappend|10 lassign|10 lindex|10 linsert|10 list llength|10 load lrange|10 lrepeat|10 lreplace|10 lreverse|10 lsearch|10 lset|10 lsort|10 mathfunc mathop memory msgcat namespace open package parray pid pkg::create pkg_mkIndex platform platform::shell proc puts pwd read refchan regexp registry regsub|10 rename return safe scan seek set socket source split string subst switch tcl_endOfWord tcl_findLibrary tcl_startOfNextWord tcl_startOfPreviousWord tcl_wordBreakAfter tcl_wordBreakBefore tcltest tclvars tell time tm trace unknown unload unset update uplevel upvar variable vwait while",c:[e.C(";[ \\t]*#","$"),e.C("^[ \\t]*#","$"),{bK:"proc",e:"[\\{]",eE:!0,c:[{cN:"title",b:"[ \\t\\n\\r]+(::)?[a-zA-Z_]((::)?[a-zA-Z0-9_])*",e:"[ \\t\\n\\r]",eW:!0,eE:!0}]},{eE:!0,v:[{b:"\\$(\\{)?(::)?[a-zA-Z_]((::)?[a-zA-Z0-9_])*\\(([a-zA-Z0-9_])*\\)",e:"[^a-zA-Z0-9_\\}\\$]"},{b:"\\$(\\{)?(::)?[a-zA-Z_]((::)?[a-zA-Z0-9_])*",e:"(\\))?[^a-zA-Z0-9_\\}\\$]"}]},{cN:"string",c:[e.BE],v:[e.inherit(e.ASM,{i:null}),e.inherit(e.QSM,{i:null})]},{cN:"number",v:[e.BNM,e.CNM]}]}}),e.registerLanguage("tex",function(e){var t={cN:"tag",b:/\\/,r:0,c:[{cN:"name",v:[{b:/[a-zA-Zа-яА-я]+[*]?/},{b:/[^a-zA-Zа-яА-я0-9]/}],starts:{eW:!0,r:0,c:[{cN:"string",v:[{b:/\[/,e:/\]/},{b:/\{/,e:/\}/}]},{b:/\s*=\s*/,eW:!0,r:0,c:[{cN:"number",b:/-?\d*\.?\d+(pt|pc|mm|cm|in|dd|cc|ex|em)?/}]}]}}]};return{c:[t,{cN:"formula",c:[t],r:0,v:[{b:/\$\$/,e:/\$\$/},{b:/\$/,e:/\$/}]},e.C("%","$",{r:0})]}}),e.registerLanguage("thrift",function(e){var t="bool byte i16 i32 i64 double string binary";return{k:{keyword:"namespace const typedef struct enum service exception void oneway set list map required optional",built_in:t,literal:"true false"},c:[e.QSM,e.NM,e.CLCM,e.CBCM,{cN:"class",bK:"struct enum service exception",e:/\{/,i:/\n/,c:[e.inherit(e.TM,{starts:{eW:!0,eE:!0}})]},{b:"\\b(set|list|map)\\s*<",e:">",k:t,c:["self"]}]}}),e.registerLanguage("tp",function(e){var t={cN:"number",b:"[1-9][0-9]*",r:0},r={cN:"symbol",b:":[^\\]]+"},a={cN:"built_in",b:"(AR|P|PAYLOAD|PR|R|SR|RSR|LBL|VR|UALM|MESSAGE|UTOOL|UFRAME|TIMER| TIMER_OVERFLOW|JOINT_MAX_SPEED|RESUME_PROG|DIAG_REC)\\[",e:"\\]",c:["self",t,r]},i={cN:"built_in",b:"(AI|AO|DI|DO|F|RI|RO|UI|UO|GI|GO|SI|SO)\\[",e:"\\]",c:["self",t,e.QSM,r]};return{k:{keyword:"ABORT ACC ADJUST AND AP_LD BREAK CALL CNT COL CONDITION CONFIG DA DB DIV DETECT ELSE END ENDFOR ERR_NUM ERROR_PROG FINE FOR GP GUARD INC IF JMP LINEAR_MAX_SPEED LOCK MOD MONITOR OFFSET Offset OR OVERRIDE PAUSE PREG PTH RT_LD RUN SELECT SKIP Skip TA TB TO TOOL_OFFSET Tool_Offset UF UT UFRAME_NUM UTOOL_NUM UNLOCK WAIT X Y Z W P R STRLEN SUBSTR FINDSTR VOFFSET PROG ATTR MN POS",literal:"ON OFF max_speed LPOS JPOS ENABLE DISABLE START STOP RESET"},c:[a,i,{cN:"keyword",b:"/(PROG|ATTR|MN|POS|END)\\b"},{cN:"keyword",b:"(CALL|RUN|POINT_LOGIC|LBL)\\b"},{cN:"keyword",b:"\\b(ACC|CNT|Skip|Offset|PSPD|RT_LD|AP_LD|Tool_Offset)"},{cN:"number",b:"\\d+(sec|msec|mm/sec|cm/min|inch/min|deg/sec|mm|in|cm)?\\b",r:0},e.C("//","[;$]"),e.C("!","[;$]"),e.C("--eg:","$"),e.QSM,{cN:"string",b:"'",e:"'"},e.CNM,{cN:"variable",b:"\\$[A-Za-z0-9_]+"}]}}),e.registerLanguage("twig",function(e){var t={cN:"params",b:"\\(",e:"\\)"},r="attribute block constant cycle date dump include max min parent random range source template_from_string",a={bK:r,k:{name:r},r:0,c:[t]},i={b:/\|[A-Za-z_]+:?/,k:"abs batch capitalize convert_encoding date date_modify default escape first format join json_encode keys last length lower merge nl2br number_format raw replace reverse round slice sort split striptags title trim upper url_encode",c:[a]},n="autoescape block do embed extends filter flush for if import include macro sandbox set spaceless use verbatim";return n=n+" "+n.split(" ").map(function(e){return"end"+e}).join(" "),{aliases:["craftcms"],cI:!0,sL:"xml",c:[e.C(/\{#/,/#}/),{cN:"template-tag",b:/\{%/,e:/%}/,c:[{cN:"name",b:/\w+/,k:n,starts:{eW:!0,c:[i,a],r:0}}]},{cN:"template-variable",b:/\{\{/,e:/}}/,c:["self",i,a]}]}}),e.registerLanguage("typescript",function(e){var t={keyword:"in if for while finally var new function do return void else break catch instanceof with throw case default try this switch continue typeof delete let yield const class public private protected get set super static implements enum export import declare type namespace abstract as from extends async await",literal:"true false null undefined NaN Infinity",built_in:"eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Error EvalError InternalError RangeError ReferenceError StopIteration SyntaxError TypeError URIError Number Math Date String RegExp Array Float32Array Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require module console window document any number boolean string void Promise"};return{aliases:["ts"],k:t,c:[{cN:"meta",b:/^\s*['"]use strict['"]/},e.ASM,e.QSM,{cN:"string",b:"`",e:"`",c:[e.BE,{cN:"subst",b:"\\$\\{",e:"\\}"}]},e.CLCM,e.CBCM,{cN:"number",v:[{b:"\\b(0[bB][01]+)"},{b:"\\b(0[oO][0-7]+)"},{b:e.CNR}],r:0},{b:"("+e.RSR+"|\\b(case|return|throw)\\b)\\s*",k:"return throw case",c:[e.CLCM,e.CBCM,e.RM,{cN:"function",b:"(\\(.*?\\)|"+e.IR+")\\s*=>",rB:!0,e:"\\s*=>",c:[{cN:"params",v:[{b:e.IR},{b:/\(\s*\)/},{b:/\(/,e:/\)/,eB:!0,eE:!0,k:t,c:["self",e.CLCM,e.CBCM]}]}]}],r:0},{cN:"function",b:"function",e:/[\{;]/,eE:!0,k:t,c:["self",e.inherit(e.TM,{b:/[A-Za-z$_][0-9A-Za-z$_]*/}),{cN:"params",b:/\(/,e:/\)/,eB:!0,eE:!0,k:t,c:[e.CLCM,e.CBCM],i:/["'\(]/}],i:/%/,r:0},{bK:"constructor",e:/\{/,eE:!0,c:["self",{cN:"params",b:/\(/,e:/\)/,eB:!0,eE:!0,k:t,c:[e.CLCM,e.CBCM],i:/["'\(]/}]},{b:/module\./,k:{built_in:"module"},r:0},{bK:"module",e:/\{/,eE:!0},{bK:"interface",e:/\{/,eE:!0,k:"interface extends"},{b:/\$[(.]/},{b:"\\."+e.IR,r:0},{cN:"meta",b:"@[A-Za-z]+"}]}}),e.registerLanguage("vala",function(e){return{k:{keyword:"char uchar unichar int uint long ulong short ushort int8 int16 int32 int64 uint8 uint16 uint32 uint64 float double bool struct enum string void weak unowned owned async signal static abstract interface override virtual delegate if while do for foreach else switch case break default return try catch public private protected internal using new this get set const stdout stdin stderr var",built_in:"DBus GLib CCode Gee Object Gtk Posix",literal:"false true null"},c:[{cN:"class",bK:"class interface namespace",e:"{",eE:!0,i:"[^,:\\n\\s\\.]",c:[e.UTM]},e.CLCM,e.CBCM,{cN:"string",b:'"""',e:'"""',r:5},e.ASM,e.QSM,e.CNM,{cN:"meta",b:"^#",e:"$",r:2}]}}),e.registerLanguage("vbnet",function(e){return{aliases:["vb"],cI:!0,k:{keyword:"addhandler addressof alias and andalso aggregate ansi as assembly auto binary by byref byval call case catch class compare const continue custom declare default delegate dim distinct do each equals else elseif end enum erase error event exit explicit finally for friend from function get global goto group handles if implements imports in inherits interface into is isfalse isnot istrue join key let lib like loop me mid mod module mustinherit mustoverride mybase myclass namespace narrowing new next not notinheritable notoverridable of off on operator option optional or order orelse overloads overridable overrides paramarray partial preserve private property protected public raiseevent readonly redim rem removehandler resume return select set shadows shared skip static step stop structure strict sub synclock take text then throw to try unicode until using when where while widening with withevents writeonly xor",built_in:"boolean byte cbool cbyte cchar cdate cdec cdbl char cint clng cobj csbyte cshort csng cstr ctype date decimal directcast double gettype getxmlnamespace iif integer long object sbyte short single string trycast typeof uinteger ulong ushort",literal:"true false nothing"},i:"//|{|}|endif|gosub|variant|wend",c:[e.inherit(e.QSM,{c:[{b:'""'}]}),e.C("'","$",{rB:!0,c:[{cN:"doctag",b:"'''|",c:[e.PWM]},{cN:"doctag",b:"",c:[e.PWM]}]}),e.CNM,{cN:"meta",b:"#",e:"$",k:{"meta-keyword":"if else elseif end region externalsource"}}]}}),e.registerLanguage("vbscript",function(e){return{aliases:["vbs"],cI:!0,k:{keyword:"call class const dim do loop erase execute executeglobal exit for each next function if then else on error option explicit new private property let get public randomize redim rem select case set stop sub while wend with end to elseif is or xor and not class_initialize class_terminate default preserve in me byval byref step resume goto",built_in:"lcase month vartype instrrev ubound setlocale getobject rgb getref string weekdayname rnd dateadd monthname now day minute isarray cbool round formatcurrency conversions csng timevalue second year space abs clng timeserial fixs len asc isempty maths dateserial atn timer isobject filter weekday datevalue ccur isdate instr datediff formatdatetime replace isnull right sgn array snumeric log cdbl hex chr lbound msgbox ucase getlocale cos cdate cbyte rtrim join hour oct typename trim strcomp int createobject loadpicture tan formatnumber mid scriptenginebuildversion scriptengine split scriptengineminorversion cint sin datepart ltrim sqr scriptenginemajorversion time derived eval date formatpercent exp inputbox left ascw chrw regexp server response request cstr err",literal:"true false null nothing empty"},i:"//",c:[e.inherit(e.QSM,{c:[{b:'""'}]}),e.C(/'/,/$/,{r:0}),e.CNM]}}),e.registerLanguage("vbscript-html",function(e){return{sL:"xml",c:[{b:"<%",e:"%>",sL:"vbscript"}]}}),e.registerLanguage("verilog",function(e){var t={keyword:"accept_on alias always always_comb always_ff always_latch and assert assign assume automatic before begin bind bins binsof bit break buf|0 bufif0 bufif1 byte case casex casez cell chandle checker class clocking cmos config const constraint context continue cover covergroup coverpoint cross deassign default defparam design disable dist do edge else end endcase endchecker endclass endclocking endconfig endfunction endgenerate endgroup endinterface endmodule endpackage endprimitive endprogram endproperty endspecify endsequence endtable endtask enum event eventually expect export extends extern final first_match for force foreach forever fork forkjoin function generate|5 genvar global highz0 highz1 if iff ifnone ignore_bins illegal_bins implements implies import incdir include initial inout input inside instance int integer interconnect interface intersect join join_any join_none large let liblist library local localparam logic longint macromodule matches medium modport module nand negedge nettype new nexttime nmos nor noshowcancelled not notif0 notif1 or output package packed parameter pmos posedge primitive priority program property protected pull0 pull1 pulldown pullup pulsestyle_ondetect pulsestyle_onevent pure rand randc randcase randsequence rcmos real realtime ref reg reject_on release repeat restrict return rnmos rpmos rtran rtranif0 rtranif1 s_always s_eventually s_nexttime s_until s_until_with scalared sequence shortint shortreal showcancelled signed small soft solve specify specparam static string strong strong0 strong1 struct super supply0 supply1 sync_accept_on sync_reject_on table tagged task this throughout time timeprecision timeunit tran tranif0 tranif1 tri tri0 tri1 triand trior trireg type typedef union unique unique0 unsigned until until_with untyped use uwire var vectored virtual void wait wait_order wand weak weak0 weak1 while wildcard wire with within wor xnor xor",literal:"null",built_in:"$finish $stop $exit $fatal $error $warning $info $realtime $time $printtimescale $bitstoreal $bitstoshortreal $itor $signed $cast $bits $stime $timeformat $realtobits $shortrealtobits $rtoi $unsigned $asserton $assertkill $assertpasson $assertfailon $assertnonvacuouson $assertoff $assertcontrol $assertpassoff $assertfailoff $assertvacuousoff $isunbounded $sampled $fell $changed $past_gclk $fell_gclk $changed_gclk $rising_gclk $steady_gclk $coverage_control $coverage_get $coverage_save $set_coverage_db_name $rose $stable $past $rose_gclk $stable_gclk $future_gclk $falling_gclk $changing_gclk $display $coverage_get_max $coverage_merge $get_coverage $load_coverage_db $typename $unpacked_dimensions $left $low $increment $clog2 $ln $log10 $exp $sqrt $pow $floor $ceil $sin $cos $tan $countbits $onehot $isunknown $fatal $warning $dimensions $right $high $size $asin $acos $atan $atan2 $hypot $sinh $cosh $tanh $asinh $acosh $atanh $countones $onehot0 $error $info $random $dist_chi_square $dist_erlang $dist_exponential $dist_normal $dist_poisson $dist_t $dist_uniform $q_initialize $q_remove $q_exam $async$and$array $async$nand$array $async$or$array $async$nor$array $sync$and$array $sync$nand$array $sync$or$array $sync$nor$array $q_add $q_full $psprintf $async$and$plane $async$nand$plane $async$or$plane $async$nor$plane $sync$and$plane $sync$nand$plane $sync$or$plane $sync$nor$plane $system $display $displayb $displayh $displayo $strobe $strobeb $strobeh $strobeo $write $readmemb $readmemh $writememh $value$plusargs $dumpvars $dumpon $dumplimit $dumpports $dumpportson $dumpportslimit $writeb $writeh $writeo $monitor $monitorb $monitorh $monitoro $writememb $dumpfile $dumpoff $dumpall $dumpflush $dumpportsoff $dumpportsall $dumpportsflush $fclose $fdisplay $fdisplayb $fdisplayh $fdisplayo $fstrobe $fstrobeb $fstrobeh $fstrobeo $swrite $swriteb $swriteh $swriteo $fscanf $fread $fseek $fflush $feof $fopen $fwrite $fwriteb $fwriteh $fwriteo $fmonitor $fmonitorb $fmonitorh $fmonitoro $sformat $sformatf $fgetc $ungetc $fgets $sscanf $rewind $ftell $ferror"};return{aliases:["v","sv","svh"],cI:!1,k:t,l:/[\w\$]+/,c:[e.CBCM,e.CLCM,e.QSM,{cN:"number",c:[e.BE],v:[{b:"\\b((\\d+'(b|h|o|d|B|H|O|D))[0-9xzXZa-fA-F_]+)"},{b:"\\B(('(b|h|o|d|B|H|O|D))[0-9xzXZa-fA-F_]+)"},{b:"\\b([0-9_])+",r:0}]},{cN:"variable",v:[{b:"#\\((?!parameter).+\\)"},{b:"\\.\\w+",r:0}]},{cN:"meta",b:"`",e:"$",k:{"meta-keyword":"define __FILE__ __LINE__ begin_keywords celldefine default_nettype define else elsif end_keywords endcelldefine endif ifdef ifndef include line nounconnected_drive pragma resetall timescale unconnected_drive undef undefineall"},r:0}]}}),e.registerLanguage("vhdl",function(e){var t="\\d(_|\\d)*",r="[eE][-+]?"+t,a=t+"(\\."+t+")?("+r+")?",i="\\w+",n=t+"#"+i+"(\\."+i+")?#("+r+")?",o="\\b("+n+"|"+a+")";return{cI:!0,k:{keyword:"abs access after alias all and architecture array assert assume assume_guarantee attribute begin block body buffer bus case component configuration constant context cover disconnect downto default else elsif end entity exit fairness file for force function generate generic group guarded if impure in inertial inout is label library linkage literal loop map mod nand new next nor not null of on open or others out package port postponed procedure process property protected pure range record register reject release rem report restrict restrict_guarantee return rol ror select sequence severity shared signal sla sll sra srl strong subtype then to transport type unaffected units until use variable vmode vprop vunit wait when while with xnor xor",built_in:"boolean bit character integer time delay_length natural positive string bit_vector file_open_kind file_open_status std_logic std_logic_vector unsigned signed boolean_vector integer_vector std_ulogic std_ulogic_vector unresolved_unsigned u_unsigned unresolved_signed u_signedreal_vector time_vector",literal:"false true note warning error failure line text side width"},i:"{",c:[e.CBCM,e.C("--","$"),e.QSM,{cN:"number",b:o,r:0},{cN:"string",b:"'(U|X|0|1|Z|W|L|H|-)'",c:[e.BE]},{cN:"symbol",b:"'[A-Za-z](_?[A-Za-z0-9])*",c:[e.BE]}]}}),e.registerLanguage("vim",function(e){return{l:/[!#@\w]+/,k:{keyword:"N|0 P|0 X|0 a|0 ab abc abo al am an|0 ar arga argd arge argdo argg argl argu as au aug aun b|0 bN ba bad bd be bel bf bl bm bn bo bp br brea breaka breakd breakl bro bufdo buffers bun bw c|0 cN cNf ca cabc caddb cad caddf cal cat cb cc ccl cd ce cex cf cfir cgetb cgete cg changes chd che checkt cl cla clo cm cmapc cme cn cnew cnf cno cnorea cnoreme co col colo com comc comp con conf cope cp cpf cq cr cs cst cu cuna cunme cw delm deb debugg delc delf dif diffg diffo diffp diffpu diffs diffthis dig di dl dell dj dli do doautoa dp dr ds dsp e|0 ea ec echoe echoh echom echon el elsei em en endfo endf endt endw ene ex exe exi exu f|0 files filet fin fina fini fir fix fo foldc foldd folddoc foldo for fu go gr grepa gu gv ha helpf helpg helpt hi hid his ia iabc if ij il im imapc ime ino inorea inoreme int is isp iu iuna iunme j|0 ju k|0 keepa kee keepj lN lNf l|0 lad laddb laddf la lan lat lb lc lch lcl lcs le lefta let lex lf lfir lgetb lgete lg lgr lgrepa lh ll lla lli lmak lm lmapc lne lnew lnf ln loadk lo loc lockv lol lope lp lpf lr ls lt lu lua luad luaf lv lvimgrepa lw m|0 ma mak map mapc marks mat me menut mes mk mks mksp mkv mkvie mod mz mzf nbc nb nbs new nm nmapc nme nn nnoreme noa no noh norea noreme norm nu nun nunme ol o|0 om omapc ome on ono onoreme opt ou ounme ow p|0 profd prof pro promptr pc ped pe perld po popu pp pre prev ps pt ptN ptf ptj ptl ptn ptp ptr pts pu pw py3 python3 py3d py3f py pyd pyf quita qa rec red redi redr redraws reg res ret retu rew ri rightb rub rubyd rubyf rund ru rv sN san sa sal sav sb sbN sba sbf sbl sbm sbn sbp sbr scrip scripte scs se setf setg setl sf sfir sh sim sig sil sl sla sm smap smapc sme sn sni sno snor snoreme sor so spelld spe spelli spellr spellu spellw sp spr sre st sta startg startr star stopi stj sts sun sunm sunme sus sv sw sy synti sync tN tabN tabc tabdo tabe tabf tabfir tabl tabm tabnew tabn tabo tabp tabr tabs tab ta tags tc tcld tclf te tf th tj tl tm tn to tp tr try ts tu u|0 undoj undol una unh unl unlo unm unme uns up ve verb vert vim vimgrepa vi viu vie vm vmapc vme vne vn vnoreme vs vu vunme windo w|0 wN wa wh wi winc winp wn wp wq wqa ws wu wv x|0 xa xmapc xm xme xn xnoreme xu xunme y|0 z|0 ~ Next Print append abbreviate abclear aboveleft all amenu anoremenu args argadd argdelete argedit argglobal arglocal argument ascii autocmd augroup aunmenu buffer bNext ball badd bdelete behave belowright bfirst blast bmodified bnext botright bprevious brewind break breakadd breakdel breaklist browse bunload bwipeout change cNext cNfile cabbrev cabclear caddbuffer caddexpr caddfile call catch cbuffer cclose center cexpr cfile cfirst cgetbuffer cgetexpr cgetfile chdir checkpath checktime clist clast close cmap cmapclear cmenu cnext cnewer cnfile cnoremap cnoreabbrev cnoremenu copy colder colorscheme command comclear compiler continue confirm copen cprevious cpfile cquit crewind cscope cstag cunmap cunabbrev cunmenu cwindow delete delmarks debug debuggreedy delcommand delfunction diffupdate diffget diffoff diffpatch diffput diffsplit digraphs display deletel djump dlist doautocmd doautoall deletep drop dsearch dsplit edit earlier echo echoerr echohl echomsg else elseif emenu endif endfor endfunction endtry endwhile enew execute exit exusage file filetype find finally finish first fixdel fold foldclose folddoopen folddoclosed foldopen function global goto grep grepadd gui gvim hardcopy help helpfind helpgrep helptags highlight hide history insert iabbrev iabclear ijump ilist imap imapclear imenu inoremap inoreabbrev inoremenu intro isearch isplit iunmap iunabbrev iunmenu join jumps keepalt keepmarks keepjumps lNext lNfile list laddexpr laddbuffer laddfile last language later lbuffer lcd lchdir lclose lcscope left leftabove lexpr lfile lfirst lgetbuffer lgetexpr lgetfile lgrep lgrepadd lhelpgrep llast llist lmake lmap lmapclear lnext lnewer lnfile lnoremap loadkeymap loadview lockmarks lockvar lolder lopen lprevious lpfile lrewind ltag lunmap luado luafile lvimgrep lvimgrepadd lwindow move mark make mapclear match menu menutranslate messages mkexrc mksession mkspell mkvimrc mkview mode mzscheme mzfile nbclose nbkey nbsart next nmap nmapclear nmenu nnoremap nnoremenu noautocmd noremap nohlsearch noreabbrev noremenu normal number nunmap nunmenu oldfiles open omap omapclear omenu only onoremap onoremenu options ounmap ounmenu ownsyntax print profdel profile promptfind promptrepl pclose pedit perl perldo pop popup ppop preserve previous psearch ptag ptNext ptfirst ptjump ptlast ptnext ptprevious ptrewind ptselect put pwd py3do py3file python pydo pyfile quit quitall qall read recover redo redir redraw redrawstatus registers resize retab return rewind right rightbelow ruby rubydo rubyfile rundo runtime rviminfo substitute sNext sandbox sargument sall saveas sbuffer sbNext sball sbfirst sblast sbmodified sbnext sbprevious sbrewind scriptnames scriptencoding scscope set setfiletype setglobal setlocal sfind sfirst shell simalt sign silent sleep slast smagic smapclear smenu snext sniff snomagic snoremap snoremenu sort source spelldump spellgood spellinfo spellrepall spellundo spellwrong split sprevious srewind stop stag startgreplace startreplace startinsert stopinsert stjump stselect sunhide sunmap sunmenu suspend sview swapname syntax syntime syncbind tNext tabNext tabclose tabedit tabfind tabfirst tablast tabmove tabnext tabonly tabprevious tabrewind tag tcl tcldo tclfile tearoff tfirst throw tjump tlast tmenu tnext topleft tprevious trewind tselect tunmenu undo undojoin undolist unabbreviate unhide unlet unlockvar unmap unmenu unsilent update vglobal version verbose vertical vimgrep vimgrepadd visual viusage view vmap vmapclear vmenu vnew vnoremap vnoremenu vsplit vunmap vunmenu write wNext wall while winsize wincmd winpos wnext wprevious wqall wsverb wundo wviminfo xit xall xmapclear xmap xmenu xnoremap xnoremenu xunmap xunmenu yank",built_in:"synIDtrans atan2 range matcharg did_filetype asin feedkeys xor argv complete_check add getwinposx getqflist getwinposy screencol clearmatches empty extend getcmdpos mzeval garbagecollect setreg ceil sqrt diff_hlID inputsecret get getfperm getpid filewritable shiftwidth max sinh isdirectory synID system inputrestore winline atan visualmode inputlist tabpagewinnr round getregtype mapcheck hasmapto histdel argidx findfile sha256 exists toupper getcmdline taglist string getmatches bufnr strftime winwidth bufexists strtrans tabpagebuflist setcmdpos remote_read printf setloclist getpos getline bufwinnr float2nr len getcmdtype diff_filler luaeval resolve libcallnr foldclosedend reverse filter has_key bufname str2float strlen setline getcharmod setbufvar index searchpos shellescape undofile foldclosed setqflist buflisted strchars str2nr virtcol floor remove undotree remote_expr winheight gettabwinvar reltime cursor tabpagenr finddir localtime acos getloclist search tanh matchend rename gettabvar strdisplaywidth type abs py3eval setwinvar tolower wildmenumode log10 spellsuggest bufloaded synconcealed nextnonblank server2client complete settabwinvar executable input wincol setmatches getftype hlID inputsave searchpair or screenrow line settabvar histadd deepcopy strpart remote_peek and eval getftime submatch screenchar winsaveview matchadd mkdir screenattr getfontname libcall reltimestr getfsize winnr invert pow getbufline byte2line soundfold repeat fnameescape tagfiles sin strwidth spellbadword trunc maparg log lispindent hostname setpos globpath remote_foreground getchar synIDattr fnamemodify cscope_connection stridx winbufnr indent min complete_add nr2char searchpairpos inputdialog values matchlist items hlexists strridx browsedir expand fmod pathshorten line2byte argc count getwinvar glob foldtextresult getreg foreground cosh matchdelete has char2nr simplify histget searchdecl iconv winrestcmd pumvisible writefile foldlevel haslocaldir keys cos matchstr foldtext histnr tan tempname getcwd byteidx getbufvar islocked escape eventhandler remote_send serverlist winrestview synstack pyeval prevnonblank readfile cindent filereadable changenr exp"},i:/;/,c:[e.NM,e.ASM,{cN:"string",b:/"(\\"|\n\\|[^"\n])*"/},e.C('"',"$"),{cN:"variable",b:/[bwtglsav]:[\w\d_]*/},{cN:"function",bK:"function function!",e:"$",r:0,c:[e.TM,{cN:"params",b:"\\(",e:"\\)"}]},{cN:"symbol",b:/<[\w-]+>/}]}}),e.registerLanguage("x86asm",function(e){return{cI:!0,l:"[.%]?"+e.IR,k:{keyword:"lock rep repe repz repne repnz xaquire xrelease bnd nobnd aaa aad aam aas adc add and arpl bb0_reset bb1_reset bound bsf bsr bswap bt btc btr bts call cbw cdq cdqe clc cld cli clts cmc cmp cmpsb cmpsd cmpsq cmpsw cmpxchg cmpxchg486 cmpxchg8b cmpxchg16b cpuid cpu_read cpu_write cqo cwd cwde daa das dec div dmint emms enter equ f2xm1 fabs fadd faddp fbld fbstp fchs fclex fcmovb fcmovbe fcmove fcmovnb fcmovnbe fcmovne fcmovnu fcmovu fcom fcomi fcomip fcomp fcompp fcos fdecstp fdisi fdiv fdivp fdivr fdivrp femms feni ffree ffreep fiadd ficom ficomp fidiv fidivr fild fimul fincstp finit fist fistp fisttp fisub fisubr fld fld1 fldcw fldenv fldl2e fldl2t fldlg2 fldln2 fldpi fldz fmul fmulp fnclex fndisi fneni fninit fnop fnsave fnstcw fnstenv fnstsw fpatan fprem fprem1 fptan frndint frstor fsave fscale fsetpm fsin fsincos fsqrt fst fstcw fstenv fstp fstsw fsub fsubp fsubr fsubrp ftst fucom fucomi fucomip fucomp fucompp fxam fxch fxtract fyl2x fyl2xp1 hlt ibts icebp idiv imul in inc incbin insb insd insw int int01 int1 int03 int3 into invd invpcid invlpg invlpga iret iretd iretq iretw jcxz jecxz jrcxz jmp jmpe lahf lar lds lea leave les lfence lfs lgdt lgs lidt lldt lmsw loadall loadall286 lodsb lodsd lodsq lodsw loop loope loopne loopnz loopz lsl lss ltr mfence monitor mov movd movq movsb movsd movsq movsw movsx movsxd movzx mul mwait neg nop not or out outsb outsd outsw packssdw packsswb packuswb paddb paddd paddsb paddsiw paddsw paddusb paddusw paddw pand pandn pause paveb pavgusb pcmpeqb pcmpeqd pcmpeqw pcmpgtb pcmpgtd pcmpgtw pdistib pf2id pfacc pfadd pfcmpeq pfcmpge pfcmpgt pfmax pfmin pfmul pfrcp pfrcpit1 pfrcpit2 pfrsqit1 pfrsqrt pfsub pfsubr pi2fd pmachriw pmaddwd pmagw pmulhriw pmulhrwa pmulhrwc pmulhw pmullw pmvgezb pmvlzb pmvnzb pmvzb pop popa popad popaw popf popfd popfq popfw por prefetch prefetchw pslld psllq psllw psrad psraw psrld psrlq psrlw psubb psubd psubsb psubsiw psubsw psubusb psubusw psubw punpckhbw punpckhdq punpckhwd punpcklbw punpckldq punpcklwd push pusha pushad pushaw pushf pushfd pushfq pushfw pxor rcl rcr rdshr rdmsr rdpmc rdtsc rdtscp ret retf retn rol ror rdm rsdc rsldt rsm rsts sahf sal salc sar sbb scasb scasd scasq scasw sfence sgdt shl shld shr shrd sidt sldt skinit smi smint smintold smsw stc std sti stosb stosd stosq stosw str sub svdc svldt svts swapgs syscall sysenter sysexit sysret test ud0 ud1 ud2b ud2 ud2a umov verr verw fwait wbinvd wrshr wrmsr xadd xbts xchg xlatb xlat xor cmove cmovz cmovne cmovnz cmova cmovnbe cmovae cmovnb cmovb cmovnae cmovbe cmovna cmovg cmovnle cmovge cmovnl cmovl cmovnge cmovle cmovng cmovc cmovnc cmovo cmovno cmovs cmovns cmovp cmovpe cmovnp cmovpo je jz jne jnz ja jnbe jae jnb jb jnae jbe jna jg jnle jge jnl jl jnge jle jng jc jnc jo jno js jns jpo jnp jpe jp sete setz setne setnz seta setnbe setae setnb setnc setb setnae setcset setbe setna setg setnle setge setnl setl setnge setle setng sets setns seto setno setpe setp setpo setnp addps addss andnps andps cmpeqps cmpeqss cmpleps cmpless cmpltps cmpltss cmpneqps cmpneqss cmpnleps cmpnless cmpnltps cmpnltss cmpordps cmpordss cmpunordps cmpunordss cmpps cmpss comiss cvtpi2ps cvtps2pi cvtsi2ss cvtss2si cvttps2pi cvttss2si divps divss ldmxcsr maxps maxss minps minss movaps movhps movlhps movlps movhlps movmskps movntps movss movups mulps mulss orps rcpps rcpss rsqrtps rsqrtss shufps sqrtps sqrtss stmxcsr subps subss ucomiss unpckhps unpcklps xorps fxrstor fxrstor64 fxsave fxsave64 xgetbv xsetbv xsave xsave64 xsaveopt xsaveopt64 xrstor xrstor64 prefetchnta prefetcht0 prefetcht1 prefetcht2 maskmovq movntq pavgb pavgw pextrw pinsrw pmaxsw pmaxub pminsw pminub pmovmskb pmulhuw psadbw pshufw pf2iw pfnacc pfpnacc pi2fw pswapd maskmovdqu clflush movntdq movnti movntpd movdqa movdqu movdq2q movq2dq paddq pmuludq pshufd pshufhw pshuflw pslldq psrldq psubq punpckhqdq punpcklqdq addpd addsd andnpd andpd cmpeqpd cmpeqsd cmplepd cmplesd cmpltpd cmpltsd cmpneqpd cmpneqsd cmpnlepd cmpnlesd cmpnltpd cmpnltsd cmpordpd cmpordsd cmpunordpd cmpunordsd cmppd comisd cvtdq2pd cvtdq2ps cvtpd2dq cvtpd2pi cvtpd2ps cvtpi2pd cvtps2dq cvtps2pd cvtsd2si cvtsd2ss cvtsi2sd cvtss2sd cvttpd2pi cvttpd2dq cvttps2dq cvttsd2si divpd divsd maxpd maxsd minpd minsd movapd movhpd movlpd movmskpd movupd mulpd mulsd orpd shufpd sqrtpd sqrtsd subpd subsd ucomisd unpckhpd unpcklpd xorpd addsubpd addsubps haddpd haddps hsubpd hsubps lddqu movddup movshdup movsldup clgi stgi vmcall vmclear vmfunc vmlaunch vmload vmmcall vmptrld vmptrst vmread vmresume vmrun vmsave vmwrite vmxoff vmxon invept invvpid pabsb pabsw pabsd palignr phaddw phaddd phaddsw phsubw phsubd phsubsw pmaddubsw pmulhrsw pshufb psignb psignw psignd extrq insertq movntsd movntss lzcnt blendpd blendps blendvpd blendvps dppd dpps extractps insertps movntdqa mpsadbw packusdw pblendvb pblendw pcmpeqq pextrb pextrd pextrq phminposuw pinsrb pinsrd pinsrq pmaxsb pmaxsd pmaxud pmaxuw pminsb pminsd pminud pminuw pmovsxbw pmovsxbd pmovsxbq pmovsxwd pmovsxwq pmovsxdq pmovzxbw pmovzxbd pmovzxbq pmovzxwd pmovzxwq pmovzxdq pmuldq pmulld ptest roundpd roundps roundsd roundss crc32 pcmpestri pcmpestrm pcmpistri pcmpistrm pcmpgtq popcnt getsec pfrcpv pfrsqrtv movbe aesenc aesenclast aesdec aesdeclast aesimc aeskeygenassist vaesenc vaesenclast vaesdec vaesdeclast vaesimc vaeskeygenassist vaddpd vaddps vaddsd vaddss vaddsubpd vaddsubps vandpd vandps vandnpd vandnps vblendpd vblendps vblendvpd vblendvps vbroadcastss vbroadcastsd vbroadcastf128 vcmpeq_ospd vcmpeqpd vcmplt_ospd vcmpltpd vcmple_ospd vcmplepd vcmpunord_qpd vcmpunordpd vcmpneq_uqpd vcmpneqpd vcmpnlt_uspd vcmpnltpd vcmpnle_uspd vcmpnlepd vcmpord_qpd vcmpordpd vcmpeq_uqpd vcmpnge_uspd vcmpngepd vcmpngt_uspd vcmpngtpd vcmpfalse_oqpd vcmpfalsepd vcmpneq_oqpd vcmpge_ospd vcmpgepd vcmpgt_ospd vcmpgtpd vcmptrue_uqpd vcmptruepd vcmplt_oqpd vcmple_oqpd vcmpunord_spd vcmpneq_uspd vcmpnlt_uqpd vcmpnle_uqpd vcmpord_spd vcmpeq_uspd vcmpnge_uqpd vcmpngt_uqpd vcmpfalse_ospd vcmpneq_ospd vcmpge_oqpd vcmpgt_oqpd vcmptrue_uspd vcmppd vcmpeq_osps vcmpeqps vcmplt_osps vcmpltps vcmple_osps vcmpleps vcmpunord_qps vcmpunordps vcmpneq_uqps vcmpneqps vcmpnlt_usps vcmpnltps vcmpnle_usps vcmpnleps vcmpord_qps vcmpordps vcmpeq_uqps vcmpnge_usps vcmpngeps vcmpngt_usps vcmpngtps vcmpfalse_oqps vcmpfalseps vcmpneq_oqps vcmpge_osps vcmpgeps vcmpgt_osps vcmpgtps vcmptrue_uqps vcmptrueps vcmplt_oqps vcmple_oqps vcmpunord_sps vcmpneq_usps vcmpnlt_uqps vcmpnle_uqps vcmpord_sps vcmpeq_usps vcmpnge_uqps vcmpngt_uqps vcmpfalse_osps vcmpneq_osps vcmpge_oqps vcmpgt_oqps vcmptrue_usps vcmpps vcmpeq_ossd vcmpeqsd vcmplt_ossd vcmpltsd vcmple_ossd vcmplesd vcmpunord_qsd vcmpunordsd vcmpneq_uqsd vcmpneqsd vcmpnlt_ussd vcmpnltsd vcmpnle_ussd vcmpnlesd vcmpord_qsd vcmpordsd vcmpeq_uqsd vcmpnge_ussd vcmpngesd vcmpngt_ussd vcmpngtsd vcmpfalse_oqsd vcmpfalsesd vcmpneq_oqsd vcmpge_ossd vcmpgesd vcmpgt_ossd vcmpgtsd vcmptrue_uqsd vcmptruesd vcmplt_oqsd vcmple_oqsd vcmpunord_ssd vcmpneq_ussd vcmpnlt_uqsd vcmpnle_uqsd vcmpord_ssd vcmpeq_ussd vcmpnge_uqsd vcmpngt_uqsd vcmpfalse_ossd vcmpneq_ossd vcmpge_oqsd vcmpgt_oqsd vcmptrue_ussd vcmpsd vcmpeq_osss vcmpeqss vcmplt_osss vcmpltss vcmple_osss vcmpless vcmpunord_qss vcmpunordss vcmpneq_uqss vcmpneqss vcmpnlt_usss vcmpnltss vcmpnle_usss vcmpnless vcmpord_qss vcmpordss vcmpeq_uqss vcmpnge_usss vcmpngess vcmpngt_usss vcmpngtss vcmpfalse_oqss vcmpfalsess vcmpneq_oqss vcmpge_osss vcmpgess vcmpgt_osss vcmpgtss vcmptrue_uqss vcmptruess vcmplt_oqss vcmple_oqss vcmpunord_sss vcmpneq_usss vcmpnlt_uqss vcmpnle_uqss vcmpord_sss vcmpeq_usss vcmpnge_uqss vcmpngt_uqss vcmpfalse_osss vcmpneq_osss vcmpge_oqss vcmpgt_oqss vcmptrue_usss vcmpss vcomisd vcomiss vcvtdq2pd vcvtdq2ps vcvtpd2dq vcvtpd2ps vcvtps2dq vcvtps2pd vcvtsd2si vcvtsd2ss vcvtsi2sd vcvtsi2ss vcvtss2sd vcvtss2si vcvttpd2dq vcvttps2dq vcvttsd2si vcvttss2si vdivpd vdivps vdivsd vdivss vdppd vdpps vextractf128 vextractps vhaddpd vhaddps vhsubpd vhsubps vinsertf128 vinsertps vlddqu vldqqu vldmxcsr vmaskmovdqu vmaskmovps vmaskmovpd vmaxpd vmaxps vmaxsd vmaxss vminpd vminps vminsd vminss vmovapd vmovaps vmovd vmovq vmovddup vmovdqa vmovqqa vmovdqu vmovqqu vmovhlps vmovhpd vmovhps vmovlhps vmovlpd vmovlps vmovmskpd vmovmskps vmovntdq vmovntqq vmovntdqa vmovntpd vmovntps vmovsd vmovshdup vmovsldup vmovss vmovupd vmovups vmpsadbw vmulpd vmulps vmulsd vmulss vorpd vorps vpabsb vpabsw vpabsd vpacksswb vpackssdw vpackuswb vpackusdw vpaddb vpaddw vpaddd vpaddq vpaddsb vpaddsw vpaddusb vpaddusw vpalignr vpand vpandn vpavgb vpavgw vpblendvb vpblendw vpcmpestri vpcmpestrm vpcmpistri vpcmpistrm vpcmpeqb vpcmpeqw vpcmpeqd vpcmpeqq vpcmpgtb vpcmpgtw vpcmpgtd vpcmpgtq vpermilpd vpermilps vperm2f128 vpextrb vpextrw vpextrd vpextrq vphaddw vphaddd vphaddsw vphminposuw vphsubw vphsubd vphsubsw vpinsrb vpinsrw vpinsrd vpinsrq vpmaddwd vpmaddubsw vpmaxsb vpmaxsw vpmaxsd vpmaxub vpmaxuw vpmaxud vpminsb vpminsw vpminsd vpminub vpminuw vpminud vpmovmskb vpmovsxbw vpmovsxbd vpmovsxbq vpmovsxwd vpmovsxwq vpmovsxdq vpmovzxbw vpmovzxbd vpmovzxbq vpmovzxwd vpmovzxwq vpmovzxdq vpmulhuw vpmulhrsw vpmulhw vpmullw vpmulld vpmuludq vpmuldq vpor vpsadbw vpshufb vpshufd vpshufhw vpshuflw vpsignb vpsignw vpsignd vpslldq vpsrldq vpsllw vpslld vpsllq vpsraw vpsrad vpsrlw vpsrld vpsrlq vptest vpsubb vpsubw vpsubd vpsubq vpsubsb vpsubsw vpsubusb vpsubusw vpunpckhbw vpunpckhwd vpunpckhdq vpunpckhqdq vpunpcklbw vpunpcklwd vpunpckldq vpunpcklqdq vpxor vrcpps vrcpss vrsqrtps vrsqrtss vroundpd vroundps vroundsd vroundss vshufpd vshufps vsqrtpd vsqrtps vsqrtsd vsqrtss vstmxcsr vsubpd vsubps vsubsd vsubss vtestps vtestpd vucomisd vucomiss vunpckhpd vunpckhps vunpcklpd vunpcklps vxorpd vxorps vzeroall vzeroupper pclmullqlqdq pclmulhqlqdq pclmullqhqdq pclmulhqhqdq pclmulqdq vpclmullqlqdq vpclmulhqlqdq vpclmullqhqdq vpclmulhqhqdq vpclmulqdq vfmadd132ps vfmadd132pd vfmadd312ps vfmadd312pd vfmadd213ps vfmadd213pd vfmadd123ps vfmadd123pd vfmadd231ps vfmadd231pd vfmadd321ps vfmadd321pd vfmaddsub132ps vfmaddsub132pd vfmaddsub312ps vfmaddsub312pd vfmaddsub213ps vfmaddsub213pd vfmaddsub123ps vfmaddsub123pd vfmaddsub231ps vfmaddsub231pd vfmaddsub321ps vfmaddsub321pd vfmsub132ps vfmsub132pd vfmsub312ps vfmsub312pd vfmsub213ps vfmsub213pd vfmsub123ps vfmsub123pd vfmsub231ps vfmsub231pd vfmsub321ps vfmsub321pd vfmsubadd132ps vfmsubadd132pd vfmsubadd312ps vfmsubadd312pd vfmsubadd213ps vfmsubadd213pd vfmsubadd123ps vfmsubadd123pd vfmsubadd231ps vfmsubadd231pd vfmsubadd321ps vfmsubadd321pd vfnmadd132ps vfnmadd132pd vfnmadd312ps vfnmadd312pd vfnmadd213ps vfnmadd213pd vfnmadd123ps vfnmadd123pd vfnmadd231ps vfnmadd231pd vfnmadd321ps vfnmadd321pd vfnmsub132ps vfnmsub132pd vfnmsub312ps vfnmsub312pd vfnmsub213ps vfnmsub213pd vfnmsub123ps vfnmsub123pd vfnmsub231ps vfnmsub231pd vfnmsub321ps vfnmsub321pd vfmadd132ss vfmadd132sd vfmadd312ss vfmadd312sd vfmadd213ss vfmadd213sd vfmadd123ss vfmadd123sd vfmadd231ss vfmadd231sd vfmadd321ss vfmadd321sd vfmsub132ss vfmsub132sd vfmsub312ss vfmsub312sd vfmsub213ss vfmsub213sd vfmsub123ss vfmsub123sd vfmsub231ss vfmsub231sd vfmsub321ss vfmsub321sd vfnmadd132ss vfnmadd132sd vfnmadd312ss vfnmadd312sd vfnmadd213ss vfnmadd213sd vfnmadd123ss vfnmadd123sd vfnmadd231ss vfnmadd231sd vfnmadd321ss vfnmadd321sd vfnmsub132ss vfnmsub132sd vfnmsub312ss vfnmsub312sd vfnmsub213ss vfnmsub213sd vfnmsub123ss vfnmsub123sd vfnmsub231ss vfnmsub231sd vfnmsub321ss vfnmsub321sd rdfsbase rdgsbase rdrand wrfsbase wrgsbase vcvtph2ps vcvtps2ph adcx adox rdseed clac stac xstore xcryptecb xcryptcbc xcryptctr xcryptcfb xcryptofb montmul xsha1 xsha256 llwpcb slwpcb lwpval lwpins vfmaddpd vfmaddps vfmaddsd vfmaddss vfmaddsubpd vfmaddsubps vfmsubaddpd vfmsubaddps vfmsubpd vfmsubps vfmsubsd vfmsubss vfnmaddpd vfnmaddps vfnmaddsd vfnmaddss vfnmsubpd vfnmsubps vfnmsubsd vfnmsubss vfrczpd vfrczps vfrczsd vfrczss vpcmov vpcomb vpcomd vpcomq vpcomub vpcomud vpcomuq vpcomuw vpcomw vphaddbd vphaddbq vphaddbw vphadddq vphaddubd vphaddubq vphaddubw vphaddudq vphadduwd vphadduwq vphaddwd vphaddwq vphsubbw vphsubdq vphsubwd vpmacsdd vpmacsdqh vpmacsdql vpmacssdd vpmacssdqh vpmacssdql vpmacsswd vpmacssww vpmacswd vpmacsww vpmadcsswd vpmadcswd vpperm vprotb vprotd vprotq vprotw vpshab vpshad vpshaq vpshaw vpshlb vpshld vpshlq vpshlw vbroadcasti128 vpblendd vpbroadcastb vpbroadcastw vpbroadcastd vpbroadcastq vpermd vpermpd vpermps vpermq vperm2i128 vextracti128 vinserti128 vpmaskmovd vpmaskmovq vpsllvd vpsllvq vpsravd vpsrlvd vpsrlvq vgatherdpd vgatherqpd vgatherdps vgatherqps vpgatherdd vpgatherqd vpgatherdq vpgatherqq xabort xbegin xend xtest andn bextr blci blcic blsi blsic blcfill blsfill blcmsk blsmsk blsr blcs bzhi mulx pdep pext rorx sarx shlx shrx tzcnt tzmsk t1mskc valignd valignq vblendmpd vblendmps vbroadcastf32x4 vbroadcastf64x4 vbroadcasti32x4 vbroadcasti64x4 vcompresspd vcompressps vcvtpd2udq vcvtps2udq vcvtsd2usi vcvtss2usi vcvttpd2udq vcvttps2udq vcvttsd2usi vcvttss2usi vcvtudq2pd vcvtudq2ps vcvtusi2sd vcvtusi2ss vexpandpd vexpandps vextractf32x4 vextractf64x4 vextracti32x4 vextracti64x4 vfixupimmpd vfixupimmps vfixupimmsd vfixupimmss vgetexppd vgetexpps vgetexpsd vgetexpss vgetmantpd vgetmantps vgetmantsd vgetmantss vinsertf32x4 vinsertf64x4 vinserti32x4 vinserti64x4 vmovdqa32 vmovdqa64 vmovdqu32 vmovdqu64 vpabsq vpandd vpandnd vpandnq vpandq vpblendmd vpblendmq vpcmpltd vpcmpled vpcmpneqd vpcmpnltd vpcmpnled vpcmpd vpcmpltq vpcmpleq vpcmpneqq vpcmpnltq vpcmpnleq vpcmpq vpcmpequd vpcmpltud vpcmpleud vpcmpnequd vpcmpnltud vpcmpnleud vpcmpud vpcmpequq vpcmpltuq vpcmpleuq vpcmpnequq vpcmpnltuq vpcmpnleuq vpcmpuq vpcompressd vpcompressq vpermi2d vpermi2pd vpermi2ps vpermi2q vpermt2d vpermt2pd vpermt2ps vpermt2q vpexpandd vpexpandq vpmaxsq vpmaxuq vpminsq vpminuq vpmovdb vpmovdw vpmovqb vpmovqd vpmovqw vpmovsdb vpmovsdw vpmovsqb vpmovsqd vpmovsqw vpmovusdb vpmovusdw vpmovusqb vpmovusqd vpmovusqw vpord vporq vprold vprolq vprolvd vprolvq vprord vprorq vprorvd vprorvq vpscatterdd vpscatterdq vpscatterqd vpscatterqq vpsraq vpsravq vpternlogd vpternlogq vptestmd vptestmq vptestnmd vptestnmq vpxord vpxorq vrcp14pd vrcp14ps vrcp14sd vrcp14ss vrndscalepd vrndscaleps vrndscalesd vrndscaless vrsqrt14pd vrsqrt14ps vrsqrt14sd vrsqrt14ss vscalefpd vscalefps vscalefsd vscalefss vscatterdpd vscatterdps vscatterqpd vscatterqps vshuff32x4 vshuff64x2 vshufi32x4 vshufi64x2 kandnw kandw kmovw knotw kortestw korw kshiftlw kshiftrw kunpckbw kxnorw kxorw vpbroadcastmb2q vpbroadcastmw2d vpconflictd vpconflictq vplzcntd vplzcntq vexp2pd vexp2ps vrcp28pd vrcp28ps vrcp28sd vrcp28ss vrsqrt28pd vrsqrt28ps vrsqrt28sd vrsqrt28ss vgatherpf0dpd vgatherpf0dps vgatherpf0qpd vgatherpf0qps vgatherpf1dpd vgatherpf1dps vgatherpf1qpd vgatherpf1qps vscatterpf0dpd vscatterpf0dps vscatterpf0qpd vscatterpf0qps vscatterpf1dpd vscatterpf1dps vscatterpf1qpd vscatterpf1qps prefetchwt1 bndmk bndcl bndcu bndcn bndmov bndldx bndstx sha1rnds4 sha1nexte sha1msg1 sha1msg2 sha256rnds2 sha256msg1 sha256msg2 hint_nop0 hint_nop1 hint_nop2 hint_nop3 hint_nop4 hint_nop5 hint_nop6 hint_nop7 hint_nop8 hint_nop9 hint_nop10 hint_nop11 hint_nop12 hint_nop13 hint_nop14 hint_nop15 hint_nop16 hint_nop17 hint_nop18 hint_nop19 hint_nop20 hint_nop21 hint_nop22 hint_nop23 hint_nop24 hint_nop25 hint_nop26 hint_nop27 hint_nop28 hint_nop29 hint_nop30 hint_nop31 hint_nop32 hint_nop33 hint_nop34 hint_nop35 hint_nop36 hint_nop37 hint_nop38 hint_nop39 hint_nop40 hint_nop41 hint_nop42 hint_nop43 hint_nop44 hint_nop45 hint_nop46 hint_nop47 hint_nop48 hint_nop49 hint_nop50 hint_nop51 hint_nop52 hint_nop53 hint_nop54 hint_nop55 hint_nop56 hint_nop57 hint_nop58 hint_nop59 hint_nop60 hint_nop61 hint_nop62 hint_nop63", -built_in:"ip eip rip al ah bl bh cl ch dl dh sil dil bpl spl r8b r9b r10b r11b r12b r13b r14b r15b ax bx cx dx si di bp sp r8w r9w r10w r11w r12w r13w r14w r15w eax ebx ecx edx esi edi ebp esp eip r8d r9d r10d r11d r12d r13d r14d r15d rax rbx rcx rdx rsi rdi rbp rsp r8 r9 r10 r11 r12 r13 r14 r15 cs ds es fs gs ss st st0 st1 st2 st3 st4 st5 st6 st7 mm0 mm1 mm2 mm3 mm4 mm5 mm6 mm7 xmm0 xmm1 xmm2 xmm3 xmm4 xmm5 xmm6 xmm7 xmm8 xmm9 xmm10 xmm11 xmm12 xmm13 xmm14 xmm15 xmm16 xmm17 xmm18 xmm19 xmm20 xmm21 xmm22 xmm23 xmm24 xmm25 xmm26 xmm27 xmm28 xmm29 xmm30 xmm31 ymm0 ymm1 ymm2 ymm3 ymm4 ymm5 ymm6 ymm7 ymm8 ymm9 ymm10 ymm11 ymm12 ymm13 ymm14 ymm15 ymm16 ymm17 ymm18 ymm19 ymm20 ymm21 ymm22 ymm23 ymm24 ymm25 ymm26 ymm27 ymm28 ymm29 ymm30 ymm31 zmm0 zmm1 zmm2 zmm3 zmm4 zmm5 zmm6 zmm7 zmm8 zmm9 zmm10 zmm11 zmm12 zmm13 zmm14 zmm15 zmm16 zmm17 zmm18 zmm19 zmm20 zmm21 zmm22 zmm23 zmm24 zmm25 zmm26 zmm27 zmm28 zmm29 zmm30 zmm31 k0 k1 k2 k3 k4 k5 k6 k7 bnd0 bnd1 bnd2 bnd3 cr0 cr1 cr2 cr3 cr4 cr8 dr0 dr1 dr2 dr3 dr8 tr3 tr4 tr5 tr6 tr7 r0 r1 r2 r3 r4 r5 r6 r7 r0b r1b r2b r3b r4b r5b r6b r7b r0w r1w r2w r3w r4w r5w r6w r7w r0d r1d r2d r3d r4d r5d r6d r7d r0h r1h r2h r3h r0l r1l r2l r3l r4l r5l r6l r7l r8l r9l r10l r11l r12l r13l r14l r15l db dw dd dq dt ddq do dy dz resb resw resd resq rest resdq reso resy resz incbin equ times byte word dword qword nosplit rel abs seg wrt strict near far a32 ptr",meta:"%define %xdefine %+ %undef %defstr %deftok %assign %strcat %strlen %substr %rotate %elif %else %endif %if %ifmacro %ifctx %ifidn %ifidni %ifid %ifnum %ifstr %iftoken %ifempty %ifenv %error %warning %fatal %rep %endrep %include %push %pop %repl %pathsearch %depend %use %arg %stacksize %local %line %comment %endcomment .nolist __FILE__ __LINE__ __SECT__ __BITS__ __OUTPUT_FORMAT__ __DATE__ __TIME__ __DATE_NUM__ __TIME_NUM__ __UTC_DATE__ __UTC_TIME__ __UTC_DATE_NUM__ __UTC_TIME_NUM__ __PASS__ struc endstruc istruc at iend align alignb sectalign daz nodaz up down zero default option assume public bits use16 use32 use64 default section segment absolute extern global common cpu float __utf16__ __utf16le__ __utf16be__ __utf32__ __utf32le__ __utf32be__ __float8__ __float16__ __float32__ __float64__ __float80m__ __float80e__ __float128l__ __float128h__ __Infinity__ __QNaN__ __SNaN__ Inf NaN QNaN SNaN float8 float16 float32 float64 float80m float80e float128l float128h __FLOAT_DAZ__ __FLOAT_ROUND__ __FLOAT__"},c:[e.C(";","$",{r:0}),{cN:"number",v:[{b:"\\b(?:([0-9][0-9_]*)?\\.[0-9_]*(?:[eE][+-]?[0-9_]+)?|(0[Xx])?[0-9][0-9_]*\\.?[0-9_]*(?:[pP](?:[+-]?[0-9_]+)?)?)\\b",r:0},{b:"\\$[0-9][0-9A-Fa-f]*",r:0},{b:"\\b(?:[0-9A-Fa-f][0-9A-Fa-f_]*[Hh]|[0-9][0-9_]*[DdTt]?|[0-7][0-7_]*[QqOo]|[0-1][0-1_]*[BbYy])\\b"},{b:"\\b(?:0[Xx][0-9A-Fa-f_]+|0[DdTt][0-9_]+|0[QqOo][0-7_]+|0[BbYy][0-1_]+)\\b"}]},e.QSM,{cN:"string",v:[{b:"'",e:"[^\\\\]'"},{b:"`",e:"[^\\\\]`"}],r:0},{cN:"symbol",v:[{b:"^\\s*[A-Za-z._?][A-Za-z0-9_$#@~.?]*(:|\\s+label)"},{b:"^\\s*%%[A-Za-z0-9_$#@~.?]*:"}],r:0},{cN:"subst",b:"%[0-9]+",r:0},{cN:"subst",b:"%!S+",r:0},{cN:"meta",b:/^\s*\.[\w_-]+/}]}}),e.registerLanguage("xl",function(e){var t="ObjectLoader Animate MovieCredits Slides Filters Shading Materials LensFlare Mapping VLCAudioVideo StereoDecoder PointCloud NetworkAccess RemoteControl RegExp ChromaKey Snowfall NodeJS Speech Charts",r={keyword:"if then else do while until for loop import with is as where when by data constant integer real text name boolean symbol infix prefix postfix block tree",literal:"true false nil",built_in:"in mod rem and or xor not abs sign floor ceil sqrt sin cos tan asin acos atan exp expm1 log log2 log10 log1p pi at text_length text_range text_find text_replace contains page slide basic_slide title_slide title subtitle fade_in fade_out fade_at clear_color color line_color line_width texture_wrap texture_transform texture scale_?x scale_?y scale_?z? translate_?x translate_?y translate_?z? rotate_?x rotate_?y rotate_?z? rectangle circle ellipse sphere path line_to move_to quad_to curve_to theme background contents locally time mouse_?x mouse_?y mouse_buttons "+t},a={cN:"string",b:'"',e:'"',i:"\\n"},i={cN:"string",b:"'",e:"'",i:"\\n"},n={cN:"string",b:"<<",e:">>"},o={cN:"number",b:"[0-9]+#[0-9A-Z_]+(\\.[0-9-A-Z_]+)?#?([Ee][+-]?[0-9]+)?"},s={bK:"import",e:"$",k:r,c:[a]},l={cN:"function",b:/[a-z][^\n]*->/,rB:!0,e:/->/,c:[e.inherit(e.TM,{starts:{eW:!0,k:r}})]};return{aliases:["tao"],l:/[a-zA-Z][a-zA-Z0-9_?]*/,k:r,c:[e.CLCM,e.CBCM,a,i,n,l,s,o,e.NM]}}),e.registerLanguage("xquery",function(e){var t="for let if while then else return where group by xquery encoding versionmodule namespace boundary-space preserve strip default collation base-uri orderingcopy-namespaces order declare import schema namespace function option in allowing emptyat tumbling window sliding window start when only end when previous next stable ascendingdescending empty greatest least some every satisfies switch case typeswitch try catch andor to union intersect instance of treat as castable cast map array delete insert intoreplace value rename copy modify update",r="false true xs:string xs:integer element item xs:date xs:datetime xs:float xs:double xs:decimal QName xs:anyURI xs:long xs:int xs:short xs:byte attribute",a={b:/\$[a-zA-Z0-9\-]+/},i={cN:"number",b:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",r:0},n={cN:"string",v:[{b:/"/,e:/"/,c:[{b:/""/,r:0}]},{b:/'/,e:/'/,c:[{b:/''/,r:0}]}]},o={cN:"meta",b:"%\\w+"},s={cN:"comment",b:"\\(:",e:":\\)",r:10,c:[{cN:"doctag",b:"@\\w+"}]},l={b:"{",e:"}"},c=[a,n,i,s,o,l];return l.c=c,{aliases:["xpath","xq"],cI:!1,l:/[a-zA-Z\$][a-zA-Z0-9_:\-]*/,i:/(proc)|(abstract)|(extends)|(until)|(#)/,k:{keyword:t,literal:r},c:c}}),e.registerLanguage("zephir",function(e){var t={cN:"string",c:[e.BE],v:[{b:'b"',e:'"'},{b:"b'",e:"'"},e.inherit(e.ASM,{i:null}),e.inherit(e.QSM,{i:null})]},r={v:[e.BNM,e.CNM]};return{aliases:["zep"],cI:!0,k:"and include_once list abstract global private echo interface as static endswitch array null if endwhile or const for endforeach self var let while isset public protected exit foreach throw elseif include __FILE__ empty require_once do xor return parent clone use __CLASS__ __LINE__ else break print eval new catch __METHOD__ case exception default die require __FUNCTION__ enddeclare final try switch continue endfor endif declare unset true false trait goto instanceof insteadof __DIR__ __NAMESPACE__ yield finally int uint long ulong char uchar double float bool boolean stringlikely unlikely",c:[e.CLCM,e.HCM,e.C("/\\*","\\*/",{c:[{cN:"doctag",b:"@[A-Za-z]+"}]}),e.C("__halt_compiler.+?;",!1,{eW:!0,k:"__halt_compiler",l:e.UIR}),{cN:"string",b:"<<<['\"]?\\w+['\"]?$",e:"^\\w+;",c:[e.BE]},{b:/(::|->)+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/},{cN:"function",bK:"function",e:/[;{]/,eE:!0,i:"\\$|\\[|%",c:[e.UTM,{cN:"params",b:"\\(",e:"\\)",c:["self",e.CBCM,t,r]}]},{cN:"class",bK:"class interface",e:"{",eE:!0,i:/[:\(\$"]/,c:[{bK:"extends implements"},e.UTM]},{bK:"namespace",e:";",i:/[\.']/,c:[e.UTM]},{bK:"use",e:";",c:[e.UTM]},{b:"=>"},t,r]}}),e}); \ No newline at end of file diff --git a/static/js/mdeditor/lib/codemirror/AUTHORS b/static/js/mdeditor/lib/codemirror/AUTHORS new file mode 100644 index 00000000..9d62d48e --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/AUTHORS @@ -0,0 +1,436 @@ +List of CodeMirror contributors. Updated before every release. + +4r2r +Aaron Brooks +Abdelouahab +Abe Fettig +Adam Ahmed +Adam King +adanlobato +Adán Lobato +Adrian Aichner +aeroson +Ahmad Amireh +Ahmad M. Zawawi +ahoward +Akeksandr Motsjonov +Alberto González Palomo +Alberto Pose +Albert Xing +Alexander Pavlov +Alexander Schepanovski +Alexander Shvets +Alexander Solovyov +Alexandre Bique +alexey-k +Alex Piggott +Aliaksei Chapyzhenka +Amsul +amuntean +Amy +Ananya Sen +anaran +AndersMad +Anders Nawroth +Anderson Mesquita +Andrea G +Andreas Reischuck +Andre von Houck +Andrey Fedorov +Andrey Klyuchnikov +Andrey Lushnikov +Andy Joslin +Andy Kimball +Andy Li +angelozerr +angelo.zerr@gmail.com +Ankit +Ankit Ahuja +Ansel Santosa +Anthony Grimes +Anton Kovalyov +areos +as3boyan +AtomicPages LLC +Atul Bhouraskar +Aurelian Oancea +Bastian Müller +Bem Jones-Bey +benbro +Beni Cherniavsky-Paskin +Benjamin DeCoste +Ben Keen +Bernhard Sirlinger +Bert Chang +Billy Moon +binny +B Krishna Chaitanya +Blaine G +blukat29 +boomyjee +borawjm +Brandon Frohs +Brandon Wamboldt +Brett Zamir +Brian Grinstead +Brian Sletten +Bruce Mitchener +Chandra Sekhar Pydi +Charles Skelton +Cheah Chu Yeow +Chris Coyier +Chris Granger +Chris Houseknecht +Chris Morgan +Christian Oyarzun +Christian Petrov +Christopher Brown +ciaranj +CodeAnimal +ComFreek +Curtis Gagliardi +dagsta +daines +Dale Jung +Dan Bentley +Dan Heberden +Daniel, Dao Quang Minh +Daniele Di Sarli +Daniel Faust +Daniel Huigens +Daniel KJ +Daniel Neel +Daniel Parnell +Danny Yoo +darealshinji +Darius Roberts +Dave Myers +David Mignot +David Pathakjee +David Vázquez +deebugger +Deep Thought +Devon Carew +dignifiedquire +Dimage Sapelkin +Dmitry Kiselyov +domagoj412 +Dominator008 +Domizio Demichelis +Doug Wikle +Drew Bratcher +Drew Hintz +Drew Khoury +Dror BG +duralog +eborden +edsharp +ekhaled +Enam Mijbah Noor +Eric Allam +eustas +Fabien O'Carroll +Fabio Zendhi Nagao +Faiza Alsaied +Fauntleroy +fbuchinger +feizhang365 +Felipe Lalanne +Felix Raab +Filip Noetzel +flack +ForbesLindesay +Forbes Lindesay +Ford_Lawnmower +Forrest Oliphant +Frank Wiegand +Gabriel Gheorghian +Gabriel Horner +Gabriel Nahmias +galambalazs +Gautam Mehta +gekkoe +Gerard Braad +Gergely Hegykozi +Giovanni Calò +Glenn Jorde +Glenn Ruehle +Golevka +Gordon Smith +Grant Skinner +greengiant +Gregory Koberger +Guillaume Massé +Guillaume Massé +Gustavo Rodrigues +Hakan Tunc +Hans Engel +Hardest +Hasan Karahan +Herculano Campos +Hiroyuki Makino +hitsthings +Hocdoc +Ian Beck +Ian Dickinson +Ian Wehrman +Ian Wetherbee +Ice White +ICHIKAWA, Yuji +ilvalle +Ingo Richter +Irakli Gozalishvili +Ivan Kurnosov +Jacob Lee +Jakob Miland +Jakub Vrana +Jakub Vrána +James Campos +James Thorne +Jamie Hill +Jan Jongboom +jankeromnes +Jan Keromnes +Jan Odvarko +Jan T. Sott +Jared Forsyth +Jason +Jason Barnabe +Jason Grout +Jason Johnston +Jason San Jose +Jason Siefken +Jaydeep Solanki +Jean Boussier +jeffkenton +Jeff Pickhardt +jem (graphite) +Jeremy Parmenter +Jochen Berger +Johan Ask +John Connor +John Lees-Miller +John Snelson +John Van Der Loo +Jonathan Malmaud +jongalloway +Jon Malmaud +Jon Sangster +Joost-Wim Boekesteijn +Joseph Pecoraro +Joshua Newman +Josh Watzman +jots +jsoojeon +Juan Benavides Romero +Jucovschi Constantin +Juho Vuori +Justin Hileman +jwallers@gmail.com +kaniga +Ken Newman +Ken Rockot +Kevin Sawicki +Kevin Ushey +Klaus Silveira +Koh Zi Han, Cliff +komakino +Konstantin Lopuhin +koops +ks-ifware +kubelsmieci +KwanEsq +Lanfei +Lanny +Laszlo Vidacs +leaf corcoran +Leonid Khachaturov +Leon Sorokin +Leonya Khachaturov +Liam Newman +LM +lochel +Lorenzo Stoakes +Luciano Longo +Luke Stagner +lynschinzer +Maksim Lin +Maksym Taran +Malay Majithia +Manuel Rego Casasnovas +Marat Dreizin +Marcel Gerber +Marco Aurélio +Marco Munizaga +Marcus Bointon +Marek Rudnicki +Marijn Haverbeke +Mário Gonçalves +Mario Pietsch +Mark Lentczner +Marko Bonaci +Martin Balek +Martín Gaitán +Martin Hasoň +Mason Malone +Mateusz Paprocki +Mathias Bynens +mats cronqvist +Matthew Beale +Matthias Bussonnier +Matthias BUSSONNIER +Matt McDonald +Matt Pass +Matt Sacks +mauricio +Maximilian Hils +Maxim Kraev +Max Kirsch +Max Xiantu +mbarkhau +Metatheos +Micah Dubinko +Michael Lehenbauer +Michael Zhou +Mighty Guava +Miguel Castillo +mihailik +Mike +Mike Brevoort +Mike Diaz +Mike Ivanov +Mike Kadin +MinRK +Miraculix87 +misfo +mloginov +Moritz Schwörer +mps +mtaran-google +Narciso Jaramillo +Nathan Williams +ndr +nerbert +nextrevision +ngn +nguillaumin +Ng Zhi An +Nicholas Bollweg +Nicholas Bollweg (Nick) +Nick Small +Niels van Groningen +nightwing +Nikita Beloglazov +Nikita Vasilyev +Nikolay Kostov +nilp0inter +Nisarg Jhaveri +nlwillia +Norman Rzepka +pablo +Page +Panupong Pasupat +paris +Patil Arpith +Patrick Stoica +Patrick Strawderman +Paul Garvin +Paul Ivanov +Pavel Feldman +Pavel Strashkin +Paweł Bartkiewicz +peteguhl +Peter Flynn +peterkroon +Peter Kroon +prasanthj +Prasanth J +Radek Piórkowski +Rahul +Randall Mason +Randy Burden +Randy Edmunds +Rasmus Erik Voel Jensen +Ray Ratchup +Richard van der Meer +Richard Z.H. Wang +Robert Crossfield +Roberto Abdelkader Martínez Pérez +robertop23 +Robert Plummer +Ruslan Osmanov +Ryan Prior +sabaca +Samuel Ainsworth +sandeepshetty +Sander AKA Redsandro +santec +Sascha Peilicke +satchmorun +sathyamoorthi +SCLINIC\jdecker +Scott Aikin +Scott Goodhew +Sebastian Zaha +shaund +shaun gilchrist +Shawn A +sheopory +Shiv Deepak +Shmuel Englard +Shubham Jain +silverwind +snasa +soliton4 +sonson +spastorelli +srajanpaliwal +Stanislav Oaserele +Stas Kobzar +Stefan Borsje +Steffen Beyer +Steve O'Hara +stoskov +Taha Jahangir +Takuji Shimokawa +Tarmil +tel +tfjgeorge +Thaddee Tyl +TheHowl +think +Thomas Dvornik +Thomas Schmid +Tim Alby +Tim Baumann +Timothy Farrell +Timothy Hatcher +TobiasBg +Tomas-A +Tomas Varaneckas +Tom Erik Støwer +Tom MacWright +Tony Jian +Travis Heppe +Triangle717 +twifkak +Vestimir Markov +vf +Vincent Woo +Volker Mische +wenli +Wesley Wiser +Will Binns-Smith +William Jamieson +William Stein +Willy +Wojtek Ptak +Xavier Mendez +Yassin N. Hassan +YNH Webdev +Yunchi Luo +Yuvi Panda +Zachary Dremann +Zhang Hao +zziuni +魏鹏刚 diff --git a/static/js/mdeditor/lib/codemirror/LICENSE b/static/js/mdeditor/lib/codemirror/LICENSE new file mode 100644 index 00000000..d21bbea5 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/LICENSE @@ -0,0 +1,19 @@ +Copyright (C) 2014 by Marijn Haverbeke and others + +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/static/js/mdeditor/lib/codemirror/README.md b/static/js/mdeditor/lib/codemirror/README.md new file mode 100644 index 00000000..bc6e7f5c --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/README.md @@ -0,0 +1,12 @@ +# CodeMirror +[![Build Status](https://travis-ci.org/codemirror/CodeMirror.svg)](https://travis-ci.org/codemirror/CodeMirror) +[![NPM version](https://img.shields.io/npm/v/codemirror.svg)](https://www.npmjs.org/package/codemirror) +[Funding status: ![maintainer happiness](https://marijnhaverbeke.nl/fund/status_s.png)](https://marijnhaverbeke.nl/fund/) + +CodeMirror is a JavaScript component that provides a code editor in +the browser. When a mode is available for the language you are coding +in, it will color your code, and optionally help with indentation. + +The project page is http://codemirror.net +The manual is at http://codemirror.net/doc/manual.html +The contributing guidelines are in [CONTRIBUTING.md](https://github.com/codemirror/CodeMirror/blob/master/CONTRIBUTING.md) diff --git a/static/js/mdeditor/lib/codemirror/addon/comment/comment.js b/static/js/mdeditor/lib/codemirror/addon/comment/comment.js new file mode 100644 index 00000000..2dd114d3 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/comment/comment.js @@ -0,0 +1,183 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var noOptions = {}; + var nonWS = /[^\s\u00a0]/; + var Pos = CodeMirror.Pos; + + function firstNonWS(str) { + var found = str.search(nonWS); + return found == -1 ? 0 : found; + } + + CodeMirror.commands.toggleComment = function(cm) { + var minLine = Infinity, ranges = cm.listSelections(), mode = null; + for (var i = ranges.length - 1; i >= 0; i--) { + var from = ranges[i].from(), to = ranges[i].to(); + if (from.line >= minLine) continue; + if (to.line >= minLine) to = Pos(minLine, 0); + minLine = from.line; + if (mode == null) { + if (cm.uncomment(from, to)) mode = "un"; + else { cm.lineComment(from, to); mode = "line"; } + } else if (mode == "un") { + cm.uncomment(from, to); + } else { + cm.lineComment(from, to); + } + } + }; + + CodeMirror.defineExtension("lineComment", function(from, to, options) { + if (!options) options = noOptions; + var self = this, mode = self.getModeAt(from); + var commentString = options.lineComment || mode.lineComment; + if (!commentString) { + if (options.blockCommentStart || mode.blockCommentStart) { + options.fullLines = true; + self.blockComment(from, to, options); + } + return; + } + var firstLine = self.getLine(from.line); + if (firstLine == null) return; + var end = Math.min(to.ch != 0 || to.line == from.line ? to.line + 1 : to.line, self.lastLine() + 1); + var pad = options.padding == null ? " " : options.padding; + var blankLines = options.commentBlankLines || from.line == to.line; + + self.operation(function() { + if (options.indent) { + var baseString = firstLine.slice(0, firstNonWS(firstLine)); + for (var i = from.line; i < end; ++i) { + var line = self.getLine(i), cut = baseString.length; + if (!blankLines && !nonWS.test(line)) continue; + if (line.slice(0, cut) != baseString) cut = firstNonWS(line); + self.replaceRange(baseString + commentString + pad, Pos(i, 0), Pos(i, cut)); + } + } else { + for (var i = from.line; i < end; ++i) { + if (blankLines || nonWS.test(self.getLine(i))) + self.replaceRange(commentString + pad, Pos(i, 0)); + } + } + }); + }); + + CodeMirror.defineExtension("blockComment", function(from, to, options) { + if (!options) options = noOptions; + var self = this, mode = self.getModeAt(from); + var startString = options.blockCommentStart || mode.blockCommentStart; + var endString = options.blockCommentEnd || mode.blockCommentEnd; + if (!startString || !endString) { + if ((options.lineComment || mode.lineComment) && options.fullLines != false) + self.lineComment(from, to, options); + return; + } + + var end = Math.min(to.line, self.lastLine()); + if (end != from.line && to.ch == 0 && nonWS.test(self.getLine(end))) --end; + + var pad = options.padding == null ? " " : options.padding; + if (from.line > end) return; + + self.operation(function() { + if (options.fullLines != false) { + var lastLineHasText = nonWS.test(self.getLine(end)); + self.replaceRange(pad + endString, Pos(end)); + self.replaceRange(startString + pad, Pos(from.line, 0)); + var lead = options.blockCommentLead || mode.blockCommentLead; + if (lead != null) for (var i = from.line + 1; i <= end; ++i) + if (i != end || lastLineHasText) + self.replaceRange(lead + pad, Pos(i, 0)); + } else { + self.replaceRange(endString, to); + self.replaceRange(startString, from); + } + }); + }); + + CodeMirror.defineExtension("uncomment", function(from, to, options) { + if (!options) options = noOptions; + var self = this, mode = self.getModeAt(from); + var end = Math.min(to.ch != 0 || to.line == from.line ? to.line : to.line - 1, self.lastLine()), start = Math.min(from.line, end); + + // Try finding line comments + var lineString = options.lineComment || mode.lineComment, lines = []; + var pad = options.padding == null ? " " : options.padding, didSomething; + lineComment: { + if (!lineString) break lineComment; + for (var i = start; i <= end; ++i) { + var line = self.getLine(i); + var found = line.indexOf(lineString); + if (found > -1 && !/comment/.test(self.getTokenTypeAt(Pos(i, found + 1)))) found = -1; + if (found == -1 && (i != end || i == start) && nonWS.test(line)) break lineComment; + if (found > -1 && nonWS.test(line.slice(0, found))) break lineComment; + lines.push(line); + } + self.operation(function() { + for (var i = start; i <= end; ++i) { + var line = lines[i - start]; + var pos = line.indexOf(lineString), endPos = pos + lineString.length; + if (pos < 0) continue; + if (line.slice(endPos, endPos + pad.length) == pad) endPos += pad.length; + didSomething = true; + self.replaceRange("", Pos(i, pos), Pos(i, endPos)); + } + }); + if (didSomething) return true; + } + + // Try block comments + var startString = options.blockCommentStart || mode.blockCommentStart; + var endString = options.blockCommentEnd || mode.blockCommentEnd; + if (!startString || !endString) return false; + var lead = options.blockCommentLead || mode.blockCommentLead; + var startLine = self.getLine(start), endLine = end == start ? startLine : self.getLine(end); + var open = startLine.indexOf(startString), close = endLine.lastIndexOf(endString); + if (close == -1 && start != end) { + endLine = self.getLine(--end); + close = endLine.lastIndexOf(endString); + } + if (open == -1 || close == -1 || + !/comment/.test(self.getTokenTypeAt(Pos(start, open + 1))) || + !/comment/.test(self.getTokenTypeAt(Pos(end, close + 1)))) + return false; + + // Avoid killing block comments completely outside the selection. + // Positions of the last startString before the start of the selection, and the first endString after it. + var lastStart = startLine.lastIndexOf(startString, from.ch); + var firstEnd = lastStart == -1 ? -1 : startLine.slice(0, from.ch).indexOf(endString, lastStart + startString.length); + if (lastStart != -1 && firstEnd != -1 && firstEnd + endString.length != from.ch) return false; + // Positions of the first endString after the end of the selection, and the last startString before it. + firstEnd = endLine.indexOf(endString, to.ch); + var almostLastStart = endLine.slice(to.ch).lastIndexOf(startString, firstEnd - to.ch); + lastStart = (firstEnd == -1 || almostLastStart == -1) ? -1 : to.ch + almostLastStart; + if (firstEnd != -1 && lastStart != -1 && lastStart != to.ch) return false; + + self.operation(function() { + self.replaceRange("", Pos(end, close - (pad && endLine.slice(close - pad.length, close) == pad ? pad.length : 0)), + Pos(end, close + endString.length)); + var openEnd = open + startString.length; + if (pad && startLine.slice(openEnd, openEnd + pad.length) == pad) openEnd += pad.length; + self.replaceRange("", Pos(start, open), Pos(start, openEnd)); + if (lead) for (var i = start + 1; i <= end; ++i) { + var line = self.getLine(i), found = line.indexOf(lead); + if (found == -1 || nonWS.test(line.slice(0, found))) continue; + var foundEnd = found + lead.length; + if (pad && line.slice(foundEnd, foundEnd + pad.length) == pad) foundEnd += pad.length; + self.replaceRange("", Pos(i, found), Pos(i, foundEnd)); + } + }); + return true; + }); +}); diff --git a/static/js/mdeditor/lib/codemirror/addon/comment/continuecomment.js b/static/js/mdeditor/lib/codemirror/addon/comment/continuecomment.js new file mode 100644 index 00000000..b11d51e6 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/comment/continuecomment.js @@ -0,0 +1,85 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + var modes = ["clike", "css", "javascript"]; + + for (var i = 0; i < modes.length; ++i) + CodeMirror.extendMode(modes[i], {blockCommentContinue: " * "}); + + function continueComment(cm) { + if (cm.getOption("disableInput")) return CodeMirror.Pass; + var ranges = cm.listSelections(), mode, inserts = []; + for (var i = 0; i < ranges.length; i++) { + var pos = ranges[i].head, token = cm.getTokenAt(pos); + if (token.type != "comment") return CodeMirror.Pass; + var modeHere = CodeMirror.innerMode(cm.getMode(), token.state).mode; + if (!mode) mode = modeHere; + else if (mode != modeHere) return CodeMirror.Pass; + + var insert = null; + if (mode.blockCommentStart && mode.blockCommentContinue) { + var end = token.string.indexOf(mode.blockCommentEnd); + var full = cm.getRange(CodeMirror.Pos(pos.line, 0), CodeMirror.Pos(pos.line, token.end)), found; + if (end != -1 && end == token.string.length - mode.blockCommentEnd.length && pos.ch >= end) { + // Comment ended, don't continue it + } else if (token.string.indexOf(mode.blockCommentStart) == 0) { + insert = full.slice(0, token.start); + if (!/^\s*$/.test(insert)) { + insert = ""; + for (var j = 0; j < token.start; ++j) insert += " "; + } + } else if ((found = full.indexOf(mode.blockCommentContinue)) != -1 && + found + mode.blockCommentContinue.length > token.start && + /^\s*$/.test(full.slice(0, found))) { + insert = full.slice(0, found); + } + if (insert != null) insert += mode.blockCommentContinue; + } + if (insert == null && mode.lineComment && continueLineCommentEnabled(cm)) { + var line = cm.getLine(pos.line), found = line.indexOf(mode.lineComment); + if (found > -1) { + insert = line.slice(0, found); + if (/\S/.test(insert)) insert = null; + else insert += mode.lineComment + line.slice(found + mode.lineComment.length).match(/^\s*/)[0]; + } + } + if (insert == null) return CodeMirror.Pass; + inserts[i] = "\n" + insert; + } + + cm.operation(function() { + for (var i = ranges.length - 1; i >= 0; i--) + cm.replaceRange(inserts[i], ranges[i].from(), ranges[i].to(), "+insert"); + }); + } + + function continueLineCommentEnabled(cm) { + var opt = cm.getOption("continueComments"); + if (opt && typeof opt == "object") + return opt.continueLineComment !== false; + return true; + } + + CodeMirror.defineOption("continueComments", null, function(cm, val, prev) { + if (prev && prev != CodeMirror.Init) + cm.removeKeyMap("continueComment"); + if (val) { + var key = "Enter"; + if (typeof val == "string") + key = val; + else if (typeof val == "object" && val.key) + key = val.key; + var map = {name: "continueComment"}; + map[key] = continueComment; + cm.addKeyMap(map); + } + }); +}); diff --git a/static/js/mdeditor/lib/codemirror/addon/dialog/dialog.css b/static/js/mdeditor/lib/codemirror/addon/dialog/dialog.css new file mode 100644 index 00000000..2e7c0fc9 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/dialog/dialog.css @@ -0,0 +1,32 @@ +.CodeMirror-dialog { + position: absolute; + left: 0; right: 0; + background: white; + z-index: 15; + padding: .1em .8em; + overflow: hidden; + color: #333; +} + +.CodeMirror-dialog-top { + border-bottom: 1px solid #eee; + top: 0; +} + +.CodeMirror-dialog-bottom { + border-top: 1px solid #eee; + bottom: 0; +} + +.CodeMirror-dialog input { + border: none; + outline: none; + background: transparent; + width: 20em; + color: inherit; + font-family: monospace; +} + +.CodeMirror-dialog button { + font-size: 70%; +} diff --git a/static/js/mdeditor/lib/codemirror/addon/dialog/dialog.js b/static/js/mdeditor/lib/codemirror/addon/dialog/dialog.js new file mode 100644 index 00000000..e0e8ad4e --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/dialog/dialog.js @@ -0,0 +1,155 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// Open simple dialogs on top of an editor. Relies on dialog.css. + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + function dialogDiv(cm, template, bottom) { + var wrap = cm.getWrapperElement(); + var dialog; + dialog = wrap.appendChild(document.createElement("div")); + if (bottom) + dialog.className = "CodeMirror-dialog CodeMirror-dialog-bottom"; + else + dialog.className = "CodeMirror-dialog CodeMirror-dialog-top"; + + if (typeof template == "string") { + dialog.innerHTML = template; + } else { // Assuming it's a detached DOM element. + dialog.appendChild(template); + } + return dialog; + } + + function closeNotification(cm, newVal) { + if (cm.state.currentNotificationClose) + cm.state.currentNotificationClose(); + cm.state.currentNotificationClose = newVal; + } + + CodeMirror.defineExtension("openDialog", function(template, callback, options) { + if (!options) options = {}; + + closeNotification(this, null); + + var dialog = dialogDiv(this, template, options.bottom); + var closed = false, me = this; + function close(newVal) { + if (typeof newVal == 'string') { + inp.value = newVal; + } else { + if (closed) return; + closed = true; + dialog.parentNode.removeChild(dialog); + me.focus(); + + if (options.onClose) options.onClose(dialog); + } + } + + var inp = dialog.getElementsByTagName("input")[0], button; + if (inp) { + if (options.value) { + inp.value = options.value; + inp.select(); + } + + if (options.onInput) + CodeMirror.on(inp, "input", function(e) { options.onInput(e, inp.value, close);}); + if (options.onKeyUp) + CodeMirror.on(inp, "keyup", function(e) {options.onKeyUp(e, inp.value, close);}); + + CodeMirror.on(inp, "keydown", function(e) { + if (options && options.onKeyDown && options.onKeyDown(e, inp.value, close)) { return; } + if (e.keyCode == 27 || (options.closeOnEnter !== false && e.keyCode == 13)) { + inp.blur(); + CodeMirror.e_stop(e); + close(); + } + if (e.keyCode == 13) callback(inp.value, e); + }); + + if (options.closeOnBlur !== false) CodeMirror.on(inp, "blur", close); + + inp.focus(); + } else if (button = dialog.getElementsByTagName("button")[0]) { + CodeMirror.on(button, "click", function() { + close(); + me.focus(); + }); + + if (options.closeOnBlur !== false) CodeMirror.on(button, "blur", close); + + button.focus(); + } + return close; + }); + + CodeMirror.defineExtension("openConfirm", function(template, callbacks, options) { + closeNotification(this, null); + var dialog = dialogDiv(this, template, options && options.bottom); + var buttons = dialog.getElementsByTagName("button"); + var closed = false, me = this, blurring = 1; + function close() { + if (closed) return; + closed = true; + dialog.parentNode.removeChild(dialog); + me.focus(); + } + buttons[0].focus(); + for (var i = 0; i < buttons.length; ++i) { + var b = buttons[i]; + (function(callback) { + CodeMirror.on(b, "click", function(e) { + CodeMirror.e_preventDefault(e); + close(); + if (callback) callback(me); + }); + })(callbacks[i]); + CodeMirror.on(b, "blur", function() { + --blurring; + setTimeout(function() { if (blurring <= 0) close(); }, 200); + }); + CodeMirror.on(b, "focus", function() { ++blurring; }); + } + }); + + /* + * openNotification + * Opens a notification, that can be closed with an optional timer + * (default 5000ms timer) and always closes on click. + * + * If a notification is opened while another is opened, it will close the + * currently opened one and open the new one immediately. + */ + CodeMirror.defineExtension("openNotification", function(template, options) { + closeNotification(this, close); + var dialog = dialogDiv(this, template, options && options.bottom); + var closed = false, doneTimer; + var duration = options && typeof options.duration !== "undefined" ? options.duration : 5000; + + function close() { + if (closed) return; + closed = true; + clearTimeout(doneTimer); + dialog.parentNode.removeChild(dialog); + } + + CodeMirror.on(dialog, 'click', function(e) { + CodeMirror.e_preventDefault(e); + close(); + }); + + if (duration) + doneTimer = setTimeout(close, duration); + + return close; + }); +}); diff --git a/static/js/mdeditor/lib/codemirror/addon/display/fullscreen.css b/static/js/mdeditor/lib/codemirror/addon/display/fullscreen.css new file mode 100644 index 00000000..437acd89 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/display/fullscreen.css @@ -0,0 +1,6 @@ +.CodeMirror-fullscreen { + position: fixed; + top: 0; left: 0; right: 0; bottom: 0; + height: auto; + z-index: 9; +} diff --git a/static/js/mdeditor/lib/codemirror/addon/display/fullscreen.js b/static/js/mdeditor/lib/codemirror/addon/display/fullscreen.js new file mode 100644 index 00000000..cd3673b9 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/display/fullscreen.js @@ -0,0 +1,41 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineOption("fullScreen", false, function(cm, val, old) { + if (old == CodeMirror.Init) old = false; + if (!old == !val) return; + if (val) setFullscreen(cm); + else setNormal(cm); + }); + + function setFullscreen(cm) { + var wrap = cm.getWrapperElement(); + cm.state.fullScreenRestore = {scrollTop: window.pageYOffset, scrollLeft: window.pageXOffset, + width: wrap.style.width, height: wrap.style.height}; + wrap.style.width = ""; + wrap.style.height = "auto"; + wrap.className += " CodeMirror-fullscreen"; + document.documentElement.style.overflow = "hidden"; + cm.refresh(); + } + + function setNormal(cm) { + var wrap = cm.getWrapperElement(); + wrap.className = wrap.className.replace(/\s*CodeMirror-fullscreen\b/, ""); + document.documentElement.style.overflow = ""; + var info = cm.state.fullScreenRestore; + wrap.style.width = info.width; wrap.style.height = info.height; + window.scrollTo(info.scrollLeft, info.scrollTop); + cm.refresh(); + } +}); diff --git a/static/js/mdeditor/lib/codemirror/addon/display/panel.js b/static/js/mdeditor/lib/codemirror/addon/display/panel.js new file mode 100644 index 00000000..22c0453e --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/display/panel.js @@ -0,0 +1,94 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + CodeMirror.defineExtension("addPanel", function(node, options) { + if (!this.state.panels) initPanels(this); + + var info = this.state.panels; + if (options && options.position == "bottom") + info.wrapper.appendChild(node); + else + info.wrapper.insertBefore(node, info.wrapper.firstChild); + var height = (options && options.height) || node.offsetHeight; + this._setSize(null, info.heightLeft -= height); + info.panels++; + return new Panel(this, node, options, height); + }); + + function Panel(cm, node, options, height) { + this.cm = cm; + this.node = node; + this.options = options; + this.height = height; + this.cleared = false; + } + + Panel.prototype.clear = function() { + if (this.cleared) return; + this.cleared = true; + var info = this.cm.state.panels; + this.cm._setSize(null, info.heightLeft += this.height); + info.wrapper.removeChild(this.node); + if (--info.panels == 0) removePanels(this.cm); + }; + + Panel.prototype.changed = function(height) { + var newHeight = height == null ? this.node.offsetHeight : height; + var info = this.cm.state.panels; + this.cm._setSize(null, info.height += (newHeight - this.height)); + this.height = newHeight; + }; + + function initPanels(cm) { + var wrap = cm.getWrapperElement(); + var style = window.getComputedStyle ? window.getComputedStyle(wrap) : wrap.currentStyle; + var height = parseInt(style.height); + var info = cm.state.panels = { + setHeight: wrap.style.height, + heightLeft: height, + panels: 0, + wrapper: document.createElement("div") + }; + wrap.parentNode.insertBefore(info.wrapper, wrap); + var hasFocus = cm.hasFocus(); + info.wrapper.appendChild(wrap); + if (hasFocus) cm.focus(); + + cm._setSize = cm.setSize; + if (height != null) cm.setSize = function(width, newHeight) { + if (newHeight == null) return this._setSize(width, newHeight); + info.setHeight = newHeight; + if (typeof newHeight != "number") { + var px = /^(\d+\.?\d*)px$/.exec(newHeight); + if (px) { + newHeight = Number(px[1]); + } else { + info.wrapper.style.height = newHeight; + newHeight = info.wrapper.offsetHeight; + info.wrapper.style.height = ""; + } + } + cm._setSize(width, info.heightLeft += (newHeight - height)); + height = newHeight; + }; + } + + function removePanels(cm) { + var info = cm.state.panels; + cm.state.panels = null; + + var wrap = cm.getWrapperElement(); + info.wrapper.parentNode.replaceChild(wrap, info.wrapper); + wrap.style.height = info.setHeight; + cm.setSize = cm._setSize; + cm.setSize(); + } +}); diff --git a/static/js/mdeditor/lib/codemirror/addon/display/placeholder.js b/static/js/mdeditor/lib/codemirror/addon/display/placeholder.js new file mode 100644 index 00000000..bb0c3931 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/display/placeholder.js @@ -0,0 +1,58 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + CodeMirror.defineOption("placeholder", "", function(cm, val, old) { + var prev = old && old != CodeMirror.Init; + if (val && !prev) { + cm.on("blur", onBlur); + cm.on("change", onChange); + onChange(cm); + } else if (!val && prev) { + cm.off("blur", onBlur); + cm.off("change", onChange); + clearPlaceholder(cm); + var wrapper = cm.getWrapperElement(); + wrapper.className = wrapper.className.replace(" CodeMirror-empty", ""); + } + + if (val && !cm.hasFocus()) onBlur(cm); + }); + + function clearPlaceholder(cm) { + if (cm.state.placeholder) { + cm.state.placeholder.parentNode.removeChild(cm.state.placeholder); + cm.state.placeholder = null; + } + } + function setPlaceholder(cm) { + clearPlaceholder(cm); + var elt = cm.state.placeholder = document.createElement("pre"); + elt.style.cssText = "height: 0; overflow: visible"; + elt.className = "CodeMirror-placeholder"; + elt.appendChild(document.createTextNode(cm.getOption("placeholder"))); + cm.display.lineSpace.insertBefore(elt, cm.display.lineSpace.firstChild); + } + + function onBlur(cm) { + if (isEmpty(cm)) setPlaceholder(cm); + } + function onChange(cm) { + var wrapper = cm.getWrapperElement(), empty = isEmpty(cm); + wrapper.className = wrapper.className.replace(" CodeMirror-empty", "") + (empty ? " CodeMirror-empty" : ""); + + if (empty) setPlaceholder(cm); + else clearPlaceholder(cm); + } + + function isEmpty(cm) { + return (cm.lineCount() === 1) && (cm.getLine(0) === ""); + } +}); diff --git a/static/js/mdeditor/lib/codemirror/addon/display/rulers.js b/static/js/mdeditor/lib/codemirror/addon/display/rulers.js new file mode 100644 index 00000000..13185d30 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/display/rulers.js @@ -0,0 +1,64 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineOption("rulers", false, function(cm, val, old) { + if (old && old != CodeMirror.Init) { + clearRulers(cm); + cm.off("refresh", refreshRulers); + } + if (val && val.length) { + setRulers(cm); + cm.on("refresh", refreshRulers); + } + }); + + function clearRulers(cm) { + for (var i = cm.display.lineSpace.childNodes.length - 1; i >= 0; i--) { + var node = cm.display.lineSpace.childNodes[i]; + if (/(^|\s)CodeMirror-ruler($|\s)/.test(node.className)) + node.parentNode.removeChild(node); + } + } + + function setRulers(cm) { + var val = cm.getOption("rulers"); + var cw = cm.defaultCharWidth(); + var left = cm.charCoords(CodeMirror.Pos(cm.firstLine(), 0), "div").left; + var minH = cm.display.scroller.offsetHeight + 30; + for (var i = 0; i < val.length; i++) { + var elt = document.createElement("div"); + elt.className = "CodeMirror-ruler"; + var col, cls = null, conf = val[i]; + if (typeof conf == "number") { + col = conf; + } else { + col = conf.column; + if (conf.className) elt.className += " " + conf.className; + if (conf.color) elt.style.borderColor = conf.color; + if (conf.lineStyle) elt.style.borderLeftStyle = conf.lineStyle; + if (conf.width) elt.style.borderLeftWidth = conf.width; + cls = val[i].className; + } + elt.style.left = (left + col * cw) + "px"; + elt.style.top = "-50px"; + elt.style.bottom = "-20px"; + elt.style.minHeight = minH + "px"; + cm.display.lineSpace.insertBefore(elt, cm.display.cursorDiv); + } + } + + function refreshRulers(cm) { + clearRulers(cm); + setRulers(cm); + } +}); diff --git a/static/js/mdeditor/lib/codemirror/addon/edit/closebrackets.js b/static/js/mdeditor/lib/codemirror/addon/edit/closebrackets.js new file mode 100644 index 00000000..ff4bb3f7 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/edit/closebrackets.js @@ -0,0 +1,161 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + var DEFAULT_BRACKETS = "()[]{}''\"\""; + var DEFAULT_TRIPLES = "'\""; + var DEFAULT_EXPLODE_ON_ENTER = "[]{}"; + var SPACE_CHAR_REGEX = /\s/; + + var Pos = CodeMirror.Pos; + + CodeMirror.defineOption("autoCloseBrackets", false, function(cm, val, old) { + if (old != CodeMirror.Init && old) + cm.removeKeyMap("autoCloseBrackets"); + if (!val) return; + var pairs = DEFAULT_BRACKETS, triples = DEFAULT_TRIPLES, explode = DEFAULT_EXPLODE_ON_ENTER; + if (typeof val == "string") pairs = val; + else if (typeof val == "object") { + if (val.pairs != null) pairs = val.pairs; + if (val.triples != null) triples = val.triples; + if (val.explode != null) explode = val.explode; + } + var map = buildKeymap(pairs, triples); + if (explode) map.Enter = buildExplodeHandler(explode); + cm.addKeyMap(map); + }); + + function charsAround(cm, pos) { + var str = cm.getRange(Pos(pos.line, pos.ch - 1), + Pos(pos.line, pos.ch + 1)); + return str.length == 2 ? str : null; + } + + // Project the token type that will exists after the given char is + // typed, and use it to determine whether it would cause the start + // of a string token. + function enteringString(cm, pos, ch) { + var line = cm.getLine(pos.line); + var token = cm.getTokenAt(pos); + if (/\bstring2?\b/.test(token.type)) return false; + var stream = new CodeMirror.StringStream(line.slice(0, pos.ch) + ch + line.slice(pos.ch), 4); + stream.pos = stream.start = token.start; + for (;;) { + var type1 = cm.getMode().token(stream, token.state); + if (stream.pos >= pos.ch + 1) return /\bstring2?\b/.test(type1); + stream.start = stream.pos; + } + } + + function buildKeymap(pairs, triples) { + var map = { + name : "autoCloseBrackets", + Backspace: function(cm) { + if (cm.getOption("disableInput")) return CodeMirror.Pass; + var ranges = cm.listSelections(); + for (var i = 0; i < ranges.length; i++) { + if (!ranges[i].empty()) return CodeMirror.Pass; + var around = charsAround(cm, ranges[i].head); + if (!around || pairs.indexOf(around) % 2 != 0) return CodeMirror.Pass; + } + for (var i = ranges.length - 1; i >= 0; i--) { + var cur = ranges[i].head; + cm.replaceRange("", Pos(cur.line, cur.ch - 1), Pos(cur.line, cur.ch + 1)); + } + } + }; + var closingBrackets = ""; + for (var i = 0; i < pairs.length; i += 2) (function(left, right) { + closingBrackets += right; + map["'" + left + "'"] = function(cm) { + if (cm.getOption("disableInput")) return CodeMirror.Pass; + var ranges = cm.listSelections(), type, next; + for (var i = 0; i < ranges.length; i++) { + var range = ranges[i], cur = range.head, curType; + var next = cm.getRange(cur, Pos(cur.line, cur.ch + 1)); + if (!range.empty()) { + curType = "surround"; + } else if (left == right && next == right) { + if (cm.getRange(cur, Pos(cur.line, cur.ch + 3)) == left + left + left) + curType = "skipThree"; + else + curType = "skip"; + } else if (left == right && cur.ch > 1 && triples.indexOf(left) >= 0 && + cm.getRange(Pos(cur.line, cur.ch - 2), cur) == left + left && + (cur.ch <= 2 || cm.getRange(Pos(cur.line, cur.ch - 3), Pos(cur.line, cur.ch - 2)) != left)) { + curType = "addFour"; + } else if (left == '"' || left == "'") { + if (!CodeMirror.isWordChar(next) && enteringString(cm, cur, left)) curType = "both"; + else return CodeMirror.Pass; + } else if (cm.getLine(cur.line).length == cur.ch || closingBrackets.indexOf(next) >= 0 || SPACE_CHAR_REGEX.test(next)) { + curType = "both"; + } else { + return CodeMirror.Pass; + } + if (!type) type = curType; + else if (type != curType) return CodeMirror.Pass; + } + + cm.operation(function() { + if (type == "skip") { + cm.execCommand("goCharRight"); + } else if (type == "skipThree") { + for (var i = 0; i < 3; i++) + cm.execCommand("goCharRight"); + } else if (type == "surround") { + var sels = cm.getSelections(); + for (var i = 0; i < sels.length; i++) + sels[i] = left + sels[i] + right; + cm.replaceSelections(sels, "around"); + } else if (type == "both") { + cm.replaceSelection(left + right, null); + cm.execCommand("goCharLeft"); + } else if (type == "addFour") { + cm.replaceSelection(left + left + left + left, "before"); + cm.execCommand("goCharRight"); + } + }); + }; + if (left != right) map["'" + right + "'"] = function(cm) { + var ranges = cm.listSelections(); + for (var i = 0; i < ranges.length; i++) { + var range = ranges[i]; + if (!range.empty() || + cm.getRange(range.head, Pos(range.head.line, range.head.ch + 1)) != right) + return CodeMirror.Pass; + } + cm.execCommand("goCharRight"); + }; + })(pairs.charAt(i), pairs.charAt(i + 1)); + return map; + } + + function buildExplodeHandler(pairs) { + return function(cm) { + if (cm.getOption("disableInput")) return CodeMirror.Pass; + var ranges = cm.listSelections(); + for (var i = 0; i < ranges.length; i++) { + if (!ranges[i].empty()) return CodeMirror.Pass; + var around = charsAround(cm, ranges[i].head); + if (!around || pairs.indexOf(around) % 2 != 0) return CodeMirror.Pass; + } + cm.operation(function() { + cm.replaceSelection("\n\n", null); + cm.execCommand("goCharLeft"); + ranges = cm.listSelections(); + for (var i = 0; i < ranges.length; i++) { + var line = ranges[i].head.line; + cm.indentLine(line, null, true); + cm.indentLine(line + 1, null, true); + } + }); + }; + } +}); diff --git a/static/js/mdeditor/lib/codemirror/addon/edit/closetag.js b/static/js/mdeditor/lib/codemirror/addon/edit/closetag.js new file mode 100644 index 00000000..e68d52d9 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/edit/closetag.js @@ -0,0 +1,166 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +/** + * Tag-closer extension for CodeMirror. + * + * This extension adds an "autoCloseTags" option that can be set to + * either true to get the default behavior, or an object to further + * configure its behavior. + * + * These are supported options: + * + * `whenClosing` (default true) + * Whether to autoclose when the '/' of a closing tag is typed. + * `whenOpening` (default true) + * Whether to autoclose the tag when the final '>' of an opening + * tag is typed. + * `dontCloseTags` (default is empty tags for HTML, none for XML) + * An array of tag names that should not be autoclosed. + * `indentTags` (default is block tags for HTML, none for XML) + * An array of tag names that should, when opened, cause a + * blank line to be added inside the tag, and the blank line and + * closing line to be indented. + * + * See demos/closetag.html for a usage example. + */ + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../fold/xml-fold")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../fold/xml-fold"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + CodeMirror.defineOption("autoCloseTags", false, function(cm, val, old) { + if (old != CodeMirror.Init && old) + cm.removeKeyMap("autoCloseTags"); + if (!val) return; + var map = {name: "autoCloseTags"}; + if (typeof val != "object" || val.whenClosing) + map["'/'"] = function(cm) { return autoCloseSlash(cm); }; + if (typeof val != "object" || val.whenOpening) + map["'>'"] = function(cm) { return autoCloseGT(cm); }; + cm.addKeyMap(map); + }); + + var htmlDontClose = ["area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", "link", "meta", "param", + "source", "track", "wbr"]; + var htmlIndent = ["applet", "blockquote", "body", "button", "div", "dl", "fieldset", "form", "frameset", "h1", "h2", "h3", "h4", + "h5", "h6", "head", "html", "iframe", "layer", "legend", "object", "ol", "p", "select", "table", "ul"]; + + function autoCloseGT(cm) { + if (cm.getOption("disableInput")) return CodeMirror.Pass; + var ranges = cm.listSelections(), replacements = []; + for (var i = 0; i < ranges.length; i++) { + if (!ranges[i].empty()) return CodeMirror.Pass; + var pos = ranges[i].head, tok = cm.getTokenAt(pos); + var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state; + if (inner.mode.name != "xml" || !state.tagName) return CodeMirror.Pass; + + var opt = cm.getOption("autoCloseTags"), html = inner.mode.configuration == "html"; + var dontCloseTags = (typeof opt == "object" && opt.dontCloseTags) || (html && htmlDontClose); + var indentTags = (typeof opt == "object" && opt.indentTags) || (html && htmlIndent); + + var tagName = state.tagName; + if (tok.end > pos.ch) tagName = tagName.slice(0, tagName.length - tok.end + pos.ch); + var lowerTagName = tagName.toLowerCase(); + // Don't process the '>' at the end of an end-tag or self-closing tag + if (!tagName || + tok.type == "string" && (tok.end != pos.ch || !/[\"\']/.test(tok.string.charAt(tok.string.length - 1)) || tok.string.length == 1) || + tok.type == "tag" && state.type == "closeTag" || + tok.string.indexOf("/") == (tok.string.length - 1) || // match something like + dontCloseTags && indexOf(dontCloseTags, lowerTagName) > -1 || + closingTagExists(cm, tagName, pos, state, true)) + return CodeMirror.Pass; + + var indent = indentTags && indexOf(indentTags, lowerTagName) > -1; + replacements[i] = {indent: indent, + text: ">" + (indent ? "\n\n" : "") + "", + newPos: indent ? CodeMirror.Pos(pos.line + 1, 0) : CodeMirror.Pos(pos.line, pos.ch + 1)}; + } + + for (var i = ranges.length - 1; i >= 0; i--) { + var info = replacements[i]; + cm.replaceRange(info.text, ranges[i].head, ranges[i].anchor, "+insert"); + var sel = cm.listSelections().slice(0); + sel[i] = {head: info.newPos, anchor: info.newPos}; + cm.setSelections(sel); + if (info.indent) { + cm.indentLine(info.newPos.line, null, true); + cm.indentLine(info.newPos.line + 1, null, true); + } + } + } + + function autoCloseCurrent(cm, typingSlash) { + var ranges = cm.listSelections(), replacements = []; + var head = typingSlash ? "/" : ""; + else if (cm.getMode().name == "htmlmixed" && inner.mode.name == "css") + replacements[i] = head + "style>"; + else + return CodeMirror.Pass; + } else { + if (!state.context || !state.context.tagName || + closingTagExists(cm, state.context.tagName, pos, state)) + return CodeMirror.Pass; + replacements[i] = head + state.context.tagName + ">"; + } + } + cm.replaceSelections(replacements); + ranges = cm.listSelections(); + for (var i = 0; i < ranges.length; i++) + if (i == ranges.length - 1 || ranges[i].head.line < ranges[i + 1].head.line) + cm.indentLine(ranges[i].head.line); + } + + function autoCloseSlash(cm) { + if (cm.getOption("disableInput")) return CodeMirror.Pass; + return autoCloseCurrent(cm, true); + } + + CodeMirror.commands.closeTag = function(cm) { return autoCloseCurrent(cm); }; + + function indexOf(collection, elt) { + if (collection.indexOf) return collection.indexOf(elt); + for (var i = 0, e = collection.length; i < e; ++i) + if (collection[i] == elt) return i; + return -1; + } + + // If xml-fold is loaded, we use its functionality to try and verify + // whether a given tag is actually unclosed. + function closingTagExists(cm, tagName, pos, state, newTag) { + if (!CodeMirror.scanForClosingTag) return false; + var end = Math.min(cm.lastLine() + 1, pos.line + 500); + var nextClose = CodeMirror.scanForClosingTag(cm, pos, null, end); + if (!nextClose || nextClose.tag != tagName) return false; + var cx = state.context; + // If the immediate wrapping context contains onCx instances of + // the same tag, a closing tag only exists if there are at least + // that many closing tags of that type following. + for (var onCx = newTag ? 1 : 0; cx && cx.tagName == tagName; cx = cx.prev) ++onCx; + pos = nextClose.to; + for (var i = 1; i < onCx; i++) { + var next = CodeMirror.scanForClosingTag(cm, pos, null, end); + if (!next || next.tag != tagName) return false; + pos = next.to; + } + return true; + } +}); diff --git a/static/js/mdeditor/lib/codemirror/addon/edit/continuelist.js b/static/js/mdeditor/lib/codemirror/addon/edit/continuelist.js new file mode 100644 index 00000000..ca8d2675 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/edit/continuelist.js @@ -0,0 +1,51 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var listRE = /^(\s*)(>[> ]*|[*+-]\s|(\d+)\.)(\s*)/, + emptyListRE = /^(\s*)(>[> ]*|[*+-]|(\d+)\.)(\s*)$/, + unorderedListRE = /[*+-]\s/; + + CodeMirror.commands.newlineAndIndentContinueMarkdownList = function(cm) { + if (cm.getOption("disableInput")) return CodeMirror.Pass; + var ranges = cm.listSelections(), replacements = []; + for (var i = 0; i < ranges.length; i++) { + var pos = ranges[i].head, match; + var eolState = cm.getStateAfter(pos.line); + var inList = eolState.list !== false; + var inQuote = eolState.quote !== false; + + if (!ranges[i].empty() || (!inList && !inQuote) || !(match = cm.getLine(pos.line).match(listRE))) { + cm.execCommand("newlineAndIndent"); + return; + } + if (cm.getLine(pos.line).match(emptyListRE)) { + cm.replaceRange("", { + line: pos.line, ch: 0 + }, { + line: pos.line, ch: pos.ch + 1 + }); + replacements[i] = "\n"; + + } else { + var indent = match[1], after = match[4]; + var bullet = unorderedListRE.test(match[2]) || match[2].indexOf(">") >= 0 + ? match[2] + : (parseInt(match[3], 10) + 1) + "."; + + replacements[i] = "\n" + indent + bullet + after; + } + } + + cm.replaceSelections(replacements); + }; +}); diff --git a/static/js/mdeditor/lib/codemirror/addon/edit/matchbrackets.js b/static/js/mdeditor/lib/codemirror/addon/edit/matchbrackets.js new file mode 100644 index 00000000..70e1ae18 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/edit/matchbrackets.js @@ -0,0 +1,120 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + var ie_lt8 = /MSIE \d/.test(navigator.userAgent) && + (document.documentMode == null || document.documentMode < 8); + + var Pos = CodeMirror.Pos; + + var matching = {"(": ")>", ")": "(<", "[": "]>", "]": "[<", "{": "}>", "}": "{<"}; + + function findMatchingBracket(cm, where, strict, config) { + var line = cm.getLineHandle(where.line), pos = where.ch - 1; + var match = (pos >= 0 && matching[line.text.charAt(pos)]) || matching[line.text.charAt(++pos)]; + if (!match) return null; + var dir = match.charAt(1) == ">" ? 1 : -1; + if (strict && (dir > 0) != (pos == where.ch)) return null; + var style = cm.getTokenTypeAt(Pos(where.line, pos + 1)); + + var found = scanForBracket(cm, Pos(where.line, pos + (dir > 0 ? 1 : 0)), dir, style || null, config); + if (found == null) return null; + return {from: Pos(where.line, pos), to: found && found.pos, + match: found && found.ch == match.charAt(0), forward: dir > 0}; + } + + // bracketRegex is used to specify which type of bracket to scan + // should be a regexp, e.g. /[[\]]/ + // + // Note: If "where" is on an open bracket, then this bracket is ignored. + // + // Returns false when no bracket was found, null when it reached + // maxScanLines and gave up + function scanForBracket(cm, where, dir, style, config) { + var maxScanLen = (config && config.maxScanLineLength) || 10000; + var maxScanLines = (config && config.maxScanLines) || 1000; + + var stack = []; + var re = config && config.bracketRegex ? config.bracketRegex : /[(){}[\]]/; + var lineEnd = dir > 0 ? Math.min(where.line + maxScanLines, cm.lastLine() + 1) + : Math.max(cm.firstLine() - 1, where.line - maxScanLines); + for (var lineNo = where.line; lineNo != lineEnd; lineNo += dir) { + var line = cm.getLine(lineNo); + if (!line) continue; + var pos = dir > 0 ? 0 : line.length - 1, end = dir > 0 ? line.length : -1; + if (line.length > maxScanLen) continue; + if (lineNo == where.line) pos = where.ch - (dir < 0 ? 1 : 0); + for (; pos != end; pos += dir) { + var ch = line.charAt(pos); + if (re.test(ch) && (style === undefined || cm.getTokenTypeAt(Pos(lineNo, pos + 1)) == style)) { + var match = matching[ch]; + if ((match.charAt(1) == ">") == (dir > 0)) stack.push(ch); + else if (!stack.length) return {pos: Pos(lineNo, pos), ch: ch}; + else stack.pop(); + } + } + } + return lineNo - dir == (dir > 0 ? cm.lastLine() : cm.firstLine()) ? false : null; + } + + function matchBrackets(cm, autoclear, config) { + // Disable brace matching in long lines, since it'll cause hugely slow updates + var maxHighlightLen = cm.state.matchBrackets.maxHighlightLineLength || 1000; + var marks = [], ranges = cm.listSelections(); + for (var i = 0; i < ranges.length; i++) { + var match = ranges[i].empty() && findMatchingBracket(cm, ranges[i].head, false, config); + if (match && cm.getLine(match.from.line).length <= maxHighlightLen) { + var style = match.match ? "CodeMirror-matchingbracket" : "CodeMirror-nonmatchingbracket"; + marks.push(cm.markText(match.from, Pos(match.from.line, match.from.ch + 1), {className: style})); + if (match.to && cm.getLine(match.to.line).length <= maxHighlightLen) + marks.push(cm.markText(match.to, Pos(match.to.line, match.to.ch + 1), {className: style})); + } + } + + if (marks.length) { + // Kludge to work around the IE bug from issue #1193, where text + // input stops going to the textare whever this fires. + if (ie_lt8 && cm.state.focused) cm.focus(); + + var clear = function() { + cm.operation(function() { + for (var i = 0; i < marks.length; i++) marks[i].clear(); + }); + }; + if (autoclear) setTimeout(clear, 800); + else return clear; + } + } + + var currentlyHighlighted = null; + function doMatchBrackets(cm) { + cm.operation(function() { + if (currentlyHighlighted) {currentlyHighlighted(); currentlyHighlighted = null;} + currentlyHighlighted = matchBrackets(cm, false, cm.state.matchBrackets); + }); + } + + CodeMirror.defineOption("matchBrackets", false, function(cm, val, old) { + if (old && old != CodeMirror.Init) + cm.off("cursorActivity", doMatchBrackets); + if (val) { + cm.state.matchBrackets = typeof val == "object" ? val : {}; + cm.on("cursorActivity", doMatchBrackets); + } + }); + + CodeMirror.defineExtension("matchBrackets", function() {matchBrackets(this, true);}); + CodeMirror.defineExtension("findMatchingBracket", function(pos, strict, config){ + return findMatchingBracket(this, pos, strict, config); + }); + CodeMirror.defineExtension("scanForBracket", function(pos, dir, style, config){ + return scanForBracket(this, pos, dir, style, config); + }); +}); diff --git a/static/js/mdeditor/lib/codemirror/addon/edit/matchtags.js b/static/js/mdeditor/lib/codemirror/addon/edit/matchtags.js new file mode 100644 index 00000000..fb1911a8 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/edit/matchtags.js @@ -0,0 +1,66 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../fold/xml-fold")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../fold/xml-fold"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineOption("matchTags", false, function(cm, val, old) { + if (old && old != CodeMirror.Init) { + cm.off("cursorActivity", doMatchTags); + cm.off("viewportChange", maybeUpdateMatch); + clear(cm); + } + if (val) { + cm.state.matchBothTags = typeof val == "object" && val.bothTags; + cm.on("cursorActivity", doMatchTags); + cm.on("viewportChange", maybeUpdateMatch); + doMatchTags(cm); + } + }); + + function clear(cm) { + if (cm.state.tagHit) cm.state.tagHit.clear(); + if (cm.state.tagOther) cm.state.tagOther.clear(); + cm.state.tagHit = cm.state.tagOther = null; + } + + function doMatchTags(cm) { + cm.state.failedTagMatch = false; + cm.operation(function() { + clear(cm); + if (cm.somethingSelected()) return; + var cur = cm.getCursor(), range = cm.getViewport(); + range.from = Math.min(range.from, cur.line); range.to = Math.max(cur.line + 1, range.to); + var match = CodeMirror.findMatchingTag(cm, cur, range); + if (!match) return; + if (cm.state.matchBothTags) { + var hit = match.at == "open" ? match.open : match.close; + if (hit) cm.state.tagHit = cm.markText(hit.from, hit.to, {className: "CodeMirror-matchingtag"}); + } + var other = match.at == "close" ? match.open : match.close; + if (other) + cm.state.tagOther = cm.markText(other.from, other.to, {className: "CodeMirror-matchingtag"}); + else + cm.state.failedTagMatch = true; + }); + } + + function maybeUpdateMatch(cm) { + if (cm.state.failedTagMatch) doMatchTags(cm); + } + + CodeMirror.commands.toMatchingTag = function(cm) { + var found = CodeMirror.findMatchingTag(cm, cm.getCursor()); + if (found) { + var other = found.at == "close" ? found.open : found.close; + if (other) cm.extendSelection(other.to, other.from); + } + }; +}); diff --git a/static/js/mdeditor/lib/codemirror/addon/edit/trailingspace.js b/static/js/mdeditor/lib/codemirror/addon/edit/trailingspace.js new file mode 100644 index 00000000..fa7b56be --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/edit/trailingspace.js @@ -0,0 +1,27 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + CodeMirror.defineOption("showTrailingSpace", false, function(cm, val, prev) { + if (prev == CodeMirror.Init) prev = false; + if (prev && !val) + cm.removeOverlay("trailingspace"); + else if (!prev && val) + cm.addOverlay({ + token: function(stream) { + for (var l = stream.string.length, i = l; i && /\s/.test(stream.string.charAt(i - 1)); --i) {} + if (i > stream.pos) { stream.pos = i; return null; } + stream.pos = l; + return "trailingspace"; + }, + name: "trailingspace" + }); + }); +}); diff --git a/static/js/mdeditor/lib/codemirror/addon/fold/brace-fold.js b/static/js/mdeditor/lib/codemirror/addon/fold/brace-fold.js new file mode 100644 index 00000000..1605f6c2 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/fold/brace-fold.js @@ -0,0 +1,105 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.registerHelper("fold", "brace", function(cm, start) { + var line = start.line, lineText = cm.getLine(line); + var startCh, tokenType; + + function findOpening(openCh) { + for (var at = start.ch, pass = 0;;) { + var found = at <= 0 ? -1 : lineText.lastIndexOf(openCh, at - 1); + if (found == -1) { + if (pass == 1) break; + pass = 1; + at = lineText.length; + continue; + } + if (pass == 1 && found < start.ch) break; + tokenType = cm.getTokenTypeAt(CodeMirror.Pos(line, found + 1)); + if (!/^(comment|string)/.test(tokenType)) return found + 1; + at = found - 1; + } + } + + var startToken = "{", endToken = "}", startCh = findOpening("{"); + if (startCh == null) { + startToken = "[", endToken = "]"; + startCh = findOpening("["); + } + + if (startCh == null) return; + var count = 1, lastLine = cm.lastLine(), end, endCh; + outer: for (var i = line; i <= lastLine; ++i) { + var text = cm.getLine(i), pos = i == line ? startCh : 0; + for (;;) { + var nextOpen = text.indexOf(startToken, pos), nextClose = text.indexOf(endToken, pos); + if (nextOpen < 0) nextOpen = text.length; + if (nextClose < 0) nextClose = text.length; + pos = Math.min(nextOpen, nextClose); + if (pos == text.length) break; + if (cm.getTokenTypeAt(CodeMirror.Pos(i, pos + 1)) == tokenType) { + if (pos == nextOpen) ++count; + else if (!--count) { end = i; endCh = pos; break outer; } + } + ++pos; + } + } + if (end == null || line == end && endCh == startCh) return; + return {from: CodeMirror.Pos(line, startCh), + to: CodeMirror.Pos(end, endCh)}; +}); + +CodeMirror.registerHelper("fold", "import", function(cm, start) { + function hasImport(line) { + if (line < cm.firstLine() || line > cm.lastLine()) return null; + var start = cm.getTokenAt(CodeMirror.Pos(line, 1)); + if (!/\S/.test(start.string)) start = cm.getTokenAt(CodeMirror.Pos(line, start.end + 1)); + if (start.type != "keyword" || start.string != "import") return null; + // Now find closing semicolon, return its position + for (var i = line, e = Math.min(cm.lastLine(), line + 10); i <= e; ++i) { + var text = cm.getLine(i), semi = text.indexOf(";"); + if (semi != -1) return {startCh: start.end, end: CodeMirror.Pos(i, semi)}; + } + } + + var start = start.line, has = hasImport(start), prev; + if (!has || hasImport(start - 1) || ((prev = hasImport(start - 2)) && prev.end.line == start - 1)) + return null; + for (var end = has.end;;) { + var next = hasImport(end.line + 1); + if (next == null) break; + end = next.end; + } + return {from: cm.clipPos(CodeMirror.Pos(start, has.startCh + 1)), to: end}; +}); + +CodeMirror.registerHelper("fold", "include", function(cm, start) { + function hasInclude(line) { + if (line < cm.firstLine() || line > cm.lastLine()) return null; + var start = cm.getTokenAt(CodeMirror.Pos(line, 1)); + if (!/\S/.test(start.string)) start = cm.getTokenAt(CodeMirror.Pos(line, start.end + 1)); + if (start.type == "meta" && start.string.slice(0, 8) == "#include") return start.start + 8; + } + + var start = start.line, has = hasInclude(start); + if (has == null || hasInclude(start - 1) != null) return null; + for (var end = start;;) { + var next = hasInclude(end + 1); + if (next == null) break; + ++end; + } + return {from: CodeMirror.Pos(start, has + 1), + to: cm.clipPos(CodeMirror.Pos(end))}; +}); + +}); diff --git a/static/js/mdeditor/lib/codemirror/addon/fold/comment-fold.js b/static/js/mdeditor/lib/codemirror/addon/fold/comment-fold.js new file mode 100644 index 00000000..b75db7ea --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/fold/comment-fold.js @@ -0,0 +1,57 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.registerGlobalHelper("fold", "comment", function(mode) { + return mode.blockCommentStart && mode.blockCommentEnd; +}, function(cm, start) { + var mode = cm.getModeAt(start), startToken = mode.blockCommentStart, endToken = mode.blockCommentEnd; + if (!startToken || !endToken) return; + var line = start.line, lineText = cm.getLine(line); + + var startCh; + for (var at = start.ch, pass = 0;;) { + var found = at <= 0 ? -1 : lineText.lastIndexOf(startToken, at - 1); + if (found == -1) { + if (pass == 1) return; + pass = 1; + at = lineText.length; + continue; + } + if (pass == 1 && found < start.ch) return; + if (/comment/.test(cm.getTokenTypeAt(CodeMirror.Pos(line, found + 1)))) { + startCh = found + startToken.length; + break; + } + at = found - 1; + } + + var depth = 1, lastLine = cm.lastLine(), end, endCh; + outer: for (var i = line; i <= lastLine; ++i) { + var text = cm.getLine(i), pos = i == line ? startCh : 0; + for (;;) { + var nextOpen = text.indexOf(startToken, pos), nextClose = text.indexOf(endToken, pos); + if (nextOpen < 0) nextOpen = text.length; + if (nextClose < 0) nextClose = text.length; + pos = Math.min(nextOpen, nextClose); + if (pos == text.length) break; + if (pos == nextOpen) ++depth; + else if (!--depth) { end = i; endCh = pos; break outer; } + ++pos; + } + } + if (end == null || line == end && endCh == startCh) return; + return {from: CodeMirror.Pos(line, startCh), + to: CodeMirror.Pos(end, endCh)}; +}); + +}); diff --git a/static/js/mdeditor/lib/codemirror/addon/fold/foldcode.js b/static/js/mdeditor/lib/codemirror/addon/fold/foldcode.js new file mode 100644 index 00000000..62911f93 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/fold/foldcode.js @@ -0,0 +1,149 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + function doFold(cm, pos, options, force) { + if (options && options.call) { + var finder = options; + options = null; + } else { + var finder = getOption(cm, options, "rangeFinder"); + } + if (typeof pos == "number") pos = CodeMirror.Pos(pos, 0); + var minSize = getOption(cm, options, "minFoldSize"); + + function getRange(allowFolded) { + var range = finder(cm, pos); + if (!range || range.to.line - range.from.line < minSize) return null; + var marks = cm.findMarksAt(range.from); + for (var i = 0; i < marks.length; ++i) { + if (marks[i].__isFold && force !== "fold") { + if (!allowFolded) return null; + range.cleared = true; + marks[i].clear(); + } + } + return range; + } + + var range = getRange(true); + if (getOption(cm, options, "scanUp")) while (!range && pos.line > cm.firstLine()) { + pos = CodeMirror.Pos(pos.line - 1, 0); + range = getRange(false); + } + if (!range || range.cleared || force === "unfold") return; + + var myWidget = makeWidget(cm, options); + CodeMirror.on(myWidget, "mousedown", function(e) { + myRange.clear(); + CodeMirror.e_preventDefault(e); + }); + var myRange = cm.markText(range.from, range.to, { + replacedWith: myWidget, + clearOnEnter: true, + __isFold: true + }); + myRange.on("clear", function(from, to) { + CodeMirror.signal(cm, "unfold", cm, from, to); + }); + CodeMirror.signal(cm, "fold", cm, range.from, range.to); + } + + function makeWidget(cm, options) { + var widget = getOption(cm, options, "widget"); + if (typeof widget == "string") { + var text = document.createTextNode(widget); + widget = document.createElement("span"); + widget.appendChild(text); + widget.className = "CodeMirror-foldmarker"; + } + return widget; + } + + // Clumsy backwards-compatible interface + CodeMirror.newFoldFunction = function(rangeFinder, widget) { + return function(cm, pos) { doFold(cm, pos, {rangeFinder: rangeFinder, widget: widget}); }; + }; + + // New-style interface + CodeMirror.defineExtension("foldCode", function(pos, options, force) { + doFold(this, pos, options, force); + }); + + CodeMirror.defineExtension("isFolded", function(pos) { + var marks = this.findMarksAt(pos); + for (var i = 0; i < marks.length; ++i) + if (marks[i].__isFold) return true; + }); + + CodeMirror.commands.toggleFold = function(cm) { + cm.foldCode(cm.getCursor()); + }; + CodeMirror.commands.fold = function(cm) { + cm.foldCode(cm.getCursor(), null, "fold"); + }; + CodeMirror.commands.unfold = function(cm) { + cm.foldCode(cm.getCursor(), null, "unfold"); + }; + CodeMirror.commands.foldAll = function(cm) { + cm.operation(function() { + for (var i = cm.firstLine(), e = cm.lastLine(); i <= e; i++) + cm.foldCode(CodeMirror.Pos(i, 0), null, "fold"); + }); + }; + CodeMirror.commands.unfoldAll = function(cm) { + cm.operation(function() { + for (var i = cm.firstLine(), e = cm.lastLine(); i <= e; i++) + cm.foldCode(CodeMirror.Pos(i, 0), null, "unfold"); + }); + }; + + CodeMirror.registerHelper("fold", "combine", function() { + var funcs = Array.prototype.slice.call(arguments, 0); + return function(cm, start) { + for (var i = 0; i < funcs.length; ++i) { + var found = funcs[i](cm, start); + if (found) return found; + } + }; + }); + + CodeMirror.registerHelper("fold", "auto", function(cm, start) { + var helpers = cm.getHelpers(start, "fold"); + for (var i = 0; i < helpers.length; i++) { + var cur = helpers[i](cm, start); + if (cur) return cur; + } + }); + + var defaultOptions = { + rangeFinder: CodeMirror.fold.auto, + widget: "\u2194", + minFoldSize: 0, + scanUp: false + }; + + CodeMirror.defineOption("foldOptions", null); + + function getOption(cm, options, name) { + if (options && options[name] !== undefined) + return options[name]; + var editorOptions = cm.options.foldOptions; + if (editorOptions && editorOptions[name] !== undefined) + return editorOptions[name]; + return defaultOptions[name]; + } + + CodeMirror.defineExtension("foldOption", function(options, name) { + return getOption(this, options, name); + }); +}); diff --git a/static/js/mdeditor/lib/codemirror/addon/fold/foldgutter.css b/static/js/mdeditor/lib/codemirror/addon/fold/foldgutter.css new file mode 100644 index 00000000..ad19ae2d --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/fold/foldgutter.css @@ -0,0 +1,20 @@ +.CodeMirror-foldmarker { + color: blue; + text-shadow: #b9f 1px 1px 2px, #b9f -1px -1px 2px, #b9f 1px -1px 2px, #b9f -1px 1px 2px; + font-family: arial; + line-height: .3; + cursor: pointer; +} +.CodeMirror-foldgutter { + width: .7em; +} +.CodeMirror-foldgutter-open, +.CodeMirror-foldgutter-folded { + cursor: pointer; +} +.CodeMirror-foldgutter-open:after { + content: "\25BE"; +} +.CodeMirror-foldgutter-folded:after { + content: "\25B8"; +} diff --git a/static/js/mdeditor/lib/codemirror/addon/fold/foldgutter.js b/static/js/mdeditor/lib/codemirror/addon/fold/foldgutter.js new file mode 100644 index 00000000..199120c7 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/fold/foldgutter.js @@ -0,0 +1,144 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("./foldcode")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "./foldcode"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineOption("foldGutter", false, function(cm, val, old) { + if (old && old != CodeMirror.Init) { + cm.clearGutter(cm.state.foldGutter.options.gutter); + cm.state.foldGutter = null; + cm.off("gutterClick", onGutterClick); + cm.off("change", onChange); + cm.off("viewportChange", onViewportChange); + cm.off("fold", onFold); + cm.off("unfold", onFold); + cm.off("swapDoc", updateInViewport); + } + if (val) { + cm.state.foldGutter = new State(parseOptions(val)); + updateInViewport(cm); + cm.on("gutterClick", onGutterClick); + cm.on("change", onChange); + cm.on("viewportChange", onViewportChange); + cm.on("fold", onFold); + cm.on("unfold", onFold); + cm.on("swapDoc", updateInViewport); + } + }); + + var Pos = CodeMirror.Pos; + + function State(options) { + this.options = options; + this.from = this.to = 0; + } + + function parseOptions(opts) { + if (opts === true) opts = {}; + if (opts.gutter == null) opts.gutter = "CodeMirror-foldgutter"; + if (opts.indicatorOpen == null) opts.indicatorOpen = "CodeMirror-foldgutter-open"; + if (opts.indicatorFolded == null) opts.indicatorFolded = "CodeMirror-foldgutter-folded"; + return opts; + } + + function isFolded(cm, line) { + var marks = cm.findMarksAt(Pos(line)); + for (var i = 0; i < marks.length; ++i) + if (marks[i].__isFold && marks[i].find().from.line == line) return true; + } + + function marker(spec) { + if (typeof spec == "string") { + var elt = document.createElement("div"); + elt.className = spec + " CodeMirror-guttermarker-subtle"; + return elt; + } else { + return spec.cloneNode(true); + } + } + + function updateFoldInfo(cm, from, to) { + var opts = cm.state.foldGutter.options, cur = from; + var minSize = cm.foldOption(opts, "minFoldSize"); + var func = cm.foldOption(opts, "rangeFinder"); + cm.eachLine(from, to, function(line) { + var mark = null; + if (isFolded(cm, cur)) { + mark = marker(opts.indicatorFolded); + } else { + var pos = Pos(cur, 0); + var range = func && func(cm, pos); + if (range && range.to.line - range.from.line >= minSize) + mark = marker(opts.indicatorOpen); + } + cm.setGutterMarker(line, opts.gutter, mark); + ++cur; + }); + } + + function updateInViewport(cm) { + var vp = cm.getViewport(), state = cm.state.foldGutter; + if (!state) return; + cm.operation(function() { + updateFoldInfo(cm, vp.from, vp.to); + }); + state.from = vp.from; state.to = vp.to; + } + + function onGutterClick(cm, line, gutter) { + var state = cm.state.foldGutter; + if (!state) return; + var opts = state.options; + if (gutter != opts.gutter) return; + cm.foldCode(Pos(line, 0), opts.rangeFinder); + } + + function onChange(cm) { + var state = cm.state.foldGutter; + if (!state) return; + var opts = state.options; + state.from = state.to = 0; + clearTimeout(state.changeUpdate); + state.changeUpdate = setTimeout(function() { updateInViewport(cm); }, opts.foldOnChangeTimeSpan || 600); + } + + function onViewportChange(cm) { + var state = cm.state.foldGutter; + if (!state) return; + var opts = state.options; + clearTimeout(state.changeUpdate); + state.changeUpdate = setTimeout(function() { + var vp = cm.getViewport(); + if (state.from == state.to || vp.from - state.to > 20 || state.from - vp.to > 20) { + updateInViewport(cm); + } else { + cm.operation(function() { + if (vp.from < state.from) { + updateFoldInfo(cm, vp.from, state.from); + state.from = vp.from; + } + if (vp.to > state.to) { + updateFoldInfo(cm, state.to, vp.to); + state.to = vp.to; + } + }); + } + }, opts.updateViewportTimeSpan || 400); + } + + function onFold(cm, from) { + var state = cm.state.foldGutter; + if (!state) return; + var line = from.line; + if (line >= state.from && line < state.to) + updateFoldInfo(cm, line, line + 1); + } +}); diff --git a/static/js/mdeditor/lib/codemirror/addon/fold/indent-fold.js b/static/js/mdeditor/lib/codemirror/addon/fold/indent-fold.js new file mode 100644 index 00000000..e29f15e9 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/fold/indent-fold.js @@ -0,0 +1,44 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.registerHelper("fold", "indent", function(cm, start) { + var tabSize = cm.getOption("tabSize"), firstLine = cm.getLine(start.line); + if (!/\S/.test(firstLine)) return; + var getIndent = function(line) { + return CodeMirror.countColumn(line, null, tabSize); + }; + var myIndent = getIndent(firstLine); + var lastLineInFold = null; + // Go through lines until we find a line that definitely doesn't belong in + // the block we're folding, or to the end. + for (var i = start.line + 1, end = cm.lastLine(); i <= end; ++i) { + var curLine = cm.getLine(i); + var curIndent = getIndent(curLine); + if (curIndent > myIndent) { + // Lines with a greater indent are considered part of the block. + lastLineInFold = i; + } else if (!/\S/.test(curLine)) { + // Empty lines might be breaks within the block we're trying to fold. + } else { + // A non-empty line at an indent equal to or less than ours marks the + // start of another block. + break; + } + } + if (lastLineInFold) return { + from: CodeMirror.Pos(start.line, firstLine.length), + to: CodeMirror.Pos(lastLineInFold, cm.getLine(lastLineInFold).length) + }; +}); + +}); diff --git a/static/js/mdeditor/lib/codemirror/addon/fold/markdown-fold.js b/static/js/mdeditor/lib/codemirror/addon/fold/markdown-fold.js new file mode 100644 index 00000000..ce84c946 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/fold/markdown-fold.js @@ -0,0 +1,49 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.registerHelper("fold", "markdown", function(cm, start) { + var maxDepth = 100; + + function isHeader(lineNo) { + var tokentype = cm.getTokenTypeAt(CodeMirror.Pos(lineNo, 0)); + return tokentype && /\bheader\b/.test(tokentype); + } + + function headerLevel(lineNo, line, nextLine) { + var match = line && line.match(/^#+/); + if (match && isHeader(lineNo)) return match[0].length; + match = nextLine && nextLine.match(/^[=\-]+\s*$/); + if (match && isHeader(lineNo + 1)) return nextLine[0] == "=" ? 1 : 2; + return maxDepth; + } + + var firstLine = cm.getLine(start.line), nextLine = cm.getLine(start.line + 1); + var level = headerLevel(start.line, firstLine, nextLine); + if (level === maxDepth) return undefined; + + var lastLineNo = cm.lastLine(); + var end = start.line, nextNextLine = cm.getLine(end + 2); + while (end < lastLineNo) { + if (headerLevel(end + 1, nextLine, nextNextLine) <= level) break; + ++end; + nextLine = nextNextLine; + nextNextLine = cm.getLine(end + 2); + } + + return { + from: CodeMirror.Pos(start.line, firstLine.length), + to: CodeMirror.Pos(end, cm.getLine(end).length) + }; +}); + +}); diff --git a/static/js/mdeditor/lib/codemirror/addon/fold/xml-fold.js b/static/js/mdeditor/lib/codemirror/addon/fold/xml-fold.js new file mode 100644 index 00000000..504727f3 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/fold/xml-fold.js @@ -0,0 +1,182 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var Pos = CodeMirror.Pos; + function cmp(a, b) { return a.line - b.line || a.ch - b.ch; } + + var nameStartChar = "A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD"; + var nameChar = nameStartChar + "\-\:\.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040"; + var xmlTagStart = new RegExp("<(/?)([" + nameStartChar + "][" + nameChar + "]*)", "g"); + + function Iter(cm, line, ch, range) { + this.line = line; this.ch = ch; + this.cm = cm; this.text = cm.getLine(line); + this.min = range ? range.from : cm.firstLine(); + this.max = range ? range.to - 1 : cm.lastLine(); + } + + function tagAt(iter, ch) { + var type = iter.cm.getTokenTypeAt(Pos(iter.line, ch)); + return type && /\btag\b/.test(type); + } + + function nextLine(iter) { + if (iter.line >= iter.max) return; + iter.ch = 0; + iter.text = iter.cm.getLine(++iter.line); + return true; + } + function prevLine(iter) { + if (iter.line <= iter.min) return; + iter.text = iter.cm.getLine(--iter.line); + iter.ch = iter.text.length; + return true; + } + + function toTagEnd(iter) { + for (;;) { + var gt = iter.text.indexOf(">", iter.ch); + if (gt == -1) { if (nextLine(iter)) continue; else return; } + if (!tagAt(iter, gt + 1)) { iter.ch = gt + 1; continue; } + var lastSlash = iter.text.lastIndexOf("/", gt); + var selfClose = lastSlash > -1 && !/\S/.test(iter.text.slice(lastSlash + 1, gt)); + iter.ch = gt + 1; + return selfClose ? "selfClose" : "regular"; + } + } + function toTagStart(iter) { + for (;;) { + var lt = iter.ch ? iter.text.lastIndexOf("<", iter.ch - 1) : -1; + if (lt == -1) { if (prevLine(iter)) continue; else return; } + if (!tagAt(iter, lt + 1)) { iter.ch = lt; continue; } + xmlTagStart.lastIndex = lt; + iter.ch = lt; + var match = xmlTagStart.exec(iter.text); + if (match && match.index == lt) return match; + } + } + + function toNextTag(iter) { + for (;;) { + xmlTagStart.lastIndex = iter.ch; + var found = xmlTagStart.exec(iter.text); + if (!found) { if (nextLine(iter)) continue; else return; } + if (!tagAt(iter, found.index + 1)) { iter.ch = found.index + 1; continue; } + iter.ch = found.index + found[0].length; + return found; + } + } + function toPrevTag(iter) { + for (;;) { + var gt = iter.ch ? iter.text.lastIndexOf(">", iter.ch - 1) : -1; + if (gt == -1) { if (prevLine(iter)) continue; else return; } + if (!tagAt(iter, gt + 1)) { iter.ch = gt; continue; } + var lastSlash = iter.text.lastIndexOf("/", gt); + var selfClose = lastSlash > -1 && !/\S/.test(iter.text.slice(lastSlash + 1, gt)); + iter.ch = gt + 1; + return selfClose ? "selfClose" : "regular"; + } + } + + function findMatchingClose(iter, tag) { + var stack = []; + for (;;) { + var next = toNextTag(iter), end, startLine = iter.line, startCh = iter.ch - (next ? next[0].length : 0); + if (!next || !(end = toTagEnd(iter))) return; + if (end == "selfClose") continue; + if (next[1]) { // closing tag + for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == next[2]) { + stack.length = i; + break; + } + if (i < 0 && (!tag || tag == next[2])) return { + tag: next[2], + from: Pos(startLine, startCh), + to: Pos(iter.line, iter.ch) + }; + } else { // opening tag + stack.push(next[2]); + } + } + } + function findMatchingOpen(iter, tag) { + var stack = []; + for (;;) { + var prev = toPrevTag(iter); + if (!prev) return; + if (prev == "selfClose") { toTagStart(iter); continue; } + var endLine = iter.line, endCh = iter.ch; + var start = toTagStart(iter); + if (!start) return; + if (start[1]) { // closing tag + stack.push(start[2]); + } else { // opening tag + for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == start[2]) { + stack.length = i; + break; + } + if (i < 0 && (!tag || tag == start[2])) return { + tag: start[2], + from: Pos(iter.line, iter.ch), + to: Pos(endLine, endCh) + }; + } + } + } + + CodeMirror.registerHelper("fold", "xml", function(cm, start) { + var iter = new Iter(cm, start.line, 0); + for (;;) { + var openTag = toNextTag(iter), end; + if (!openTag || iter.line != start.line || !(end = toTagEnd(iter))) return; + if (!openTag[1] && end != "selfClose") { + var start = Pos(iter.line, iter.ch); + var close = findMatchingClose(iter, openTag[2]); + return close && {from: start, to: close.from}; + } + } + }); + CodeMirror.findMatchingTag = function(cm, pos, range) { + var iter = new Iter(cm, pos.line, pos.ch, range); + if (iter.text.indexOf(">") == -1 && iter.text.indexOf("<") == -1) return; + var end = toTagEnd(iter), to = end && Pos(iter.line, iter.ch); + var start = end && toTagStart(iter); + if (!end || !start || cmp(iter, pos) > 0) return; + var here = {from: Pos(iter.line, iter.ch), to: to, tag: start[2]}; + if (end == "selfClose") return {open: here, close: null, at: "open"}; + + if (start[1]) { // closing tag + return {open: findMatchingOpen(iter, start[2]), close: here, at: "close"}; + } else { // opening tag + iter = new Iter(cm, to.line, to.ch, range); + return {open: here, close: findMatchingClose(iter, start[2]), at: "open"}; + } + }; + + CodeMirror.findEnclosingTag = function(cm, pos, range) { + var iter = new Iter(cm, pos.line, pos.ch, range); + for (;;) { + var open = findMatchingOpen(iter); + if (!open) break; + var forward = new Iter(cm, pos.line, pos.ch, range); + var close = findMatchingClose(forward, open.tag); + if (close) return {open: open, close: close}; + } + }; + + // Used by addon/edit/closetag.js + CodeMirror.scanForClosingTag = function(cm, pos, name, end) { + var iter = new Iter(cm, pos.line, pos.ch, end ? {from: 0, to: end} : null); + return findMatchingClose(iter, name); + }; +}); diff --git a/static/js/mdeditor/lib/codemirror/addon/hint/anyword-hint.js b/static/js/mdeditor/lib/codemirror/addon/hint/anyword-hint.js new file mode 100644 index 00000000..8e74a920 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/hint/anyword-hint.js @@ -0,0 +1,41 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var WORD = /[\w$]+/, RANGE = 500; + + CodeMirror.registerHelper("hint", "anyword", function(editor, options) { + var word = options && options.word || WORD; + var range = options && options.range || RANGE; + var cur = editor.getCursor(), curLine = editor.getLine(cur.line); + var end = cur.ch, start = end; + while (start && word.test(curLine.charAt(start - 1))) --start; + var curWord = start != end && curLine.slice(start, end); + + var list = [], seen = {}; + var re = new RegExp(word.source, "g"); + for (var dir = -1; dir <= 1; dir += 2) { + var line = cur.line, endLine = Math.min(Math.max(line + dir * range, editor.firstLine()), editor.lastLine()) + dir; + for (; line != endLine; line += dir) { + var text = editor.getLine(line), m; + while (m = re.exec(text)) { + if (line == cur.line && m[0] === curWord) continue; + if ((!curWord || m[0].lastIndexOf(curWord, 0) == 0) && !Object.prototype.hasOwnProperty.call(seen, m[0])) { + seen[m[0]] = true; + list.push(m[0]); + } + } + } + } + return {list: list, from: CodeMirror.Pos(cur.line, start), to: CodeMirror.Pos(cur.line, end)}; + }); +}); diff --git a/static/js/mdeditor/lib/codemirror/addon/hint/css-hint.js b/static/js/mdeditor/lib/codemirror/addon/hint/css-hint.js new file mode 100644 index 00000000..488da344 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/hint/css-hint.js @@ -0,0 +1,56 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../../mode/css/css")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../../mode/css/css"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var pseudoClasses = {link: 1, visited: 1, active: 1, hover: 1, focus: 1, + "first-letter": 1, "first-line": 1, "first-child": 1, + before: 1, after: 1, lang: 1}; + + CodeMirror.registerHelper("hint", "css", function(cm) { + var cur = cm.getCursor(), token = cm.getTokenAt(cur); + var inner = CodeMirror.innerMode(cm.getMode(), token.state); + if (inner.mode.name != "css") return; + + var start = token.start, end = cur.ch, word = token.string.slice(0, end - start); + if (/[^\w$_-]/.test(word)) { + word = ""; start = end = cur.ch; + } + + var spec = CodeMirror.resolveMode("text/css"); + + var result = []; + function add(keywords) { + for (var name in keywords) + if (!word || name.lastIndexOf(word, 0) == 0) + result.push(name); + } + + var st = inner.state.state; + if (st == "pseudo" || token.type == "variable-3") { + add(pseudoClasses); + } else if (st == "block" || st == "maybeprop") { + add(spec.propertyKeywords); + } else if (st == "prop" || st == "parens" || st == "at" || st == "params") { + add(spec.valueKeywords); + add(spec.colorKeywords); + } else if (st == "media" || st == "media_parens") { + add(spec.mediaTypes); + add(spec.mediaFeatures); + } + + if (result.length) return { + list: result, + from: CodeMirror.Pos(cur.line, start), + to: CodeMirror.Pos(cur.line, end) + }; + }); +}); diff --git a/static/js/mdeditor/lib/codemirror/addon/hint/html-hint.js b/static/js/mdeditor/lib/codemirror/addon/hint/html-hint.js new file mode 100644 index 00000000..c6769bca --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/hint/html-hint.js @@ -0,0 +1,348 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("./xml-hint")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "./xml-hint"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var langs = "ab aa af ak sq am ar an hy as av ae ay az bm ba eu be bn bh bi bs br bg my ca ch ce ny zh cv kw co cr hr cs da dv nl dz en eo et ee fo fj fi fr ff gl ka de el gn gu ht ha he hz hi ho hu ia id ie ga ig ik io is it iu ja jv kl kn kr ks kk km ki rw ky kv kg ko ku kj la lb lg li ln lo lt lu lv gv mk mg ms ml mt mi mr mh mn na nv nb nd ne ng nn no ii nr oc oj cu om or os pa pi fa pl ps pt qu rm rn ro ru sa sc sd se sm sg sr gd sn si sk sl so st es su sw ss sv ta te tg th ti bo tk tl tn to tr ts tt tw ty ug uk ur uz ve vi vo wa cy wo fy xh yi yo za zu".split(" "); + var targets = ["_blank", "_self", "_top", "_parent"]; + var charsets = ["ascii", "utf-8", "utf-16", "latin1", "latin1"]; + var methods = ["get", "post", "put", "delete"]; + var encs = ["application/x-www-form-urlencoded", "multipart/form-data", "text/plain"]; + var media = ["all", "screen", "print", "embossed", "braille", "handheld", "print", "projection", "screen", "tty", "tv", "speech", + "3d-glasses", "resolution [>][<][=] [X]", "device-aspect-ratio: X/Y", "orientation:portrait", + "orientation:landscape", "device-height: [X]", "device-width: [X]"]; + var s = { attrs: {} }; // Simple tag, reused for a whole lot of tags + + var data = { + a: { + attrs: { + href: null, ping: null, type: null, + media: media, + target: targets, + hreflang: langs + } + }, + abbr: s, + acronym: s, + address: s, + applet: s, + area: { + attrs: { + alt: null, coords: null, href: null, target: null, ping: null, + media: media, hreflang: langs, type: null, + shape: ["default", "rect", "circle", "poly"] + } + }, + article: s, + aside: s, + audio: { + attrs: { + src: null, mediagroup: null, + crossorigin: ["anonymous", "use-credentials"], + preload: ["none", "metadata", "auto"], + autoplay: ["", "autoplay"], + loop: ["", "loop"], + controls: ["", "controls"] + } + }, + b: s, + base: { attrs: { href: null, target: targets } }, + basefont: s, + bdi: s, + bdo: s, + big: s, + blockquote: { attrs: { cite: null } }, + body: s, + br: s, + button: { + attrs: { + form: null, formaction: null, name: null, value: null, + autofocus: ["", "autofocus"], + disabled: ["", "autofocus"], + formenctype: encs, + formmethod: methods, + formnovalidate: ["", "novalidate"], + formtarget: targets, + type: ["submit", "reset", "button"] + } + }, + canvas: { attrs: { width: null, height: null } }, + caption: s, + center: s, + cite: s, + code: s, + col: { attrs: { span: null } }, + colgroup: { attrs: { span: null } }, + command: { + attrs: { + type: ["command", "checkbox", "radio"], + label: null, icon: null, radiogroup: null, command: null, title: null, + disabled: ["", "disabled"], + checked: ["", "checked"] + } + }, + data: { attrs: { value: null } }, + datagrid: { attrs: { disabled: ["", "disabled"], multiple: ["", "multiple"] } }, + datalist: { attrs: { data: null } }, + dd: s, + del: { attrs: { cite: null, datetime: null } }, + details: { attrs: { open: ["", "open"] } }, + dfn: s, + dir: s, + div: s, + dl: s, + dt: s, + em: s, + embed: { attrs: { src: null, type: null, width: null, height: null } }, + eventsource: { attrs: { src: null } }, + fieldset: { attrs: { disabled: ["", "disabled"], form: null, name: null } }, + figcaption: s, + figure: s, + font: s, + footer: s, + form: { + attrs: { + action: null, name: null, + "accept-charset": charsets, + autocomplete: ["on", "off"], + enctype: encs, + method: methods, + novalidate: ["", "novalidate"], + target: targets + } + }, + frame: s, + frameset: s, + h1: s, h2: s, h3: s, h4: s, h5: s, h6: s, + head: { + attrs: {}, + children: ["title", "base", "link", "style", "meta", "script", "noscript", "command"] + }, + header: s, + hgroup: s, + hr: s, + html: { + attrs: { manifest: null }, + children: ["head", "body"] + }, + i: s, + iframe: { + attrs: { + src: null, srcdoc: null, name: null, width: null, height: null, + sandbox: ["allow-top-navigation", "allow-same-origin", "allow-forms", "allow-scripts"], + seamless: ["", "seamless"] + } + }, + img: { + attrs: { + alt: null, src: null, ismap: null, usemap: null, width: null, height: null, + crossorigin: ["anonymous", "use-credentials"] + } + }, + input: { + attrs: { + alt: null, dirname: null, form: null, formaction: null, + height: null, list: null, max: null, maxlength: null, min: null, + name: null, pattern: null, placeholder: null, size: null, src: null, + step: null, value: null, width: null, + accept: ["audio/*", "video/*", "image/*"], + autocomplete: ["on", "off"], + autofocus: ["", "autofocus"], + checked: ["", "checked"], + disabled: ["", "disabled"], + formenctype: encs, + formmethod: methods, + formnovalidate: ["", "novalidate"], + formtarget: targets, + multiple: ["", "multiple"], + readonly: ["", "readonly"], + required: ["", "required"], + type: ["hidden", "text", "search", "tel", "url", "email", "password", "datetime", "date", "month", + "week", "time", "datetime-local", "number", "range", "color", "checkbox", "radio", + "file", "submit", "image", "reset", "button"] + } + }, + ins: { attrs: { cite: null, datetime: null } }, + kbd: s, + keygen: { + attrs: { + challenge: null, form: null, name: null, + autofocus: ["", "autofocus"], + disabled: ["", "disabled"], + keytype: ["RSA"] + } + }, + label: { attrs: { "for": null, form: null } }, + legend: s, + li: { attrs: { value: null } }, + link: { + attrs: { + href: null, type: null, + hreflang: langs, + media: media, + sizes: ["all", "16x16", "16x16 32x32", "16x16 32x32 64x64"] + } + }, + map: { attrs: { name: null } }, + mark: s, + menu: { attrs: { label: null, type: ["list", "context", "toolbar"] } }, + meta: { + attrs: { + content: null, + charset: charsets, + name: ["viewport", "application-name", "author", "description", "generator", "keywords"], + "http-equiv": ["content-language", "content-type", "default-style", "refresh"] + } + }, + meter: { attrs: { value: null, min: null, low: null, high: null, max: null, optimum: null } }, + nav: s, + noframes: s, + noscript: s, + object: { + attrs: { + data: null, type: null, name: null, usemap: null, form: null, width: null, height: null, + typemustmatch: ["", "typemustmatch"] + } + }, + ol: { attrs: { reversed: ["", "reversed"], start: null, type: ["1", "a", "A", "i", "I"] } }, + optgroup: { attrs: { disabled: ["", "disabled"], label: null } }, + option: { attrs: { disabled: ["", "disabled"], label: null, selected: ["", "selected"], value: null } }, + output: { attrs: { "for": null, form: null, name: null } }, + p: s, + param: { attrs: { name: null, value: null } }, + pre: s, + progress: { attrs: { value: null, max: null } }, + q: { attrs: { cite: null } }, + rp: s, + rt: s, + ruby: s, + s: s, + samp: s, + script: { + attrs: { + type: ["text/javascript"], + src: null, + async: ["", "async"], + defer: ["", "defer"], + charset: charsets + } + }, + section: s, + select: { + attrs: { + form: null, name: null, size: null, + autofocus: ["", "autofocus"], + disabled: ["", "disabled"], + multiple: ["", "multiple"] + } + }, + small: s, + source: { attrs: { src: null, type: null, media: null } }, + span: s, + strike: s, + strong: s, + style: { + attrs: { + type: ["text/css"], + media: media, + scoped: null + } + }, + sub: s, + summary: s, + sup: s, + table: s, + tbody: s, + td: { attrs: { colspan: null, rowspan: null, headers: null } }, + textarea: { + attrs: { + dirname: null, form: null, maxlength: null, name: null, placeholder: null, + rows: null, cols: null, + autofocus: ["", "autofocus"], + disabled: ["", "disabled"], + readonly: ["", "readonly"], + required: ["", "required"], + wrap: ["soft", "hard"] + } + }, + tfoot: s, + th: { attrs: { colspan: null, rowspan: null, headers: null, scope: ["row", "col", "rowgroup", "colgroup"] } }, + thead: s, + time: { attrs: { datetime: null } }, + title: s, + tr: s, + track: { + attrs: { + src: null, label: null, "default": null, + kind: ["subtitles", "captions", "descriptions", "chapters", "metadata"], + srclang: langs + } + }, + tt: s, + u: s, + ul: s, + "var": s, + video: { + attrs: { + src: null, poster: null, width: null, height: null, + crossorigin: ["anonymous", "use-credentials"], + preload: ["auto", "metadata", "none"], + autoplay: ["", "autoplay"], + mediagroup: ["movie"], + muted: ["", "muted"], + controls: ["", "controls"] + } + }, + wbr: s + }; + + var globalAttrs = { + accesskey: ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"], + "class": null, + contenteditable: ["true", "false"], + contextmenu: null, + dir: ["ltr", "rtl", "auto"], + draggable: ["true", "false", "auto"], + dropzone: ["copy", "move", "link", "string:", "file:"], + hidden: ["hidden"], + id: null, + inert: ["inert"], + itemid: null, + itemprop: null, + itemref: null, + itemscope: ["itemscope"], + itemtype: null, + lang: ["en", "es"], + spellcheck: ["true", "false"], + style: null, + tabindex: ["1", "2", "3", "4", "5", "6", "7", "8", "9"], + title: null, + translate: ["yes", "no"], + onclick: null, + rel: ["stylesheet", "alternate", "author", "bookmark", "help", "license", "next", "nofollow", "noreferrer", "prefetch", "prev", "search", "tag"] + }; + function populate(obj) { + for (var attr in globalAttrs) if (globalAttrs.hasOwnProperty(attr)) + obj.attrs[attr] = globalAttrs[attr]; + } + + populate(s); + for (var tag in data) if (data.hasOwnProperty(tag) && data[tag] != s) + populate(data[tag]); + + CodeMirror.htmlSchema = data; + function htmlHint(cm, options) { + var local = {schemaInfo: data}; + if (options) for (var opt in options) local[opt] = options[opt]; + return CodeMirror.hint.xml(cm, local); + } + CodeMirror.registerHelper("hint", "html", htmlHint); +}); diff --git a/static/js/mdeditor/lib/codemirror/addon/hint/javascript-hint.js b/static/js/mdeditor/lib/codemirror/addon/hint/javascript-hint.js new file mode 100644 index 00000000..7bcbf4a0 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/hint/javascript-hint.js @@ -0,0 +1,146 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + var Pos = CodeMirror.Pos; + + function forEach(arr, f) { + for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]); + } + + function arrayContains(arr, item) { + if (!Array.prototype.indexOf) { + var i = arr.length; + while (i--) { + if (arr[i] === item) { + return true; + } + } + return false; + } + return arr.indexOf(item) != -1; + } + + function scriptHint(editor, keywords, getToken, options) { + // Find the token at the cursor + var cur = editor.getCursor(), token = getToken(editor, cur); + if (/\b(?:string|comment)\b/.test(token.type)) return; + token.state = CodeMirror.innerMode(editor.getMode(), token.state).state; + + // If it's not a 'word-style' token, ignore the token. + if (!/^[\w$_]*$/.test(token.string)) { + token = {start: cur.ch, end: cur.ch, string: "", state: token.state, + type: token.string == "." ? "property" : null}; + } else if (token.end > cur.ch) { + token.end = cur.ch; + token.string = token.string.slice(0, cur.ch - token.start); + } + + var tprop = token; + // If it is a property, find out what it is a property of. + while (tprop.type == "property") { + tprop = getToken(editor, Pos(cur.line, tprop.start)); + if (tprop.string != ".") return; + tprop = getToken(editor, Pos(cur.line, tprop.start)); + if (!context) var context = []; + context.push(tprop); + } + return {list: getCompletions(token, context, keywords, options), + from: Pos(cur.line, token.start), + to: Pos(cur.line, token.end)}; + } + + function javascriptHint(editor, options) { + return scriptHint(editor, javascriptKeywords, + function (e, cur) {return e.getTokenAt(cur);}, + options); + }; + CodeMirror.registerHelper("hint", "javascript", javascriptHint); + + function getCoffeeScriptToken(editor, cur) { + // This getToken, it is for coffeescript, imitates the behavior of + // getTokenAt method in javascript.js, that is, returning "property" + // type and treat "." as indepenent token. + var token = editor.getTokenAt(cur); + if (cur.ch == token.start + 1 && token.string.charAt(0) == '.') { + token.end = token.start; + token.string = '.'; + token.type = "property"; + } + else if (/^\.[\w$_]*$/.test(token.string)) { + token.type = "property"; + token.start++; + token.string = token.string.replace(/\./, ''); + } + return token; + } + + function coffeescriptHint(editor, options) { + return scriptHint(editor, coffeescriptKeywords, getCoffeeScriptToken, options); + } + CodeMirror.registerHelper("hint", "coffeescript", coffeescriptHint); + + var stringProps = ("charAt charCodeAt indexOf lastIndexOf substring substr slice trim trimLeft trimRight " + + "toUpperCase toLowerCase split concat match replace search").split(" "); + var arrayProps = ("length concat join splice push pop shift unshift slice reverse sort indexOf " + + "lastIndexOf every some filter forEach map reduce reduceRight ").split(" "); + var funcProps = "prototype apply call bind".split(" "); + var javascriptKeywords = ("break case catch continue debugger default delete do else false finally for function " + + "if in instanceof new null return switch throw true try typeof var void while with").split(" "); + var coffeescriptKeywords = ("and break catch class continue delete do else extends false finally for " + + "if in instanceof isnt new no not null of off on or return switch then throw true try typeof until void while with yes").split(" "); + + function getCompletions(token, context, keywords, options) { + var found = [], start = token.string, global = options && options.globalScope || window; + function maybeAdd(str) { + if (str.lastIndexOf(start, 0) == 0 && !arrayContains(found, str)) found.push(str); + } + function gatherCompletions(obj) { + if (typeof obj == "string") forEach(stringProps, maybeAdd); + else if (obj instanceof Array) forEach(arrayProps, maybeAdd); + else if (obj instanceof Function) forEach(funcProps, maybeAdd); + for (var name in obj) maybeAdd(name); + } + + if (context && context.length) { + // If this is a property, see if it belongs to some object we can + // find in the current environment. + var obj = context.pop(), base; + if (obj.type && obj.type.indexOf("variable") === 0) { + if (options && options.additionalContext) + base = options.additionalContext[obj.string]; + if (!options || options.useGlobalScope !== false) + base = base || global[obj.string]; + } else if (obj.type == "string") { + base = ""; + } else if (obj.type == "atom") { + base = 1; + } else if (obj.type == "function") { + if (global.jQuery != null && (obj.string == '$' || obj.string == 'jQuery') && + (typeof global.jQuery == 'function')) + base = global.jQuery(); + else if (global._ != null && (obj.string == '_') && (typeof global._ == 'function')) + base = global._(); + } + while (base != null && context.length) + base = base[context.pop().string]; + if (base != null) gatherCompletions(base); + } else { + // If not, just look in the global object and any local scope + // (reading into JS mode internals to get at the local and global variables) + for (var v = token.state.localVars; v; v = v.next) maybeAdd(v.name); + for (var v = token.state.globalVars; v; v = v.next) maybeAdd(v.name); + if (!options || options.useGlobalScope !== false) + gatherCompletions(global); + forEach(keywords, maybeAdd); + } + return found; + } +}); diff --git a/static/js/mdeditor/lib/codemirror/addon/hint/show-hint.css b/static/js/mdeditor/lib/codemirror/addon/hint/show-hint.css new file mode 100644 index 00000000..924e638f --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/hint/show-hint.css @@ -0,0 +1,38 @@ +.CodeMirror-hints { + position: absolute; + z-index: 10; + overflow: hidden; + list-style: none; + + margin: 0; + padding: 2px; + + -webkit-box-shadow: 2px 3px 5px rgba(0,0,0,.2); + -moz-box-shadow: 2px 3px 5px rgba(0,0,0,.2); + box-shadow: 2px 3px 5px rgba(0,0,0,.2); + border-radius: 3px; + border: 1px solid silver; + + background: white; + font-size: 90%; + font-family: monospace; + + max-height: 20em; + overflow-y: auto; +} + +.CodeMirror-hint { + margin: 0; + padding: 0 4px; + border-radius: 2px; + max-width: 19em; + overflow: hidden; + white-space: pre; + color: black; + cursor: pointer; +} + +li.CodeMirror-hint-active { + background: #08f; + color: white; +} diff --git a/static/js/mdeditor/lib/codemirror/addon/hint/show-hint.js b/static/js/mdeditor/lib/codemirror/addon/hint/show-hint.js new file mode 100644 index 00000000..f5446194 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/hint/show-hint.js @@ -0,0 +1,394 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var HINT_ELEMENT_CLASS = "CodeMirror-hint"; + var ACTIVE_HINT_ELEMENT_CLASS = "CodeMirror-hint-active"; + + // This is the old interface, kept around for now to stay + // backwards-compatible. + CodeMirror.showHint = function(cm, getHints, options) { + if (!getHints) return cm.showHint(options); + if (options && options.async) getHints.async = true; + var newOpts = {hint: getHints}; + if (options) for (var prop in options) newOpts[prop] = options[prop]; + return cm.showHint(newOpts); + }; + + var asyncRunID = 0; + function retrieveHints(getter, cm, options, then) { + if (getter.async) { + var id = ++asyncRunID; + getter(cm, function(hints) { + if (asyncRunID == id) then(hints); + }, options); + } else { + then(getter(cm, options)); + } + } + + CodeMirror.defineExtension("showHint", function(options) { + // We want a single cursor position. + if (this.listSelections().length > 1 || this.somethingSelected()) return; + + if (this.state.completionActive) this.state.completionActive.close(); + var completion = this.state.completionActive = new Completion(this, options); + var getHints = completion.options.hint; + if (!getHints) return; + + CodeMirror.signal(this, "startCompletion", this); + return retrieveHints(getHints, this, completion.options, function(hints) { completion.showHints(hints); }); + }); + + function Completion(cm, options) { + this.cm = cm; + this.options = this.buildOptions(options); + this.widget = this.onClose = null; + } + + Completion.prototype = { + close: function() { + if (!this.active()) return; + this.cm.state.completionActive = null; + + if (this.widget) this.widget.close(); + if (this.onClose) this.onClose(); + CodeMirror.signal(this.cm, "endCompletion", this.cm); + }, + + active: function() { + return this.cm.state.completionActive == this; + }, + + pick: function(data, i) { + var completion = data.list[i]; + if (completion.hint) completion.hint(this.cm, data, completion); + else this.cm.replaceRange(getText(completion), completion.from || data.from, + completion.to || data.to, "complete"); + CodeMirror.signal(data, "pick", completion); + this.close(); + }, + + showHints: function(data) { + if (!data || !data.list.length || !this.active()) return this.close(); + + if (this.options.completeSingle && data.list.length == 1) + this.pick(data, 0); + else + this.showWidget(data); + }, + + showWidget: function(data) { + this.widget = new Widget(this, data); + CodeMirror.signal(data, "shown"); + + var debounce = 0, completion = this, finished; + var closeOn = this.options.closeCharacters; + var startPos = this.cm.getCursor(), startLen = this.cm.getLine(startPos.line).length; + + var requestAnimationFrame = window.requestAnimationFrame || function(fn) { + return setTimeout(fn, 1000/60); + }; + var cancelAnimationFrame = window.cancelAnimationFrame || clearTimeout; + + function done() { + if (finished) return; + finished = true; + completion.close(); + completion.cm.off("cursorActivity", activity); + if (data) CodeMirror.signal(data, "close"); + } + + function update() { + if (finished) return; + CodeMirror.signal(data, "update"); + retrieveHints(completion.options.hint, completion.cm, completion.options, finishUpdate); + } + function finishUpdate(data_) { + data = data_; + if (finished) return; + if (!data || !data.list.length) return done(); + if (completion.widget) completion.widget.close(); + completion.widget = new Widget(completion, data); + } + + function clearDebounce() { + if (debounce) { + cancelAnimationFrame(debounce); + debounce = 0; + } + } + + function activity() { + clearDebounce(); + var pos = completion.cm.getCursor(), line = completion.cm.getLine(pos.line); + if (pos.line != startPos.line || line.length - pos.ch != startLen - startPos.ch || + pos.ch < startPos.ch || completion.cm.somethingSelected() || + (pos.ch && closeOn.test(line.charAt(pos.ch - 1)))) { + completion.close(); + } else { + debounce = requestAnimationFrame(update); + if (completion.widget) completion.widget.close(); + } + } + this.cm.on("cursorActivity", activity); + this.onClose = done; + }, + + buildOptions: function(options) { + var editor = this.cm.options.hintOptions; + var out = {}; + for (var prop in defaultOptions) out[prop] = defaultOptions[prop]; + if (editor) for (var prop in editor) + if (editor[prop] !== undefined) out[prop] = editor[prop]; + if (options) for (var prop in options) + if (options[prop] !== undefined) out[prop] = options[prop]; + return out; + } + }; + + function getText(completion) { + if (typeof completion == "string") return completion; + else return completion.text; + } + + function buildKeyMap(completion, handle) { + var baseMap = { + Up: function() {handle.moveFocus(-1);}, + Down: function() {handle.moveFocus(1);}, + PageUp: function() {handle.moveFocus(-handle.menuSize() + 1, true);}, + PageDown: function() {handle.moveFocus(handle.menuSize() - 1, true);}, + Home: function() {handle.setFocus(0);}, + End: function() {handle.setFocus(handle.length - 1);}, + Enter: handle.pick, + Tab: handle.pick, + Esc: handle.close + }; + var custom = completion.options.customKeys; + var ourMap = custom ? {} : baseMap; + function addBinding(key, val) { + var bound; + if (typeof val != "string") + bound = function(cm) { return val(cm, handle); }; + // This mechanism is deprecated + else if (baseMap.hasOwnProperty(val)) + bound = baseMap[val]; + else + bound = val; + ourMap[key] = bound; + } + if (custom) + for (var key in custom) if (custom.hasOwnProperty(key)) + addBinding(key, custom[key]); + var extra = completion.options.extraKeys; + if (extra) + for (var key in extra) if (extra.hasOwnProperty(key)) + addBinding(key, extra[key]); + return ourMap; + } + + function getHintElement(hintsElement, el) { + while (el && el != hintsElement) { + if (el.nodeName.toUpperCase() === "LI" && el.parentNode == hintsElement) return el; + el = el.parentNode; + } + } + + function Widget(completion, data) { + this.completion = completion; + this.data = data; + var widget = this, cm = completion.cm; + + var hints = this.hints = document.createElement("ul"); + hints.className = "CodeMirror-hints"; + this.selectedHint = data.selectedHint || 0; + + var completions = data.list; + for (var i = 0; i < completions.length; ++i) { + var elt = hints.appendChild(document.createElement("li")), cur = completions[i]; + var className = HINT_ELEMENT_CLASS + (i != this.selectedHint ? "" : " " + ACTIVE_HINT_ELEMENT_CLASS); + if (cur.className != null) className = cur.className + " " + className; + elt.className = className; + if (cur.render) cur.render(elt, data, cur); + else elt.appendChild(document.createTextNode(cur.displayText || getText(cur))); + elt.hintId = i; + } + + var pos = cm.cursorCoords(completion.options.alignWithWord ? data.from : null); + var left = pos.left, top = pos.bottom, below = true; + hints.style.left = left + "px"; + hints.style.top = top + "px"; + // If we're at the edge of the screen, then we want the menu to appear on the left of the cursor. + var winW = window.innerWidth || Math.max(document.body.offsetWidth, document.documentElement.offsetWidth); + var winH = window.innerHeight || Math.max(document.body.offsetHeight, document.documentElement.offsetHeight); + (completion.options.container || document.body).appendChild(hints); + var box = hints.getBoundingClientRect(), overlapY = box.bottom - winH; + if (overlapY > 0) { + var height = box.bottom - box.top, curTop = pos.top - (pos.bottom - box.top); + if (curTop - height > 0) { // Fits above cursor + hints.style.top = (top = pos.top - height) + "px"; + below = false; + } else if (height > winH) { + hints.style.height = (winH - 5) + "px"; + hints.style.top = (top = pos.bottom - box.top) + "px"; + var cursor = cm.getCursor(); + if (data.from.ch != cursor.ch) { + pos = cm.cursorCoords(cursor); + hints.style.left = (left = pos.left) + "px"; + box = hints.getBoundingClientRect(); + } + } + } + var overlapX = box.right - winW; + if (overlapX > 0) { + if (box.right - box.left > winW) { + hints.style.width = (winW - 5) + "px"; + overlapX -= (box.right - box.left) - winW; + } + hints.style.left = (left = pos.left - overlapX) + "px"; + } + + cm.addKeyMap(this.keyMap = buildKeyMap(completion, { + moveFocus: function(n, avoidWrap) { widget.changeActive(widget.selectedHint + n, avoidWrap); }, + setFocus: function(n) { widget.changeActive(n); }, + menuSize: function() { return widget.screenAmount(); }, + length: completions.length, + close: function() { completion.close(); }, + pick: function() { widget.pick(); }, + data: data + })); + + if (completion.options.closeOnUnfocus) { + var closingOnBlur; + cm.on("blur", this.onBlur = function() { closingOnBlur = setTimeout(function() { completion.close(); }, 100); }); + cm.on("focus", this.onFocus = function() { clearTimeout(closingOnBlur); }); + } + + var startScroll = cm.getScrollInfo(); + cm.on("scroll", this.onScroll = function() { + var curScroll = cm.getScrollInfo(), editor = cm.getWrapperElement().getBoundingClientRect(); + var newTop = top + startScroll.top - curScroll.top; + var point = newTop - (window.pageYOffset || (document.documentElement || document.body).scrollTop); + if (!below) point += hints.offsetHeight; + if (point <= editor.top || point >= editor.bottom) return completion.close(); + hints.style.top = newTop + "px"; + hints.style.left = (left + startScroll.left - curScroll.left) + "px"; + }); + + CodeMirror.on(hints, "dblclick", function(e) { + var t = getHintElement(hints, e.target || e.srcElement); + if (t && t.hintId != null) {widget.changeActive(t.hintId); widget.pick();} + }); + + CodeMirror.on(hints, "click", function(e) { + var t = getHintElement(hints, e.target || e.srcElement); + if (t && t.hintId != null) { + widget.changeActive(t.hintId); + if (completion.options.completeOnSingleClick) widget.pick(); + } + }); + + CodeMirror.on(hints, "mousedown", function() { + setTimeout(function(){cm.focus();}, 20); + }); + + CodeMirror.signal(data, "select", completions[0], hints.firstChild); + return true; + } + + Widget.prototype = { + close: function() { + if (this.completion.widget != this) return; + this.completion.widget = null; + this.hints.parentNode.removeChild(this.hints); + this.completion.cm.removeKeyMap(this.keyMap); + + var cm = this.completion.cm; + if (this.completion.options.closeOnUnfocus) { + cm.off("blur", this.onBlur); + cm.off("focus", this.onFocus); + } + cm.off("scroll", this.onScroll); + }, + + pick: function() { + this.completion.pick(this.data, this.selectedHint); + }, + + changeActive: function(i, avoidWrap) { + if (i >= this.data.list.length) + i = avoidWrap ? this.data.list.length - 1 : 0; + else if (i < 0) + i = avoidWrap ? 0 : this.data.list.length - 1; + if (this.selectedHint == i) return; + var node = this.hints.childNodes[this.selectedHint]; + node.className = node.className.replace(" " + ACTIVE_HINT_ELEMENT_CLASS, ""); + node = this.hints.childNodes[this.selectedHint = i]; + node.className += " " + ACTIVE_HINT_ELEMENT_CLASS; + if (node.offsetTop < this.hints.scrollTop) + this.hints.scrollTop = node.offsetTop - 3; + else if (node.offsetTop + node.offsetHeight > this.hints.scrollTop + this.hints.clientHeight) + this.hints.scrollTop = node.offsetTop + node.offsetHeight - this.hints.clientHeight + 3; + CodeMirror.signal(this.data, "select", this.data.list[this.selectedHint], node); + }, + + screenAmount: function() { + return Math.floor(this.hints.clientHeight / this.hints.firstChild.offsetHeight) || 1; + } + }; + + CodeMirror.registerHelper("hint", "auto", function(cm, options) { + var helpers = cm.getHelpers(cm.getCursor(), "hint"), words; + if (helpers.length) { + for (var i = 0; i < helpers.length; i++) { + var cur = helpers[i](cm, options); + if (cur && cur.list.length) return cur; + } + } else if (words = cm.getHelper(cm.getCursor(), "hintWords")) { + if (words) return CodeMirror.hint.fromList(cm, {words: words}); + } else if (CodeMirror.hint.anyword) { + return CodeMirror.hint.anyword(cm, options); + } + }); + + CodeMirror.registerHelper("hint", "fromList", function(cm, options) { + var cur = cm.getCursor(), token = cm.getTokenAt(cur); + var found = []; + for (var i = 0; i < options.words.length; i++) { + var word = options.words[i]; + if (word.slice(0, token.string.length) == token.string) + found.push(word); + } + + if (found.length) return { + list: found, + from: CodeMirror.Pos(cur.line, token.start), + to: CodeMirror.Pos(cur.line, token.end) + }; + }); + + CodeMirror.commands.autocomplete = CodeMirror.showHint; + + var defaultOptions = { + hint: CodeMirror.hint.auto, + completeSingle: true, + alignWithWord: true, + closeCharacters: /[\s()\[\]{};:>,]/, + closeOnUnfocus: true, + completeOnSingleClick: false, + container: null, + customKeys: null, + extraKeys: null + }; + + CodeMirror.defineOption("hintOptions", null); +}); diff --git a/static/js/mdeditor/lib/codemirror/addon/hint/sql-hint.js b/static/js/mdeditor/lib/codemirror/addon/hint/sql-hint.js new file mode 100644 index 00000000..5b0cc769 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/hint/sql-hint.js @@ -0,0 +1,240 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../../mode/sql/sql")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../../mode/sql/sql"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var tables; + var defaultTable; + var keywords; + var CONS = { + QUERY_DIV: ";", + ALIAS_KEYWORD: "AS" + }; + var Pos = CodeMirror.Pos; + + function getKeywords(editor) { + var mode = editor.doc.modeOption; + if (mode === "sql") mode = "text/x-sql"; + return CodeMirror.resolveMode(mode).keywords; + } + + function getText(item) { + return typeof item == "string" ? item : item.text; + } + + function getItem(list, item) { + if (!list.slice) return list[item]; + for (var i = list.length - 1; i >= 0; i--) if (getText(list[i]) == item) + return list[i]; + } + + function shallowClone(object) { + var result = {}; + for (var key in object) if (object.hasOwnProperty(key)) + result[key] = object[key]; + return result; + } + + function match(string, word) { + var len = string.length; + var sub = getText(word).substr(0, len); + return string.toUpperCase() === sub.toUpperCase(); + } + + function addMatches(result, search, wordlist, formatter) { + for (var word in wordlist) { + if (!wordlist.hasOwnProperty(word)) continue; + if (Array.isArray(wordlist)) { + word = wordlist[word]; + } + if (match(search, word)) { + result.push(formatter(word)); + } + } + } + + function cleanName(name) { + // Get rid name from backticks(`) and preceding dot(.) + if (name.charAt(0) == ".") { + name = name.substr(1); + } + return name.replace(/`/g, ""); + } + + function insertBackticks(name) { + var nameParts = getText(name).split("."); + for (var i = 0; i < nameParts.length; i++) + nameParts[i] = "`" + nameParts[i] + "`"; + var escaped = nameParts.join("."); + if (typeof name == "string") return escaped; + name = shallowClone(name); + name.text = escaped; + return name; + } + + function nameCompletion(cur, token, result, editor) { + // Try to complete table, colunm names and return start position of completion + var useBacktick = false; + var nameParts = []; + var start = token.start; + var cont = true; + while (cont) { + cont = (token.string.charAt(0) == "."); + useBacktick = useBacktick || (token.string.charAt(0) == "`"); + + start = token.start; + nameParts.unshift(cleanName(token.string)); + + token = editor.getTokenAt(Pos(cur.line, token.start)); + if (token.string == ".") { + cont = true; + token = editor.getTokenAt(Pos(cur.line, token.start)); + } + } + + // Try to complete table names + var string = nameParts.join("."); + addMatches(result, string, tables, function(w) { + return useBacktick ? insertBackticks(w) : w; + }); + + // Try to complete columns from defaultTable + addMatches(result, string, defaultTable, function(w) { + return useBacktick ? insertBackticks(w) : w; + }); + + // Try to complete columns + string = nameParts.pop(); + var table = nameParts.join("."); + + // Check if table is available. If not, find table by Alias + if (!getItem(tables, table)) + table = findTableByAlias(table, editor); + + var columns = getItem(tables, table); + if (columns && Array.isArray(tables) && columns.columns) + columns = columns.columns; + + if (columns) { + addMatches(result, string, columns, function(w) { + if (typeof w == "string") { + w = table + "." + w; + } else { + w = shallowClone(w); + w.text = table + "." + w.text; + } + return useBacktick ? insertBackticks(w) : w; + }); + } + + return start; + } + + function eachWord(lineText, f) { + if (!lineText) return; + var excepted = /[,;]/g; + var words = lineText.split(" "); + for (var i = 0; i < words.length; i++) { + f(words[i]?words[i].replace(excepted, '') : ''); + } + } + + function convertCurToNumber(cur) { + // max characters of a line is 999,999. + return cur.line + cur.ch / Math.pow(10, 6); + } + + function convertNumberToCur(num) { + return Pos(Math.floor(num), +num.toString().split('.').pop()); + } + + function findTableByAlias(alias, editor) { + var doc = editor.doc; + var fullQuery = doc.getValue(); + var aliasUpperCase = alias.toUpperCase(); + var previousWord = ""; + var table = ""; + var separator = []; + var validRange = { + start: Pos(0, 0), + end: Pos(editor.lastLine(), editor.getLineHandle(editor.lastLine()).length) + }; + + //add separator + var indexOfSeparator = fullQuery.indexOf(CONS.QUERY_DIV); + while(indexOfSeparator != -1) { + separator.push(doc.posFromIndex(indexOfSeparator)); + indexOfSeparator = fullQuery.indexOf(CONS.QUERY_DIV, indexOfSeparator+1); + } + separator.unshift(Pos(0, 0)); + separator.push(Pos(editor.lastLine(), editor.getLineHandle(editor.lastLine()).text.length)); + + //find valid range + var prevItem = 0; + var current = convertCurToNumber(editor.getCursor()); + for (var i=0; i< separator.length; i++) { + var _v = convertCurToNumber(separator[i]); + if (current > prevItem && current <= _v) { + validRange = { start: convertNumberToCur(prevItem), end: convertNumberToCur(_v) }; + break; + } + prevItem = _v; + } + + var query = doc.getRange(validRange.start, validRange.end, false); + + for (var i = 0; i < query.length; i++) { + var lineText = query[i]; + eachWord(lineText, function(word) { + var wordUpperCase = word.toUpperCase(); + if (wordUpperCase === aliasUpperCase && getItem(tables, previousWord)) + table = previousWord; + if (wordUpperCase !== CONS.ALIAS_KEYWORD) + previousWord = word; + }); + if (table) break; + } + return table; + } + + CodeMirror.registerHelper("hint", "sql", function(editor, options) { + tables = (options && options.tables) || {}; + var defaultTableName = options && options.defaultTable; + defaultTable = (defaultTableName && getItem(tables, defaultTableName)) || []; + keywords = keywords || getKeywords(editor); + + var cur = editor.getCursor(); + var result = []; + var token = editor.getTokenAt(cur), start, end, search; + if (token.end > cur.ch) { + token.end = cur.ch; + token.string = token.string.slice(0, cur.ch - token.start); + } + + if (token.string.match(/^[.`\w@]\w*$/)) { + search = token.string; + start = token.start; + end = token.end; + } else { + start = end = cur.ch; + search = ""; + } + if (search.charAt(0) == "." || search.charAt(0) == "`") { + start = nameCompletion(cur, token, result, editor); + } else { + addMatches(result, search, tables, function(w) {return w;}); + addMatches(result, search, defaultTable, function(w) {return w;}); + addMatches(result, search, keywords, function(w) {return w.toUpperCase();}); + } + + return {list: result, from: Pos(cur.line, start), to: Pos(cur.line, end)}; + }); +}); diff --git a/static/js/mdeditor/lib/codemirror/addon/hint/xml-hint.js b/static/js/mdeditor/lib/codemirror/addon/hint/xml-hint.js new file mode 100644 index 00000000..9b9baa0c --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/hint/xml-hint.js @@ -0,0 +1,110 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var Pos = CodeMirror.Pos; + + function getHints(cm, options) { + var tags = options && options.schemaInfo; + var quote = (options && options.quoteChar) || '"'; + if (!tags) return; + var cur = cm.getCursor(), token = cm.getTokenAt(cur); + if (token.end > cur.ch) { + token.end = cur.ch; + token.string = token.string.slice(0, cur.ch - token.start); + } + var inner = CodeMirror.innerMode(cm.getMode(), token.state); + if (inner.mode.name != "xml") return; + var result = [], replaceToken = false, prefix; + var tag = /\btag\b/.test(token.type) && !/>$/.test(token.string); + var tagName = tag && /^\w/.test(token.string), tagStart; + + if (tagName) { + var before = cm.getLine(cur.line).slice(Math.max(0, token.start - 2), token.start); + var tagType = /<\/$/.test(before) ? "close" : /<$/.test(before) ? "open" : null; + if (tagType) tagStart = token.start - (tagType == "close" ? 2 : 1); + } else if (tag && token.string == "<") { + tagType = "open"; + } else if (tag && token.string == ""); + } else { + // Attribute completion + var curTag = tags[inner.state.tagName], attrs = curTag && curTag.attrs; + var globalAttrs = tags["!attrs"]; + if (!attrs && !globalAttrs) return; + if (!attrs) { + attrs = globalAttrs; + } else if (globalAttrs) { // Combine tag-local and global attributes + var set = {}; + for (var nm in globalAttrs) if (globalAttrs.hasOwnProperty(nm)) set[nm] = globalAttrs[nm]; + for (var nm in attrs) if (attrs.hasOwnProperty(nm)) set[nm] = attrs[nm]; + attrs = set; + } + if (token.type == "string" || token.string == "=") { // A value + var before = cm.getRange(Pos(cur.line, Math.max(0, cur.ch - 60)), + Pos(cur.line, token.type == "string" ? token.start : token.end)); + var atName = before.match(/([^\s\u00a0=<>\"\']+)=$/), atValues; + if (!atName || !attrs.hasOwnProperty(atName[1]) || !(atValues = attrs[atName[1]])) return; + if (typeof atValues == 'function') atValues = atValues.call(this, cm); // Functions can be used to supply values for autocomplete widget + if (token.type == "string") { + prefix = token.string; + var n = 0; + if (/['"]/.test(token.string.charAt(0))) { + quote = token.string.charAt(0); + prefix = token.string.slice(1); + n++; + } + var len = token.string.length; + if (/['"]/.test(token.string.charAt(len - 1))) { + quote = token.string.charAt(len - 1); + prefix = token.string.substr(n, len - 2); + } + replaceToken = true; + } + for (var i = 0; i < atValues.length; ++i) if (!prefix || atValues[i].lastIndexOf(prefix, 0) == 0) + result.push(quote + atValues[i] + quote); + } else { // An attribute name + if (token.type == "attribute") { + prefix = token.string; + replaceToken = true; + } + for (var attr in attrs) if (attrs.hasOwnProperty(attr) && (!prefix || attr.lastIndexOf(prefix, 0) == 0)) + result.push(attr); + } + } + return { + list: result, + from: replaceToken ? Pos(cur.line, tagStart == null ? token.start : tagStart) : cur, + to: replaceToken ? Pos(cur.line, token.end) : cur + }; + } + + CodeMirror.registerHelper("hint", "xml", getHints); +}); diff --git a/static/js/mdeditor/lib/codemirror/addon/lint/coffeescript-lint.js b/static/js/mdeditor/lib/codemirror/addon/lint/coffeescript-lint.js new file mode 100644 index 00000000..7e39428f --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/lint/coffeescript-lint.js @@ -0,0 +1,41 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// Depends on coffeelint.js from http://www.coffeelint.org/js/coffeelint.js + +// declare global: coffeelint + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.registerHelper("lint", "coffeescript", function(text) { + var found = []; + var parseError = function(err) { + var loc = err.lineNumber; + found.push({from: CodeMirror.Pos(loc-1, 0), + to: CodeMirror.Pos(loc, 0), + severity: err.level, + message: err.message}); + }; + try { + var res = coffeelint.lint(text); + for(var i = 0; i < res.length; i++) { + parseError(res[i]); + } + } catch(e) { + found.push({from: CodeMirror.Pos(e.location.first_line, 0), + to: CodeMirror.Pos(e.location.last_line, e.location.last_column), + severity: 'error', + message: e.message}); + } + return found; +}); + +}); diff --git a/static/js/mdeditor/lib/codemirror/addon/lint/css-lint.js b/static/js/mdeditor/lib/codemirror/addon/lint/css-lint.js new file mode 100644 index 00000000..1f61b479 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/lint/css-lint.js @@ -0,0 +1,35 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// Depends on csslint.js from https://github.com/stubbornella/csslint + +// declare global: CSSLint + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.registerHelper("lint", "css", function(text) { + var found = []; + if (!window.CSSLint) return found; + var results = CSSLint.verify(text), messages = results.messages, message = null; + for ( var i = 0; i < messages.length; i++) { + message = messages[i]; + var startLine = message.line -1, endLine = message.line -1, startCol = message.col -1, endCol = message.col; + found.push({ + from: CodeMirror.Pos(startLine, startCol), + to: CodeMirror.Pos(endLine, endCol), + message: message.message, + severity : message.type + }); + } + return found; +}); + +}); diff --git a/static/js/mdeditor/lib/codemirror/addon/lint/javascript-lint.js b/static/js/mdeditor/lib/codemirror/addon/lint/javascript-lint.js new file mode 100644 index 00000000..3d65ba69 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/lint/javascript-lint.js @@ -0,0 +1,136 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + // declare global: JSHINT + + var bogus = [ "Dangerous comment" ]; + + var warnings = [ [ "Expected '{'", + "Statement body should be inside '{ }' braces." ] ]; + + var errors = [ "Missing semicolon", "Extra comma", "Missing property name", + "Unmatched ", " and instead saw", " is not defined", + "Unclosed string", "Stopping, unable to continue" ]; + + function validator(text, options) { + if (!window.JSHINT) return []; + JSHINT(text, options); + var errors = JSHINT.data().errors, result = []; + if (errors) parseErrors(errors, result); + return result; + } + + CodeMirror.registerHelper("lint", "javascript", validator); + + function cleanup(error) { + // All problems are warnings by default + fixWith(error, warnings, "warning", true); + fixWith(error, errors, "error"); + + return isBogus(error) ? null : error; + } + + function fixWith(error, fixes, severity, force) { + var description, fix, find, replace, found; + + description = error.description; + + for ( var i = 0; i < fixes.length; i++) { + fix = fixes[i]; + find = (typeof fix === "string" ? fix : fix[0]); + replace = (typeof fix === "string" ? null : fix[1]); + found = description.indexOf(find) !== -1; + + if (force || found) { + error.severity = severity; + } + if (found && replace) { + error.description = replace; + } + } + } + + function isBogus(error) { + var description = error.description; + for ( var i = 0; i < bogus.length; i++) { + if (description.indexOf(bogus[i]) !== -1) { + return true; + } + } + return false; + } + + function parseErrors(errors, output) { + for ( var i = 0; i < errors.length; i++) { + var error = errors[i]; + if (error) { + var linetabpositions, index; + + linetabpositions = []; + + // This next block is to fix a problem in jshint. Jshint + // replaces + // all tabs with spaces then performs some checks. The error + // positions (character/space) are then reported incorrectly, + // not taking the replacement step into account. Here we look + // at the evidence line and try to adjust the character position + // to the correct value. + if (error.evidence) { + // Tab positions are computed once per line and cached + var tabpositions = linetabpositions[error.line]; + if (!tabpositions) { + var evidence = error.evidence; + tabpositions = []; + // ugggh phantomjs does not like this + // forEachChar(evidence, function(item, index) { + Array.prototype.forEach.call(evidence, function(item, + index) { + if (item === '\t') { + // First col is 1 (not 0) to match error + // positions + tabpositions.push(index + 1); + } + }); + linetabpositions[error.line] = tabpositions; + } + if (tabpositions.length > 0) { + var pos = error.character; + tabpositions.forEach(function(tabposition) { + if (pos > tabposition) pos -= 1; + }); + error.character = pos; + } + } + + var start = error.character - 1, end = start + 1; + if (error.evidence) { + index = error.evidence.substring(start).search(/.\b/); + if (index > -1) { + end += index; + } + } + + // Convert to format expected by validation service + error.description = error.reason;// + "(jshint)"; + error.start = error.character; + error.end = end; + error = cleanup(error); + + if (error) + output.push({message: error.description, + severity: error.severity, + from: CodeMirror.Pos(error.line - 1, start), + to: CodeMirror.Pos(error.line - 1, end)}); + } + } + } +}); diff --git a/static/js/mdeditor/lib/codemirror/addon/lint/json-lint.js b/static/js/mdeditor/lib/codemirror/addon/lint/json-lint.js new file mode 100644 index 00000000..9dbb616b --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/lint/json-lint.js @@ -0,0 +1,31 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// Depends on jsonlint.js from https://github.com/zaach/jsonlint + +// declare global: jsonlint + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.registerHelper("lint", "json", function(text) { + var found = []; + jsonlint.parseError = function(str, hash) { + var loc = hash.loc; + found.push({from: CodeMirror.Pos(loc.first_line - 1, loc.first_column), + to: CodeMirror.Pos(loc.last_line - 1, loc.last_column), + message: str}); + }; + try { jsonlint.parse(text); } + catch(e) {} + return found; +}); + +}); diff --git a/static/js/mdeditor/lib/codemirror/addon/lint/lint.css b/static/js/mdeditor/lib/codemirror/addon/lint/lint.css new file mode 100644 index 00000000..414a9a0e --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/lint/lint.css @@ -0,0 +1,73 @@ +/* The lint marker gutter */ +.CodeMirror-lint-markers { + width: 16px; +} + +.CodeMirror-lint-tooltip { + background-color: infobackground; + border: 1px solid black; + border-radius: 4px 4px 4px 4px; + color: infotext; + font-family: monospace; + font-size: 10pt; + overflow: hidden; + padding: 2px 5px; + position: fixed; + white-space: pre; + white-space: pre-wrap; + z-index: 100; + max-width: 600px; + opacity: 0; + transition: opacity .4s; + -moz-transition: opacity .4s; + -webkit-transition: opacity .4s; + -o-transition: opacity .4s; + -ms-transition: opacity .4s; +} + +.CodeMirror-lint-mark-error, .CodeMirror-lint-mark-warning { + background-position: left bottom; + background-repeat: repeat-x; +} + +.CodeMirror-lint-mark-error { + background-image: + url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJDw4cOCW1/KIAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAHElEQVQI12NggIL/DAz/GdA5/xkY/qPKMDAwAADLZwf5rvm+LQAAAABJRU5ErkJggg==") + ; +} + +.CodeMirror-lint-mark-warning { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJFhQXEbhTg7YAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAMklEQVQI12NkgIIvJ3QXMjAwdDN+OaEbysDA4MPAwNDNwMCwiOHLCd1zX07o6kBVGQEAKBANtobskNMAAAAASUVORK5CYII="); +} + +.CodeMirror-lint-marker-error, .CodeMirror-lint-marker-warning { + background-position: center center; + background-repeat: no-repeat; + cursor: pointer; + display: inline-block; + height: 16px; + width: 16px; + vertical-align: middle; + position: relative; +} + +.CodeMirror-lint-message-error, .CodeMirror-lint-message-warning { + padding-left: 18px; + background-position: top left; + background-repeat: no-repeat; +} + +.CodeMirror-lint-marker-error, .CodeMirror-lint-message-error { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAHlBMVEW7AAC7AACxAAC7AAC7AAAAAAC4AAC5AAD///+7AAAUdclpAAAABnRSTlMXnORSiwCK0ZKSAAAATUlEQVR42mWPOQ7AQAgDuQLx/z8csYRmPRIFIwRGnosRrpamvkKi0FTIiMASR3hhKW+hAN6/tIWhu9PDWiTGNEkTtIOucA5Oyr9ckPgAWm0GPBog6v4AAAAASUVORK5CYII="); +} + +.CodeMirror-lint-marker-warning, .CodeMirror-lint-message-warning { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAANlBMVEX/uwDvrwD/uwD/uwD/uwD/uwD/uwD/uwD/uwD6twD/uwAAAADurwD2tQD7uAD+ugAAAAD/uwDhmeTRAAAADHRSTlMJ8mN1EYcbmiixgACm7WbuAAAAVklEQVR42n3PUQqAIBBFUU1LLc3u/jdbOJoW1P08DA9Gba8+YWJ6gNJoNYIBzAA2chBth5kLmG9YUoG0NHAUwFXwO9LuBQL1giCQb8gC9Oro2vp5rncCIY8L8uEx5ZkAAAAASUVORK5CYII="); +} + +.CodeMirror-lint-marker-multiple { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAMAAADzjKfhAAAACVBMVEUAAAAAAAC/v7914kyHAAAAAXRSTlMAQObYZgAAACNJREFUeNo1ioEJAAAIwmz/H90iFFSGJgFMe3gaLZ0od+9/AQZ0ADosbYraAAAAAElFTkSuQmCC"); + background-repeat: no-repeat; + background-position: right bottom; + width: 100%; height: 100%; +} diff --git a/static/js/mdeditor/lib/codemirror/addon/lint/lint.js b/static/js/mdeditor/lib/codemirror/addon/lint/lint.js new file mode 100644 index 00000000..18eb7090 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/lint/lint.js @@ -0,0 +1,205 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + var GUTTER_ID = "CodeMirror-lint-markers"; + + function showTooltip(e, content) { + var tt = document.createElement("div"); + tt.className = "CodeMirror-lint-tooltip"; + tt.appendChild(content.cloneNode(true)); + document.body.appendChild(tt); + + function position(e) { + if (!tt.parentNode) return CodeMirror.off(document, "mousemove", position); + tt.style.top = Math.max(0, e.clientY - tt.offsetHeight - 5) + "px"; + tt.style.left = (e.clientX + 5) + "px"; + } + CodeMirror.on(document, "mousemove", position); + position(e); + if (tt.style.opacity != null) tt.style.opacity = 1; + return tt; + } + function rm(elt) { + if (elt.parentNode) elt.parentNode.removeChild(elt); + } + function hideTooltip(tt) { + if (!tt.parentNode) return; + if (tt.style.opacity == null) rm(tt); + tt.style.opacity = 0; + setTimeout(function() { rm(tt); }, 600); + } + + function showTooltipFor(e, content, node) { + var tooltip = showTooltip(e, content); + function hide() { + CodeMirror.off(node, "mouseout", hide); + if (tooltip) { hideTooltip(tooltip); tooltip = null; } + } + var poll = setInterval(function() { + if (tooltip) for (var n = node;; n = n.parentNode) { + if (n && n.nodeType == 11) n = n.host; + if (n == document.body) return; + if (!n) { hide(); break; } + } + if (!tooltip) return clearInterval(poll); + }, 400); + CodeMirror.on(node, "mouseout", hide); + } + + function LintState(cm, options, hasGutter) { + this.marked = []; + this.options = options; + this.timeout = null; + this.hasGutter = hasGutter; + this.onMouseOver = function(e) { onMouseOver(cm, e); }; + } + + function parseOptions(cm, options) { + if (options instanceof Function) return {getAnnotations: options}; + if (!options || options === true) options = {}; + if (!options.getAnnotations) options.getAnnotations = cm.getHelper(CodeMirror.Pos(0, 0), "lint"); + if (!options.getAnnotations) throw new Error("Required option 'getAnnotations' missing (lint addon)"); + return options; + } + + function clearMarks(cm) { + var state = cm.state.lint; + if (state.hasGutter) cm.clearGutter(GUTTER_ID); + for (var i = 0; i < state.marked.length; ++i) + state.marked[i].clear(); + state.marked.length = 0; + } + + function makeMarker(labels, severity, multiple, tooltips) { + var marker = document.createElement("div"), inner = marker; + marker.className = "CodeMirror-lint-marker-" + severity; + if (multiple) { + inner = marker.appendChild(document.createElement("div")); + inner.className = "CodeMirror-lint-marker-multiple"; + } + + if (tooltips != false) CodeMirror.on(inner, "mouseover", function(e) { + showTooltipFor(e, labels, inner); + }); + + return marker; + } + + function getMaxSeverity(a, b) { + if (a == "error") return a; + else return b; + } + + function groupByLine(annotations) { + var lines = []; + for (var i = 0; i < annotations.length; ++i) { + var ann = annotations[i], line = ann.from.line; + (lines[line] || (lines[line] = [])).push(ann); + } + return lines; + } + + function annotationTooltip(ann) { + var severity = ann.severity; + if (!severity) severity = "error"; + var tip = document.createElement("div"); + tip.className = "CodeMirror-lint-message-" + severity; + tip.appendChild(document.createTextNode(ann.message)); + return tip; + } + + function startLinting(cm) { + var state = cm.state.lint, options = state.options; + var passOptions = options.options || options; // Support deprecated passing of `options` property in options + if (options.async || options.getAnnotations.async) + options.getAnnotations(cm.getValue(), updateLinting, passOptions, cm); + else + updateLinting(cm, options.getAnnotations(cm.getValue(), passOptions, cm)); + } + + function updateLinting(cm, annotationsNotSorted) { + clearMarks(cm); + var state = cm.state.lint, options = state.options; + + var annotations = groupByLine(annotationsNotSorted); + + for (var line = 0; line < annotations.length; ++line) { + var anns = annotations[line]; + if (!anns) continue; + + var maxSeverity = null; + var tipLabel = state.hasGutter && document.createDocumentFragment(); + + for (var i = 0; i < anns.length; ++i) { + var ann = anns[i]; + var severity = ann.severity; + if (!severity) severity = "error"; + maxSeverity = getMaxSeverity(maxSeverity, severity); + + if (options.formatAnnotation) ann = options.formatAnnotation(ann); + if (state.hasGutter) tipLabel.appendChild(annotationTooltip(ann)); + + if (ann.to) state.marked.push(cm.markText(ann.from, ann.to, { + className: "CodeMirror-lint-mark-" + severity, + __annotation: ann + })); + } + + if (state.hasGutter) + cm.setGutterMarker(line, GUTTER_ID, makeMarker(tipLabel, maxSeverity, anns.length > 1, + state.options.tooltips)); + } + if (options.onUpdateLinting) options.onUpdateLinting(annotationsNotSorted, annotations, cm); + } + + function onChange(cm) { + var state = cm.state.lint; + clearTimeout(state.timeout); + state.timeout = setTimeout(function(){startLinting(cm);}, state.options.delay || 500); + } + + function popupSpanTooltip(ann, e) { + var target = e.target || e.srcElement; + showTooltipFor(e, annotationTooltip(ann), target); + } + + function onMouseOver(cm, e) { + var target = e.target || e.srcElement; + if (!/\bCodeMirror-lint-mark-/.test(target.className)) return; + var box = target.getBoundingClientRect(), x = (box.left + box.right) / 2, y = (box.top + box.bottom) / 2; + var spans = cm.findMarksAt(cm.coordsChar({left: x, top: y}, "client")); + for (var i = 0; i < spans.length; ++i) { + var ann = spans[i].__annotation; + if (ann) return popupSpanTooltip(ann, e); + } + } + + CodeMirror.defineOption("lint", false, function(cm, val, old) { + if (old && old != CodeMirror.Init) { + clearMarks(cm); + cm.off("change", onChange); + CodeMirror.off(cm.getWrapperElement(), "mouseover", cm.state.lint.onMouseOver); + delete cm.state.lint; + } + + if (val) { + var gutters = cm.getOption("gutters"), hasLintGutter = false; + for (var i = 0; i < gutters.length; ++i) if (gutters[i] == GUTTER_ID) hasLintGutter = true; + var state = cm.state.lint = new LintState(cm, parseOptions(cm, val), hasLintGutter); + cm.on("change", onChange); + if (state.options.tooltips != false) + CodeMirror.on(cm.getWrapperElement(), "mouseover", state.onMouseOver); + + startLinting(cm); + } + }); +}); diff --git a/static/js/mdeditor/lib/codemirror/addon/lint/yaml-lint.js b/static/js/mdeditor/lib/codemirror/addon/lint/yaml-lint.js new file mode 100644 index 00000000..3f77e525 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/lint/yaml-lint.js @@ -0,0 +1,28 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +// Depends on js-yaml.js from https://github.com/nodeca/js-yaml + +// declare global: jsyaml + +CodeMirror.registerHelper("lint", "yaml", function(text) { + var found = []; + try { jsyaml.load(text); } + catch(e) { + var loc = e.mark; + found.push({ from: CodeMirror.Pos(loc.line, loc.column), to: CodeMirror.Pos(loc.line, loc.column), message: e.message }); + } + return found; +}); + +}); diff --git a/static/js/mdeditor/lib/codemirror/addon/merge/merge.css b/static/js/mdeditor/lib/codemirror/addon/merge/merge.css new file mode 100644 index 00000000..a6a80e43 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/merge/merge.css @@ -0,0 +1,112 @@ +.CodeMirror-merge { + position: relative; + border: 1px solid #ddd; + white-space: pre; +} + +.CodeMirror-merge, .CodeMirror-merge .CodeMirror { + height: 350px; +} + +.CodeMirror-merge-2pane .CodeMirror-merge-pane { width: 47%; } +.CodeMirror-merge-2pane .CodeMirror-merge-gap { width: 6%; } +.CodeMirror-merge-3pane .CodeMirror-merge-pane { width: 31%; } +.CodeMirror-merge-3pane .CodeMirror-merge-gap { width: 3.5%; } + +.CodeMirror-merge-pane { + display: inline-block; + white-space: normal; + vertical-align: top; +} +.CodeMirror-merge-pane-rightmost { + position: absolute; + right: 0px; + z-index: 1; +} + +.CodeMirror-merge-gap { + z-index: 2; + display: inline-block; + height: 100%; + -moz-box-sizing: border-box; + box-sizing: border-box; + overflow: hidden; + border-left: 1px solid #ddd; + border-right: 1px solid #ddd; + position: relative; + background: #f8f8f8; +} + +.CodeMirror-merge-scrolllock-wrap { + position: absolute; + bottom: 0; left: 50%; +} +.CodeMirror-merge-scrolllock { + position: relative; + left: -50%; + cursor: pointer; + color: #555; + line-height: 1; +} + +.CodeMirror-merge-copybuttons-left, .CodeMirror-merge-copybuttons-right { + position: absolute; + left: 0; top: 0; + right: 0; bottom: 0; + line-height: 1; +} + +.CodeMirror-merge-copy { + position: absolute; + cursor: pointer; + color: #44c; +} + +.CodeMirror-merge-copy-reverse { + position: absolute; + cursor: pointer; + color: #44c; +} + +.CodeMirror-merge-copybuttons-left .CodeMirror-merge-copy { left: 2px; } +.CodeMirror-merge-copybuttons-right .CodeMirror-merge-copy { right: 2px; } + +.CodeMirror-merge-r-inserted, .CodeMirror-merge-l-inserted { + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAACCAYAAACddGYaAAAAGUlEQVQI12MwuCXy3+CWyH8GBgYGJgYkAABZbAQ9ELXurwAAAABJRU5ErkJggg==); + background-position: bottom left; + background-repeat: repeat-x; +} + +.CodeMirror-merge-r-deleted, .CodeMirror-merge-l-deleted { + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAACCAYAAACddGYaAAAAGUlEQVQI12M4Kyb2/6yY2H8GBgYGJgYkAABURgPz6Ks7wQAAAABJRU5ErkJggg==); + background-position: bottom left; + background-repeat: repeat-x; +} + +.CodeMirror-merge-r-chunk { background: #ffffe0; } +.CodeMirror-merge-r-chunk-start { border-top: 1px solid #ee8; } +.CodeMirror-merge-r-chunk-end { border-bottom: 1px solid #ee8; } +.CodeMirror-merge-r-connect { fill: #ffffe0; stroke: #ee8; stroke-width: 1px; } + +.CodeMirror-merge-l-chunk { background: #eef; } +.CodeMirror-merge-l-chunk-start { border-top: 1px solid #88e; } +.CodeMirror-merge-l-chunk-end { border-bottom: 1px solid #88e; } +.CodeMirror-merge-l-connect { fill: #eef; stroke: #88e; stroke-width: 1px; } + +.CodeMirror-merge-l-chunk.CodeMirror-merge-r-chunk { background: #dfd; } +.CodeMirror-merge-l-chunk-start.CodeMirror-merge-r-chunk-start { border-top: 1px solid #4e4; } +.CodeMirror-merge-l-chunk-end.CodeMirror-merge-r-chunk-end { border-bottom: 1px solid #4e4; } + +.CodeMirror-merge-collapsed-widget:before { + content: "(...)"; +} +.CodeMirror-merge-collapsed-widget { + cursor: pointer; + color: #88b; + background: #eef; + border: 1px solid #ddf; + font-size: 90%; + padding: 0 3px; + border-radius: 4px; +} +.CodeMirror-merge-collapsed-line .CodeMirror-gutter-elt { display: none; } diff --git a/static/js/mdeditor/lib/codemirror/addon/merge/merge.js b/static/js/mdeditor/lib/codemirror/addon/merge/merge.js new file mode 100644 index 00000000..f1f3aafc --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/merge/merge.js @@ -0,0 +1,735 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// declare global: diff_match_patch, DIFF_INSERT, DIFF_DELETE, DIFF_EQUAL + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("diff_match_patch")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "diff_match_patch"], mod); + else // Plain browser env + mod(CodeMirror, diff_match_patch); +})(function(CodeMirror, diff_match_patch) { + "use strict"; + var Pos = CodeMirror.Pos; + var svgNS = "http://www.w3.org/2000/svg"; + + function DiffView(mv, type) { + this.mv = mv; + this.type = type; + this.classes = type == "left" + ? {chunk: "CodeMirror-merge-l-chunk", + start: "CodeMirror-merge-l-chunk-start", + end: "CodeMirror-merge-l-chunk-end", + insert: "CodeMirror-merge-l-inserted", + del: "CodeMirror-merge-l-deleted", + connect: "CodeMirror-merge-l-connect"} + : {chunk: "CodeMirror-merge-r-chunk", + start: "CodeMirror-merge-r-chunk-start", + end: "CodeMirror-merge-r-chunk-end", + insert: "CodeMirror-merge-r-inserted", + del: "CodeMirror-merge-r-deleted", + connect: "CodeMirror-merge-r-connect"}; + } + + DiffView.prototype = { + constructor: DiffView, + init: function(pane, orig, options) { + this.edit = this.mv.edit; + this.orig = CodeMirror(pane, copyObj({value: orig, readOnly: !this.mv.options.allowEditingOriginals}, copyObj(options))); + + this.diff = getDiff(asString(orig), asString(options.value)); + this.chunks = getChunks(this.diff); + this.diffOutOfDate = this.dealigned = false; + + this.showDifferences = options.showDifferences !== false; + this.forceUpdate = registerUpdate(this); + setScrollLock(this, true, false); + registerScroll(this); + }, + setShowDifferences: function(val) { + val = val !== false; + if (val != this.showDifferences) { + this.showDifferences = val; + this.forceUpdate("full"); + } + } + }; + + function ensureDiff(dv) { + if (dv.diffOutOfDate) { + dv.diff = getDiff(dv.orig.getValue(), dv.edit.getValue()); + dv.chunks = getChunks(dv.diff); + dv.diffOutOfDate = false; + CodeMirror.signal(dv.edit, "updateDiff", dv.diff); + } + } + + var updating = false; + function registerUpdate(dv) { + var edit = {from: 0, to: 0, marked: []}; + var orig = {from: 0, to: 0, marked: []}; + var debounceChange, updatingFast = false; + function update(mode) { + updating = true; + updatingFast = false; + if (mode == "full") { + if (dv.svg) clear(dv.svg); + if (dv.copyButtons) clear(dv.copyButtons); + clearMarks(dv.edit, edit.marked, dv.classes); + clearMarks(dv.orig, orig.marked, dv.classes); + edit.from = edit.to = orig.from = orig.to = 0; + } + ensureDiff(dv); + if (dv.showDifferences) { + updateMarks(dv.edit, dv.diff, edit, DIFF_INSERT, dv.classes); + updateMarks(dv.orig, dv.diff, orig, DIFF_DELETE, dv.classes); + } + makeConnections(dv); + + if (dv.mv.options.connect == "align") + alignChunks(dv); + updating = false; + } + function setDealign(fast) { + if (updating) return; + dv.dealigned = true; + set(fast); + } + function set(fast) { + if (updating || updatingFast) return; + clearTimeout(debounceChange); + if (fast === true) updatingFast = true; + debounceChange = setTimeout(update, fast === true ? 20 : 250); + } + function change(_cm, change) { + if (!dv.diffOutOfDate) { + dv.diffOutOfDate = true; + edit.from = edit.to = orig.from = orig.to = 0; + } + // Update faster when a line was added/removed + setDealign(change.text.length - 1 != change.to.line - change.from.line); + } + dv.edit.on("change", change); + dv.orig.on("change", change); + dv.edit.on("markerAdded", setDealign); + dv.edit.on("markerCleared", setDealign); + dv.orig.on("markerAdded", setDealign); + dv.orig.on("markerCleared", setDealign); + dv.edit.on("viewportChange", function() { set(false); }); + dv.orig.on("viewportChange", function() { set(false); }); + update(); + return update; + } + + function registerScroll(dv) { + dv.edit.on("scroll", function() { + syncScroll(dv, DIFF_INSERT) && makeConnections(dv); + }); + dv.orig.on("scroll", function() { + syncScroll(dv, DIFF_DELETE) && makeConnections(dv); + }); + } + + function syncScroll(dv, type) { + // Change handler will do a refresh after a timeout when diff is out of date + if (dv.diffOutOfDate) return false; + if (!dv.lockScroll) return true; + var editor, other, now = +new Date; + if (type == DIFF_INSERT) { editor = dv.edit; other = dv.orig; } + else { editor = dv.orig; other = dv.edit; } + // Don't take action if the position of this editor was recently set + // (to prevent feedback loops) + if (editor.state.scrollSetBy == dv && (editor.state.scrollSetAt || 0) + 50 > now) return false; + + var sInfo = editor.getScrollInfo(); + if (dv.mv.options.connect == "align") { + targetPos = sInfo.top; + } else { + var halfScreen = .5 * sInfo.clientHeight, midY = sInfo.top + halfScreen; + var mid = editor.lineAtHeight(midY, "local"); + var around = chunkBoundariesAround(dv.chunks, mid, type == DIFF_INSERT); + var off = getOffsets(editor, type == DIFF_INSERT ? around.edit : around.orig); + var offOther = getOffsets(other, type == DIFF_INSERT ? around.orig : around.edit); + var ratio = (midY - off.top) / (off.bot - off.top); + var targetPos = (offOther.top - halfScreen) + ratio * (offOther.bot - offOther.top); + + var botDist, mix; + // Some careful tweaking to make sure no space is left out of view + // when scrolling to top or bottom. + if (targetPos > sInfo.top && (mix = sInfo.top / halfScreen) < 1) { + targetPos = targetPos * mix + sInfo.top * (1 - mix); + } else if ((botDist = sInfo.height - sInfo.clientHeight - sInfo.top) < halfScreen) { + var otherInfo = other.getScrollInfo(); + var botDistOther = otherInfo.height - otherInfo.clientHeight - targetPos; + if (botDistOther > botDist && (mix = botDist / halfScreen) < 1) + targetPos = targetPos * mix + (otherInfo.height - otherInfo.clientHeight - botDist) * (1 - mix); + } + } + + other.scrollTo(sInfo.left, targetPos); + other.state.scrollSetAt = now; + other.state.scrollSetBy = dv; + return true; + } + + function getOffsets(editor, around) { + var bot = around.after; + if (bot == null) bot = editor.lastLine() + 1; + return {top: editor.heightAtLine(around.before || 0, "local"), + bot: editor.heightAtLine(bot, "local")}; + } + + function setScrollLock(dv, val, action) { + dv.lockScroll = val; + if (val && action != false) syncScroll(dv, DIFF_INSERT) && makeConnections(dv); + dv.lockButton.innerHTML = val ? "\u21db\u21da" : "\u21db  \u21da"; + } + + // Updating the marks for editor content + + function clearMarks(editor, arr, classes) { + for (var i = 0; i < arr.length; ++i) { + var mark = arr[i]; + if (mark instanceof CodeMirror.TextMarker) { + mark.clear(); + } else if (mark.parent) { + editor.removeLineClass(mark, "background", classes.chunk); + editor.removeLineClass(mark, "background", classes.start); + editor.removeLineClass(mark, "background", classes.end); + } + } + arr.length = 0; + } + + // FIXME maybe add a margin around viewport to prevent too many updates + function updateMarks(editor, diff, state, type, classes) { + var vp = editor.getViewport(); + editor.operation(function() { + if (state.from == state.to || vp.from - state.to > 20 || state.from - vp.to > 20) { + clearMarks(editor, state.marked, classes); + markChanges(editor, diff, type, state.marked, vp.from, vp.to, classes); + state.from = vp.from; state.to = vp.to; + } else { + if (vp.from < state.from) { + markChanges(editor, diff, type, state.marked, vp.from, state.from, classes); + state.from = vp.from; + } + if (vp.to > state.to) { + markChanges(editor, diff, type, state.marked, state.to, vp.to, classes); + state.to = vp.to; + } + } + }); + } + + function markChanges(editor, diff, type, marks, from, to, classes) { + var pos = Pos(0, 0); + var top = Pos(from, 0), bot = editor.clipPos(Pos(to - 1)); + var cls = type == DIFF_DELETE ? classes.del : classes.insert; + function markChunk(start, end) { + var bfrom = Math.max(from, start), bto = Math.min(to, end); + for (var i = bfrom; i < bto; ++i) { + var line = editor.addLineClass(i, "background", classes.chunk); + if (i == start) editor.addLineClass(line, "background", classes.start); + if (i == end - 1) editor.addLineClass(line, "background", classes.end); + marks.push(line); + } + // When the chunk is empty, make sure a horizontal line shows up + if (start == end && bfrom == end && bto == end) { + if (bfrom) + marks.push(editor.addLineClass(bfrom - 1, "background", classes.end)); + else + marks.push(editor.addLineClass(bfrom, "background", classes.start)); + } + } + + var chunkStart = 0; + for (var i = 0; i < diff.length; ++i) { + var part = diff[i], tp = part[0], str = part[1]; + if (tp == DIFF_EQUAL) { + var cleanFrom = pos.line + (startOfLineClean(diff, i) ? 0 : 1); + moveOver(pos, str); + var cleanTo = pos.line + (endOfLineClean(diff, i) ? 1 : 0); + if (cleanTo > cleanFrom) { + if (i) markChunk(chunkStart, cleanFrom); + chunkStart = cleanTo; + } + } else { + if (tp == type) { + var end = moveOver(pos, str, true); + var a = posMax(top, pos), b = posMin(bot, end); + if (!posEq(a, b)) + marks.push(editor.markText(a, b, {className: cls})); + pos = end; + } + } + } + if (chunkStart <= pos.line) markChunk(chunkStart, pos.line + 1); + } + + // Updating the gap between editor and original + + function makeConnections(dv) { + if (!dv.showDifferences) return; + + if (dv.svg) { + clear(dv.svg); + var w = dv.gap.offsetWidth; + attrs(dv.svg, "width", w, "height", dv.gap.offsetHeight); + } + if (dv.copyButtons) clear(dv.copyButtons); + + var vpEdit = dv.edit.getViewport(), vpOrig = dv.orig.getViewport(); + var sTopEdit = dv.edit.getScrollInfo().top, sTopOrig = dv.orig.getScrollInfo().top; + for (var i = 0; i < dv.chunks.length; i++) { + var ch = dv.chunks[i]; + if (ch.editFrom <= vpEdit.to && ch.editTo >= vpEdit.from && + ch.origFrom <= vpOrig.to && ch.origTo >= vpOrig.from) + drawConnectorsForChunk(dv, ch, sTopOrig, sTopEdit, w); + } + } + + function getMatchingOrigLine(editLine, chunks) { + var editStart = 0, origStart = 0; + for (var i = 0; i < chunks.length; i++) { + var chunk = chunks[i]; + if (chunk.editTo > editLine && chunk.editFrom <= editLine) return null; + if (chunk.editFrom > editLine) break; + editStart = chunk.editTo; + origStart = chunk.origTo; + } + return origStart + (editLine - editStart); + } + + function findAlignedLines(dv, other) { + var linesToAlign = []; + for (var i = 0; i < dv.chunks.length; i++) { + var chunk = dv.chunks[i]; + linesToAlign.push([chunk.origTo, chunk.editTo, other ? getMatchingOrigLine(chunk.editTo, other.chunks) : null]); + } + if (other) { + for (var i = 0; i < other.chunks.length; i++) { + var chunk = other.chunks[i]; + for (var j = 0; j < linesToAlign.length; j++) { + var align = linesToAlign[j]; + if (align[1] == chunk.editTo) { + j = -1; + break; + } else if (align[1] > chunk.editTo) { + break; + } + } + if (j > -1) + linesToAlign.splice(j - 1, 0, [getMatchingOrigLine(chunk.editTo, dv.chunks), chunk.editTo, chunk.origTo]); + } + } + return linesToAlign; + } + + function alignChunks(dv, force) { + if (!dv.dealigned && !force) return; + if (!dv.orig.curOp) return dv.orig.operation(function() { + alignChunks(dv, force); + }); + + dv.dealigned = false; + var other = dv.mv.left == dv ? dv.mv.right : dv.mv.left; + if (other) { + ensureDiff(other); + other.dealigned = false; + } + var linesToAlign = findAlignedLines(dv, other); + + // Clear old aligners + var aligners = dv.mv.aligners; + for (var i = 0; i < aligners.length; i++) + aligners[i].clear(); + aligners.length = 0; + + var cm = [dv.orig, dv.edit], scroll = []; + if (other) cm.push(other.orig); + for (var i = 0; i < cm.length; i++) + scroll.push(cm[i].getScrollInfo().top); + + for (var ln = 0; ln < linesToAlign.length; ln++) + alignLines(cm, linesToAlign[ln], aligners); + + for (var i = 0; i < cm.length; i++) + cm[i].scrollTo(null, scroll[i]); + } + + function alignLines(cm, lines, aligners) { + var maxOffset = 0, offset = []; + for (var i = 0; i < cm.length; i++) if (lines[i] != null) { + var off = cm[i].heightAtLine(lines[i], "local"); + offset[i] = off; + maxOffset = Math.max(maxOffset, off); + } + for (var i = 0; i < cm.length; i++) if (lines[i] != null) { + var diff = maxOffset - offset[i]; + if (diff > 1) + aligners.push(padAbove(cm[i], lines[i], diff)); + } + } + + function padAbove(cm, line, size) { + var above = true; + if (line > cm.lastLine()) { + line--; + above = false; + } + var elt = document.createElement("div"); + elt.className = "CodeMirror-merge-spacer"; + elt.style.height = size + "px"; elt.style.minWidth = "1px"; + return cm.addLineWidget(line, elt, {height: size, above: above}); + } + + function drawConnectorsForChunk(dv, chunk, sTopOrig, sTopEdit, w) { + var flip = dv.type == "left"; + var top = dv.orig.heightAtLine(chunk.origFrom, "local") - sTopOrig; + if (dv.svg) { + var topLpx = top; + var topRpx = dv.edit.heightAtLine(chunk.editFrom, "local") - sTopEdit; + if (flip) { var tmp = topLpx; topLpx = topRpx; topRpx = tmp; } + var botLpx = dv.orig.heightAtLine(chunk.origTo, "local") - sTopOrig; + var botRpx = dv.edit.heightAtLine(chunk.editTo, "local") - sTopEdit; + if (flip) { var tmp = botLpx; botLpx = botRpx; botRpx = tmp; } + var curveTop = " C " + w/2 + " " + topRpx + " " + w/2 + " " + topLpx + " " + (w + 2) + " " + topLpx; + var curveBot = " C " + w/2 + " " + botLpx + " " + w/2 + " " + botRpx + " -1 " + botRpx; + attrs(dv.svg.appendChild(document.createElementNS(svgNS, "path")), + "d", "M -1 " + topRpx + curveTop + " L " + (w + 2) + " " + botLpx + curveBot + " z", + "class", dv.classes.connect); + } + if (dv.copyButtons) { + var copy = dv.copyButtons.appendChild(elt("div", dv.type == "left" ? "\u21dd" : "\u21dc", + "CodeMirror-merge-copy")); + var editOriginals = dv.mv.options.allowEditingOriginals; + copy.title = editOriginals ? "Push to left" : "Revert chunk"; + copy.chunk = chunk; + copy.style.top = top + "px"; + + if (editOriginals) { + var topReverse = dv.orig.heightAtLine(chunk.editFrom, "local") - sTopEdit; + var copyReverse = dv.copyButtons.appendChild(elt("div", dv.type == "right" ? "\u21dd" : "\u21dc", + "CodeMirror-merge-copy-reverse")); + copyReverse.title = "Push to right"; + copyReverse.chunk = {editFrom: chunk.origFrom, editTo: chunk.origTo, + origFrom: chunk.editFrom, origTo: chunk.editTo}; + copyReverse.style.top = topReverse + "px"; + dv.type == "right" ? copyReverse.style.left = "2px" : copyReverse.style.right = "2px"; + } + } + } + + function copyChunk(dv, to, from, chunk) { + if (dv.diffOutOfDate) return; + to.replaceRange(from.getRange(Pos(chunk.origFrom, 0), Pos(chunk.origTo, 0)), + Pos(chunk.editFrom, 0), Pos(chunk.editTo, 0)); + } + + // Merge view, containing 0, 1, or 2 diff views. + + var MergeView = CodeMirror.MergeView = function(node, options) { + if (!(this instanceof MergeView)) return new MergeView(node, options); + + this.options = options; + var origLeft = options.origLeft, origRight = options.origRight == null ? options.orig : options.origRight; + + var hasLeft = origLeft != null, hasRight = origRight != null; + var panes = 1 + (hasLeft ? 1 : 0) + (hasRight ? 1 : 0); + var wrap = [], left = this.left = null, right = this.right = null; + var self = this; + + if (hasLeft) { + left = this.left = new DiffView(this, "left"); + var leftPane = elt("div", null, "CodeMirror-merge-pane"); + wrap.push(leftPane); + wrap.push(buildGap(left)); + } + + var editPane = elt("div", null, "CodeMirror-merge-pane"); + wrap.push(editPane); + + if (hasRight) { + right = this.right = new DiffView(this, "right"); + wrap.push(buildGap(right)); + var rightPane = elt("div", null, "CodeMirror-merge-pane"); + wrap.push(rightPane); + } + + (hasRight ? rightPane : editPane).className += " CodeMirror-merge-pane-rightmost"; + + wrap.push(elt("div", null, null, "height: 0; clear: both;")); + + var wrapElt = this.wrap = node.appendChild(elt("div", wrap, "CodeMirror-merge CodeMirror-merge-" + panes + "pane")); + this.edit = CodeMirror(editPane, copyObj(options)); + + if (left) left.init(leftPane, origLeft, options); + if (right) right.init(rightPane, origRight, options); + + if (options.collapseIdentical) { + updating = true; + this.editor().operation(function() { + collapseIdenticalStretches(self, options.collapseIdentical); + }); + updating = false; + } + if (options.connect == "align") { + this.aligners = []; + alignChunks(this.left || this.right, true); + } + + var onResize = function() { + if (left) makeConnections(left); + if (right) makeConnections(right); + }; + CodeMirror.on(window, "resize", onResize); + var resizeInterval = setInterval(function() { + for (var p = wrapElt.parentNode; p && p != document.body; p = p.parentNode) {} + if (!p) { clearInterval(resizeInterval); CodeMirror.off(window, "resize", onResize); } + }, 5000); + }; + + function buildGap(dv) { + var lock = dv.lockButton = elt("div", null, "CodeMirror-merge-scrolllock"); + lock.title = "Toggle locked scrolling"; + var lockWrap = elt("div", [lock], "CodeMirror-merge-scrolllock-wrap"); + CodeMirror.on(lock, "click", function() { setScrollLock(dv, !dv.lockScroll); }); + var gapElts = [lockWrap]; + if (dv.mv.options.revertButtons !== false) { + dv.copyButtons = elt("div", null, "CodeMirror-merge-copybuttons-" + dv.type); + CodeMirror.on(dv.copyButtons, "click", function(e) { + var node = e.target || e.srcElement; + if (!node.chunk) return; + if (node.className == "CodeMirror-merge-copy-reverse") { + copyChunk(dv, dv.orig, dv.edit, node.chunk); + return; + } + copyChunk(dv, dv.edit, dv.orig, node.chunk); + }); + gapElts.unshift(dv.copyButtons); + } + if (dv.mv.options.connect != "align") { + var svg = document.createElementNS && document.createElementNS(svgNS, "svg"); + if (svg && !svg.createSVGRect) svg = null; + dv.svg = svg; + if (svg) gapElts.push(svg); + } + + return dv.gap = elt("div", gapElts, "CodeMirror-merge-gap"); + } + + MergeView.prototype = { + constuctor: MergeView, + editor: function() { return this.edit; }, + rightOriginal: function() { return this.right && this.right.orig; }, + leftOriginal: function() { return this.left && this.left.orig; }, + setShowDifferences: function(val) { + if (this.right) this.right.setShowDifferences(val); + if (this.left) this.left.setShowDifferences(val); + }, + rightChunks: function() { + if (this.right) { ensureDiff(this.right); return this.right.chunks; } + }, + leftChunks: function() { + if (this.left) { ensureDiff(this.left); return this.left.chunks; } + } + }; + + function asString(obj) { + if (typeof obj == "string") return obj; + else return obj.getValue(); + } + + // Operations on diffs + + var dmp = new diff_match_patch(); + function getDiff(a, b) { + var diff = dmp.diff_main(a, b); + dmp.diff_cleanupSemantic(diff); + // The library sometimes leaves in empty parts, which confuse the algorithm + for (var i = 0; i < diff.length; ++i) { + var part = diff[i]; + if (!part[1]) { + diff.splice(i--, 1); + } else if (i && diff[i - 1][0] == part[0]) { + diff.splice(i--, 1); + diff[i][1] += part[1]; + } + } + return diff; + } + + function getChunks(diff) { + var chunks = []; + var startEdit = 0, startOrig = 0; + var edit = Pos(0, 0), orig = Pos(0, 0); + for (var i = 0; i < diff.length; ++i) { + var part = diff[i], tp = part[0]; + if (tp == DIFF_EQUAL) { + var startOff = startOfLineClean(diff, i) ? 0 : 1; + var cleanFromEdit = edit.line + startOff, cleanFromOrig = orig.line + startOff; + moveOver(edit, part[1], null, orig); + var endOff = endOfLineClean(diff, i) ? 1 : 0; + var cleanToEdit = edit.line + endOff, cleanToOrig = orig.line + endOff; + if (cleanToEdit > cleanFromEdit) { + if (i) chunks.push({origFrom: startOrig, origTo: cleanFromOrig, + editFrom: startEdit, editTo: cleanFromEdit}); + startEdit = cleanToEdit; startOrig = cleanToOrig; + } + } else { + moveOver(tp == DIFF_INSERT ? edit : orig, part[1]); + } + } + if (startEdit <= edit.line || startOrig <= orig.line) + chunks.push({origFrom: startOrig, origTo: orig.line + 1, + editFrom: startEdit, editTo: edit.line + 1}); + return chunks; + } + + function endOfLineClean(diff, i) { + if (i == diff.length - 1) return true; + var next = diff[i + 1][1]; + if (next.length == 1 || next.charCodeAt(0) != 10) return false; + if (i == diff.length - 2) return true; + next = diff[i + 2][1]; + return next.length > 1 && next.charCodeAt(0) == 10; + } + + function startOfLineClean(diff, i) { + if (i == 0) return true; + var last = diff[i - 1][1]; + if (last.charCodeAt(last.length - 1) != 10) return false; + if (i == 1) return true; + last = diff[i - 2][1]; + return last.charCodeAt(last.length - 1) == 10; + } + + function chunkBoundariesAround(chunks, n, nInEdit) { + var beforeE, afterE, beforeO, afterO; + for (var i = 0; i < chunks.length; i++) { + var chunk = chunks[i]; + var fromLocal = nInEdit ? chunk.editFrom : chunk.origFrom; + var toLocal = nInEdit ? chunk.editTo : chunk.origTo; + if (afterE == null) { + if (fromLocal > n) { afterE = chunk.editFrom; afterO = chunk.origFrom; } + else if (toLocal > n) { afterE = chunk.editTo; afterO = chunk.origTo; } + } + if (toLocal <= n) { beforeE = chunk.editTo; beforeO = chunk.origTo; } + else if (fromLocal <= n) { beforeE = chunk.editFrom; beforeO = chunk.origFrom; } + } + return {edit: {before: beforeE, after: afterE}, orig: {before: beforeO, after: afterO}}; + } + + function collapseSingle(cm, from, to) { + cm.addLineClass(from, "wrap", "CodeMirror-merge-collapsed-line"); + var widget = document.createElement("span"); + widget.className = "CodeMirror-merge-collapsed-widget"; + widget.title = "Identical text collapsed. Click to expand."; + var mark = cm.markText(Pos(from, 0), Pos(to - 1), { + inclusiveLeft: true, + inclusiveRight: true, + replacedWith: widget, + clearOnEnter: true + }); + function clear() { + mark.clear(); + cm.removeLineClass(from, "wrap", "CodeMirror-merge-collapsed-line"); + } + widget.addEventListener("click", clear); + return {mark: mark, clear: clear}; + } + + function collapseStretch(size, editors) { + var marks = []; + function clear() { + for (var i = 0; i < marks.length; i++) marks[i].clear(); + } + for (var i = 0; i < editors.length; i++) { + var editor = editors[i]; + var mark = collapseSingle(editor.cm, editor.line, editor.line + size); + marks.push(mark); + mark.mark.on("clear", clear); + } + return marks[0].mark; + } + + function unclearNearChunks(dv, margin, off, clear) { + for (var i = 0; i < dv.chunks.length; i++) { + var chunk = dv.chunks[i]; + for (var l = chunk.editFrom - margin; l < chunk.editTo + margin; l++) { + var pos = l + off; + if (pos >= 0 && pos < clear.length) clear[pos] = false; + } + } + } + + function collapseIdenticalStretches(mv, margin) { + if (typeof margin != "number") margin = 2; + var clear = [], edit = mv.editor(), off = edit.firstLine(); + for (var l = off, e = edit.lastLine(); l <= e; l++) clear.push(true); + if (mv.left) unclearNearChunks(mv.left, margin, off, clear); + if (mv.right) unclearNearChunks(mv.right, margin, off, clear); + + for (var i = 0; i < clear.length; i++) { + if (clear[i]) { + var line = i + off; + for (var size = 1; i < clear.length - 1 && clear[i + 1]; i++, size++) {} + if (size > margin) { + var editors = [{line: line, cm: edit}]; + if (mv.left) editors.push({line: getMatchingOrigLine(line, mv.left.chunks), cm: mv.left.orig}); + if (mv.right) editors.push({line: getMatchingOrigLine(line, mv.right.chunks), cm: mv.right.orig}); + var mark = collapseStretch(size, editors); + if (mv.options.onCollapse) mv.options.onCollapse(mv, line, size, mark); + } + } + } + } + + // General utilities + + function elt(tag, content, className, style) { + var e = document.createElement(tag); + if (className) e.className = className; + if (style) e.style.cssText = style; + if (typeof content == "string") e.appendChild(document.createTextNode(content)); + else if (content) for (var i = 0; i < content.length; ++i) e.appendChild(content[i]); + return e; + } + + function clear(node) { + for (var count = node.childNodes.length; count > 0; --count) + node.removeChild(node.firstChild); + } + + function attrs(elt) { + for (var i = 1; i < arguments.length; i += 2) + elt.setAttribute(arguments[i], arguments[i+1]); + } + + function copyObj(obj, target) { + if (!target) target = {}; + for (var prop in obj) if (obj.hasOwnProperty(prop)) target[prop] = obj[prop]; + return target; + } + + function moveOver(pos, str, copy, other) { + var out = copy ? Pos(pos.line, pos.ch) : pos, at = 0; + for (;;) { + var nl = str.indexOf("\n", at); + if (nl == -1) break; + ++out.line; + if (other) ++other.line; + at = nl + 1; + } + out.ch = (at ? 0 : out.ch) + (str.length - at); + if (other) other.ch = (at ? 0 : other.ch) + (str.length - at); + return out; + } + + function posMin(a, b) { return (a.line - b.line || a.ch - b.ch) < 0 ? a : b; } + function posMax(a, b) { return (a.line - b.line || a.ch - b.ch) > 0 ? a : b; } + function posEq(a, b) { return a.line == b.line && a.ch == b.ch; } +}); diff --git a/static/js/mdeditor/lib/codemirror/addon/mode/loadmode.js b/static/js/mdeditor/lib/codemirror/addon/mode/loadmode.js new file mode 100644 index 00000000..10117ec2 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/mode/loadmode.js @@ -0,0 +1,64 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), "cjs"); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], function(CM) { mod(CM, "amd"); }); + else // Plain browser env + mod(CodeMirror, "plain"); +})(function(CodeMirror, env) { + if (!CodeMirror.modeURL) CodeMirror.modeURL = "../mode/%N/%N.js"; + + var loading = {}; + function splitCallback(cont, n) { + var countDown = n; + return function() { if (--countDown == 0) cont(); }; + } + function ensureDeps(mode, cont) { + var deps = CodeMirror.modes[mode].dependencies; + if (!deps) return cont(); + var missing = []; + for (var i = 0; i < deps.length; ++i) { + if (!CodeMirror.modes.hasOwnProperty(deps[i])) + missing.push(deps[i]); + } + if (!missing.length) return cont(); + var split = splitCallback(cont, missing.length); + for (var i = 0; i < missing.length; ++i) + CodeMirror.requireMode(missing[i], split); + } + + CodeMirror.requireMode = function(mode, cont) { + if (typeof mode != "string") mode = mode.name; + if (CodeMirror.modes.hasOwnProperty(mode)) return ensureDeps(mode, cont); + if (loading.hasOwnProperty(mode)) return loading[mode].push(cont); + + var file = CodeMirror.modeURL.replace(/%N/g, mode); + if (env == "plain") { + var script = document.createElement("script"); + script.src = file; + var others = document.getElementsByTagName("script")[0]; + var list = loading[mode] = [cont]; + CodeMirror.on(script, "load", function() { + ensureDeps(mode, function() { + for (var i = 0; i < list.length; ++i) list[i](); + }); + }); + others.parentNode.insertBefore(script, others); + } else if (env == "cjs") { + require(file); + cont(); + } else if (env == "amd") { + requirejs([file], cont); + } + }; + + CodeMirror.autoLoadMode = function(instance, mode) { + if (!CodeMirror.modes.hasOwnProperty(mode)) + CodeMirror.requireMode(mode, function() { + instance.setOption("mode", instance.getOption("mode")); + }); + }; +}); diff --git a/static/js/mdeditor/lib/codemirror/addon/mode/multiplex.js b/static/js/mdeditor/lib/codemirror/addon/mode/multiplex.js new file mode 100644 index 00000000..6a95b323 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/mode/multiplex.js @@ -0,0 +1,118 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.multiplexingMode = function(outer /*, others */) { + // Others should be {open, close, mode [, delimStyle] [, innerStyle]} objects + var others = Array.prototype.slice.call(arguments, 1); + var n_others = others.length; + + function indexOf(string, pattern, from) { + if (typeof pattern == "string") return string.indexOf(pattern, from); + var m = pattern.exec(from ? string.slice(from) : string); + return m ? m.index + from : -1; + } + + return { + startState: function() { + return { + outer: CodeMirror.startState(outer), + innerActive: null, + inner: null + }; + }, + + copyState: function(state) { + return { + outer: CodeMirror.copyState(outer, state.outer), + innerActive: state.innerActive, + inner: state.innerActive && CodeMirror.copyState(state.innerActive.mode, state.inner) + }; + }, + + token: function(stream, state) { + if (!state.innerActive) { + var cutOff = Infinity, oldContent = stream.string; + for (var i = 0; i < n_others; ++i) { + var other = others[i]; + var found = indexOf(oldContent, other.open, stream.pos); + if (found == stream.pos) { + stream.match(other.open); + state.innerActive = other; + state.inner = CodeMirror.startState(other.mode, outer.indent ? outer.indent(state.outer, "") : 0); + return other.delimStyle; + } else if (found != -1 && found < cutOff) { + cutOff = found; + } + } + if (cutOff != Infinity) stream.string = oldContent.slice(0, cutOff); + var outerToken = outer.token(stream, state.outer); + if (cutOff != Infinity) stream.string = oldContent; + return outerToken; + } else { + var curInner = state.innerActive, oldContent = stream.string; + if (!curInner.close && stream.sol()) { + state.innerActive = state.inner = null; + return this.token(stream, state); + } + var found = curInner.close ? indexOf(oldContent, curInner.close, stream.pos) : -1; + if (found == stream.pos) { + stream.match(curInner.close); + state.innerActive = state.inner = null; + return curInner.delimStyle; + } + if (found > -1) stream.string = oldContent.slice(0, found); + var innerToken = curInner.mode.token(stream, state.inner); + if (found > -1) stream.string = oldContent; + + if (curInner.innerStyle) { + if (innerToken) innerToken = innerToken + ' ' + curInner.innerStyle; + else innerToken = curInner.innerStyle; + } + + return innerToken; + } + }, + + indent: function(state, textAfter) { + var mode = state.innerActive ? state.innerActive.mode : outer; + if (!mode.indent) return CodeMirror.Pass; + return mode.indent(state.innerActive ? state.inner : state.outer, textAfter); + }, + + blankLine: function(state) { + var mode = state.innerActive ? state.innerActive.mode : outer; + if (mode.blankLine) { + mode.blankLine(state.innerActive ? state.inner : state.outer); + } + if (!state.innerActive) { + for (var i = 0; i < n_others; ++i) { + var other = others[i]; + if (other.open === "\n") { + state.innerActive = other; + state.inner = CodeMirror.startState(other.mode, mode.indent ? mode.indent(state.outer, "") : 0); + } + } + } else if (state.innerActive.close === "\n") { + state.innerActive = state.inner = null; + } + }, + + electricChars: outer.electricChars, + + innerMode: function(state) { + return state.inner ? {state: state.inner, mode: state.innerActive.mode} : {state: state.outer, mode: outer}; + } + }; +}; + +}); diff --git a/static/js/mdeditor/lib/codemirror/addon/mode/multiplex_test.js b/static/js/mdeditor/lib/codemirror/addon/mode/multiplex_test.js new file mode 100644 index 00000000..d3394342 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/mode/multiplex_test.js @@ -0,0 +1,33 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function() { + CodeMirror.defineMode("markdown_with_stex", function(){ + var inner = CodeMirror.getMode({}, "stex"); + var outer = CodeMirror.getMode({}, "markdown"); + + var innerOptions = { + open: '$', + close: '$', + mode: inner, + delimStyle: 'delim', + innerStyle: 'inner' + }; + + return CodeMirror.multiplexingMode(outer, innerOptions); + }); + + var mode = CodeMirror.getMode({}, "markdown_with_stex"); + + function MT(name) { + test.mode( + name, + mode, + Array.prototype.slice.call(arguments, 1), + 'multiplexing'); + } + + MT( + "stexInsideMarkdown", + "[strong **Equation:**] [delim $][inner&tag \\pi][delim $]"); +})(); diff --git a/static/js/mdeditor/lib/codemirror/addon/mode/overlay.js b/static/js/mdeditor/lib/codemirror/addon/mode/overlay.js new file mode 100644 index 00000000..e1b9ed37 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/mode/overlay.js @@ -0,0 +1,85 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// Utility function that allows modes to be combined. The mode given +// as the base argument takes care of most of the normal mode +// functionality, but a second (typically simple) mode is used, which +// can override the style of text. Both modes get to parse all of the +// text, but when both assign a non-null style to a piece of code, the +// overlay wins, unless the combine argument was true and not overridden, +// or state.overlay.combineTokens was true, in which case the styles are +// combined. + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.overlayMode = function(base, overlay, combine) { + return { + startState: function() { + return { + base: CodeMirror.startState(base), + overlay: CodeMirror.startState(overlay), + basePos: 0, baseCur: null, + overlayPos: 0, overlayCur: null, + streamSeen: null + }; + }, + copyState: function(state) { + return { + base: CodeMirror.copyState(base, state.base), + overlay: CodeMirror.copyState(overlay, state.overlay), + basePos: state.basePos, baseCur: null, + overlayPos: state.overlayPos, overlayCur: null + }; + }, + + token: function(stream, state) { + if (stream != state.streamSeen || + Math.min(state.basePos, state.overlayPos) < stream.start) { + state.streamSeen = stream; + state.basePos = state.overlayPos = stream.start; + } + + if (stream.start == state.basePos) { + state.baseCur = base.token(stream, state.base); + state.basePos = stream.pos; + } + if (stream.start == state.overlayPos) { + stream.pos = stream.start; + state.overlayCur = overlay.token(stream, state.overlay); + state.overlayPos = stream.pos; + } + stream.pos = Math.min(state.basePos, state.overlayPos); + + // state.overlay.combineTokens always takes precedence over combine, + // unless set to null + if (state.overlayCur == null) return state.baseCur; + else if (state.baseCur != null && + state.overlay.combineTokens || + combine && state.overlay.combineTokens == null) + return state.baseCur + " " + state.overlayCur; + else return state.overlayCur; + }, + + indent: base.indent && function(state, textAfter) { + return base.indent(state.base, textAfter); + }, + electricChars: base.electricChars, + + innerMode: function(state) { return {state: state.base, mode: base}; }, + + blankLine: function(state) { + if (base.blankLine) base.blankLine(state.base); + if (overlay.blankLine) overlay.blankLine(state.overlay); + } + }; +}; + +}); diff --git a/static/js/mdeditor/lib/codemirror/addon/mode/simple.js b/static/js/mdeditor/lib/codemirror/addon/mode/simple.js new file mode 100644 index 00000000..795328b8 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/mode/simple.js @@ -0,0 +1,213 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineSimpleMode = function(name, states) { + CodeMirror.defineMode(name, function(config) { + return CodeMirror.simpleMode(config, states); + }); + }; + + CodeMirror.simpleMode = function(config, states) { + ensureState(states, "start"); + var states_ = {}, meta = states.meta || {}, hasIndentation = false; + for (var state in states) if (state != meta && states.hasOwnProperty(state)) { + var list = states_[state] = [], orig = states[state]; + for (var i = 0; i < orig.length; i++) { + var data = orig[i]; + list.push(new Rule(data, states)); + if (data.indent || data.dedent) hasIndentation = true; + } + } + var mode = { + startState: function() { + return {state: "start", pending: null, + local: null, localState: null, + indent: hasIndentation ? [] : null}; + }, + copyState: function(state) { + var s = {state: state.state, pending: state.pending, + local: state.local, localState: null, + indent: state.indent && state.indent.slice(0)}; + if (state.localState) + s.localState = CodeMirror.copyState(state.local.mode, state.localState); + if (state.stack) + s.stack = state.stack.slice(0); + for (var pers = state.persistentStates; pers; pers = pers.next) + s.persistentStates = {mode: pers.mode, + spec: pers.spec, + state: pers.state == state.localState ? s.localState : CodeMirror.copyState(pers.mode, pers.state), + next: s.persistentStates}; + return s; + }, + token: tokenFunction(states_, config), + innerMode: function(state) { return state.local && {mode: state.local.mode, state: state.localState}; }, + indent: indentFunction(states_, meta) + }; + if (meta) for (var prop in meta) if (meta.hasOwnProperty(prop)) + mode[prop] = meta[prop]; + return mode; + }; + + function ensureState(states, name) { + if (!states.hasOwnProperty(name)) + throw new Error("Undefined state " + name + "in simple mode"); + } + + function toRegex(val, caret) { + if (!val) return /(?:)/; + var flags = ""; + if (val instanceof RegExp) { + if (val.ignoreCase) flags = "i"; + val = val.source; + } else { + val = String(val); + } + return new RegExp((caret === false ? "" : "^") + "(?:" + val + ")", flags); + } + + function asToken(val) { + if (!val) return null; + if (typeof val == "string") return val.replace(/\./g, " "); + var result = []; + for (var i = 0; i < val.length; i++) + result.push(val[i] && val[i].replace(/\./g, " ")); + return result; + } + + function Rule(data, states) { + if (data.next || data.push) ensureState(states, data.next || data.push); + this.regex = toRegex(data.regex); + this.token = asToken(data.token); + this.data = data; + } + + function tokenFunction(states, config) { + return function(stream, state) { + if (state.pending) { + var pend = state.pending.shift(); + if (state.pending.length == 0) state.pending = null; + stream.pos += pend.text.length; + return pend.token; + } + + if (state.local) { + if (state.local.end && stream.match(state.local.end)) { + var tok = state.local.endToken || null; + state.local = state.localState = null; + return tok; + } else { + var tok = state.local.mode.token(stream, state.localState), m; + if (state.local.endScan && (m = state.local.endScan.exec(stream.current()))) + stream.pos = stream.start + m.index; + return tok; + } + } + + var curState = states[state.state]; + for (var i = 0; i < curState.length; i++) { + var rule = curState[i]; + var matches = (!rule.data.sol || stream.sol()) && stream.match(rule.regex); + if (matches) { + if (rule.data.next) { + state.state = rule.data.next; + } else if (rule.data.push) { + (state.stack || (state.stack = [])).push(state.state); + state.state = rule.data.push; + } else if (rule.data.pop && state.stack && state.stack.length) { + state.state = state.stack.pop(); + } + + if (rule.data.mode) + enterLocalMode(config, state, rule.data.mode, rule.token); + if (rule.data.indent) + state.indent.push(stream.indentation() + config.indentUnit); + if (rule.data.dedent) + state.indent.pop(); + if (matches.length > 2) { + state.pending = []; + for (var j = 2; j < matches.length; j++) + if (matches[j]) + state.pending.push({text: matches[j], token: rule.token[j - 1]}); + stream.backUp(matches[0].length - (matches[1] ? matches[1].length : 0)); + return rule.token[0]; + } else if (rule.token && rule.token.join) { + return rule.token[0]; + } else { + return rule.token; + } + } + } + stream.next(); + return null; + }; + } + + function cmp(a, b) { + if (a === b) return true; + if (!a || typeof a != "object" || !b || typeof b != "object") return false; + var props = 0; + for (var prop in a) if (a.hasOwnProperty(prop)) { + if (!b.hasOwnProperty(prop) || !cmp(a[prop], b[prop])) return false; + props++; + } + for (var prop in b) if (b.hasOwnProperty(prop)) props--; + return props == 0; + } + + function enterLocalMode(config, state, spec, token) { + var pers; + if (spec.persistent) for (var p = state.persistentStates; p && !pers; p = p.next) + if (spec.spec ? cmp(spec.spec, p.spec) : spec.mode == p.mode) pers = p; + var mode = pers ? pers.mode : spec.mode || CodeMirror.getMode(config, spec.spec); + var lState = pers ? pers.state : CodeMirror.startState(mode); + if (spec.persistent && !pers) + state.persistentStates = {mode: mode, spec: spec.spec, state: lState, next: state.persistentStates}; + + state.localState = lState; + state.local = {mode: mode, + end: spec.end && toRegex(spec.end), + endScan: spec.end && spec.forceEnd !== false && toRegex(spec.end, false), + endToken: token && token.join ? token[token.length - 1] : token}; + } + + function indexOf(val, arr) { + for (var i = 0; i < arr.length; i++) if (arr[i] === val) return true; + } + + function indentFunction(states, meta) { + return function(state, textAfter, line) { + if (state.local && state.local.mode.indent) + return state.local.mode.indent(state.localState, textAfter, line); + if (state.indent == null || state.local || meta.dontIndentStates && indexOf(state.state, meta.dontIndentStates) > -1) + return CodeMirror.Pass; + + var pos = state.indent.length - 1, rules = states[state.state]; + scan: for (;;) { + for (var i = 0; i < rules.length; i++) { + var rule = rules[i]; + if (rule.data.dedent && rule.data.dedentIfLineStart !== false) { + var m = rule.regex.exec(textAfter); + if (m && m[0]) { + pos--; + if (rule.next || rule.push) rules = states[rule.next || rule.push]; + textAfter = textAfter.slice(m[0].length); + continue scan; + } + } + } + break; + } + return pos < 0 ? 0 : state.indent[pos]; + }; + } +}); diff --git a/static/js/mdeditor/lib/codemirror/addon/runmode/colorize.js b/static/js/mdeditor/lib/codemirror/addon/runmode/colorize.js new file mode 100644 index 00000000..eb7060d0 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/runmode/colorize.js @@ -0,0 +1,40 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("./runmode")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "./runmode"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var isBlock = /^(p|li|div|h\\d|pre|blockquote|td)$/; + + function textContent(node, out) { + if (node.nodeType == 3) return out.push(node.nodeValue); + for (var ch = node.firstChild; ch; ch = ch.nextSibling) { + textContent(ch, out); + if (isBlock.test(node.nodeType)) out.push("\n"); + } + } + + CodeMirror.colorize = function(collection, defaultMode) { + if (!collection) collection = document.body.getElementsByTagName("pre"); + + for (var i = 0; i < collection.length; ++i) { + var node = collection[i]; + var mode = node.getAttribute("data-lang") || defaultMode; + if (!mode) continue; + + var text = []; + textContent(node, text); + node.innerHTML = ""; + CodeMirror.runMode(text.join(""), mode, node); + + node.className += " cm-s-default"; + } + }; +}); diff --git a/static/js/mdeditor/lib/codemirror/addon/runmode/runmode-standalone.js b/static/js/mdeditor/lib/codemirror/addon/runmode/runmode-standalone.js new file mode 100644 index 00000000..f4f352c8 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/runmode/runmode-standalone.js @@ -0,0 +1,157 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +window.CodeMirror = {}; + +(function() { +"use strict"; + +function splitLines(string){ return string.split(/\r?\n|\r/); }; + +function StringStream(string) { + this.pos = this.start = 0; + this.string = string; + this.lineStart = 0; +} +StringStream.prototype = { + eol: function() {return this.pos >= this.string.length;}, + sol: function() {return this.pos == 0;}, + peek: function() {return this.string.charAt(this.pos) || null;}, + next: function() { + if (this.pos < this.string.length) + return this.string.charAt(this.pos++); + }, + eat: function(match) { + var ch = this.string.charAt(this.pos); + if (typeof match == "string") var ok = ch == match; + else var ok = ch && (match.test ? match.test(ch) : match(ch)); + if (ok) {++this.pos; return ch;} + }, + eatWhile: function(match) { + var start = this.pos; + while (this.eat(match)){} + return this.pos > start; + }, + eatSpace: function() { + var start = this.pos; + while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos; + return this.pos > start; + }, + skipToEnd: function() {this.pos = this.string.length;}, + skipTo: function(ch) { + var found = this.string.indexOf(ch, this.pos); + if (found > -1) {this.pos = found; return true;} + }, + backUp: function(n) {this.pos -= n;}, + column: function() {return this.start - this.lineStart;}, + indentation: function() {return 0;}, + match: function(pattern, consume, caseInsensitive) { + if (typeof pattern == "string") { + var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;}; + var substr = this.string.substr(this.pos, pattern.length); + if (cased(substr) == cased(pattern)) { + if (consume !== false) this.pos += pattern.length; + return true; + } + } else { + var match = this.string.slice(this.pos).match(pattern); + if (match && match.index > 0) return null; + if (match && consume !== false) this.pos += match[0].length; + return match; + } + }, + current: function(){return this.string.slice(this.start, this.pos);}, + hideFirstChars: function(n, inner) { + this.lineStart += n; + try { return inner(); } + finally { this.lineStart -= n; } + } +}; +CodeMirror.StringStream = StringStream; + +CodeMirror.startState = function (mode, a1, a2) { + return mode.startState ? mode.startState(a1, a2) : true; +}; + +var modes = CodeMirror.modes = {}, mimeModes = CodeMirror.mimeModes = {}; +CodeMirror.defineMode = function (name, mode) { + if (arguments.length > 2) + mode.dependencies = Array.prototype.slice.call(arguments, 2); + modes[name] = mode; +}; +CodeMirror.defineMIME = function (mime, spec) { mimeModes[mime] = spec; }; +CodeMirror.resolveMode = function(spec) { + if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) { + spec = mimeModes[spec]; + } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) { + spec = mimeModes[spec.name]; + } + if (typeof spec == "string") return {name: spec}; + else return spec || {name: "null"}; +}; +CodeMirror.getMode = function (options, spec) { + spec = CodeMirror.resolveMode(spec); + var mfactory = modes[spec.name]; + if (!mfactory) throw new Error("Unknown mode: " + spec); + return mfactory(options, spec); +}; +CodeMirror.registerHelper = CodeMirror.registerGlobalHelper = Math.min; +CodeMirror.defineMode("null", function() { + return {token: function(stream) {stream.skipToEnd();}}; +}); +CodeMirror.defineMIME("text/plain", "null"); + +CodeMirror.runMode = function (string, modespec, callback, options) { + var mode = CodeMirror.getMode({ indentUnit: 2 }, modespec); + + if (callback.nodeType == 1) { + var tabSize = (options && options.tabSize) || 4; + var node = callback, col = 0; + node.innerHTML = ""; + callback = function (text, style) { + if (text == "\n") { + node.appendChild(document.createElement("br")); + col = 0; + return; + } + var content = ""; + // replace tabs + for (var pos = 0; ;) { + var idx = text.indexOf("\t", pos); + if (idx == -1) { + content += text.slice(pos); + col += text.length - pos; + break; + } else { + col += idx - pos; + content += text.slice(pos, idx); + var size = tabSize - col % tabSize; + col += size; + for (var i = 0; i < size; ++i) content += " "; + pos = idx + 1; + } + } + + if (style) { + var sp = node.appendChild(document.createElement("span")); + sp.className = "cm-" + style.replace(/ +/g, " cm-"); + sp.appendChild(document.createTextNode(content)); + } else { + node.appendChild(document.createTextNode(content)); + } + }; + } + + var lines = splitLines(string), state = (options && options.state) || CodeMirror.startState(mode); + for (var i = 0, e = lines.length; i < e; ++i) { + if (i) callback("\n"); + var stream = new CodeMirror.StringStream(lines[i]); + if (!stream.string && mode.blankLine) mode.blankLine(state); + while (!stream.eol()) { + var style = mode.token(stream, state); + callback(stream.current(), style, i, stream.start, state); + stream.start = stream.pos; + } + } +}; +})(); diff --git a/static/js/mdeditor/lib/codemirror/addon/runmode/runmode.js b/static/js/mdeditor/lib/codemirror/addon/runmode/runmode.js new file mode 100644 index 00000000..07d2279f --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/runmode/runmode.js @@ -0,0 +1,72 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.runMode = function(string, modespec, callback, options) { + var mode = CodeMirror.getMode(CodeMirror.defaults, modespec); + var ie = /MSIE \d/.test(navigator.userAgent); + var ie_lt9 = ie && (document.documentMode == null || document.documentMode < 9); + + if (callback.nodeType == 1) { + var tabSize = (options && options.tabSize) || CodeMirror.defaults.tabSize; + var node = callback, col = 0; + node.innerHTML = ""; + callback = function(text, style) { + if (text == "\n") { + // Emitting LF or CRLF on IE8 or earlier results in an incorrect display. + // Emitting a carriage return makes everything ok. + node.appendChild(document.createTextNode(ie_lt9 ? '\r' : text)); + col = 0; + return; + } + var content = ""; + // replace tabs + for (var pos = 0;;) { + var idx = text.indexOf("\t", pos); + if (idx == -1) { + content += text.slice(pos); + col += text.length - pos; + break; + } else { + col += idx - pos; + content += text.slice(pos, idx); + var size = tabSize - col % tabSize; + col += size; + for (var i = 0; i < size; ++i) content += " "; + pos = idx + 1; + } + } + + if (style) { + var sp = node.appendChild(document.createElement("span")); + sp.className = "cm-" + style.replace(/ +/g, " cm-"); + sp.appendChild(document.createTextNode(content)); + } else { + node.appendChild(document.createTextNode(content)); + } + }; + } + + var lines = CodeMirror.splitLines(string), state = (options && options.state) || CodeMirror.startState(mode); + for (var i = 0, e = lines.length; i < e; ++i) { + if (i) callback("\n"); + var stream = new CodeMirror.StringStream(lines[i]); + if (!stream.string && mode.blankLine) mode.blankLine(state); + while (!stream.eol()) { + var style = mode.token(stream, state); + callback(stream.current(), style, i, stream.start, state); + stream.start = stream.pos; + } + } +}; + +}); diff --git a/static/js/mdeditor/lib/codemirror/addon/runmode/runmode.node.js b/static/js/mdeditor/lib/codemirror/addon/runmode/runmode.node.js new file mode 100644 index 00000000..8b8140b4 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/runmode/runmode.node.js @@ -0,0 +1,120 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +/* Just enough of CodeMirror to run runMode under node.js */ + +// declare global: StringStream + +function splitLines(string){ return string.split(/\r?\n|\r/); }; + +function StringStream(string) { + this.pos = this.start = 0; + this.string = string; + this.lineStart = 0; +} +StringStream.prototype = { + eol: function() {return this.pos >= this.string.length;}, + sol: function() {return this.pos == 0;}, + peek: function() {return this.string.charAt(this.pos) || null;}, + next: function() { + if (this.pos < this.string.length) + return this.string.charAt(this.pos++); + }, + eat: function(match) { + var ch = this.string.charAt(this.pos); + if (typeof match == "string") var ok = ch == match; + else var ok = ch && (match.test ? match.test(ch) : match(ch)); + if (ok) {++this.pos; return ch;} + }, + eatWhile: function(match) { + var start = this.pos; + while (this.eat(match)){} + return this.pos > start; + }, + eatSpace: function() { + var start = this.pos; + while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos; + return this.pos > start; + }, + skipToEnd: function() {this.pos = this.string.length;}, + skipTo: function(ch) { + var found = this.string.indexOf(ch, this.pos); + if (found > -1) {this.pos = found; return true;} + }, + backUp: function(n) {this.pos -= n;}, + column: function() {return this.start - this.lineStart;}, + indentation: function() {return 0;}, + match: function(pattern, consume, caseInsensitive) { + if (typeof pattern == "string") { + var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;}; + var substr = this.string.substr(this.pos, pattern.length); + if (cased(substr) == cased(pattern)) { + if (consume !== false) this.pos += pattern.length; + return true; + } + } else { + var match = this.string.slice(this.pos).match(pattern); + if (match && match.index > 0) return null; + if (match && consume !== false) this.pos += match[0].length; + return match; + } + }, + current: function(){return this.string.slice(this.start, this.pos);}, + hideFirstChars: function(n, inner) { + this.lineStart += n; + try { return inner(); } + finally { this.lineStart -= n; } + } +}; +exports.StringStream = StringStream; + +exports.startState = function(mode, a1, a2) { + return mode.startState ? mode.startState(a1, a2) : true; +}; + +var modes = exports.modes = {}, mimeModes = exports.mimeModes = {}; +exports.defineMode = function(name, mode) { + if (arguments.length > 2) + mode.dependencies = Array.prototype.slice.call(arguments, 2); + modes[name] = mode; +}; +exports.defineMIME = function(mime, spec) { mimeModes[mime] = spec; }; + +exports.defineMode("null", function() { + return {token: function(stream) {stream.skipToEnd();}}; +}); +exports.defineMIME("text/plain", "null"); + +exports.resolveMode = function(spec) { + if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) { + spec = mimeModes[spec]; + } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) { + spec = mimeModes[spec.name]; + } + if (typeof spec == "string") return {name: spec}; + else return spec || {name: "null"}; +}; +exports.getMode = function(options, spec) { + spec = exports.resolveMode(spec); + var mfactory = modes[spec.name]; + if (!mfactory) throw new Error("Unknown mode: " + spec); + return mfactory(options, spec); +}; +exports.registerHelper = exports.registerGlobalHelper = Math.min; + +exports.runMode = function(string, modespec, callback, options) { + var mode = exports.getMode({indentUnit: 2}, modespec); + var lines = splitLines(string), state = (options && options.state) || exports.startState(mode); + for (var i = 0, e = lines.length; i < e; ++i) { + if (i) callback("\n"); + var stream = new exports.StringStream(lines[i]); + if (!stream.string && mode.blankLine) mode.blankLine(state); + while (!stream.eol()) { + var style = mode.token(stream, state); + callback(stream.current(), style, i, stream.start, state); + stream.start = stream.pos; + } + } +}; + +require.cache[require.resolve("../../lib/codemirror")] = require.cache[require.resolve("./runmode.node")]; diff --git a/static/js/mdeditor/lib/codemirror/addon/scroll/annotatescrollbar.js b/static/js/mdeditor/lib/codemirror/addon/scroll/annotatescrollbar.js new file mode 100644 index 00000000..54aeacf2 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/scroll/annotatescrollbar.js @@ -0,0 +1,100 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineExtension("annotateScrollbar", function(options) { + if (typeof options == "string") options = {className: options}; + return new Annotation(this, options); + }); + + CodeMirror.defineOption("scrollButtonHeight", 0); + + function Annotation(cm, options) { + this.cm = cm; + this.options = options; + this.buttonHeight = options.scrollButtonHeight || cm.getOption("scrollButtonHeight"); + this.annotations = []; + this.doRedraw = this.doUpdate = null; + this.div = cm.getWrapperElement().appendChild(document.createElement("div")); + this.div.style.cssText = "position: absolute; right: 0; top: 0; z-index: 7; pointer-events: none"; + this.computeScale(); + + function scheduleRedraw(delay) { + clearTimeout(self.doRedraw); + self.doRedraw = setTimeout(function() { self.redraw(); }, delay); + } + + var self = this; + cm.on("refresh", this.resizeHandler = function() { + clearTimeout(self.doUpdate); + self.doUpdate = setTimeout(function() { + if (self.computeScale()) scheduleRedraw(20); + }, 100); + }); + cm.on("markerAdded", this.resizeHandler); + cm.on("markerCleared", this.resizeHandler); + if (options.listenForChanges !== false) + cm.on("change", this.changeHandler = function() { + scheduleRedraw(250); + }); + } + + Annotation.prototype.computeScale = function() { + var cm = this.cm; + var hScale = (cm.getWrapperElement().clientHeight - cm.display.barHeight - this.buttonHeight * 2) / + cm.heightAtLine(cm.lastLine() + 1, "local"); + if (hScale != this.hScale) { + this.hScale = hScale; + return true; + } + }; + + Annotation.prototype.update = function(annotations) { + this.annotations = annotations; + this.redraw(); + }; + + Annotation.prototype.redraw = function(compute) { + if (compute !== false) this.computeScale(); + var cm = this.cm, hScale = this.hScale; + + var frag = document.createDocumentFragment(), anns = this.annotations; + if (cm.display.barWidth) for (var i = 0, nextTop; i < anns.length; i++) { + var ann = anns[i]; + var top = nextTop || cm.charCoords(ann.from, "local").top * hScale; + var bottom = cm.charCoords(ann.to, "local").bottom * hScale; + while (i < anns.length - 1) { + nextTop = cm.charCoords(anns[i + 1].from, "local").top * hScale; + if (nextTop > bottom + .9) break; + ann = anns[++i]; + bottom = cm.charCoords(ann.to, "local").bottom * hScale; + } + if (bottom == top) continue; + var height = Math.max(bottom - top, 3); + + var elt = frag.appendChild(document.createElement("div")); + elt.style.cssText = "position: absolute; right: 0px; width: " + Math.max(cm.display.barWidth - 1, 2) + "px; top: " + + (top + this.buttonHeight) + "px; height: " + height + "px"; + elt.className = this.options.className; + } + this.div.textContent = ""; + this.div.appendChild(frag); + }; + + Annotation.prototype.clear = function() { + this.cm.off("refresh", this.resizeHandler); + this.cm.off("markerAdded", this.resizeHandler); + this.cm.off("markerCleared", this.resizeHandler); + if (this.changeHandler) this.cm.off("change", this.changeHandler); + this.div.parentNode.removeChild(this.div); + }; +}); diff --git a/static/js/mdeditor/lib/codemirror/addon/scroll/scrollpastend.js b/static/js/mdeditor/lib/codemirror/addon/scroll/scrollpastend.js new file mode 100644 index 00000000..008ae4c7 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/scroll/scrollpastend.js @@ -0,0 +1,46 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineOption("scrollPastEnd", false, function(cm, val, old) { + if (old && old != CodeMirror.Init) { + cm.off("change", onChange); + cm.off("refresh", updateBottomMargin); + cm.display.lineSpace.parentNode.style.paddingBottom = ""; + cm.state.scrollPastEndPadding = null; + } + if (val) { + cm.on("change", onChange); + cm.on("refresh", updateBottomMargin); + updateBottomMargin(cm); + } + }); + + function onChange(cm, change) { + if (CodeMirror.changeEnd(change).line == cm.lastLine()) + updateBottomMargin(cm); + } + + function updateBottomMargin(cm) { + var padding = ""; + if (cm.lineCount() > 1) { + var totalH = cm.display.scroller.clientHeight - 30, + lastLineH = cm.getLineHandle(cm.lastLine()).height; + padding = (totalH - lastLineH) + "px"; + } + if (cm.state.scrollPastEndPadding != padding) { + cm.state.scrollPastEndPadding = padding; + cm.display.lineSpace.parentNode.style.paddingBottom = padding; + cm.setSize(); + } + } +}); diff --git a/static/js/mdeditor/lib/codemirror/addon/scroll/simplescrollbars.css b/static/js/mdeditor/lib/codemirror/addon/scroll/simplescrollbars.css new file mode 100644 index 00000000..5eea7aa1 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/scroll/simplescrollbars.css @@ -0,0 +1,66 @@ +.CodeMirror-simplescroll-horizontal div, .CodeMirror-simplescroll-vertical div { + position: absolute; + background: #ccc; + -moz-box-sizing: border-box; + box-sizing: border-box; + border: 1px solid #bbb; + border-radius: 2px; +} + +.CodeMirror-simplescroll-horizontal, .CodeMirror-simplescroll-vertical { + position: absolute; + z-index: 6; + background: #eee; +} + +.CodeMirror-simplescroll-horizontal { + bottom: 0; left: 0; + height: 8px; +} +.CodeMirror-simplescroll-horizontal div { + bottom: 0; + height: 100%; +} + +.CodeMirror-simplescroll-vertical { + right: 0; top: 0; + width: 8px; +} +.CodeMirror-simplescroll-vertical div { + right: 0; + width: 100%; +} + + +.CodeMirror-overlayscroll .CodeMirror-scrollbar-filler, .CodeMirror-overlayscroll .CodeMirror-gutter-filler { + display: none; +} + +.CodeMirror-overlayscroll-horizontal div, .CodeMirror-overlayscroll-vertical div { + position: absolute; + background: #bcd; + border-radius: 3px; +} + +.CodeMirror-overlayscroll-horizontal, .CodeMirror-overlayscroll-vertical { + position: absolute; + z-index: 6; +} + +.CodeMirror-overlayscroll-horizontal { + bottom: 0; left: 0; + height: 6px; +} +.CodeMirror-overlayscroll-horizontal div { + bottom: 0; + height: 100%; +} + +.CodeMirror-overlayscroll-vertical { + right: 0; top: 0; + width: 6px; +} +.CodeMirror-overlayscroll-vertical div { + right: 0; + width: 100%; +} diff --git a/static/js/mdeditor/lib/codemirror/addon/scroll/simplescrollbars.js b/static/js/mdeditor/lib/codemirror/addon/scroll/simplescrollbars.js new file mode 100644 index 00000000..bb06adb8 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/scroll/simplescrollbars.js @@ -0,0 +1,141 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + function Bar(cls, orientation, scroll) { + this.orientation = orientation; + this.scroll = scroll; + this.screen = this.total = this.size = 1; + this.pos = 0; + + this.node = document.createElement("div"); + this.node.className = cls + "-" + orientation; + this.inner = this.node.appendChild(document.createElement("div")); + + var self = this; + CodeMirror.on(this.inner, "mousedown", function(e) { + if (e.which != 1) return; + CodeMirror.e_preventDefault(e); + var axis = self.orientation == "horizontal" ? "pageX" : "pageY"; + var start = e[axis], startpos = self.pos; + function done() { + CodeMirror.off(document, "mousemove", move); + CodeMirror.off(document, "mouseup", done); + } + function move(e) { + if (e.which != 1) return done(); + self.moveTo(startpos + (e[axis] - start) * (self.total / self.size)); + } + CodeMirror.on(document, "mousemove", move); + CodeMirror.on(document, "mouseup", done); + }); + + CodeMirror.on(this.node, "click", function(e) { + CodeMirror.e_preventDefault(e); + var innerBox = self.inner.getBoundingClientRect(), where; + if (self.orientation == "horizontal") + where = e.clientX < innerBox.left ? -1 : e.clientX > innerBox.right ? 1 : 0; + else + where = e.clientY < innerBox.top ? -1 : e.clientY > innerBox.bottom ? 1 : 0; + self.moveTo(self.pos + where * self.screen); + }); + + function onWheel(e) { + var moved = CodeMirror.wheelEventPixels(e)[self.orientation == "horizontal" ? "x" : "y"]; + var oldPos = self.pos; + self.moveTo(self.pos + moved); + if (self.pos != oldPos) CodeMirror.e_preventDefault(e); + } + CodeMirror.on(this.node, "mousewheel", onWheel); + CodeMirror.on(this.node, "DOMMouseScroll", onWheel); + } + + Bar.prototype.moveTo = function(pos, update) { + if (pos < 0) pos = 0; + if (pos > this.total - this.screen) pos = this.total - this.screen; + if (pos == this.pos) return; + this.pos = pos; + this.inner.style[this.orientation == "horizontal" ? "left" : "top"] = + (pos * (this.size / this.total)) + "px"; + if (update !== false) this.scroll(pos, this.orientation); + }; + + Bar.prototype.update = function(scrollSize, clientSize, barSize) { + this.screen = clientSize; + this.total = scrollSize; + this.size = barSize; + + // FIXME clip to min size? + this.inner.style[this.orientation == "horizontal" ? "width" : "height"] = + this.screen * (this.size / this.total) + "px"; + this.inner.style[this.orientation == "horizontal" ? "left" : "top"] = + this.pos * (this.size / this.total) + "px"; + }; + + function SimpleScrollbars(cls, place, scroll) { + this.addClass = cls; + this.horiz = new Bar(cls, "horizontal", scroll); + place(this.horiz.node); + this.vert = new Bar(cls, "vertical", scroll); + place(this.vert.node); + this.width = null; + } + + SimpleScrollbars.prototype.update = function(measure) { + if (this.width == null) { + var style = window.getComputedStyle ? window.getComputedStyle(this.horiz.node) : this.horiz.node.currentStyle; + if (style) this.width = parseInt(style.height); + } + var width = this.width || 0; + + var needsH = measure.scrollWidth > measure.clientWidth + 1; + var needsV = measure.scrollHeight > measure.clientHeight + 1; + this.vert.node.style.display = needsV ? "block" : "none"; + this.horiz.node.style.display = needsH ? "block" : "none"; + + if (needsV) { + this.vert.update(measure.scrollHeight, measure.clientHeight, + measure.viewHeight - (needsH ? width : 0)); + this.vert.node.style.display = "block"; + this.vert.node.style.bottom = needsH ? width + "px" : "0"; + } + if (needsH) { + this.horiz.update(measure.scrollWidth, measure.clientWidth, + measure.viewWidth - (needsV ? width : 0) - measure.barLeft); + this.horiz.node.style.right = needsV ? width + "px" : "0"; + this.horiz.node.style.left = measure.barLeft + "px"; + } + + return {right: needsV ? width : 0, bottom: needsH ? width : 0}; + }; + + SimpleScrollbars.prototype.setScrollTop = function(pos) { + this.vert.moveTo(pos, false); + }; + + SimpleScrollbars.prototype.setScrollLeft = function(pos) { + this.horiz.moveTo(pos, false); + }; + + SimpleScrollbars.prototype.clear = function() { + var parent = this.horiz.node.parentNode; + parent.removeChild(this.horiz.node); + parent.removeChild(this.vert.node); + }; + + CodeMirror.scrollbarModel.simple = function(place, scroll) { + return new SimpleScrollbars("CodeMirror-simplescroll", place, scroll); + }; + CodeMirror.scrollbarModel.overlay = function(place, scroll) { + return new SimpleScrollbars("CodeMirror-overlayscroll", place, scroll); + }; +}); diff --git a/static/js/mdeditor/lib/codemirror/addon/search/match-highlighter.js b/static/js/mdeditor/lib/codemirror/addon/search/match-highlighter.js new file mode 100644 index 00000000..e9a22721 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/search/match-highlighter.js @@ -0,0 +1,128 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// Highlighting text that matches the selection +// +// Defines an option highlightSelectionMatches, which, when enabled, +// will style strings that match the selection throughout the +// document. +// +// The option can be set to true to simply enable it, or to a +// {minChars, style, wordsOnly, showToken, delay} object to explicitly +// configure it. minChars is the minimum amount of characters that should be +// selected for the behavior to occur, and style is the token style to +// apply to the matches. This will be prefixed by "cm-" to create an +// actual CSS class name. If wordsOnly is enabled, the matches will be +// highlighted only if the selected text is a word. showToken, when enabled, +// will cause the current token to be highlighted when nothing is selected. +// delay is used to specify how much time to wait, in milliseconds, before +// highlighting the matches. + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var DEFAULT_MIN_CHARS = 2; + var DEFAULT_TOKEN_STYLE = "matchhighlight"; + var DEFAULT_DELAY = 100; + var DEFAULT_WORDS_ONLY = false; + + function State(options) { + if (typeof options == "object") { + this.minChars = options.minChars; + this.style = options.style; + this.showToken = options.showToken; + this.delay = options.delay; + this.wordsOnly = options.wordsOnly; + } + if (this.style == null) this.style = DEFAULT_TOKEN_STYLE; + if (this.minChars == null) this.minChars = DEFAULT_MIN_CHARS; + if (this.delay == null) this.delay = DEFAULT_DELAY; + if (this.wordsOnly == null) this.wordsOnly = DEFAULT_WORDS_ONLY; + this.overlay = this.timeout = null; + } + + CodeMirror.defineOption("highlightSelectionMatches", false, function(cm, val, old) { + if (old && old != CodeMirror.Init) { + var over = cm.state.matchHighlighter.overlay; + if (over) cm.removeOverlay(over); + clearTimeout(cm.state.matchHighlighter.timeout); + cm.state.matchHighlighter = null; + cm.off("cursorActivity", cursorActivity); + } + if (val) { + cm.state.matchHighlighter = new State(val); + highlightMatches(cm); + cm.on("cursorActivity", cursorActivity); + } + }); + + function cursorActivity(cm) { + var state = cm.state.matchHighlighter; + clearTimeout(state.timeout); + state.timeout = setTimeout(function() {highlightMatches(cm);}, state.delay); + } + + function highlightMatches(cm) { + cm.operation(function() { + var state = cm.state.matchHighlighter; + if (state.overlay) { + cm.removeOverlay(state.overlay); + state.overlay = null; + } + if (!cm.somethingSelected() && state.showToken) { + var re = state.showToken === true ? /[\w$]/ : state.showToken; + var cur = cm.getCursor(), line = cm.getLine(cur.line), start = cur.ch, end = start; + while (start && re.test(line.charAt(start - 1))) --start; + while (end < line.length && re.test(line.charAt(end))) ++end; + if (start < end) + cm.addOverlay(state.overlay = makeOverlay(line.slice(start, end), re, state.style)); + return; + } + var from = cm.getCursor("from"), to = cm.getCursor("to"); + if (from.line != to.line) return; + if (state.wordsOnly && !isWord(cm, from, to)) return; + var selection = cm.getRange(from, to).replace(/^\s+|\s+$/g, ""); + if (selection.length >= state.minChars) + cm.addOverlay(state.overlay = makeOverlay(selection, false, state.style)); + }); + } + + function isWord(cm, from, to) { + var str = cm.getRange(from, to); + if (str.match(/^\w+$/) !== null) { + if (from.ch > 0) { + var pos = {line: from.line, ch: from.ch - 1}; + var chr = cm.getRange(pos, from); + if (chr.match(/\W/) === null) return false; + } + if (to.ch < cm.getLine(from.line).length) { + var pos = {line: to.line, ch: to.ch + 1}; + var chr = cm.getRange(to, pos); + if (chr.match(/\W/) === null) return false; + } + return true; + } else return false; + } + + function boundariesAround(stream, re) { + return (!stream.start || !re.test(stream.string.charAt(stream.start - 1))) && + (stream.pos == stream.string.length || !re.test(stream.string.charAt(stream.pos))); + } + + function makeOverlay(query, hasBoundary, style) { + return {token: function(stream) { + if (stream.match(query) && + (!hasBoundary || boundariesAround(stream, hasBoundary))) + return style; + stream.next(); + stream.skipTo(query.charAt(0)) || stream.skipToEnd(); + }}; + } +}); diff --git a/static/js/mdeditor/lib/codemirror/addon/search/matchesonscrollbar.css b/static/js/mdeditor/lib/codemirror/addon/search/matchesonscrollbar.css new file mode 100644 index 00000000..77932cc9 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/search/matchesonscrollbar.css @@ -0,0 +1,8 @@ +.CodeMirror-search-match { + background: gold; + border-top: 1px solid orange; + border-bottom: 1px solid orange; + -moz-box-sizing: border-box; + box-sizing: border-box; + opacity: .5; +} diff --git a/static/js/mdeditor/lib/codemirror/addon/search/matchesonscrollbar.js b/static/js/mdeditor/lib/codemirror/addon/search/matchesonscrollbar.js new file mode 100644 index 00000000..dbd67a4a --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/search/matchesonscrollbar.js @@ -0,0 +1,95 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("./searchcursor"), require("../scroll/annotatescrollbar")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "./searchcursor", "../scroll/annotatescrollbar"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineExtension("showMatchesOnScrollbar", function(query, caseFold, options) { + if (typeof options == "string") options = {className: options}; + if (!options) options = {}; + return new SearchAnnotation(this, query, caseFold, options); + }); + + function SearchAnnotation(cm, query, caseFold, options) { + this.cm = cm; + var annotateOptions = {listenForChanges: false}; + for (var prop in options) annotateOptions[prop] = options[prop]; + if (!annotateOptions.className) annotateOptions.className = "CodeMirror-search-match"; + this.annotation = cm.annotateScrollbar(annotateOptions); + this.query = query; + this.caseFold = caseFold; + this.gap = {from: cm.firstLine(), to: cm.lastLine() + 1}; + this.matches = []; + this.update = null; + + this.findMatches(); + this.annotation.update(this.matches); + + var self = this; + cm.on("change", this.changeHandler = function(_cm, change) { self.onChange(change); }); + } + + var MAX_MATCHES = 1000; + + SearchAnnotation.prototype.findMatches = function() { + if (!this.gap) return; + for (var i = 0; i < this.matches.length; i++) { + var match = this.matches[i]; + if (match.from.line >= this.gap.to) break; + if (match.to.line >= this.gap.from) this.matches.splice(i--, 1); + } + var cursor = this.cm.getSearchCursor(this.query, CodeMirror.Pos(this.gap.from, 0), this.caseFold); + while (cursor.findNext()) { + var match = {from: cursor.from(), to: cursor.to()}; + if (match.from.line >= this.gap.to) break; + this.matches.splice(i++, 0, match); + if (this.matches.length > MAX_MATCHES) break; + } + this.gap = null; + }; + + function offsetLine(line, changeStart, sizeChange) { + if (line <= changeStart) return line; + return Math.max(changeStart, line + sizeChange); + } + + SearchAnnotation.prototype.onChange = function(change) { + var startLine = change.from.line; + var endLine = CodeMirror.changeEnd(change).line; + var sizeChange = endLine - change.to.line; + if (this.gap) { + this.gap.from = Math.min(offsetLine(this.gap.from, startLine, sizeChange), change.from.line); + this.gap.to = Math.max(offsetLine(this.gap.to, startLine, sizeChange), change.from.line); + } else { + this.gap = {from: change.from.line, to: endLine + 1}; + } + + if (sizeChange) for (var i = 0; i < this.matches.length; i++) { + var match = this.matches[i]; + var newFrom = offsetLine(match.from.line, startLine, sizeChange); + if (newFrom != match.from.line) match.from = CodeMirror.Pos(newFrom, match.from.ch); + var newTo = offsetLine(match.to.line, startLine, sizeChange); + if (newTo != match.to.line) match.to = CodeMirror.Pos(newTo, match.to.ch); + } + clearTimeout(this.update); + var self = this; + this.update = setTimeout(function() { self.updateAfterChange(); }, 250); + }; + + SearchAnnotation.prototype.updateAfterChange = function() { + this.findMatches(); + this.annotation.update(this.matches); + }; + + SearchAnnotation.prototype.clear = function() { + this.cm.off("change", this.changeHandler); + this.annotation.clear(); + }; +}); diff --git a/static/js/mdeditor/lib/codemirror/addon/search/search.js b/static/js/mdeditor/lib/codemirror/addon/search/search.js new file mode 100644 index 00000000..0251067a --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/search/search.js @@ -0,0 +1,164 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// Define search commands. Depends on dialog.js or another +// implementation of the openDialog method. + +// Replace works a little oddly -- it will do the replace on the next +// Ctrl-G (or whatever is bound to findNext) press. You prevent a +// replace by making sure the match is no longer selected when hitting +// Ctrl-G. + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("./searchcursor"), require("../dialog/dialog")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "./searchcursor", "../dialog/dialog"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + function searchOverlay(query, caseInsensitive) { + if (typeof query == "string") + query = new RegExp(query.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"), caseInsensitive ? "gi" : "g"); + else if (!query.global) + query = new RegExp(query.source, query.ignoreCase ? "gi" : "g"); + + return {token: function(stream) { + query.lastIndex = stream.pos; + var match = query.exec(stream.string); + if (match && match.index == stream.pos) { + stream.pos += match[0].length; + return "searching"; + } else if (match) { + stream.pos = match.index; + } else { + stream.skipToEnd(); + } + }}; + } + + function SearchState() { + this.posFrom = this.posTo = this.query = null; + this.overlay = null; + } + function getSearchState(cm) { + return cm.state.search || (cm.state.search = new SearchState()); + } + function queryCaseInsensitive(query) { + return typeof query == "string" && query == query.toLowerCase(); + } + function getSearchCursor(cm, query, pos) { + // Heuristic: if the query string is all lowercase, do a case insensitive search. + return cm.getSearchCursor(query, pos, queryCaseInsensitive(query)); + } + function dialog(cm, text, shortText, deflt, f) { + if (cm.openDialog) cm.openDialog(text, f, {value: deflt}); + else f(prompt(shortText, deflt)); + } + function confirmDialog(cm, text, shortText, fs) { + if (cm.openConfirm) cm.openConfirm(text, fs); + else if (confirm(shortText)) fs[0](); + } + function parseQuery(query) { + var isRE = query.match(/^\/(.*)\/([a-z]*)$/); + if (isRE) { + try { query = new RegExp(isRE[1], isRE[2].indexOf("i") == -1 ? "" : "i"); } + catch(e) {} // Not a regular expression after all, do a string search + } + if (typeof query == "string" ? query == "" : query.test("")) + query = /x^/; + return query; + } + var queryDialog = + 'Search: (Use /re/ syntax for regexp search)'; + function doSearch(cm, rev) { + var state = getSearchState(cm); + if (state.query) return findNext(cm, rev); + dialog(cm, queryDialog, "Search for:", cm.getSelection(), function(query) { + cm.operation(function() { + if (!query || state.query) return; + state.query = parseQuery(query); + cm.removeOverlay(state.overlay, queryCaseInsensitive(state.query)); + state.overlay = searchOverlay(state.query, queryCaseInsensitive(state.query)); + cm.addOverlay(state.overlay); + if (cm.showMatchesOnScrollbar) { + if (state.annotate) { state.annotate.clear(); state.annotate = null; } + state.annotate = cm.showMatchesOnScrollbar(state.query, queryCaseInsensitive(state.query)); + } + state.posFrom = state.posTo = cm.getCursor(); + findNext(cm, rev); + }); + }); + } + function findNext(cm, rev) {cm.operation(function() { + var state = getSearchState(cm); + var cursor = getSearchCursor(cm, state.query, rev ? state.posFrom : state.posTo); + if (!cursor.find(rev)) { + cursor = getSearchCursor(cm, state.query, rev ? CodeMirror.Pos(cm.lastLine()) : CodeMirror.Pos(cm.firstLine(), 0)); + if (!cursor.find(rev)) return; + } + cm.setSelection(cursor.from(), cursor.to()); + cm.scrollIntoView({from: cursor.from(), to: cursor.to()}); + state.posFrom = cursor.from(); state.posTo = cursor.to(); + });} + function clearSearch(cm) {cm.operation(function() { + var state = getSearchState(cm); + if (!state.query) return; + state.query = null; + cm.removeOverlay(state.overlay); + if (state.annotate) { state.annotate.clear(); state.annotate = null; } + });} + + var replaceQueryDialog = + 'Replace: (Use /re/ syntax for regexp search)'; + var replacementQueryDialog = 'With: '; + var doReplaceConfirm = "Replace? "; + function replace(cm, all) { + if (cm.getOption("readOnly")) return; + dialog(cm, replaceQueryDialog, "Replace:", cm.getSelection(), function(query) { + if (!query) return; + query = parseQuery(query); + dialog(cm, replacementQueryDialog, "Replace with:", "", function(text) { + if (all) { + cm.operation(function() { + for (var cursor = getSearchCursor(cm, query); cursor.findNext();) { + if (typeof query != "string") { + var match = cm.getRange(cursor.from(), cursor.to()).match(query); + cursor.replace(text.replace(/\$(\d)/g, function(_, i) {return match[i];})); + } else cursor.replace(text); + } + }); + } else { + clearSearch(cm); + var cursor = getSearchCursor(cm, query, cm.getCursor()); + var advance = function() { + var start = cursor.from(), match; + if (!(match = cursor.findNext())) { + cursor = getSearchCursor(cm, query); + if (!(match = cursor.findNext()) || + (start && cursor.from().line == start.line && cursor.from().ch == start.ch)) return; + } + cm.setSelection(cursor.from(), cursor.to()); + cm.scrollIntoView({from: cursor.from(), to: cursor.to()}); + confirmDialog(cm, doReplaceConfirm, "Replace?", + [function() {doReplace(match);}, advance]); + }; + var doReplace = function(match) { + cursor.replace(typeof query == "string" ? text : + text.replace(/\$(\d)/g, function(_, i) {return match[i];})); + advance(); + }; + advance(); + } + }); + }); + } + + CodeMirror.commands.find = function(cm) {clearSearch(cm); doSearch(cm);}; + CodeMirror.commands.findNext = doSearch; + CodeMirror.commands.findPrev = function(cm) {doSearch(cm, true);}; + CodeMirror.commands.clearSearch = clearSearch; + CodeMirror.commands.replace = replace; + CodeMirror.commands.replaceAll = function(cm) {replace(cm, true);}; +}); diff --git a/static/js/mdeditor/lib/codemirror/addon/search/searchcursor.js b/static/js/mdeditor/lib/codemirror/addon/search/searchcursor.js new file mode 100644 index 00000000..55c108b5 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/search/searchcursor.js @@ -0,0 +1,189 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + var Pos = CodeMirror.Pos; + + function SearchCursor(doc, query, pos, caseFold) { + this.atOccurrence = false; this.doc = doc; + if (caseFold == null && typeof query == "string") caseFold = false; + + pos = pos ? doc.clipPos(pos) : Pos(0, 0); + this.pos = {from: pos, to: pos}; + + // The matches method is filled in based on the type of query. + // It takes a position and a direction, and returns an object + // describing the next occurrence of the query, or null if no + // more matches were found. + if (typeof query != "string") { // Regexp match + if (!query.global) query = new RegExp(query.source, query.ignoreCase ? "ig" : "g"); + this.matches = function(reverse, pos) { + if (reverse) { + query.lastIndex = 0; + var line = doc.getLine(pos.line).slice(0, pos.ch), cutOff = 0, match, start; + for (;;) { + query.lastIndex = cutOff; + var newMatch = query.exec(line); + if (!newMatch) break; + match = newMatch; + start = match.index; + cutOff = match.index + (match[0].length || 1); + if (cutOff == line.length) break; + } + var matchLen = (match && match[0].length) || 0; + if (!matchLen) { + if (start == 0 && line.length == 0) {match = undefined;} + else if (start != doc.getLine(pos.line).length) { + matchLen++; + } + } + } else { + query.lastIndex = pos.ch; + var line = doc.getLine(pos.line), match = query.exec(line); + var matchLen = (match && match[0].length) || 0; + var start = match && match.index; + if (start + matchLen != line.length && !matchLen) matchLen = 1; + } + if (match && matchLen) + return {from: Pos(pos.line, start), + to: Pos(pos.line, start + matchLen), + match: match}; + }; + } else { // String query + var origQuery = query; + if (caseFold) query = query.toLowerCase(); + var fold = caseFold ? function(str){return str.toLowerCase();} : function(str){return str;}; + var target = query.split("\n"); + // Different methods for single-line and multi-line queries + if (target.length == 1) { + if (!query.length) { + // Empty string would match anything and never progress, so + // we define it to match nothing instead. + this.matches = function() {}; + } else { + this.matches = function(reverse, pos) { + if (reverse) { + var orig = doc.getLine(pos.line).slice(0, pos.ch), line = fold(orig); + var match = line.lastIndexOf(query); + if (match > -1) { + match = adjustPos(orig, line, match); + return {from: Pos(pos.line, match), to: Pos(pos.line, match + origQuery.length)}; + } + } else { + var orig = doc.getLine(pos.line).slice(pos.ch), line = fold(orig); + var match = line.indexOf(query); + if (match > -1) { + match = adjustPos(orig, line, match) + pos.ch; + return {from: Pos(pos.line, match), to: Pos(pos.line, match + origQuery.length)}; + } + } + }; + } + } else { + var origTarget = origQuery.split("\n"); + this.matches = function(reverse, pos) { + var last = target.length - 1; + if (reverse) { + if (pos.line - (target.length - 1) < doc.firstLine()) return; + if (fold(doc.getLine(pos.line).slice(0, origTarget[last].length)) != target[target.length - 1]) return; + var to = Pos(pos.line, origTarget[last].length); + for (var ln = pos.line - 1, i = last - 1; i >= 1; --i, --ln) + if (target[i] != fold(doc.getLine(ln))) return; + var line = doc.getLine(ln), cut = line.length - origTarget[0].length; + if (fold(line.slice(cut)) != target[0]) return; + return {from: Pos(ln, cut), to: to}; + } else { + if (pos.line + (target.length - 1) > doc.lastLine()) return; + var line = doc.getLine(pos.line), cut = line.length - origTarget[0].length; + if (fold(line.slice(cut)) != target[0]) return; + var from = Pos(pos.line, cut); + for (var ln = pos.line + 1, i = 1; i < last; ++i, ++ln) + if (target[i] != fold(doc.getLine(ln))) return; + if (fold(doc.getLine(ln).slice(0, origTarget[last].length)) != target[last]) return; + return {from: from, to: Pos(ln, origTarget[last].length)}; + } + }; + } + } + } + + SearchCursor.prototype = { + findNext: function() {return this.find(false);}, + findPrevious: function() {return this.find(true);}, + + find: function(reverse) { + var self = this, pos = this.doc.clipPos(reverse ? this.pos.from : this.pos.to); + function savePosAndFail(line) { + var pos = Pos(line, 0); + self.pos = {from: pos, to: pos}; + self.atOccurrence = false; + return false; + } + + for (;;) { + if (this.pos = this.matches(reverse, pos)) { + this.atOccurrence = true; + return this.pos.match || true; + } + if (reverse) { + if (!pos.line) return savePosAndFail(0); + pos = Pos(pos.line-1, this.doc.getLine(pos.line-1).length); + } + else { + var maxLine = this.doc.lineCount(); + if (pos.line == maxLine - 1) return savePosAndFail(maxLine); + pos = Pos(pos.line + 1, 0); + } + } + }, + + from: function() {if (this.atOccurrence) return this.pos.from;}, + to: function() {if (this.atOccurrence) return this.pos.to;}, + + replace: function(newText) { + if (!this.atOccurrence) return; + var lines = CodeMirror.splitLines(newText); + this.doc.replaceRange(lines, this.pos.from, this.pos.to); + this.pos.to = Pos(this.pos.from.line + lines.length - 1, + lines[lines.length - 1].length + (lines.length == 1 ? this.pos.from.ch : 0)); + } + }; + + // Maps a position in a case-folded line back to a position in the original line + // (compensating for codepoints increasing in number during folding) + function adjustPos(orig, folded, pos) { + if (orig.length == folded.length) return pos; + for (var pos1 = Math.min(pos, orig.length);;) { + var len1 = orig.slice(0, pos1).toLowerCase().length; + if (len1 < pos) ++pos1; + else if (len1 > pos) --pos1; + else return pos1; + } + } + + CodeMirror.defineExtension("getSearchCursor", function(query, pos, caseFold) { + return new SearchCursor(this.doc, query, pos, caseFold); + }); + CodeMirror.defineDocExtension("getSearchCursor", function(query, pos, caseFold) { + return new SearchCursor(this, query, pos, caseFold); + }); + + CodeMirror.defineExtension("selectMatches", function(query, caseFold) { + var ranges = [], next; + var cur = this.getSearchCursor(query, this.getCursor("from"), caseFold); + while (next = cur.findNext()) { + if (CodeMirror.cmpPos(cur.to(), this.getCursor("to")) > 0) break; + ranges.push({anchor: cur.from(), head: cur.to()}); + } + if (ranges.length) + this.setSelections(ranges, 0); + }); +}); diff --git a/static/js/mdeditor/lib/codemirror/addon/selection/active-line.js b/static/js/mdeditor/lib/codemirror/addon/selection/active-line.js new file mode 100644 index 00000000..22da2e0a --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/selection/active-line.js @@ -0,0 +1,71 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// Because sometimes you need to style the cursor's line. +// +// Adds an option 'styleActiveLine' which, when enabled, gives the +// active line's wrapping
the CSS class "CodeMirror-activeline", +// and gives its background
the class "CodeMirror-activeline-background". + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + var WRAP_CLASS = "CodeMirror-activeline"; + var BACK_CLASS = "CodeMirror-activeline-background"; + + CodeMirror.defineOption("styleActiveLine", false, function(cm, val, old) { + var prev = old && old != CodeMirror.Init; + if (val && !prev) { + cm.state.activeLines = []; + updateActiveLines(cm, cm.listSelections()); + cm.on("beforeSelectionChange", selectionChange); + } else if (!val && prev) { + cm.off("beforeSelectionChange", selectionChange); + clearActiveLines(cm); + delete cm.state.activeLines; + } + }); + + function clearActiveLines(cm) { + for (var i = 0; i < cm.state.activeLines.length; i++) { + cm.removeLineClass(cm.state.activeLines[i], "wrap", WRAP_CLASS); + cm.removeLineClass(cm.state.activeLines[i], "background", BACK_CLASS); + } + } + + function sameArray(a, b) { + if (a.length != b.length) return false; + for (var i = 0; i < a.length; i++) + if (a[i] != b[i]) return false; + return true; + } + + function updateActiveLines(cm, ranges) { + var active = []; + for (var i = 0; i < ranges.length; i++) { + var range = ranges[i]; + if (!range.empty()) continue; + var line = cm.getLineHandleVisualStart(range.head.line); + if (active[active.length - 1] != line) active.push(line); + } + if (sameArray(cm.state.activeLines, active)) return; + cm.operation(function() { + clearActiveLines(cm); + for (var i = 0; i < active.length; i++) { + cm.addLineClass(active[i], "wrap", WRAP_CLASS); + cm.addLineClass(active[i], "background", BACK_CLASS); + } + cm.state.activeLines = active; + }); + } + + function selectionChange(cm, sel) { + updateActiveLines(cm, sel.ranges); + } +}); diff --git a/static/js/mdeditor/lib/codemirror/addon/selection/mark-selection.js b/static/js/mdeditor/lib/codemirror/addon/selection/mark-selection.js new file mode 100644 index 00000000..5c42d21e --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/selection/mark-selection.js @@ -0,0 +1,118 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// Because sometimes you need to mark the selected *text*. +// +// Adds an option 'styleSelectedText' which, when enabled, gives +// selected text the CSS class given as option value, or +// "CodeMirror-selectedtext" when the value is not a string. + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineOption("styleSelectedText", false, function(cm, val, old) { + var prev = old && old != CodeMirror.Init; + if (val && !prev) { + cm.state.markedSelection = []; + cm.state.markedSelectionStyle = typeof val == "string" ? val : "CodeMirror-selectedtext"; + reset(cm); + cm.on("cursorActivity", onCursorActivity); + cm.on("change", onChange); + } else if (!val && prev) { + cm.off("cursorActivity", onCursorActivity); + cm.off("change", onChange); + clear(cm); + cm.state.markedSelection = cm.state.markedSelectionStyle = null; + } + }); + + function onCursorActivity(cm) { + cm.operation(function() { update(cm); }); + } + + function onChange(cm) { + if (cm.state.markedSelection.length) + cm.operation(function() { clear(cm); }); + } + + var CHUNK_SIZE = 8; + var Pos = CodeMirror.Pos; + var cmp = CodeMirror.cmpPos; + + function coverRange(cm, from, to, addAt) { + if (cmp(from, to) == 0) return; + var array = cm.state.markedSelection; + var cls = cm.state.markedSelectionStyle; + for (var line = from.line;;) { + var start = line == from.line ? from : Pos(line, 0); + var endLine = line + CHUNK_SIZE, atEnd = endLine >= to.line; + var end = atEnd ? to : Pos(endLine, 0); + var mark = cm.markText(start, end, {className: cls}); + if (addAt == null) array.push(mark); + else array.splice(addAt++, 0, mark); + if (atEnd) break; + line = endLine; + } + } + + function clear(cm) { + var array = cm.state.markedSelection; + for (var i = 0; i < array.length; ++i) array[i].clear(); + array.length = 0; + } + + function reset(cm) { + clear(cm); + var ranges = cm.listSelections(); + for (var i = 0; i < ranges.length; i++) + coverRange(cm, ranges[i].from(), ranges[i].to()); + } + + function update(cm) { + if (!cm.somethingSelected()) return clear(cm); + if (cm.listSelections().length > 1) return reset(cm); + + var from = cm.getCursor("start"), to = cm.getCursor("end"); + + var array = cm.state.markedSelection; + if (!array.length) return coverRange(cm, from, to); + + var coverStart = array[0].find(), coverEnd = array[array.length - 1].find(); + if (!coverStart || !coverEnd || to.line - from.line < CHUNK_SIZE || + cmp(from, coverEnd.to) >= 0 || cmp(to, coverStart.from) <= 0) + return reset(cm); + + while (cmp(from, coverStart.from) > 0) { + array.shift().clear(); + coverStart = array[0].find(); + } + if (cmp(from, coverStart.from) < 0) { + if (coverStart.to.line - from.line < CHUNK_SIZE) { + array.shift().clear(); + coverRange(cm, from, coverStart.to, 0); + } else { + coverRange(cm, from, coverStart.from, 0); + } + } + + while (cmp(to, coverEnd.to) < 0) { + array.pop().clear(); + coverEnd = array[array.length - 1].find(); + } + if (cmp(to, coverEnd.to) > 0) { + if (to.line - coverEnd.from.line < CHUNK_SIZE) { + array.pop().clear(); + coverRange(cm, coverEnd.from, to); + } else { + coverRange(cm, coverEnd.to, to); + } + } + } +}); diff --git a/static/js/mdeditor/lib/codemirror/addon/selection/selection-pointer.js b/static/js/mdeditor/lib/codemirror/addon/selection/selection-pointer.js new file mode 100644 index 00000000..ef5e404a --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/selection/selection-pointer.js @@ -0,0 +1,98 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineOption("selectionPointer", false, function(cm, val) { + var data = cm.state.selectionPointer; + if (data) { + CodeMirror.off(cm.getWrapperElement(), "mousemove", data.mousemove); + CodeMirror.off(cm.getWrapperElement(), "mouseout", data.mouseout); + CodeMirror.off(window, "scroll", data.windowScroll); + cm.off("cursorActivity", reset); + cm.off("scroll", reset); + cm.state.selectionPointer = null; + cm.display.lineDiv.style.cursor = ""; + } + if (val) { + data = cm.state.selectionPointer = { + value: typeof val == "string" ? val : "default", + mousemove: function(event) { mousemove(cm, event); }, + mouseout: function(event) { mouseout(cm, event); }, + windowScroll: function() { reset(cm); }, + rects: null, + mouseX: null, mouseY: null, + willUpdate: false + }; + CodeMirror.on(cm.getWrapperElement(), "mousemove", data.mousemove); + CodeMirror.on(cm.getWrapperElement(), "mouseout", data.mouseout); + CodeMirror.on(window, "scroll", data.windowScroll); + cm.on("cursorActivity", reset); + cm.on("scroll", reset); + } + }); + + function mousemove(cm, event) { + var data = cm.state.selectionPointer; + if (event.buttons == null ? event.which : event.buttons) { + data.mouseX = data.mouseY = null; + } else { + data.mouseX = event.clientX; + data.mouseY = event.clientY; + } + scheduleUpdate(cm); + } + + function mouseout(cm, event) { + if (!cm.getWrapperElement().contains(event.relatedTarget)) { + var data = cm.state.selectionPointer; + data.mouseX = data.mouseY = null; + scheduleUpdate(cm); + } + } + + function reset(cm) { + cm.state.selectionPointer.rects = null; + scheduleUpdate(cm); + } + + function scheduleUpdate(cm) { + if (!cm.state.selectionPointer.willUpdate) { + cm.state.selectionPointer.willUpdate = true; + setTimeout(function() { + update(cm); + cm.state.selectionPointer.willUpdate = false; + }, 50); + } + } + + function update(cm) { + var data = cm.state.selectionPointer; + if (!data) return; + if (data.rects == null && data.mouseX != null) { + data.rects = []; + if (cm.somethingSelected()) { + for (var sel = cm.display.selectionDiv.firstChild; sel; sel = sel.nextSibling) + data.rects.push(sel.getBoundingClientRect()); + } + } + var inside = false; + if (data.mouseX != null) for (var i = 0; i < data.rects.length; i++) { + var rect = data.rects[i]; + if (rect.left <= data.mouseX && rect.right >= data.mouseX && + rect.top <= data.mouseY && rect.bottom >= data.mouseY) + inside = true; + } + var cursor = inside ? data.value : ""; + if (cm.display.lineDiv.style.cursor != cursor) + cm.display.lineDiv.style.cursor = cursor; + } +}); diff --git a/static/js/mdeditor/lib/codemirror/addon/tern/tern.css b/static/js/mdeditor/lib/codemirror/addon/tern/tern.css new file mode 100644 index 00000000..76fba33d --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/tern/tern.css @@ -0,0 +1,86 @@ +.CodeMirror-Tern-completion { + padding-left: 22px; + position: relative; +} +.CodeMirror-Tern-completion:before { + position: absolute; + left: 2px; + bottom: 2px; + border-radius: 50%; + font-size: 12px; + font-weight: bold; + height: 15px; + width: 15px; + line-height: 16px; + text-align: center; + color: white; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +.CodeMirror-Tern-completion-unknown:before { + content: "?"; + background: #4bb; +} +.CodeMirror-Tern-completion-object:before { + content: "O"; + background: #77c; +} +.CodeMirror-Tern-completion-fn:before { + content: "F"; + background: #7c7; +} +.CodeMirror-Tern-completion-array:before { + content: "A"; + background: #c66; +} +.CodeMirror-Tern-completion-number:before { + content: "1"; + background: #999; +} +.CodeMirror-Tern-completion-string:before { + content: "S"; + background: #999; +} +.CodeMirror-Tern-completion-bool:before { + content: "B"; + background: #999; +} + +.CodeMirror-Tern-completion-guess { + color: #999; +} + +.CodeMirror-Tern-tooltip { + border: 1px solid silver; + border-radius: 3px; + color: #444; + padding: 2px 5px; + font-size: 90%; + font-family: monospace; + background-color: white; + white-space: pre-wrap; + + max-width: 40em; + position: absolute; + z-index: 10; + -webkit-box-shadow: 2px 3px 5px rgba(0,0,0,.2); + -moz-box-shadow: 2px 3px 5px rgba(0,0,0,.2); + box-shadow: 2px 3px 5px rgba(0,0,0,.2); + + transition: opacity 1s; + -moz-transition: opacity 1s; + -webkit-transition: opacity 1s; + -o-transition: opacity 1s; + -ms-transition: opacity 1s; +} + +.CodeMirror-Tern-hint-doc { + max-width: 25em; + margin-top: -3px; +} + +.CodeMirror-Tern-fname { color: black; } +.CodeMirror-Tern-farg { color: #70a; } +.CodeMirror-Tern-farg-current { text-decoration: underline; } +.CodeMirror-Tern-type { color: #07c; } +.CodeMirror-Tern-fhint-guess { opacity: .7; } diff --git a/static/js/mdeditor/lib/codemirror/addon/tern/tern.js b/static/js/mdeditor/lib/codemirror/addon/tern/tern.js new file mode 100644 index 00000000..b049549d --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/tern/tern.js @@ -0,0 +1,697 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// Glue code between CodeMirror and Tern. +// +// Create a CodeMirror.TernServer to wrap an actual Tern server, +// register open documents (CodeMirror.Doc instances) with it, and +// call its methods to activate the assisting functions that Tern +// provides. +// +// Options supported (all optional): +// * defs: An array of JSON definition data structures. +// * plugins: An object mapping plugin names to configuration +// options. +// * getFile: A function(name, c) that can be used to access files in +// the project that haven't been loaded yet. Simply do c(null) to +// indicate that a file is not available. +// * fileFilter: A function(value, docName, doc) that will be applied +// to documents before passing them on to Tern. +// * switchToDoc: A function(name, doc) that should, when providing a +// multi-file view, switch the view or focus to the named file. +// * showError: A function(editor, message) that can be used to +// override the way errors are displayed. +// * completionTip: Customize the content in tooltips for completions. +// Is passed a single argument—the completion's data as returned by +// Tern—and may return a string, DOM node, or null to indicate that +// no tip should be shown. By default the docstring is shown. +// * typeTip: Like completionTip, but for the tooltips shown for type +// queries. +// * responseFilter: A function(doc, query, request, error, data) that +// will be applied to the Tern responses before treating them +// +// +// It is possible to run the Tern server in a web worker by specifying +// these additional options: +// * useWorker: Set to true to enable web worker mode. You'll probably +// want to feature detect the actual value you use here, for example +// !!window.Worker. +// * workerScript: The main script of the worker. Point this to +// wherever you are hosting worker.js from this directory. +// * workerDeps: An array of paths pointing (relative to workerScript) +// to the Acorn and Tern libraries and any Tern plugins you want to +// load. Or, if you minified those into a single script and included +// them in the workerScript, simply leave this undefined. + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + // declare global: tern + + CodeMirror.TernServer = function(options) { + var self = this; + this.options = options || {}; + var plugins = this.options.plugins || (this.options.plugins = {}); + if (!plugins.doc_comment) plugins.doc_comment = true; + if (this.options.useWorker) { + this.server = new WorkerServer(this); + } else { + this.server = new tern.Server({ + getFile: function(name, c) { return getFile(self, name, c); }, + async: true, + defs: this.options.defs || [], + plugins: plugins + }); + } + this.docs = Object.create(null); + this.trackChange = function(doc, change) { trackChange(self, doc, change); }; + + this.cachedArgHints = null; + this.activeArgHints = null; + this.jumpStack = []; + + this.getHint = function(cm, c) { return hint(self, cm, c); }; + this.getHint.async = true; + }; + + CodeMirror.TernServer.prototype = { + addDoc: function(name, doc) { + var data = {doc: doc, name: name, changed: null}; + this.server.addFile(name, docValue(this, data)); + CodeMirror.on(doc, "change", this.trackChange); + return this.docs[name] = data; + }, + + delDoc: function(id) { + var found = resolveDoc(this, id); + if (!found) return; + CodeMirror.off(found.doc, "change", this.trackChange); + delete this.docs[found.name]; + this.server.delFile(found.name); + }, + + hideDoc: function(id) { + closeArgHints(this); + var found = resolveDoc(this, id); + if (found && found.changed) sendDoc(this, found); + }, + + complete: function(cm) { + cm.showHint({hint: this.getHint}); + }, + + showType: function(cm, pos, c) { showContextInfo(this, cm, pos, "type", c); }, + + showDocs: function(cm, pos, c) { showContextInfo(this, cm, pos, "documentation", c); }, + + updateArgHints: function(cm) { updateArgHints(this, cm); }, + + jumpToDef: function(cm) { jumpToDef(this, cm); }, + + jumpBack: function(cm) { jumpBack(this, cm); }, + + rename: function(cm) { rename(this, cm); }, + + selectName: function(cm) { selectName(this, cm); }, + + request: function (cm, query, c, pos) { + var self = this; + var doc = findDoc(this, cm.getDoc()); + var request = buildRequest(this, doc, query, pos); + + this.server.request(request, function (error, data) { + if (!error && self.options.responseFilter) + data = self.options.responseFilter(doc, query, request, error, data); + c(error, data); + }); + }, + + destroy: function () { + if (this.worker) { + this.worker.terminate(); + this.worker = null; + } + } + }; + + var Pos = CodeMirror.Pos; + var cls = "CodeMirror-Tern-"; + var bigDoc = 250; + + function getFile(ts, name, c) { + var buf = ts.docs[name]; + if (buf) + c(docValue(ts, buf)); + else if (ts.options.getFile) + ts.options.getFile(name, c); + else + c(null); + } + + function findDoc(ts, doc, name) { + for (var n in ts.docs) { + var cur = ts.docs[n]; + if (cur.doc == doc) return cur; + } + if (!name) for (var i = 0;; ++i) { + n = "[doc" + (i || "") + "]"; + if (!ts.docs[n]) { name = n; break; } + } + return ts.addDoc(name, doc); + } + + function resolveDoc(ts, id) { + if (typeof id == "string") return ts.docs[id]; + if (id instanceof CodeMirror) id = id.getDoc(); + if (id instanceof CodeMirror.Doc) return findDoc(ts, id); + } + + function trackChange(ts, doc, change) { + var data = findDoc(ts, doc); + + var argHints = ts.cachedArgHints; + if (argHints && argHints.doc == doc && cmpPos(argHints.start, change.to) <= 0) + ts.cachedArgHints = null; + + var changed = data.changed; + if (changed == null) + data.changed = changed = {from: change.from.line, to: change.from.line}; + var end = change.from.line + (change.text.length - 1); + if (change.from.line < changed.to) changed.to = changed.to - (change.to.line - end); + if (end >= changed.to) changed.to = end + 1; + if (changed.from > change.from.line) changed.from = change.from.line; + + if (doc.lineCount() > bigDoc && change.to - changed.from > 100) setTimeout(function() { + if (data.changed && data.changed.to - data.changed.from > 100) sendDoc(ts, data); + }, 200); + } + + function sendDoc(ts, doc) { + ts.server.request({files: [{type: "full", name: doc.name, text: docValue(ts, doc)}]}, function(error) { + if (error) window.console.error(error); + else doc.changed = null; + }); + } + + // Completion + + function hint(ts, cm, c) { + ts.request(cm, {type: "completions", types: true, docs: true, urls: true}, function(error, data) { + if (error) return showError(ts, cm, error); + var completions = [], after = ""; + var from = data.start, to = data.end; + if (cm.getRange(Pos(from.line, from.ch - 2), from) == "[\"" && + cm.getRange(to, Pos(to.line, to.ch + 2)) != "\"]") + after = "\"]"; + + for (var i = 0; i < data.completions.length; ++i) { + var completion = data.completions[i], className = typeToIcon(completion.type); + if (data.guess) className += " " + cls + "guess"; + completions.push({text: completion.name + after, + displayText: completion.name, + className: className, + data: completion}); + } + + var obj = {from: from, to: to, list: completions}; + var tooltip = null; + CodeMirror.on(obj, "close", function() { remove(tooltip); }); + CodeMirror.on(obj, "update", function() { remove(tooltip); }); + CodeMirror.on(obj, "select", function(cur, node) { + remove(tooltip); + var content = ts.options.completionTip ? ts.options.completionTip(cur.data) : cur.data.doc; + if (content) { + tooltip = makeTooltip(node.parentNode.getBoundingClientRect().right + window.pageXOffset, + node.getBoundingClientRect().top + window.pageYOffset, content); + tooltip.className += " " + cls + "hint-doc"; + } + }); + c(obj); + }); + } + + function typeToIcon(type) { + var suffix; + if (type == "?") suffix = "unknown"; + else if (type == "number" || type == "string" || type == "bool") suffix = type; + else if (/^fn\(/.test(type)) suffix = "fn"; + else if (/^\[/.test(type)) suffix = "array"; + else suffix = "object"; + return cls + "completion " + cls + "completion-" + suffix; + } + + // Type queries + + function showContextInfo(ts, cm, pos, queryName, c) { + ts.request(cm, queryName, function(error, data) { + if (error) return showError(ts, cm, error); + if (ts.options.typeTip) { + var tip = ts.options.typeTip(data); + } else { + var tip = elt("span", null, elt("strong", null, data.type || "not found")); + if (data.doc) + tip.appendChild(document.createTextNode(" — " + data.doc)); + if (data.url) { + tip.appendChild(document.createTextNode(" ")); + var child = tip.appendChild(elt("a", null, "[docs]")); + child.href = data.url; + child.target = "_blank"; + } + } + tempTooltip(cm, tip); + if (c) c(); + }, pos); + } + + // Maintaining argument hints + + function updateArgHints(ts, cm) { + closeArgHints(ts); + + if (cm.somethingSelected()) return; + var state = cm.getTokenAt(cm.getCursor()).state; + var inner = CodeMirror.innerMode(cm.getMode(), state); + if (inner.mode.name != "javascript") return; + var lex = inner.state.lexical; + if (lex.info != "call") return; + + var ch, argPos = lex.pos || 0, tabSize = cm.getOption("tabSize"); + for (var line = cm.getCursor().line, e = Math.max(0, line - 9), found = false; line >= e; --line) { + var str = cm.getLine(line), extra = 0; + for (var pos = 0;;) { + var tab = str.indexOf("\t", pos); + if (tab == -1) break; + extra += tabSize - (tab + extra) % tabSize - 1; + pos = tab + 1; + } + ch = lex.column - extra; + if (str.charAt(ch) == "(") {found = true; break;} + } + if (!found) return; + + var start = Pos(line, ch); + var cache = ts.cachedArgHints; + if (cache && cache.doc == cm.getDoc() && cmpPos(start, cache.start) == 0) + return showArgHints(ts, cm, argPos); + + ts.request(cm, {type: "type", preferFunction: true, end: start}, function(error, data) { + if (error || !data.type || !(/^fn\(/).test(data.type)) return; + ts.cachedArgHints = { + start: pos, + type: parseFnType(data.type), + name: data.exprName || data.name || "fn", + guess: data.guess, + doc: cm.getDoc() + }; + showArgHints(ts, cm, argPos); + }); + } + + function showArgHints(ts, cm, pos) { + closeArgHints(ts); + + var cache = ts.cachedArgHints, tp = cache.type; + var tip = elt("span", cache.guess ? cls + "fhint-guess" : null, + elt("span", cls + "fname", cache.name), "("); + for (var i = 0; i < tp.args.length; ++i) { + if (i) tip.appendChild(document.createTextNode(", ")); + var arg = tp.args[i]; + tip.appendChild(elt("span", cls + "farg" + (i == pos ? " " + cls + "farg-current" : ""), arg.name || "?")); + if (arg.type != "?") { + tip.appendChild(document.createTextNode(":\u00a0")); + tip.appendChild(elt("span", cls + "type", arg.type)); + } + } + tip.appendChild(document.createTextNode(tp.rettype ? ") ->\u00a0" : ")")); + if (tp.rettype) tip.appendChild(elt("span", cls + "type", tp.rettype)); + var place = cm.cursorCoords(null, "page"); + ts.activeArgHints = makeTooltip(place.right + 1, place.bottom, tip); + } + + function parseFnType(text) { + var args = [], pos = 3; + + function skipMatching(upto) { + var depth = 0, start = pos; + for (;;) { + var next = text.charAt(pos); + if (upto.test(next) && !depth) return text.slice(start, pos); + if (/[{\[\(]/.test(next)) ++depth; + else if (/[}\]\)]/.test(next)) --depth; + ++pos; + } + } + + // Parse arguments + if (text.charAt(pos) != ")") for (;;) { + var name = text.slice(pos).match(/^([^, \(\[\{]+): /); + if (name) { + pos += name[0].length; + name = name[1]; + } + args.push({name: name, type: skipMatching(/[\),]/)}); + if (text.charAt(pos) == ")") break; + pos += 2; + } + + var rettype = text.slice(pos).match(/^\) -> (.*)$/); + + return {args: args, rettype: rettype && rettype[1]}; + } + + // Moving to the definition of something + + function jumpToDef(ts, cm) { + function inner(varName) { + var req = {type: "definition", variable: varName || null}; + var doc = findDoc(ts, cm.getDoc()); + ts.server.request(buildRequest(ts, doc, req), function(error, data) { + if (error) return showError(ts, cm, error); + if (!data.file && data.url) { window.open(data.url); return; } + + if (data.file) { + var localDoc = ts.docs[data.file], found; + if (localDoc && (found = findContext(localDoc.doc, data))) { + ts.jumpStack.push({file: doc.name, + start: cm.getCursor("from"), + end: cm.getCursor("to")}); + moveTo(ts, doc, localDoc, found.start, found.end); + return; + } + } + showError(ts, cm, "Could not find a definition."); + }); + } + + if (!atInterestingExpression(cm)) + dialog(cm, "Jump to variable", function(name) { if (name) inner(name); }); + else + inner(); + } + + function jumpBack(ts, cm) { + var pos = ts.jumpStack.pop(), doc = pos && ts.docs[pos.file]; + if (!doc) return; + moveTo(ts, findDoc(ts, cm.getDoc()), doc, pos.start, pos.end); + } + + function moveTo(ts, curDoc, doc, start, end) { + doc.doc.setSelection(start, end); + if (curDoc != doc && ts.options.switchToDoc) { + closeArgHints(ts); + ts.options.switchToDoc(doc.name, doc.doc); + } + } + + // The {line,ch} representation of positions makes this rather awkward. + function findContext(doc, data) { + var before = data.context.slice(0, data.contextOffset).split("\n"); + var startLine = data.start.line - (before.length - 1); + var start = Pos(startLine, (before.length == 1 ? data.start.ch : doc.getLine(startLine).length) - before[0].length); + + var text = doc.getLine(startLine).slice(start.ch); + for (var cur = startLine + 1; cur < doc.lineCount() && text.length < data.context.length; ++cur) + text += "\n" + doc.getLine(cur); + if (text.slice(0, data.context.length) == data.context) return data; + + var cursor = doc.getSearchCursor(data.context, 0, false); + var nearest, nearestDist = Infinity; + while (cursor.findNext()) { + var from = cursor.from(), dist = Math.abs(from.line - start.line) * 10000; + if (!dist) dist = Math.abs(from.ch - start.ch); + if (dist < nearestDist) { nearest = from; nearestDist = dist; } + } + if (!nearest) return null; + + if (before.length == 1) + nearest.ch += before[0].length; + else + nearest = Pos(nearest.line + (before.length - 1), before[before.length - 1].length); + if (data.start.line == data.end.line) + var end = Pos(nearest.line, nearest.ch + (data.end.ch - data.start.ch)); + else + var end = Pos(nearest.line + (data.end.line - data.start.line), data.end.ch); + return {start: nearest, end: end}; + } + + function atInterestingExpression(cm) { + var pos = cm.getCursor("end"), tok = cm.getTokenAt(pos); + if (tok.start < pos.ch && (tok.type == "comment" || tok.type == "string")) return false; + return /\w/.test(cm.getLine(pos.line).slice(Math.max(pos.ch - 1, 0), pos.ch + 1)); + } + + // Variable renaming + + function rename(ts, cm) { + var token = cm.getTokenAt(cm.getCursor()); + if (!/\w/.test(token.string)) return showError(ts, cm, "Not at a variable"); + dialog(cm, "New name for " + token.string, function(newName) { + ts.request(cm, {type: "rename", newName: newName, fullDocs: true}, function(error, data) { + if (error) return showError(ts, cm, error); + applyChanges(ts, data.changes); + }); + }); + } + + function selectName(ts, cm) { + var name = findDoc(ts, cm.doc).name; + ts.request(cm, {type: "refs"}, function(error, data) { + if (error) return showError(ts, cm, error); + var ranges = [], cur = 0; + for (var i = 0; i < data.refs.length; i++) { + var ref = data.refs[i]; + if (ref.file == name) { + ranges.push({anchor: ref.start, head: ref.end}); + if (cmpPos(cur, ref.start) >= 0 && cmpPos(cur, ref.end) <= 0) + cur = ranges.length - 1; + } + } + cm.setSelections(ranges, cur); + }); + } + + var nextChangeOrig = 0; + function applyChanges(ts, changes) { + var perFile = Object.create(null); + for (var i = 0; i < changes.length; ++i) { + var ch = changes[i]; + (perFile[ch.file] || (perFile[ch.file] = [])).push(ch); + } + for (var file in perFile) { + var known = ts.docs[file], chs = perFile[file];; + if (!known) continue; + chs.sort(function(a, b) { return cmpPos(b.start, a.start); }); + var origin = "*rename" + (++nextChangeOrig); + for (var i = 0; i < chs.length; ++i) { + var ch = chs[i]; + known.doc.replaceRange(ch.text, ch.start, ch.end, origin); + } + } + } + + // Generic request-building helper + + function buildRequest(ts, doc, query, pos) { + var files = [], offsetLines = 0, allowFragments = !query.fullDocs; + if (!allowFragments) delete query.fullDocs; + if (typeof query == "string") query = {type: query}; + query.lineCharPositions = true; + if (query.end == null) { + query.end = pos || doc.doc.getCursor("end"); + if (doc.doc.somethingSelected()) + query.start = doc.doc.getCursor("start"); + } + var startPos = query.start || query.end; + + if (doc.changed) { + if (doc.doc.lineCount() > bigDoc && allowFragments !== false && + doc.changed.to - doc.changed.from < 100 && + doc.changed.from <= startPos.line && doc.changed.to > query.end.line) { + files.push(getFragmentAround(doc, startPos, query.end)); + query.file = "#0"; + var offsetLines = files[0].offsetLines; + if (query.start != null) query.start = Pos(query.start.line - -offsetLines, query.start.ch); + query.end = Pos(query.end.line - offsetLines, query.end.ch); + } else { + files.push({type: "full", + name: doc.name, + text: docValue(ts, doc)}); + query.file = doc.name; + doc.changed = null; + } + } else { + query.file = doc.name; + } + for (var name in ts.docs) { + var cur = ts.docs[name]; + if (cur.changed && cur != doc) { + files.push({type: "full", name: cur.name, text: docValue(ts, cur)}); + cur.changed = null; + } + } + + return {query: query, files: files}; + } + + function getFragmentAround(data, start, end) { + var doc = data.doc; + var minIndent = null, minLine = null, endLine, tabSize = 4; + for (var p = start.line - 1, min = Math.max(0, p - 50); p >= min; --p) { + var line = doc.getLine(p), fn = line.search(/\bfunction\b/); + if (fn < 0) continue; + var indent = CodeMirror.countColumn(line, null, tabSize); + if (minIndent != null && minIndent <= indent) continue; + minIndent = indent; + minLine = p; + } + if (minLine == null) minLine = min; + var max = Math.min(doc.lastLine(), end.line + 20); + if (minIndent == null || minIndent == CodeMirror.countColumn(doc.getLine(start.line), null, tabSize)) + endLine = max; + else for (endLine = end.line + 1; endLine < max; ++endLine) { + var indent = CodeMirror.countColumn(doc.getLine(endLine), null, tabSize); + if (indent <= minIndent) break; + } + var from = Pos(minLine, 0); + + return {type: "part", + name: data.name, + offsetLines: from.line, + text: doc.getRange(from, Pos(endLine, 0))}; + } + + // Generic utilities + + var cmpPos = CodeMirror.cmpPos; + + function elt(tagname, cls /*, ... elts*/) { + var e = document.createElement(tagname); + if (cls) e.className = cls; + for (var i = 2; i < arguments.length; ++i) { + var elt = arguments[i]; + if (typeof elt == "string") elt = document.createTextNode(elt); + e.appendChild(elt); + } + return e; + } + + function dialog(cm, text, f) { + if (cm.openDialog) + cm.openDialog(text + ": ", f); + else + f(prompt(text, "")); + } + + // Tooltips + + function tempTooltip(cm, content) { + if (cm.state.ternTooltip) remove(cm.state.ternTooltip); + var where = cm.cursorCoords(); + var tip = cm.state.ternTooltip = makeTooltip(where.right + 1, where.bottom, content); + function maybeClear() { + old = true; + if (!mouseOnTip) clear(); + } + function clear() { + cm.state.ternTooltip = null; + if (!tip.parentNode) return; + cm.off("cursorActivity", clear); + cm.off('blur', clear); + cm.off('scroll', clear); + fadeOut(tip); + } + var mouseOnTip = false, old = false; + CodeMirror.on(tip, "mousemove", function() { mouseOnTip = true; }); + CodeMirror.on(tip, "mouseout", function(e) { + if (!CodeMirror.contains(tip, e.relatedTarget || e.toElement)) { + if (old) clear(); + else mouseOnTip = false; + } + }); + setTimeout(maybeClear, 1700); + cm.on("cursorActivity", clear); + cm.on('blur', clear); + cm.on('scroll', clear); + } + + function makeTooltip(x, y, content) { + var node = elt("div", cls + "tooltip", content); + node.style.left = x + "px"; + node.style.top = y + "px"; + document.body.appendChild(node); + return node; + } + + function remove(node) { + var p = node && node.parentNode; + if (p) p.removeChild(node); + } + + function fadeOut(tooltip) { + tooltip.style.opacity = "0"; + setTimeout(function() { remove(tooltip); }, 1100); + } + + function showError(ts, cm, msg) { + if (ts.options.showError) + ts.options.showError(cm, msg); + else + tempTooltip(cm, String(msg)); + } + + function closeArgHints(ts) { + if (ts.activeArgHints) { remove(ts.activeArgHints); ts.activeArgHints = null; } + } + + function docValue(ts, doc) { + var val = doc.doc.getValue(); + if (ts.options.fileFilter) val = ts.options.fileFilter(val, doc.name, doc.doc); + return val; + } + + // Worker wrapper + + function WorkerServer(ts) { + var worker = ts.worker = new Worker(ts.options.workerScript); + worker.postMessage({type: "init", + defs: ts.options.defs, + plugins: ts.options.plugins, + scripts: ts.options.workerDeps}); + var msgId = 0, pending = {}; + + function send(data, c) { + if (c) { + data.id = ++msgId; + pending[msgId] = c; + } + worker.postMessage(data); + } + worker.onmessage = function(e) { + var data = e.data; + if (data.type == "getFile") { + getFile(ts, data.name, function(err, text) { + send({type: "getFile", err: String(err), text: text, id: data.id}); + }); + } else if (data.type == "debug") { + window.console.log(data.message); + } else if (data.id && pending[data.id]) { + pending[data.id](data.err, data.body); + delete pending[data.id]; + } + }; + worker.onerror = function(e) { + for (var id in pending) pending[id](e); + pending = {}; + }; + + this.addFile = function(name, text) { send({type: "add", name: name, text: text}); }; + this.delFile = function(name) { send({type: "del", name: name}); }; + this.request = function(body, c) { send({type: "req", body: body}, c); }; + } +}); diff --git a/static/js/mdeditor/lib/codemirror/addon/tern/worker.js b/static/js/mdeditor/lib/codemirror/addon/tern/worker.js new file mode 100644 index 00000000..48277af8 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/tern/worker.js @@ -0,0 +1,44 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// declare global: tern, server + +var server; + +this.onmessage = function(e) { + var data = e.data; + switch (data.type) { + case "init": return startServer(data.defs, data.plugins, data.scripts); + case "add": return server.addFile(data.name, data.text); + case "del": return server.delFile(data.name); + case "req": return server.request(data.body, function(err, reqData) { + postMessage({id: data.id, body: reqData, err: err && String(err)}); + }); + case "getFile": + var c = pending[data.id]; + delete pending[data.id]; + return c(data.err, data.text); + default: throw new Error("Unknown message type: " + data.type); + } +}; + +var nextId = 0, pending = {}; +function getFile(file, c) { + postMessage({type: "getFile", name: file, id: ++nextId}); + pending[nextId] = c; +} + +function startServer(defs, plugins, scripts) { + if (scripts) importScripts.apply(null, scripts); + + server = new tern.Server({ + getFile: getFile, + async: true, + defs: defs, + plugins: plugins + }); +} + +var console = { + log: function(v) { postMessage({type: "debug", message: v}); } +}; diff --git a/static/js/mdeditor/lib/codemirror/addon/wrap/hardwrap.js b/static/js/mdeditor/lib/codemirror/addon/wrap/hardwrap.js new file mode 100644 index 00000000..fe9b4dd6 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addon/wrap/hardwrap.js @@ -0,0 +1,139 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var Pos = CodeMirror.Pos; + + function findParagraph(cm, pos, options) { + var startRE = options.paragraphStart || cm.getHelper(pos, "paragraphStart"); + for (var start = pos.line, first = cm.firstLine(); start > first; --start) { + var line = cm.getLine(start); + if (startRE && startRE.test(line)) break; + if (!/\S/.test(line)) { ++start; break; } + } + var endRE = options.paragraphEnd || cm.getHelper(pos, "paragraphEnd"); + for (var end = pos.line + 1, last = cm.lastLine(); end <= last; ++end) { + var line = cm.getLine(end); + if (endRE && endRE.test(line)) { ++end; break; } + if (!/\S/.test(line)) break; + } + return {from: start, to: end}; + } + + function findBreakPoint(text, column, wrapOn, killTrailingSpace) { + for (var at = column; at > 0; --at) + if (wrapOn.test(text.slice(at - 1, at + 1))) break; + if (at == 0) at = column; + var endOfText = at; + if (killTrailingSpace) + while (text.charAt(endOfText - 1) == " ") --endOfText; + return {from: endOfText, to: at}; + } + + function wrapRange(cm, from, to, options) { + from = cm.clipPos(from); to = cm.clipPos(to); + var column = options.column || 80; + var wrapOn = options.wrapOn || /\s\S|-[^\.\d]/; + var killTrailing = options.killTrailingSpace !== false; + var changes = [], curLine = "", curNo = from.line; + var lines = cm.getRange(from, to, false); + if (!lines.length) return null; + var leadingSpace = lines[0].match(/^[ \t]*/)[0]; + + for (var i = 0; i < lines.length; ++i) { + var text = lines[i], oldLen = curLine.length, spaceInserted = 0; + if (curLine && text && !wrapOn.test(curLine.charAt(curLine.length - 1) + text.charAt(0))) { + curLine += " "; + spaceInserted = 1; + } + var spaceTrimmed = ""; + if (i) { + spaceTrimmed = text.match(/^\s*/)[0]; + text = text.slice(spaceTrimmed.length); + } + curLine += text; + if (i) { + var firstBreak = curLine.length > column && leadingSpace == spaceTrimmed && + findBreakPoint(curLine, column, wrapOn, killTrailing); + // If this isn't broken, or is broken at a different point, remove old break + if (!firstBreak || firstBreak.from != oldLen || firstBreak.to != oldLen + spaceInserted) { + changes.push({text: [spaceInserted ? " " : ""], + from: Pos(curNo, oldLen), + to: Pos(curNo + 1, spaceTrimmed.length)}); + } else { + curLine = leadingSpace + text; + ++curNo; + } + } + while (curLine.length > column) { + var bp = findBreakPoint(curLine, column, wrapOn, killTrailing); + changes.push({text: ["", leadingSpace], + from: Pos(curNo, bp.from), + to: Pos(curNo, bp.to)}); + curLine = leadingSpace + curLine.slice(bp.to); + ++curNo; + } + } + if (changes.length) cm.operation(function() { + for (var i = 0; i < changes.length; ++i) { + var change = changes[i]; + cm.replaceRange(change.text, change.from, change.to); + } + }); + return changes.length ? {from: changes[0].from, to: CodeMirror.changeEnd(changes[changes.length - 1])} : null; + } + + CodeMirror.defineExtension("wrapParagraph", function(pos, options) { + options = options || {}; + if (!pos) pos = this.getCursor(); + var para = findParagraph(this, pos, options); + return wrapRange(this, Pos(para.from, 0), Pos(para.to - 1), options); + }); + + CodeMirror.commands.wrapLines = function(cm) { + cm.operation(function() { + var ranges = cm.listSelections(), at = cm.lastLine() + 1; + for (var i = ranges.length - 1; i >= 0; i--) { + var range = ranges[i], span; + if (range.empty()) { + var para = findParagraph(cm, range.head, {}); + span = {from: Pos(para.from, 0), to: Pos(para.to - 1)}; + } else { + span = {from: range.from(), to: range.to()}; + } + if (span.to.line >= at) continue; + at = span.from.line; + wrapRange(cm, span.from, span.to, {}); + } + }); + }; + + CodeMirror.defineExtension("wrapRange", function(from, to, options) { + return wrapRange(this, from, to, options || {}); + }); + + CodeMirror.defineExtension("wrapParagraphsInRange", function(from, to, options) { + options = options || {}; + var cm = this, paras = []; + for (var line = from.line; line <= to.line;) { + var para = findParagraph(cm, Pos(line, 0), options); + paras.push(para); + line = para.to; + } + var madeChange = false; + if (paras.length) cm.operation(function() { + for (var i = paras.length - 1; i >= 0; --i) + madeChange = madeChange || wrapRange(cm, Pos(paras[i].from, 0), Pos(paras[i].to - 1), options); + }); + return madeChange; + }); +}); diff --git a/static/js/mdeditor/lib/codemirror/addons.min.js b/static/js/mdeditor/lib/codemirror/addons.min.js new file mode 100644 index 00000000..a0980800 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/addons.min.js @@ -0,0 +1,4 @@ +/*! Editor.md v1.5.0 | addons.min.js | Open source online markdown editor. | MIT License | By: Pandao | https://github.com/pandao/editor.md | 2015-06-09 */ +!function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],e):e(CodeMirror)}(function(e){e.defineOption("showTrailingSpace",!1,function(t,i,o){o==e.Init&&(o=!1),o&&!i?t.removeOverlay("trailingspace"):!o&&i&&t.addOverlay({token:function(e){for(var t=e.string.length,i=t;i&&/\s/.test(e.string.charAt(i-1));--i);return i>e.pos?(e.pos=i,null):(e.pos=t,"trailingspace")},name:"trailingspace"})})}),function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],e):e(CodeMirror)}(function(e){function t(e,t,i){var o,r=e.getWrapperElement();return o=r.appendChild(document.createElement("div")),i?o.className="CodeMirror-dialog CodeMirror-dialog-bottom":o.className="CodeMirror-dialog CodeMirror-dialog-top","string"==typeof t?o.innerHTML=t:o.appendChild(t),o}function i(e,t){e.state.currentNotificationClose&&e.state.currentNotificationClose(),e.state.currentNotificationClose=t}e.defineExtension("openDialog",function(o,r,n){function a(e){if("string"==typeof e)h.value=e;else{if(c)return;c=!0,l.parentNode.removeChild(l),d.focus(),n.onClose&&n.onClose(l)}}n||(n={}),i(this,null);var s,l=t(this,o,n.bottom),c=!1,d=this,h=l.getElementsByTagName("input")[0];return h?(n.value&&(h.value=n.value,h.select()),n.onInput&&e.on(h,"input",function(e){n.onInput(e,h.value,a)}),n.onKeyUp&&e.on(h,"keyup",function(e){n.onKeyUp(e,h.value,a)}),e.on(h,"keydown",function(t){n&&n.onKeyDown&&n.onKeyDown(t,h.value,a)||((27==t.keyCode||n.closeOnEnter!==!1&&13==t.keyCode)&&(h.blur(),e.e_stop(t),a()),13==t.keyCode&&r(h.value,t))}),n.closeOnBlur!==!1&&e.on(h,"blur",a),h.focus()):(s=l.getElementsByTagName("button")[0])&&(e.on(s,"click",function(){a(),d.focus()}),n.closeOnBlur!==!1&&e.on(s,"blur",a),s.focus()),a}),e.defineExtension("openConfirm",function(o,r,n){function a(){c||(c=!0,s.parentNode.removeChild(s),d.focus())}i(this,null);var s=t(this,o,n&&n.bottom),l=s.getElementsByTagName("button"),c=!1,d=this,h=1;l[0].focus();for(var u=0;u=h&&a()},200)}),e.on(f,"focus",function(){++h})}}),e.defineExtension("openNotification",function(o,r){function n(){l||(l=!0,clearTimeout(a),s.parentNode.removeChild(s))}i(this,n);var a,s=t(this,o,r&&r.bottom),l=!1,c=r&&"undefined"!=typeof r.duration?r.duration:5e3;return e.on(s,"click",function(t){e.e_preventDefault(t),n()}),c&&(a=setTimeout(n,c)),n})}),function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],e):e(CodeMirror)}(function(e){"use strict";function t(e,t,r,n){if(this.atOccurrence=!1,this.doc=e,null==n&&"string"==typeof t&&(n=!1),r=r?e.clipPos(r):o(0,0),this.pos={from:r,to:r},"string"!=typeof t)t.global||(t=new RegExp(t.source,t.ignoreCase?"ig":"g")),this.matches=function(i,r){if(i){t.lastIndex=0;for(var n,a,s=e.getLine(r.line).slice(0,r.ch),l=0;;){t.lastIndex=l;var c=t.exec(s);if(!c)break;if(n=c,a=n.index,l=n.index+(n[0].length||1),l==s.length)break}var d=n&&n[0].length||0;d||(0==a&&0==s.length?n=void 0:a!=e.getLine(r.line).length&&d++)}else{t.lastIndex=r.ch;var s=e.getLine(r.line),n=t.exec(s),d=n&&n[0].length||0,a=n&&n.index;a+d==s.length||d||(d=1)}return n&&d?{from:o(r.line,a),to:o(r.line,a+d),match:n}:void 0};else{var a=t;n&&(t=t.toLowerCase());var s=n?function(e){return e.toLowerCase()}:function(e){return e},l=t.split("\n");if(1==l.length)t.length?this.matches=function(r,n){if(r){var l=e.getLine(n.line).slice(0,n.ch),c=s(l),d=c.lastIndexOf(t);if(d>-1)return d=i(l,c,d),{from:o(n.line,d),to:o(n.line,d+a.length)}}else{var l=e.getLine(n.line).slice(n.ch),c=s(l),d=c.indexOf(t);if(d>-1)return d=i(l,c,d)+n.ch,{from:o(n.line,d),to:o(n.line,d+a.length)}}}:this.matches=function(){};else{var c=a.split("\n");this.matches=function(t,i){var r=l.length-1;if(t){if(i.line-(l.length-1)=1;--d,--a)if(l[d]!=s(e.getLine(a)))return;var h=e.getLine(a),u=h.length-c[0].length;if(s(h.slice(u))!=l[0])return;return{from:o(a,u),to:n}}if(!(i.line+(l.length-1)>e.lastLine())){var h=e.getLine(i.line),u=h.length-c[0].length;if(s(h.slice(u))==l[0]){for(var f=o(i.line,u),a=i.line+1,d=1;r>d;++d,++a)if(l[d]!=s(e.getLine(a)))return;if(s(e.getLine(a).slice(0,c[r].length))==l[r])return{from:f,to:o(a,c[r].length)}}}}}}}function i(e,t,i){if(e.length==t.length)return i;for(var o=Math.min(i,e.length);;){var r=e.slice(0,o).toLowerCase().length;if(i>r)++o;else{if(!(r>i))return o;--o}}}var o=e.Pos;t.prototype={findNext:function(){return this.find(!1)},findPrevious:function(){return this.find(!0)},find:function(e){function t(e){var t=o(e,0);return i.pos={from:t,to:t},i.atOccurrence=!1,!1}for(var i=this,r=this.doc.clipPos(e?this.pos.from:this.pos.to);;){if(this.pos=this.matches(e,r))return this.atOccurrence=!0,this.pos.match||!0;if(e){if(!r.line)return t(0);r=o(r.line-1,this.doc.getLine(r.line-1).length)}else{var n=this.doc.lineCount();if(r.line==n-1)return t(n);r=o(r.line+1,0)}}},from:function(){return this.atOccurrence?this.pos.from:void 0},to:function(){return this.atOccurrence?this.pos.to:void 0},replace:function(t){if(this.atOccurrence){var i=e.splitLines(t);this.doc.replaceRange(i,this.pos.from,this.pos.to),this.pos.to=o(this.pos.from.line+i.length-1,i[i.length-1].length+(1==i.length?this.pos.from.ch:0))}}},e.defineExtension("getSearchCursor",function(e,i,o){return new t(this.doc,e,i,o)}),e.defineDocExtension("getSearchCursor",function(e,i,o){return new t(this,e,i,o)}),e.defineExtension("selectMatches",function(t,i){for(var o,r=[],n=this.getSearchCursor(t,this.getCursor("from"),i);(o=n.findNext())&&!(e.cmpPos(n.to(),this.getCursor("to"))>0);)r.push({anchor:n.from(),head:n.to()});r.length&&this.setSelections(r,0)})}),function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror"),require("./searchcursor"),require("../dialog/dialog")):"function"==typeof define&&define.amd?define(["../../lib/codemirror","./searchcursor","../dialog/dialog"],e):e(CodeMirror)}(function(e){"use strict";function t(e,t){return"string"==typeof e?e=new RegExp(e.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&"),t?"gi":"g"):e.global||(e=new RegExp(e.source,e.ignoreCase?"gi":"g")),{token:function(t){e.lastIndex=t.pos;var i=e.exec(t.string);return i&&i.index==t.pos?(t.pos+=i[0].length,"searching"):void(i?t.pos=i.index:t.skipToEnd())}}}function i(){this.posFrom=this.posTo=this.query=null,this.overlay=null}function o(e){return e.state.search||(e.state.search=new i)}function r(e){return"string"==typeof e&&e==e.toLowerCase()}function n(e,t,i){return e.getSearchCursor(t,i,r(t))}function a(e,t,i,o,r){e.openDialog?e.openDialog(t,r,{value:o}):r(prompt(i,o))}function s(e,t,i,o){e.openConfirm?e.openConfirm(t,o):confirm(i)&&o[0]()}function l(e){var t=e.match(/^\/(.*)\/([a-z]*)$/);if(t)try{e=new RegExp(t[1],-1==t[2].indexOf("i")?"":"i")}catch(i){}return("string"==typeof e?""==e:e.test(""))&&(e=/x^/),e}function c(e,i){var n=o(e);return n.query?d(e,i):void a(e,f,"Search for:",e.getSelection(),function(o){e.operation(function(){o&&!n.query&&(n.query=l(o),e.removeOverlay(n.overlay,r(n.query)),n.overlay=t(n.query,r(n.query)),e.addOverlay(n.overlay),e.showMatchesOnScrollbar&&(n.annotate&&(n.annotate.clear(),n.annotate=null),n.annotate=e.showMatchesOnScrollbar(n.query,r(n.query))),n.posFrom=n.posTo=e.getCursor(),d(e,i))})})}function d(t,i){t.operation(function(){var r=o(t),a=n(t,r.query,i?r.posFrom:r.posTo);(a.find(i)||(a=n(t,r.query,i?e.Pos(t.lastLine()):e.Pos(t.firstLine(),0)),a.find(i)))&&(t.setSelection(a.from(),a.to()),t.scrollIntoView({from:a.from(),to:a.to()}),r.posFrom=a.from(),r.posTo=a.to())})}function h(e){e.operation(function(){var t=o(e);t.query&&(t.query=null,e.removeOverlay(t.overlay),t.annotate&&(t.annotate.clear(),t.annotate=null))})}function u(e,t){e.getOption("readOnly")||a(e,g,"Replace:",e.getSelection(),function(i){i&&(i=l(i),a(e,p,"Replace with:","",function(o){if(t)e.operation(function(){for(var t=n(e,i);t.findNext();)if("string"!=typeof i){var r=e.getRange(t.from(),t.to()).match(i);t.replace(o.replace(/\$(\d)/g,function(e,t){return r[t]}))}else t.replace(o)});else{h(e);var r=n(e,i,e.getCursor()),a=function(){var t,o=r.from();!(t=r.findNext())&&(r=n(e,i),!(t=r.findNext())||o&&r.from().line==o.line&&r.from().ch==o.ch)||(e.setSelection(r.from(),r.to()),e.scrollIntoView({from:r.from(),to:r.to()}),s(e,m,"Replace?",[function(){l(t)},a]))},l=function(e){r.replace("string"==typeof i?o:o.replace(/\$(\d)/g,function(t,i){return e[i]})),a()};a()}}))})}var f='Search: (Use /re/ syntax for regexp search)',g='Replace: (Use /re/ syntax for regexp search)',p='With: ',m="Replace? ";e.commands.find=function(e){h(e),c(e)},e.commands.findNext=c,e.commands.findPrev=function(e){c(e,!0)},e.commands.clearSearch=h,e.commands.replace=u,e.commands.replaceAll=function(e){u(e,!0)}}),function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],e):e(CodeMirror)}(function(e){"use strict";function t(e,t){function i(e){clearTimeout(o.doRedraw),o.doRedraw=setTimeout(function(){o.redraw()},e)}this.cm=e,this.options=t,this.buttonHeight=t.scrollButtonHeight||e.getOption("scrollButtonHeight"),this.annotations=[],this.doRedraw=this.doUpdate=null,this.div=e.getWrapperElement().appendChild(document.createElement("div")),this.div.style.cssText="position: absolute; right: 0; top: 0; z-index: 7; pointer-events: none",this.computeScale();var o=this;e.on("refresh",this.resizeHandler=function(){clearTimeout(o.doUpdate),o.doUpdate=setTimeout(function(){o.computeScale()&&i(20)},100)}),e.on("markerAdded",this.resizeHandler),e.on("markerCleared",this.resizeHandler),t.listenForChanges!==!1&&e.on("change",this.changeHandler=function(){i(250)})}e.defineExtension("annotateScrollbar",function(e){return"string"==typeof e&&(e={className:e}),new t(this,e)}),e.defineOption("scrollButtonHeight",0),t.prototype.computeScale=function(){var e=this.cm,t=(e.getWrapperElement().clientHeight-e.display.barHeight-2*this.buttonHeight)/e.heightAtLine(e.lastLine()+1,"local");return t!=this.hScale?(this.hScale=t,!0):void 0},t.prototype.update=function(e){this.annotations=e,this.redraw()},t.prototype.redraw=function(e){e!==!1&&this.computeScale();var t=this.cm,i=this.hScale,o=document.createDocumentFragment(),r=this.annotations;if(t.display.barWidth)for(var n,a=0;ac+.9));)s=r[++a],c=t.charCoords(s.to,"local").bottom*i;if(c!=l){var d=Math.max(c-l,3),h=o.appendChild(document.createElement("div"));h.style.cssText="position: absolute; right: 0px; width: "+Math.max(t.display.barWidth-1,2)+"px; top: "+(l+this.buttonHeight)+"px; height: "+d+"px",h.className=this.options.className}}this.div.textContent="",this.div.appendChild(o)},t.prototype.clear=function(){this.cm.off("refresh",this.resizeHandler),this.cm.off("markerAdded",this.resizeHandler),this.cm.off("markerCleared",this.resizeHandler),this.changeHandler&&this.cm.off("change",this.changeHandler),this.div.parentNode.removeChild(this.div)}}),function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror"),require("./searchcursor"),require("../scroll/annotatescrollbar")):"function"==typeof define&&define.amd?define(["../../lib/codemirror","./searchcursor","../scroll/annotatescrollbar"],e):e(CodeMirror)}(function(e){"use strict";function t(e,t,i,o){this.cm=e;var r={listenForChanges:!1};for(var n in o)r[n]=o[n];r.className||(r.className="CodeMirror-search-match"),this.annotation=e.annotateScrollbar(r),this.query=t,this.caseFold=i,this.gap={from:e.firstLine(),to:e.lastLine()+1},this.matches=[],this.update=null,this.findMatches(),this.annotation.update(this.matches);var a=this;e.on("change",this.changeHandler=function(e,t){a.onChange(t)})}function i(e,t,i){return t>=e?e:Math.max(t,e+i)}e.defineExtension("showMatchesOnScrollbar",function(e,i,o){return"string"==typeof o&&(o={className:o}),o||(o={}),new t(this,e,i,o)});var o=1e3;t.prototype.findMatches=function(){if(this.gap){for(var t=0;t=this.gap.to)break;i.to.line>=this.gap.from&&this.matches.splice(t--,1)}for(var r=this.cm.getSearchCursor(this.query,e.Pos(this.gap.from,0),this.caseFold);r.findNext();){var i={from:r.from(),to:r.to()};if(i.from.line>=this.gap.to)break;if(this.matches.splice(t++,0,i),this.matches.length>o)break}this.gap=null}},t.prototype.onChange=function(t){var o=t.from.line,r=e.changeEnd(t).line,n=r-t.to.line;if(this.gap?(this.gap.from=Math.min(i(this.gap.from,o,n),t.from.line),this.gap.to=Math.max(i(this.gap.to,o,n),t.from.line)):this.gap={from:t.from.line,to:r+1},n)for(var a=0;ac.ch&&(v=v.slice(0,v.length-d.end+c.ch));var w=v.toLowerCase();if(!v||"string"==d.type&&(d.end!=c.ch||!/[\"\']/.test(d.string.charAt(d.string.length-1))||1==d.string.length)||"tag"==d.type&&"closeTag"==u.type||d.string.indexOf("/")==d.string.length-1||p&&r(p,w)>-1||n(t,v,c,u,!0))return e.Pass;var b=m&&r(m,w)>-1;o[l]={indent:b,text:">"+(b?"\n\n":"")+"",newPos:b?e.Pos(c.line+1,0):e.Pos(c.line,c.ch+1)}}for(var l=i.length-1;l>=0;l--){var y=o[l];t.replaceRange(y.text,i[l].head,i[l].anchor,"+insert");var k=t.listSelections().slice(0);k[l]={head:y.newPos,anchor:y.newPos},t.setSelections(k),y.indent&&(t.indentLine(y.newPos.line,null,!0),t.indentLine(y.newPos.line+1,null,!0))}}function i(t,i){for(var o=t.listSelections(),r=[],a=i?"/":"";else{if("htmlmixed"!=t.getMode().name||"css"!=d.mode.name)return e.Pass;r[s]=a+"style>"}else{if(!h.context||!h.context.tagName||n(t,h.context.tagName,l,h))return e.Pass;r[s]=a+h.context.tagName+">"}}t.replaceSelections(r),o=t.listSelections();for(var s=0;si;++i)if(e[i]==t)return i;return-1}function n(t,i,o,r,n){if(!e.scanForClosingTag)return!1;var a=Math.min(t.lastLine()+1,o.line+500),s=e.scanForClosingTag(t,o,null,a);if(!s||s.tag!=i)return!1;for(var l=r.context,c=n?1:0;l&&l.tagName==i;l=l.prev)++c;o=s.to;for(var d=1;c>d;d++){var h=e.scanForClosingTag(t,o,null,a);if(!h||h.tag!=i)return!1;o=h.to}return!0}e.defineOption("autoCloseTags",!1,function(i,r,n){if(n!=e.Init&&n&&i.removeKeyMap("autoCloseTags"),r){var a={name:"autoCloseTags"};("object"!=typeof r||r.whenClosing)&&(a["'/'"]=function(e){return o(e)}),("object"!=typeof r||r.whenOpening)&&(a["'>'"]=function(e){return t(e)}),i.addKeyMap(a)}});var a=["area","base","br","col","command","embed","hr","img","input","keygen","link","meta","param","source","track","wbr"],s=["applet","blockquote","body","button","div","dl","fieldset","form","frameset","h1","h2","h3","h4","h5","h6","head","html","iframe","layer","legend","object","ol","p","select","table","ul"];e.commands.closeTag=function(e){return i(e)}}),function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],e):e(CodeMirror)}(function(e){"use strict";function t(t,r,n,a){function s(e){var i=l(t,r);if(!i||i.to.line-i.from.linet.firstLine();)r=e.Pos(r.line-1,0),d=s(!1);if(d&&!d.cleared&&"unfold"!==a){var h=i(t,n);e.on(h,"mousedown",function(t){u.clear(),e.e_preventDefault(t)});var u=t.markText(d.from,d.to,{replacedWith:h,clearOnEnter:!0,__isFold:!0});u.on("clear",function(i,o){e.signal(t,"unfold",t,i,o)}),e.signal(t,"fold",t,d.from,d.to)}}function i(e,t){var i=o(e,t,"widget");if("string"==typeof i){var r=document.createTextNode(i);i=document.createElement("span"),i.appendChild(r),i.className="CodeMirror-foldmarker"}return i}function o(e,t,i){if(t&&void 0!==t[i])return t[i];var o=e.options.foldOptions;return o&&void 0!==o[i]?o[i]:r[i]}e.newFoldFunction=function(e,i){return function(o,r){t(o,r,{rangeFinder:e,widget:i})}},e.defineExtension("foldCode",function(e,i,o){t(this,e,i,o)}),e.defineExtension("isFolded",function(e){for(var t=this.findMarksAt(e),i=0;i=i;i++)t.foldCode(e.Pos(i,0),null,"fold")})},e.commands.unfoldAll=function(t){t.operation(function(){for(var i=t.firstLine(),o=t.lastLine();o>=i;i++)t.foldCode(e.Pos(i,0),null,"unfold")})},e.registerHelper("fold","combine",function(){var e=Array.prototype.slice.call(arguments,0);return function(t,i){for(var o=0;o=s&&(i=r(n.indicatorOpen))}e.setGutterMarker(t,n.gutter,i),++a})}function a(e){var t=e.getViewport(),i=e.state.foldGutter;i&&(e.operation(function(){n(e,t.from,t.to)}),i.from=t.from,i.to=t.to)}function s(e,t,i){var o=e.state.foldGutter;if(o){var r=o.options;i==r.gutter&&e.foldCode(h(t,0),r.rangeFinder)}}function l(e){var t=e.state.foldGutter;if(t){var i=t.options;t.from=t.to=0,clearTimeout(t.changeUpdate),t.changeUpdate=setTimeout(function(){a(e)},i.foldOnChangeTimeSpan||600)}}function c(e){var t=e.state.foldGutter;if(t){var i=t.options;clearTimeout(t.changeUpdate),t.changeUpdate=setTimeout(function(){var i=e.getViewport();t.from==t.to||i.from-t.to>20||t.from-i.to>20?a(e):e.operation(function(){i.fromt.to&&(n(e,t.to,i.to),t.to=i.to)})},i.updateViewportTimeSpan||400)}}function d(e,t){var i=e.state.foldGutter;if(i){var o=t.line;o>=i.from&&o=l;++l){var d=t.getLine(l),h=n(d);if(h>a)s=l;else if(/\S/.test(d))break}return s?{from:e.Pos(i.line,r.length),to:e.Pos(s,t.getLine(s).length)}:void 0}})}),function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],e):e(CodeMirror)}(function(e){"use strict";e.registerHelper("fold","brace",function(t,i){function o(o){for(var r=i.ch,l=0;;){var c=0>=r?-1:s.lastIndexOf(o,r-1);if(-1!=c){if(1==l&&c=g;++g)for(var p=t.getLine(g),m=g==a?r:0;;){var v=p.indexOf(l,m),w=p.indexOf(c,m);if(0>v&&(v=p.length),0>w&&(w=p.length),m=Math.min(v,w),m==p.length)break;if(t.getTokenTypeAt(e.Pos(g,m+1))==n)if(m==v)++u;else if(!--u){d=g,h=m;break e}++m}if(null!=d&&(a!=d||h!=r))return{from:e.Pos(a,r),to:e.Pos(d,h)}}}),e.registerHelper("fold","import",function(t,i){function o(i){if(it.lastLine())return null;var o=t.getTokenAt(e.Pos(i,1));if(/\S/.test(o.string)||(o=t.getTokenAt(e.Pos(i,o.end+1))),"keyword"!=o.type||"import"!=o.string)return null;for(var r=i,n=Math.min(t.lastLine(),i+10);n>=r;++r){var a=t.getLine(r),s=a.indexOf(";");if(-1!=s)return{startCh:o.end,end:e.Pos(r,s)}}}var r,i=i.line,n=o(i);if(!n||o(i-1)||(r=o(i-2))&&r.end.line==i-1)return null;for(var a=n.end;;){var s=o(a.line+1);if(null==s)break;a=s.end}return{from:t.clipPos(e.Pos(i,n.startCh+1)),to:a}}),e.registerHelper("fold","include",function(t,i){function o(i){if(it.lastLine())return null;var o=t.getTokenAt(e.Pos(i,1));return/\S/.test(o.string)||(o=t.getTokenAt(e.Pos(i,o.end+1))),"meta"==o.type&&"#include"==o.string.slice(0,8)?o.start+8:void 0}var i=i.line,r=o(i);if(null==r||null!=o(i-1))return null;for(var n=i;;){var a=o(n+1);if(null==a)break;++n}return{from:e.Pos(i,r+1),to:t.clipPos(e.Pos(n))}})}),function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],e):e(CodeMirror)}(function(e){"use strict";function t(e,t){return e.line-t.line||e.ch-t.ch}function i(e,t,i,o){this.line=t,this.ch=i,this.cm=e,this.text=e.getLine(t),this.min=o?o.from:e.firstLine(),this.max=o?o.to-1:e.lastLine()}function o(e,t){var i=e.cm.getTokenTypeAt(u(e.line,t));return i&&/\btag\b/.test(i)}function r(e){return e.line>=e.max?void 0:(e.ch=0,e.text=e.cm.getLine(++e.line),!0)}function n(e){return e.line<=e.min?void 0:(e.text=e.cm.getLine(--e.line),e.ch=e.text.length,!0)}function a(e){for(;;){var t=e.text.indexOf(">",e.ch);if(-1==t){if(r(e))continue;return}{if(o(e,t+1)){var i=e.text.lastIndexOf("/",t),n=i>-1&&!/\S/.test(e.text.slice(i+1,t));return e.ch=t+1,n?"selfClose":"regular"}e.ch=t+1}}}function s(e){for(;;){var t=e.ch?e.text.lastIndexOf("<",e.ch-1):-1;if(-1==t){if(n(e))continue;return}if(o(e,t+1)){p.lastIndex=t,e.ch=t;var i=p.exec(e.text);if(i&&i.index==t)return i}else e.ch=t}}function l(e){for(;;){p.lastIndex=e.ch;var t=p.exec(e.text);if(!t){if(r(e))continue;return}{if(o(e,t.index+1))return e.ch=t.index+t[0].length,t;e.ch=t.index+1}}}function c(e){for(;;){var t=e.ch?e.text.lastIndexOf(">",e.ch-1):-1;if(-1==t){if(n(e))continue;return}{if(o(e,t+1)){var i=e.text.lastIndexOf("/",t),r=i>-1&&!/\S/.test(e.text.slice(i+1,t));return e.ch=t+1,r?"selfClose":"regular"}e.ch=t}}}function d(e,t){for(var i=[];;){var o,r=l(e),n=e.line,s=e.ch-(r?r[0].length:0);if(!r||!(o=a(e)))return;if("selfClose"!=o)if(r[1]){for(var c=i.length-1;c>=0;--c)if(i[c]==r[2]){i.length=c;break}if(0>c&&(!t||t==r[2]))return{tag:r[2],from:u(n,s),to:u(e.line,e.ch)}}else i.push(r[2])}}function h(e,t){for(var i=[];;){var o=c(e);if(!o)return;if("selfClose"!=o){var r=e.line,n=e.ch,a=s(e);if(!a)return;if(a[1])i.push(a[2]);else{for(var l=i.length-1;l>=0;--l)if(i[l]==a[2]){i.length=l;break}if(0>l&&(!t||t==a[2]))return{tag:a[2],from:u(e.line,e.ch),to:u(r,n)}}}else s(e)}}var u=e.Pos,f="A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD",g=f+"-:.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040",p=new RegExp("<(/?)(["+f+"]["+g+"]*)","g");e.registerHelper("fold","xml",function(e,t){for(var o=new i(e,t.line,0);;){var r,n=l(o);if(!n||o.line!=t.line||!(r=a(o)))return;if(!n[1]&&"selfClose"!=r){var t=u(o.line,o.ch),s=d(o,n[2]);return s&&{from:t,to:s.from}}}}),e.findMatchingTag=function(e,o,r){var n=new i(e,o.line,o.ch,r);if(-1!=n.text.indexOf(">")||-1!=n.text.indexOf("<")){var l=a(n),c=l&&u(n.line,n.ch),f=l&&s(n);if(l&&f&&!(t(n,o)>0)){var g={from:u(n.line,n.ch),to:c,tag:f[2]};return"selfClose"==l?{open:g,close:null,at:"open"}:f[1]?{open:h(n,f[2]),close:g,at:"close"}:(n=new i(e,c.line,c.ch,r),{open:g,close:d(n,f[2]),at:"open"})}}},e.findEnclosingTag=function(e,t,o){for(var r=new i(e,t.line,t.ch,o);;){var n=h(r);if(!n)break;var a=new i(e,t.line,t.ch,o),s=d(a,n.tag);if(s)return{open:n,close:s}}},e.scanForClosingTag=function(e,t,o,r){var n=new i(e,t.line,t.ch,r?{from:0,to:r}:null);return d(n,o)}}),function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],e):e(CodeMirror)}(function(e){"use strict";e.registerHelper("fold","markdown",function(t,i){function o(i){var o=t.getTokenTypeAt(e.Pos(i,0));return o&&/\bheader\b/.test(o)}function r(e,t,i){var r=t&&t.match(/^#+/);return r&&o(e)?r[0].length:(r=i&&i.match(/^[=\-]+\s*$/),r&&o(e+1)?"="==i[0]?1:2:n)}var n=100,a=t.getLine(i.line),s=t.getLine(i.line+1),l=r(i.line,a,s);if(l===n)return void 0;for(var c=t.lastLine(),d=i.line,h=t.getLine(d+2);c>d&&!(r(d+1,s,h)<=l);)++d,s=h,h=t.getLine(d+2);return{from:e.Pos(i.line,a.length),to:e.Pos(d,t.getLine(d).length)}})}),function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],e):e(CodeMirror)}(function(e){"use strict";e.registerGlobalHelper("fold","comment",function(e){return e.blockCommentStart&&e.blockCommentEnd},function(t,i){var o=t.getModeAt(i),r=o.blockCommentStart,n=o.blockCommentEnd;if(r&&n){for(var a,s=i.line,l=t.getLine(s),c=i.ch,d=0;;){var h=0>=c?-1:l.lastIndexOf(r,c-1);if(-1!=h){if(1==d&&h=m;++m)for(var v=t.getLine(m),w=m==s?a:0;;){var b=v.indexOf(r,w),y=v.indexOf(n,w);if(0>b&&(b=v.length),0>y&&(y=v.length),w=Math.min(b,y),w==v.length)break;if(w==b)++g;else if(!--g){u=m,f=w;break e}++w}if(null!=u&&(s!=u||f!=a))return{from:e.Pos(s,a),to:e.Pos(u,f)}}})}),function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],e):e(CodeMirror)}(function(e){"use strict";e.overlayMode=function(t,i,o){return{startState:function(){return{base:e.startState(t),overlay:e.startState(i),basePos:0,baseCur:null,overlayPos:0,overlayCur:null,streamSeen:null}},copyState:function(o){return{base:e.copyState(t,o.base),overlay:e.copyState(i,o.overlay),basePos:o.basePos,baseCur:null,overlayPos:o.overlayPos,overlayCur:null}},token:function(e,r){return(e!=r.streamSeen||Math.min(r.basePos,r.overlayPos)=i.ch+1)return/\bstring2?\b/.test(s);a.start=a.pos}}function o(o,r){for(var n={name:"autoCloseBrackets",Backspace:function(i){if(i.getOption("disableInput"))return e.Pass;for(var r=i.listSelections(),n=0;n=0;n--){var s=r[n].head;i.replaceRange("",c(s.line,s.ch-1),c(s.line,s.ch+1))}}},a="",s=0;s1&&r.indexOf(t)>=0&&n.getRange(c(p.line,p.ch-2),p)==t+t&&(p.ch<=2||n.getRange(c(p.line,p.ch-3),c(p.line,p.ch-2))!=t))f="addFour";else if('"'==t||"'"==t){if(e.isWordChar(d)||!i(n,p,t))return e.Pass;f="both"}else{if(!(n.getLine(p.line).length==p.ch||a.indexOf(d)>=0||l.test(d)))return e.Pass;f="both"}else f="surround";if(s){if(s!=f)return e.Pass}else s=f}n.operation(function(){if("skip"==s)n.execCommand("goCharRight");else if("skipThree"==s)for(var e=0;3>e;e++)n.execCommand("goCharRight");else if("surround"==s){for(var i=n.getSelections(),e=0;es&&e.addOverlay(t.overlay=a(n.slice(s,l),i,t.style)))}var c=e.getCursor("from"),d=e.getCursor("to");if(c.line==d.line&&(!t.wordsOnly||r(e,c,d))){var h=e.getRange(c,d).replace(/^\s+|\s+$/g,"");h.length>=t.minChars&&e.addOverlay(t.overlay=a(h,!1,t.style))}})}function r(e,t,i){var o=e.getRange(t,i);if(null!==o.match(/^\w+$/)){if(t.ch>0){var r={line:t.line,ch:t.ch-1},n=e.getRange(r,t);if(null===n.match(/\W/))return!1}if(i.ch=15){presto=false;webkit=true}var flipCtrlCmd=mac&&(qtwebkit||presto&&(presto_version==null||presto_version<12.11));var captureRightClick=gecko||(ie&&ie_version>=9);var sawReadOnlySpans=false,sawCollapsedSpans=false;function CodeMirror(place,options){if(!(this instanceof CodeMirror)){return new CodeMirror(place,options)}this.options=options=options?copyObj(options):{};copyObj(defaults,options,false);setGuttersForLineNumbers(options);var doc=options.value;if(typeof doc=="string"){doc=new Doc(doc,options.mode)}this.doc=doc;var input=new CodeMirror.inputStyles[options.inputStyle](this);var display=this.display=new Display(place,doc,input);display.wrapper.CodeMirror=this;updateGutters(this);themeChanged(this);if(options.lineWrapping){this.display.wrapper.className+=" CodeMirror-wrap"}if(options.autofocus&&!mobile){display.input.focus()}initScrollbars(this);this.state={keyMaps:[],overlays:[],modeGen:0,overwrite:false,focused:false,suppressEdits:false,pasteIncoming:false,cutIncoming:false,draggingText:false,highlight:new Delayed(),keySeq:null};var cm=this;if(ie&&ie_version<11){setTimeout(function(){cm.display.input.reset(true)},20)}registerEventHandlers(this);ensureGlobalHandlers();startOperation(this);this.curOp.forceUpdate=true;attachDoc(this,doc);if((options.autofocus&&!mobile)||cm.hasFocus()){setTimeout(bind(onFocus,this),20)}else{onBlur(this)}for(var opt in optionHandlers){if(optionHandlers.hasOwnProperty(opt)){optionHandlers[opt](this,options[opt],Init)}}maybeUpdateLineNumberWidth(this);if(options.finishInit){options.finishInit(this)}for(var i=0;id.maxLineLength){d.maxLineLength=len;d.maxLine=line}})}function setGuttersForLineNumbers(options){var found=indexOf(options.gutters,"CodeMirror-linenumbers");if(found==-1&&options.lineNumbers){options.gutters=options.gutters.concat(["CodeMirror-linenumbers"])}else{if(found>-1&&!options.lineNumbers){options.gutters=options.gutters.slice(0);options.gutters.splice(found,1)}}}function measureForScrollbars(cm){var d=cm.display,gutterW=d.gutters.offsetWidth;var docH=Math.round(cm.doc.height+paddingVert(cm.display));return{clientHeight:d.scroller.clientHeight,viewHeight:d.wrapper.clientHeight,scrollWidth:d.scroller.scrollWidth,clientWidth:d.scroller.clientWidth,viewWidth:d.wrapper.clientWidth,barLeft:cm.options.fixedGutter?gutterW:0,docHeight:docH,scrollHeight:docH+scrollGap(cm)+d.barHeight,nativeBarWidth:d.nativeBarWidth,gutterWidth:gutterW}}function NativeScrollbars(place,scroll,cm){this.cm=cm;var vert=this.vert=elt("div",[elt("div",null,null,"min-width: 1px")],"CodeMirror-vscrollbar");var horiz=this.horiz=elt("div",[elt("div",null,null,"height: 100%; min-height: 1px")],"CodeMirror-hscrollbar");place(vert);place(horiz);on(vert,"scroll",function(){if(vert.clientHeight){scroll(vert.scrollTop,"vertical")}});on(horiz,"scroll",function(){if(horiz.clientWidth){scroll(horiz.scrollLeft,"horizontal")}});this.checkedOverlay=false;if(ie&&ie_version<8){this.horiz.style.minHeight=this.vert.style.minWidth="18px"}}NativeScrollbars.prototype=copyObj({update:function(measure){var needsH=measure.scrollWidth>measure.clientWidth+1;var needsV=measure.scrollHeight>measure.clientHeight+1;var sWidth=measure.nativeBarWidth;if(needsV){this.vert.style.display="block";this.vert.style.bottom=needsH?sWidth+"px":"0";var totalHeight=measure.viewHeight-(needsH?sWidth:0);this.vert.firstChild.style.height=Math.max(0,measure.scrollHeight-measure.clientHeight+totalHeight)+"px" +}else{this.vert.style.display="";this.vert.firstChild.style.height="0"}if(needsH){this.horiz.style.display="block";this.horiz.style.right=needsV?sWidth+"px":"0";this.horiz.style.left=measure.barLeft+"px";var totalWidth=measure.viewWidth-measure.barLeft-(needsV?sWidth:0);this.horiz.firstChild.style.width=(measure.scrollWidth-measure.clientWidth+totalWidth)+"px"}else{this.horiz.style.display="";this.horiz.firstChild.style.width="0"}if(!this.checkedOverlay&&measure.clientHeight>0){if(sWidth==0){this.overlayHack()}this.checkedOverlay=true}return{right:needsV?sWidth:0,bottom:needsH?sWidth:0}},setScrollLeft:function(pos){if(this.horiz.scrollLeft!=pos){this.horiz.scrollLeft=pos}},setScrollTop:function(pos){if(this.vert.scrollTop!=pos){this.vert.scrollTop=pos}},overlayHack:function(){var w=mac&&!mac_geMountainLion?"12px":"18px";this.horiz.style.minHeight=this.vert.style.minWidth=w;var self=this;var barMouseDown=function(e){if(e_target(e)!=self.vert&&e_target(e)!=self.horiz){operation(self.cm,onMouseDown)(e)}};on(this.vert,"mousedown",barMouseDown);on(this.horiz,"mousedown",barMouseDown)},clear:function(){var parent=this.horiz.parentNode;parent.removeChild(this.horiz);parent.removeChild(this.vert)}},NativeScrollbars.prototype);function NullScrollbars(){}NullScrollbars.prototype=copyObj({update:function(){return{bottom:0,right:0}},setScrollLeft:function(){},setScrollTop:function(){},clear:function(){}},NullScrollbars.prototype);CodeMirror.scrollbarModel={"native":NativeScrollbars,"null":NullScrollbars};function initScrollbars(cm){if(cm.display.scrollbars){cm.display.scrollbars.clear();if(cm.display.scrollbars.addClass){rmClass(cm.display.wrapper,cm.display.scrollbars.addClass)}}cm.display.scrollbars=new CodeMirror.scrollbarModel[cm.options.scrollbarStyle](function(node){cm.display.wrapper.insertBefore(node,cm.display.scrollbarFiller);on(node,"mousedown",function(){if(cm.state.focused){setTimeout(function(){cm.display.input.focus()},0)}});node.setAttribute("cm-not-content","true")},function(pos,axis){if(axis=="horizontal"){setScrollLeft(cm,pos)}else{setScrollTop(cm,pos)}},cm);if(cm.display.scrollbars.addClass){addClass(cm.display.wrapper,cm.display.scrollbars.addClass)}}function updateScrollbars(cm,measure){if(!measure){measure=measureForScrollbars(cm)}var startWidth=cm.display.barWidth,startHeight=cm.display.barHeight;updateScrollbarsInner(cm,measure);for(var i=0;i<4&&startWidth!=cm.display.barWidth||startHeight!=cm.display.barHeight;i++){if(startWidth!=cm.display.barWidth&&cm.options.lineWrapping){updateHeightsInViewport(cm)}updateScrollbarsInner(cm,measureForScrollbars(cm));startWidth=cm.display.barWidth;startHeight=cm.display.barHeight}}function updateScrollbarsInner(cm,measure){var d=cm.display;var sizes=d.scrollbars.update(measure);d.sizer.style.paddingRight=(d.barWidth=sizes.right)+"px";d.sizer.style.paddingBottom=(d.barHeight=sizes.bottom)+"px";if(sizes.right&&sizes.bottom){d.scrollbarFiller.style.display="block";d.scrollbarFiller.style.height=sizes.bottom+"px";d.scrollbarFiller.style.width=sizes.right+"px"}else{d.scrollbarFiller.style.display=""}if(sizes.bottom&&cm.options.coverGutterNextToScrollbar&&cm.options.fixedGutter){d.gutterFiller.style.display="block";d.gutterFiller.style.height=sizes.bottom+"px";d.gutterFiller.style.width=measure.gutterWidth+"px"}else{d.gutterFiller.style.display=""}}function visibleLines(display,doc,viewport){var top=viewport&&viewport.top!=null?Math.max(0,viewport.top):display.scroller.scrollTop;top=Math.floor(top-paddingTop(display));var bottom=viewport&&viewport.bottom!=null?viewport.bottom:top+display.wrapper.clientHeight;var from=lineAtHeight(doc,top),to=lineAtHeight(doc,bottom);if(viewport&&viewport.ensure){var ensureFrom=viewport.ensure.from.line,ensureTo=viewport.ensure.to.line;if(ensureFrom=to){from=lineAtHeight(doc,heightAtLine(getLine(doc,ensureTo))-display.wrapper.clientHeight);to=ensureTo}}}return{from:from,to:Math.max(to,from+1)}}function alignHorizontally(cm){var display=cm.display,view=display.view;if(!display.alignWidgets&&(!display.gutters.firstChild||!cm.options.fixedGutter)){return}var comp=compensateForHScroll(display)-display.scroller.scrollLeft+cm.doc.scrollLeft;var gutterW=display.gutters.offsetWidth,left=comp+"px";for(var i=0;i=display.viewFrom&&update.visible.to<=display.viewTo&&(display.updateLineNumbers==null||display.updateLineNumbers>=display.viewTo)&&display.renderedView==display.view&&countDirtyView(cm)==0){return false}if(maybeUpdateLineNumberWidth(cm)){resetView(cm);update.dims=getDimensions(cm)}var end=doc.first+doc.size;var from=Math.max(update.visible.from-cm.options.viewportMargin,doc.first);var to=Math.min(end,update.visible.to+cm.options.viewportMargin);if(display.viewFromto&&display.viewTo-to<20){to=Math.min(end,display.viewTo)}if(sawCollapsedSpans){from=visualLineNo(cm.doc,from);to=visualLineEndNo(cm.doc,to)}var different=from!=display.viewFrom||to!=display.viewTo||display.lastWrapHeight!=update.wrapperHeight||display.lastWrapWidth!=update.wrapperWidth;adjustView(cm,from,to);display.viewOffset=heightAtLine(getLine(cm.doc,display.viewFrom));cm.display.mover.style.top=display.viewOffset+"px";var toUpdate=countDirtyView(cm);if(!different&&toUpdate==0&&!update.force&&display.renderedView==display.view&&(display.updateLineNumbers==null||display.updateLineNumbers>=display.viewTo)){return false}var focused=activeElt();if(toUpdate>4){display.lineDiv.style.display="none"}patchDisplay(cm,display.updateLineNumbers,update.dims);if(toUpdate>4){display.lineDiv.style.display=""}display.renderedView=display.view;if(focused&&activeElt()!=focused&&focused.offsetHeight){focused.focus()}removeChildren(display.cursorDiv);removeChildren(display.selectionDiv);display.gutters.style.height=0;if(different){display.lastWrapHeight=update.wrapperHeight;display.lastWrapWidth=update.wrapperWidth;startWorker(cm,400)}display.updateLineNumbers=null;return true}function postUpdateDisplay(cm,update){var force=update.force,viewport=update.viewport;for(var first=true;;first=false){if(first&&cm.options.lineWrapping&&update.oldDisplayWidth!=displayWidth(cm)){force=true}else{force=false;if(viewport&&viewport.top!=null){viewport={top:Math.min(cm.doc.height+paddingVert(cm.display)-displayHeight(cm),viewport.top)}}update.visible=visibleLines(cm.display,cm.doc,viewport);if(update.visible.from>=cm.display.viewFrom&&update.visible.to<=cm.display.viewTo){break}}if(!updateDisplayIfNeeded(cm,update)){break}updateHeightsInViewport(cm);var barMeasure=measureForScrollbars(cm);updateSelection(cm);setDocumentHeight(cm,barMeasure);updateScrollbars(cm,barMeasure)}update.signal(cm,"update",cm);if(cm.display.viewFrom!=cm.display.reportedViewFrom||cm.display.viewTo!=cm.display.reportedViewTo){update.signal(cm,"viewportChange",cm,cm.display.viewFrom,cm.display.viewTo);cm.display.reportedViewFrom=cm.display.viewFrom;cm.display.reportedViewTo=cm.display.viewTo}}function updateDisplaySimple(cm,viewport){var update=new DisplayUpdate(cm,viewport);if(updateDisplayIfNeeded(cm,update)){updateHeightsInViewport(cm);postUpdateDisplay(cm,update);var barMeasure=measureForScrollbars(cm);updateSelection(cm);setDocumentHeight(cm,barMeasure);updateScrollbars(cm,barMeasure);update.finish()}}function setDocumentHeight(cm,measure){cm.display.sizer.style.minHeight=measure.docHeight+"px";var total=measure.docHeight+cm.display.barHeight; +cm.display.heightForcer.style.top=total+"px";cm.display.gutters.style.height=Math.max(total+scrollGap(cm),measure.clientHeight)+"px"}function updateHeightsInViewport(cm){var display=cm.display;var prevBottom=display.lineDiv.offsetTop;for(var i=0;i0.001||diff<-0.001){updateLineHeight(cur.line,height);updateWidgetHeight(cur.line);if(cur.rest){for(var j=0;j-1){updateNumber=false}updateLineForChanges(cm,lineView,lineN,dims)}if(updateNumber){removeChildren(lineView.lineNumber);lineView.lineNumber.appendChild(document.createTextNode(lineNumberFor(cm.options,lineN)))}cur=lineView.node.nextSibling}}lineN+=lineView.size}while(cur){cur=rm(cur)}}function updateLineForChanges(cm,lineView,lineN,dims){for(var j=0;j1){if(lastCopied&&lastCopied.join("\n")==inserted){multiPaste=sel.ranges.length%lastCopied.length==0&&map(lastCopied,splitLines)}else{if(textLines.length==sel.ranges.length){multiPaste=map(textLines,function(l){return[l]})}}}for(var i=sel.ranges.length-1;i>=0;i--){var range=sel.ranges[i];var from=range.from(),to=range.to();if(range.empty()){if(deleted&&deleted>0){from=Pos(from.line,from.ch-deleted)}else{if(cm.state.overwrite&&!cm.state.pasteIncoming){to=Pos(to.line,Math.min(getLine(doc,to.line).text.length,to.ch+lst(textLines).length))}}}var updateInput=cm.curOp.updateInput;var changeEvent={from:from,to:to,text:multiPaste?multiPaste[i%multiPaste.length]:textLines,origin:cm.state.pasteIncoming?"paste":cm.state.cutIncoming?"cut":"+input"};makeChange(cm.doc,changeEvent);signalLater(cm,"inputRead",cm,changeEvent);if(inserted&&!cm.state.pasteIncoming&&cm.options.electricChars&&cm.options.smartIndent&&range.head.ch<100&&(!i||sel.ranges[i-1].head.line!=range.head.line)){var mode=cm.getModeAt(range.head);var end=changeEnd(changeEvent);if(mode.electricChars){for(var j=0;j-1){indentLine(cm,end.line,"smart");break}}}else{if(mode.electricInput){if(mode.electricInput.test(getLine(doc,end.line).text.slice(0,end.ch))){indentLine(cm,end.line,"smart")}}}}}ensureCursorVisible(cm);cm.curOp.updateInput=updateInput;cm.curOp.typing=true;cm.state.pasteIncoming=cm.state.cutIncoming=false}function copyableRanges(cm){var text=[],ranges=[];for(var i=0;i=9&&input.hasSelection){input.hasSelection=null}input.poll()});on(te,"paste",function(){if(webkit&&!cm.state.fakedLastChar&&!(new Date-cm.state.lastMiddleDown<200)){var start=te.selectionStart,end=te.selectionEnd;te.value+="$";te.selectionEnd=end;te.selectionStart=start;cm.state.fakedLastChar=true}cm.state.pasteIncoming=true;input.fastPoll()});function prepareCopyCut(e){if(cm.somethingSelected()){lastCopied=cm.getSelections();if(input.inaccurateSelection){input.prevInput="";input.inaccurateSelection=false;te.value=lastCopied.join("\n");selectInput(te)}}else{var ranges=copyableRanges(cm);lastCopied=ranges.text;if(e.type=="cut"){cm.setSelections(ranges.ranges,null,sel_dontScroll)}else{input.prevInput="";te.value=ranges.text.join("\n");selectInput(te)}}if(e.type=="cut"){cm.state.cutIncoming=true}}on(te,"cut",prepareCopyCut);on(te,"copy",prepareCopyCut);on(display.scroller,"paste",function(e){if(eventInWidget(display,e)){return}cm.state.pasteIncoming=true;input.focus()});on(display.lineSpace,"selectstart",function(e){if(!eventInWidget(display,e)){e_preventDefault(e)}})},prepareSelection:function(){var cm=this.cm,display=cm.display,doc=cm.doc;var result=prepareSelection(cm);if(cm.options.moveInputWithCursor){var headPos=cursorCoords(cm,doc.sel.primary().head,"div");var wrapOff=display.wrapper.getBoundingClientRect(),lineOff=display.lineDiv.getBoundingClientRect();result.teTop=Math.max(0,Math.min(display.wrapper.clientHeight-10,headPos.top+lineOff.top-wrapOff.top));result.teLeft=Math.max(0,Math.min(display.wrapper.clientWidth-10,headPos.left+lineOff.left-wrapOff.left))}return result},showSelection:function(drawn){var cm=this.cm,display=cm.display;removeChildrenAndAdd(display.cursorDiv,drawn.cursors);removeChildrenAndAdd(display.selectionDiv,drawn.selection);if(drawn.teTop!=null){this.wrapper.style.top=drawn.teTop+"px";this.wrapper.style.left=drawn.teLeft+"px"}},reset:function(typing){if(this.contextMenuPending){return}var minimal,selected,cm=this.cm,doc=cm.doc;if(cm.somethingSelected()){this.prevInput="";var range=doc.sel.primary();minimal=hasCopyEvent&&(range.to().line-range.from().line>100||(selected=cm.getSelection()).length>1000);var content=minimal?"-":selected||cm.getSelection();this.textarea.value=content;if(cm.state.focused){selectInput(this.textarea)}if(ie&&ie_version>=9){this.hasSelection=content}}else{if(!typing){this.prevInput=this.textarea.value="";if(ie&&ie_version>=9){this.hasSelection=null}}}this.inaccurateSelection=minimal},getField:function(){return this.textarea},supportsTouch:function(){return false},focus:function(){if(this.cm.options.readOnly!="nocursor"&&(!mobile||activeElt()!=this.textarea)){try{this.textarea.focus()}catch(e){}}},blur:function(){this.textarea.blur()},resetPosition:function(){this.wrapper.style.top=this.wrapper.style.left=0},receivedFocus:function(){this.slowPoll()},slowPoll:function(){var input=this;if(input.pollingFast){return}input.polling.set(this.cm.options.pollInterval,function(){input.poll();if(input.cm.state.focused){input.slowPoll()}})},fastPoll:function(){var missed=false,input=this;input.pollingFast=true;function p(){var changed=input.poll();if(!changed&&!missed){missed=true;input.polling.set(60,p)}else{input.pollingFast=false;input.slowPoll()}}input.polling.set(20,p)},poll:function(){var cm=this.cm,input=this.textarea,prevInput=this.prevInput;if(!cm.state.focused||(hasSelection(input)&&!prevInput)||isReadOnly(cm)||cm.options.disableInput||cm.state.keySeq){return false}if(cm.state.pasteIncoming&&cm.state.fakedLastChar){input.value=input.value.substring(0,input.value.length-1);cm.state.fakedLastChar=false}var text=input.value;if(text==prevInput&&!cm.somethingSelected()){return false}if(ie&&ie_version>=9&&this.hasSelection===text||mac&&/[\uf700-\uf7ff]/.test(text)){cm.display.input.reset();return false}if(text.charCodeAt(0)==8203&&cm.doc.sel==cm.display.selForContextMenu&&!prevInput){prevInput="\u200b" +}var same=0,l=Math.min(prevInput.length,text.length);while(same1000||text.indexOf("\n")>-1){input.value=self.prevInput=""}else{self.prevInput=text}});return true},ensurePolled:function(){if(this.pollingFast&&this.poll()){this.pollingFast=false}},onKeyPress:function(){if(ie&&ie_version>=9){this.hasSelection=null}this.fastPoll()},onContextMenu:function(e){var input=this,cm=input.cm,display=cm.display,te=input.textarea;var pos=posFromMouse(cm,e),scrollPos=display.scroller.scrollTop;if(!pos||presto){return}var reset=cm.options.resetSelectionOnContextMenu;if(reset&&cm.doc.sel.contains(pos)==-1){operation(cm,setSelection)(cm.doc,simpleSelection(pos),sel_dontScroll)}var oldCSS=te.style.cssText;input.wrapper.style.position="absolute";te.style.cssText="position: fixed; width: 30px; height: 30px; top: "+(e.clientY-5)+"px; left: "+(e.clientX-5)+"px; z-index: 1000; background: "+(ie?"rgba(255, 255, 255, .05)":"transparent")+"; outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);";if(webkit){var oldScrollY=window.scrollY}display.input.focus();if(webkit){window.scrollTo(null,oldScrollY)}display.input.reset();if(!cm.somethingSelected()){te.value=input.prevInput=" "}input.contextMenuPending=true;display.selForContextMenu=cm.doc.sel;clearTimeout(display.detectingSelectAll);function prepareSelectAllHack(){if(te.selectionStart!=null){var selected=cm.somethingSelected();var extval=te.value="\u200b"+(selected?te.value:"");input.prevInput=selected?"":"\u200b";te.selectionStart=1;te.selectionEnd=extval.length;display.selForContextMenu=cm.doc.sel}}function rehide(){input.contextMenuPending=false;input.wrapper.style.position="relative";te.style.cssText=oldCSS;if(ie&&ie_version<9){display.scrollbars.setScrollTop(display.scroller.scrollTop=scrollPos)}if(te.selectionStart!=null){if(!ie||(ie&&ie_version<9)){prepareSelectAllHack()}var i=0,poll=function(){if(display.selForContextMenu==cm.doc.sel&&te.selectionStart==0){operation(cm,commands.selectAll)(cm)}else{if(i++<10){display.detectingSelectAll=setTimeout(poll,500)}else{display.input.reset()}}};display.detectingSelectAll=setTimeout(poll,200)}}if(ie&&ie_version>=9){prepareSelectAllHack()}if(captureRightClick){e_stop(e);var mouseup=function(){off(window,"mouseup",mouseup);setTimeout(rehide,20)};on(window,"mouseup",mouseup)}else{setTimeout(rehide,50)}},setUneditable:nothing,needsContentAttribute:false},TextareaInput.prototype);function ContentEditableInput(cm){this.cm=cm;this.lastAnchorNode=this.lastAnchorOffset=this.lastFocusNode=this.lastFocusOffset=null;this.polling=new Delayed()}ContentEditableInput.prototype=copyObj({init:function(display){var input=this,cm=input.cm;var div=input.div=display.lineDiv;div.contentEditable="true";disableBrowserMagic(div);on(div,"paste",function(e){var pasted=e.clipboardData&&e.clipboardData.getData("text/plain");if(pasted){e.preventDefault();cm.replaceSelection(pasted,null,"paste")}});on(div,"compositionstart",function(e){var data=e.data;input.composing={sel:cm.doc.sel,data:data,startData:data};if(!data){return}var prim=cm.doc.sel.primary();var line=cm.getLine(prim.head.line);var found=line.indexOf(data,Math.max(0,prim.head.ch-data.length));if(found>-1&&found<=prim.head.ch){input.composing.sel=simpleSelection(Pos(prim.head.line,found),Pos(prim.head.line,found+data.length))}});on(div,"compositionupdate",function(e){input.composing.data=e.data});on(div,"compositionend",function(e){var ours=input.composing;if(!ours){return}if(e.data!=ours.startData&&!/\u200b/.test(e.data)){ours.data=e.data}setTimeout(function(){if(!ours.handled){input.applyComposition(ours)}if(input.composing==ours){input.composing=null}},50)});on(div,"touchstart",function(){input.forceCompositionEnd()});on(div,"input",function(){if(input.composing){return}if(!input.pollContent()){runInOp(input.cm,function(){regChange(cm)})}});function onCopyCut(e){if(cm.somethingSelected()){lastCopied=cm.getSelections();if(e.type=="cut"){cm.replaceSelection("",null,"cut")}}else{var ranges=copyableRanges(cm);lastCopied=ranges.text;if(e.type=="cut"){cm.operation(function(){cm.setSelections(ranges.ranges,0,sel_dontScroll);cm.replaceSelection("",null,"cut")})}}if(e.clipboardData&&!ios){e.preventDefault();e.clipboardData.clearData();e.clipboardData.setData("text/plain",lastCopied.join("\n"))}else{var kludge=hiddenTextarea(),te=kludge.firstChild;cm.display.lineSpace.insertBefore(kludge,cm.display.lineSpace.firstChild);te.value=lastCopied.join("\n");var hadFocus=document.activeElement;selectInput(te);setTimeout(function(){cm.display.lineSpace.removeChild(kludge);hadFocus.focus()},50)}}on(div,"copy",onCopyCut);on(div,"cut",onCopyCut)},prepareSelection:function(){var result=prepareSelection(this.cm,false);result.focus=this.cm.state.focused;return result},showSelection:function(info){if(!info||!this.cm.display.view.length){return +}if(info.focus){this.showPrimarySelection()}this.showMultipleSelections(info)},showPrimarySelection:function(){var sel=window.getSelection(),prim=this.cm.doc.sel.primary();var curAnchor=domToPos(this.cm,sel.anchorNode,sel.anchorOffset);var curFocus=domToPos(this.cm,sel.focusNode,sel.focusOffset);if(curAnchor&&!curAnchor.bad&&curFocus&&!curFocus.bad&&cmp(minPos(curAnchor,curFocus),prim.from())==0&&cmp(maxPos(curAnchor,curFocus),prim.to())==0){return}var start=posToDOM(this.cm,prim.from());var end=posToDOM(this.cm,prim.to());if(!start&&!end){return}var view=this.cm.display.view;var old=sel.rangeCount&&sel.getRangeAt(0);if(!start){start={node:view[0].measure.map[2],offset:0}}else{if(!end){var measure=view[view.length-1].measure;var map=measure.maps?measure.maps[measure.maps.length-1]:measure.map;end={node:map[map.length-1],offset:map[map.length-2]-map[map.length-3]}}}try{var rng=range(start.node,start.offset,end.offset,end.node)}catch(e){}if(rng){sel.removeAllRanges();sel.addRange(rng);if(old&&sel.anchorNode==null){sel.addRange(old)}}this.rememberSelection()},showMultipleSelections:function(info){removeChildrenAndAdd(this.cm.display.cursorDiv,info.cursors);removeChildrenAndAdd(this.cm.display.selectionDiv,info.selection)},rememberSelection:function(){var sel=window.getSelection();this.lastAnchorNode=sel.anchorNode;this.lastAnchorOffset=sel.anchorOffset;this.lastFocusNode=sel.focusNode;this.lastFocusOffset=sel.focusOffset},selectionInEditor:function(){var sel=window.getSelection();if(!sel.rangeCount){return false}var node=sel.getRangeAt(0).commonAncestorContainer;return contains(this.div,node)},focus:function(){if(this.cm.options.readOnly!="nocursor"){this.div.focus()}},blur:function(){this.div.blur()},getField:function(){return this.div},supportsTouch:function(){return true},receivedFocus:function(){var input=this;if(this.selectionInEditor()){this.pollSelection()}else{runInOp(this.cm,function(){input.cm.curOp.selectionChanged=true})}function poll(){if(input.cm.state.focused){input.pollSelection();input.polling.set(input.cm.options.pollInterval,poll)}}this.polling.set(this.cm.options.pollInterval,poll)},pollSelection:function(){if(this.composing){return}var sel=window.getSelection(),cm=this.cm;if(sel.anchorNode!=this.lastAnchorNode||sel.anchorOffset!=this.lastAnchorOffset||sel.focusNode!=this.lastFocusNode||sel.focusOffset!=this.lastFocusOffset){this.rememberSelection();var anchor=domToPos(cm,sel.anchorNode,sel.anchorOffset);var head=domToPos(cm,sel.focusNode,sel.focusOffset);if(anchor&&head){runInOp(cm,function(){setSelection(cm.doc,simpleSelection(anchor,head),sel_dontScroll);if(anchor.bad||head.bad){cm.curOp.selectionChanged=true}})}}},pollContent:function(){var cm=this.cm,display=cm.display,sel=cm.doc.sel.primary();var from=sel.from(),to=sel.to();if(from.linedisplay.viewTo-1){return false}var fromIndex;if(from.line==display.viewFrom||(fromIndex=findViewIndex(cm,from.line))==0){var fromLine=lineNo(display.view[0].line);var fromNode=display.view[0].node}else{var fromLine=lineNo(display.view[fromIndex].line);var fromNode=display.view[fromIndex-1].node.nextSibling}var toIndex=findViewIndex(cm,to.line);if(toIndex==display.view.length-1){var toLine=display.viewTo-1;var toNode=display.view[toIndex].node}else{var toLine=lineNo(display.view[toIndex+1].line)-1;var toNode=display.view[toIndex+1].node.previousSibling}var newText=splitLines(domTextBetween(cm,fromNode,toNode,fromLine,toLine));var oldText=getBetween(cm.doc,Pos(fromLine,0),Pos(toLine,getLine(cm.doc,toLine).text.length));while(newText.length>1&&oldText.length>1){if(lst(newText)==lst(oldText)){newText.pop();oldText.pop();toLine--}else{if(newText[0]==oldText[0]){newText.shift();oldText.shift();fromLine++}else{break}}}var cutFront=0,cutEnd=0;var newTop=newText[0],oldTop=oldText[0],maxCutFront=Math.min(newTop.length,oldTop.length);while(cutFront1||newText[0]||cmp(chFrom,chTo)){replaceRange(cm.doc,newText,chFrom,chTo,"+input");return true}},ensurePolled:function(){this.forceCompositionEnd()},reset:function(){this.forceCompositionEnd()},forceCompositionEnd:function(){if(!this.composing||this.composing.handled){return}this.applyComposition(this.composing);this.composing.handled=true;this.div.blur();this.div.focus()},applyComposition:function(composing){if(composing.data&&composing.data!=composing.startData){operation(this.cm,applyTextInput)(this.cm,composing.data,0,composing.sel) +}},setUneditable:function(node){node.setAttribute("contenteditable","false")},onKeyPress:function(e){e.preventDefault();operation(this.cm,applyTextInput)(this.cm,String.fromCharCode(e.charCode==null?e.keyCode:e.charCode),0)},onContextMenu:nothing,resetPosition:nothing,needsContentAttribute:true},ContentEditableInput.prototype);function posToDOM(cm,pos){var view=findViewForLine(cm,pos.line);if(!view||view.hidden){return null}var line=getLine(cm.doc,pos.line);var info=mapFromLineView(view,line,pos.line);var order=getOrder(line),side="left";if(order){var partPos=getBidiPartAt(order,pos.ch);side=partPos%2?"right":"left"}var result=nodeAndOffsetInLineMap(info.map,pos.ch,"left");result.offset=result.collapse=="right"?result.end:result.start;return result}function badPos(pos,bad){if(bad){pos.bad=true}return pos}function domToPos(cm,node,offset){var lineNode;if(node==cm.display.lineDiv){lineNode=cm.display.lineDiv.childNodes[offset];if(!lineNode){return badPos(cm.clipPos(Pos(cm.display.viewTo-1)),true)}node=null;offset=0}else{for(lineNode=node;;lineNode=lineNode.parentNode){if(!lineNode||lineNode==cm.display.lineDiv){return null}if(lineNode.parentNode&&lineNode.parentNode==cm.display.lineDiv){break}}}for(var i=0;i=0&&cmp(pos,range.to())<=0){return i}}return -1}};function Range(anchor,head){this.anchor=anchor;this.head=head +}Range.prototype={from:function(){return minPos(this.anchor,this.head)},to:function(){return maxPos(this.anchor,this.head)},empty:function(){return this.head.line==this.anchor.line&&this.head.ch==this.anchor.ch}};function normalizeSelection(ranges,primIndex){var prim=ranges[primIndex];ranges.sort(function(a,b){return cmp(a.from(),b.from())});primIndex=indexOf(ranges,prim);for(var i=1;i=0){var from=minPos(prev.from(),cur.from()),to=maxPos(prev.to(),cur.to());var inv=prev.empty()?cur.from()==cur.head:prev.from()==prev.head;if(i<=primIndex){--primIndex}ranges.splice(--i,2,new Range(inv?to:from,inv?from:to))}}return new Selection(ranges,primIndex)}function simpleSelection(anchor,head){return new Selection([new Range(anchor,head||anchor)],0)}function clipLine(doc,n){return Math.max(doc.first,Math.min(n,doc.first+doc.size-1))}function clipPos(doc,pos){if(pos.linelast){return Pos(last,getLine(doc,last).text.length)}return clipToLen(pos,getLine(doc,pos.line).text.length)}function clipToLen(pos,linelen){var ch=pos.ch;if(ch==null||ch>linelen){return Pos(pos.line,linelen)}else{if(ch<0){return Pos(pos.line,0)}else{return pos}}}function isLine(doc,l){return l>=doc.first&&l=curPos.ch:sp.to>curPos.ch))){if(mayClear){signal(m,"beforeCursorEnter");if(m.explicitlyCleared){if(!line.markedSpans){break}else{--i;continue}}}if(!m.atomic){continue}var newPos=m.find(dir<0?-1:1);if(cmp(newPos,curPos)==0){newPos.ch+=dir; +if(newPos.ch<0){if(newPos.line>doc.first){newPos=clipPos(doc,Pos(newPos.line-1))}else{newPos=null}}else{if(newPos.ch>line.text.length){if(newPos.line3){add(left,leftPos.top,null,leftPos.bottom);left=leftSide;if(leftPos.bottomend.bottom||rightPos.bottom==end.bottom&&rightPos.right>end.right){end=rightPos}if(left0){display.blinker=setInterval(function(){display.cursorDiv.style.visibility=(on=!on)?"":"hidden"},cm.options.cursorBlinkRate)}else{if(cm.options.cursorBlinkRate<0){display.cursorDiv.style.visibility="hidden"}}}function startWorker(cm,time){if(cm.doc.mode.startState&&cm.doc.frontier=cm.display.viewTo){return}var end=+new Date+cm.options.workTime;var state=copyState(doc.mode,getStateBefore(cm,doc.frontier));var changedLines=[];doc.iter(doc.frontier,Math.min(doc.first+doc.size,cm.display.viewTo+500),function(line){if(doc.frontier>=cm.display.viewFrom){var oldStyles=line.styles; +var highlighted=highlightLine(cm,line,state,true);line.styles=highlighted.styles;var oldCls=line.styleClasses,newCls=highlighted.classes;if(newCls){line.styleClasses=newCls}else{if(oldCls){line.styleClasses=null}}var ischange=!oldStyles||oldStyles.length!=line.styles.length||oldCls!=newCls&&(!oldCls||!newCls||oldCls.bgClass!=newCls.bgClass||oldCls.textClass!=newCls.textClass);for(var i=0;!ischange&&iend){startWorker(cm,cm.options.workDelay);return true}});if(changedLines.length){runInOp(cm,function(){for(var i=0;ilim;--search){if(search<=doc.first){return doc.first}var line=getLine(doc,search-1);if(line.stateAfter&&(!precise||search<=doc.frontier)){return search}var indented=countColumn(line.text,null,cm.options.tabSize);if(minline==null||minindent>indented){minline=search-1;minindent=indented}}return minline}function getStateBefore(cm,n,precise){var doc=cm.doc,display=cm.display;if(!doc.mode.startState){return true}var pos=findStartLine(cm,n,precise),state=pos>doc.first&&getLine(doc,pos-1).stateAfter;if(!state){state=startState(doc.mode)}else{state=copyState(doc.mode,state)}doc.iter(pos,n,function(line){processLine(cm,line.text,state);var save=pos==n-1||pos%5==0||pos>=display.viewFrom&&pos2){heights.push((cur.bottom+next.top)/2-rect.top)}}}heights.push(rect.bottom-rect.top)}}function mapFromLineView(lineView,line,lineN){if(lineView.line==line){return{map:lineView.measure.map,cache:lineView.measure.cache}}for(var i=0;ilineN){return{map:lineView.measure.maps[i],cache:lineView.measure.caches[i],before:true}}}}function updateExternalMeasurement(cm,line){line=visualLine(line);var lineN=lineNo(line);var view=cm.display.externalMeasured=new LineView(cm.doc,line,lineN);view.lineN=lineN;var built=view.built=buildLineContent(cm,view);view.text=built.pre;removeChildrenAndAdd(cm.display.lineMeasure,built.pre);return view}function measureChar(cm,line,ch,bias){return measureCharPrepared(cm,prepareMeasureForLine(cm,line),ch,bias)}function findViewForLine(cm,lineN){if(lineN>=cm.display.viewFrom&&lineN=ext.lineN&&lineNch){end=mEnd-mStart;start=end-1;if(ch>=mEnd){collapse="right"}}}}if(start!=null){node=map[i+2];if(mStart==mEnd&&bias==(node.insertLeft?"left":"right")){collapse=bias}if(bias=="left"&&start==0){while(i&&map[i-2]==map[i-3]&&map[i-1].insertLeft){node=map[(i-=3)+2];collapse="left"}}if(bias=="right"&&start==mEnd-mStart){while(i0){collapse=bias="right"}var rects;if(cm.options.lineWrapping&&(rects=node.getClientRects()).length>1){rect=rects[bias=="right"?rects.length-1:0]}else{rect=node.getBoundingClientRect()}}if(ie&&ie_version<9&&!start&&(!rect||!rect.left&&!rect.right)){var rSpan=node.parentNode.getClientRects()[0];if(rSpan){rect={left:rSpan.left,right:rSpan.left+charWidth(cm.display),top:rSpan.top,bottom:rSpan.bottom}}else{rect=nullRect}}var rtop=rect.top-prepared.rect.top,rbot=rect.bottom-prepared.rect.top;var mid=(rtop+rbot)/2;var heights=prepared.view.measure.heights;for(var i=0;ipart.from){return get(ch-1)}return get(ch,right)}var order=getOrder(lineObj),ch=pos.ch;if(!order){return get(ch)}var partPos=getBidiPartAt(order,ch);var val=getBidi(ch,partPos);if(bidiOther!=null){val.other=getBidi(ch,bidiOther)}return val}function estimateCoords(cm,pos){var left=0,pos=clipPos(cm.doc,pos);if(!cm.options.lineWrapping){left=charWidth(cm.display)*pos.ch}var lineObj=getLine(cm.doc,pos.line);var top=heightAtLine(lineObj)+paddingTop(cm.display);return{left:left,right:left,top:top,bottom:top+lineObj.height}}function PosWithInfo(line,ch,outside,xRel){var pos=Pos(line,ch);pos.xRel=xRel;if(outside){pos.outside=true}return pos}function coordsChar(cm,x,y){var doc=cm.doc;y+=cm.display.viewOffset;if(y<0){return PosWithInfo(doc.first,0,true,-1)}var lineN=lineAtHeight(doc,y),last=doc.first+doc.size-1;if(lineN>last){return PosWithInfo(doc.first+doc.size-1,getLine(doc,last).text.length,true,1)}if(x<0){x=0}var lineObj=getLine(doc,lineN);for(;;){var found=coordsCharInner(cm,lineObj,lineN,x,y);var merged=collapsedSpanAtEnd(lineObj);var mergedPos=merged&&merged.find(0,true);if(merged&&(found.ch>mergedPos.from.ch||found.ch==mergedPos.from.ch&&found.xRel>0)){lineN=lineNo(lineObj=mergedPos.to.line)}else{return found}}}function coordsCharInner(cm,lineObj,lineNo,x,y){var innerOff=y-heightAtLine(lineObj);var wrongLine=false,adjust=2*cm.display.wrapper.clientWidth;var preparedMeasure=prepareMeasureForLine(cm,lineObj);function getX(ch){var sp=cursorCoords(cm,Pos(lineNo,ch),"line",lineObj,preparedMeasure);wrongLine=true;if(innerOff>sp.bottom){return sp.left-adjust}else{if(innerOfftoX){return PosWithInfo(lineNo,to,toOutside,1)}for(;;){if(bidi?to==from||to==moveVisually(lineObj,from,1):to-from<=1){var ch=x1?1:0);return pos}var step=Math.ceil(dist/2),middle=from+step;if(bidi){middle=from;for(var i=0;ix){to=middle;toX=middleX;if(toOutside=wrongLine){toX+=1000}dist=step}else{from=middle;fromX=middleX;fromOutside=wrongLine;dist-=step}}}var measureText;function textHeight(display){if(display.cachedTextHeight!=null){return display.cachedTextHeight}if(measureText==null){measureText=elt("pre");for(var i=0;i<49;++i){measureText.appendChild(document.createTextNode("x"));measureText.appendChild(elt("br"))}measureText.appendChild(document.createTextNode("x"))}removeChildrenAndAdd(display.measure,measureText);var height=measureText.offsetHeight/50;if(height>3){display.cachedTextHeight=height}removeChildren(display.measure);return height||1}function charWidth(display){if(display.cachedCharWidth!=null){return display.cachedCharWidth}var anchor=elt("span","xxxxxxxxxx");var pre=elt("pre",[anchor]);removeChildrenAndAdd(display.measure,pre);var rect=anchor.getBoundingClientRect(),width=(rect.right-rect.left)/10;if(width>2){display.cachedCharWidth=width}return width||10}var operationGroup=null;var nextOpId=0;function startOperation(cm){cm.curOp={cm:cm,viewChanged:false,startHeight:cm.doc.height,forceUpdate:false,updateInput:null,typing:false,changeObjs:null,cursorActivityHandlers:null,cursorActivityCalled:0,selectionChanged:false,updateMaxLine:false,scrollLeft:null,scrollTop:null,scrollToPos:null,id:++nextOpId};if(operationGroup){operationGroup.ops.push(cm.curOp)}else{cm.curOp.ownsGroup=operationGroup={ops:[cm.curOp],delayedCallbacks:[]}}}function fireCallbacksForOps(group){var callbacks=group.delayedCallbacks,i=0; +do{for(;i=display.viewTo)||display.maxLineChanged&&cm.options.lineWrapping;op.update=op.mustUpdate&&new DisplayUpdate(cm,op.mustUpdate&&{top:op.scrollTop,ensure:op.scrollToPos},op.forceUpdate)}function endOperation_W1(op){op.updatedDisplay=op.mustUpdate&&updateDisplayIfNeeded(op.cm,op.update)}function endOperation_R2(op){var cm=op.cm,display=cm.display;if(op.updatedDisplay){updateHeightsInViewport(cm)}op.barMeasure=measureForScrollbars(cm);if(display.maxLineChanged&&!cm.options.lineWrapping){op.adjustWidthTo=measureChar(cm,display.maxLine,display.maxLine.text.length).left+3;cm.display.sizerWidth=op.adjustWidthTo;op.barMeasure.scrollWidth=Math.max(display.scroller.clientWidth,display.sizer.offsetLeft+op.adjustWidthTo+scrollGap(cm)+cm.display.barWidth);op.maxScrollLeft=Math.max(0,display.sizer.offsetLeft+op.adjustWidthTo-displayWidth(cm))}if(op.updatedDisplay||op.selectionChanged){op.preparedSelection=display.input.prepareSelection()}}function endOperation_W2(op){var cm=op.cm;if(op.adjustWidthTo!=null){cm.display.sizer.style.minWidth=op.adjustWidthTo+"px";if(op.maxScrollLeft
]", + "[link ]", + "[tag&bracket <][tag div][tag&bracket >]", + "[tag&bracket ]"); + +})(); diff --git a/static/js/mdeditor/lib/codemirror/mode/meta.js b/static/js/mdeditor/lib/codemirror/mode/meta.js new file mode 100644 index 00000000..e110288a --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/meta.js @@ -0,0 +1,177 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.modeInfo = [ + {name: "APL", mime: "text/apl", mode: "apl", ext: ["dyalog", "apl"]}, + {name: "Asterisk", mime: "text/x-asterisk", mode: "asterisk", file: /^extensions\.conf$/i}, + {name: "C", mime: "text/x-csrc", mode: "clike", ext: ["c", "h"]}, + {name: "C++", mime: "text/x-c++src", mode: "clike", ext: ["cpp", "c++", "cc", "cxx", "hpp", "h++", "hh", "hxx"], alias: ["cpp"]}, + {name: "Cobol", mime: "text/x-cobol", mode: "cobol", ext: ["cob", "cpy"]}, + {name: "C#", mime: "text/x-csharp", mode: "clike", ext: ["cs"], alias: ["csharp"]}, + {name: "Clojure", mime: "text/x-clojure", mode: "clojure", ext: ["clj"]}, + {name: "CoffeeScript", mime: "text/x-coffeescript", mode: "coffeescript", ext: ["coffee"], alias: ["coffee", "coffee-script"]}, + {name: "Common Lisp", mime: "text/x-common-lisp", mode: "commonlisp", ext: ["cl", "lisp", "el"], alias: ["lisp"]}, + {name: "Cypher", mime: "application/x-cypher-query", mode: "cypher", ext: ["cyp", "cypher"]}, + {name: "Cython", mime: "text/x-cython", mode: "python", ext: ["pyx", "pxd", "pxi"]}, + {name: "CSS", mime: "text/css", mode: "css", ext: ["css"]}, + {name: "CQL", mime: "text/x-cassandra", mode: "sql", ext: ["cql"]}, + {name: "D", mime: "text/x-d", mode: "d", ext: ["d"]}, + {name: "Dart", mimes: ["application/dart", "text/x-dart"], mode: "dart", ext: ["dart"]}, + {name: "diff", mime: "text/x-diff", mode: "diff", ext: ["diff", "patch"]}, + {name: "Django", mime: "text/x-django", mode: "django"}, + {name: "Dockerfile", mime: "text/x-dockerfile", mode: "dockerfile", file: /^Dockerfile$/}, + {name: "DTD", mime: "application/xml-dtd", mode: "dtd", ext: ["dtd"]}, + {name: "Dylan", mime: "text/x-dylan", mode: "dylan", ext: ["dylan", "dyl", "intr"]}, + {name: "EBNF", mime: "text/x-ebnf", mode: "ebnf"}, + {name: "ECL", mime: "text/x-ecl", mode: "ecl", ext: ["ecl"]}, + {name: "Eiffel", mime: "text/x-eiffel", mode: "eiffel", ext: ["e"]}, + {name: "Embedded Javascript", mime: "application/x-ejs", mode: "htmlembedded", ext: ["ejs"]}, + {name: "Embedded Ruby", mime: "application/x-erb", mode: "htmlembedded", ext: ["erb"]}, + {name: "Erlang", mime: "text/x-erlang", mode: "erlang", ext: ["erl"]}, + {name: "Forth", mime: "text/x-forth", mode: "forth", ext: ["forth", "fth", "4th"]}, + {name: "Fortran", mime: "text/x-fortran", mode: "fortran", ext: ["f", "for", "f77", "f90"]}, + {name: "F#", mime: "text/x-fsharp", mode: "mllike", ext: ["fs"], alias: ["fsharp"]}, + {name: "Gas", mime: "text/x-gas", mode: "gas", ext: ["s"]}, + {name: "Gherkin", mime: "text/x-feature", mode: "gherkin", ext: ["feature"]}, + {name: "GitHub Flavored Markdown", mime: "text/x-gfm", mode: "gfm", file: /^(readme|contributing|history).md$/i}, + {name: "Go", mime: "text/x-go", mode: "go", ext: ["go"]}, + {name: "Groovy", mime: "text/x-groovy", mode: "groovy", ext: ["groovy"]}, + {name: "HAML", mime: "text/x-haml", mode: "haml", ext: ["haml"]}, + {name: "Haskell", mime: "text/x-haskell", mode: "haskell", ext: ["hs"]}, + {name: "Haxe", mime: "text/x-haxe", mode: "haxe", ext: ["hx"]}, + {name: "HXML", mime: "text/x-hxml", mode: "haxe", ext: ["hxml"]}, + {name: "ASP.NET", mime: "application/x-aspx", mode: "htmlembedded", ext: ["aspx"], alias: ["asp", "aspx"]}, + {name: "HTML", mime: "text/html", mode: "htmlmixed", ext: ["html", "htm"], alias: ["xhtml"]}, + {name: "HTTP", mime: "message/http", mode: "http"}, + {name: "IDL", mime: "text/x-idl", mode: "idl", ext: ["pro"]}, + {name: "Jade", mime: "text/x-jade", mode: "jade", ext: ["jade"]}, + {name: "Java", mime: "text/x-java", mode: "clike", ext: ["java"]}, + {name: "Java Server Pages", mime: "application/x-jsp", mode: "htmlembedded", ext: ["jsp"], alias: ["jsp"]}, + {name: "JavaScript", mimes: ["text/javascript", "text/ecmascript", "application/javascript", "application/x-javascript", "application/ecmascript"], + mode: "javascript", ext: ["js"], alias: ["ecmascript", "js", "node"]}, + {name: "JSON", mimes: ["application/json", "application/x-json"], mode: "javascript", ext: ["json", "map"], alias: ["json5"]}, + {name: "JSON-LD", mime: "application/ld+json", mode: "javascript", ext: ["jsonld"], alias: ["jsonld"]}, + {name: "Jinja2", mime: "null", mode: "jinja2"}, + {name: "Julia", mime: "text/x-julia", mode: "julia", ext: ["jl"]}, + {name: "Kotlin", mime: "text/x-kotlin", mode: "kotlin", ext: ["kt"]}, + {name: "LESS", mime: "text/x-less", mode: "css", ext: ["less"]}, + {name: "LiveScript", mime: "text/x-livescript", mode: "livescript", ext: ["ls"], alias: ["ls"]}, + {name: "Lua", mime: "text/x-lua", mode: "lua", ext: ["lua"]}, + {name: "Markdown", mime: "text/x-markdown", mode: "markdown", ext: ["markdown", "md", "mkd"]}, + {name: "mIRC", mime: "text/mirc", mode: "mirc"}, + {name: "MariaDB SQL", mime: "text/x-mariadb", mode: "sql"}, + {name: "Modelica", mime: "text/x-modelica", mode: "modelica", ext: ["mo"]}, + {name: "MS SQL", mime: "text/x-mssql", mode: "sql"}, + {name: "MySQL", mime: "text/x-mysql", mode: "sql"}, + {name: "Nginx", mime: "text/x-nginx-conf", mode: "nginx", file: /nginx.*\.conf$/i}, + {name: "NTriples", mime: "text/n-triples", mode: "ntriples", ext: ["nt"]}, + {name: "Objective C", mime: "text/x-objectivec", mode: "clike", ext: ["m", "mm"]}, + {name: "OCaml", mime: "text/x-ocaml", mode: "mllike", ext: ["ml", "mli", "mll", "mly"]}, + {name: "Octave", mime: "text/x-octave", mode: "octave", ext: ["m"]}, + {name: "Pascal", mime: "text/x-pascal", mode: "pascal", ext: ["p", "pas"]}, + {name: "PEG.js", mime: "null", mode: "pegjs", ext: ["jsonld"]}, + {name: "Perl", mime: "text/x-perl", mode: "perl", ext: ["pl", "pm"]}, + {name: "PHP", mime: "application/x-httpd-php", mode: "php", ext: ["php", "php3", "php4", "php5", "phtml"]}, + {name: "Pig", mime: "text/x-pig", mode: "pig", ext: ["pig"]}, + {name: "Plain Text", mime: "text/plain", mode: "null", ext: ["txt", "text", "conf", "def", "list", "log"]}, + {name: "PLSQL", mime: "text/x-plsql", mode: "sql", ext: ["pls"]}, + {name: "Properties files", mime: "text/x-properties", mode: "properties", ext: ["properties", "ini", "in"], alias: ["ini", "properties"]}, + {name: "Python", mime: "text/x-python", mode: "python", ext: ["py", "pyw"]}, + {name: "Puppet", mime: "text/x-puppet", mode: "puppet", ext: ["pp"]}, + {name: "Q", mime: "text/x-q", mode: "q", ext: ["q"]}, + {name: "R", mime: "text/x-rsrc", mode: "r", ext: ["r"], alias: ["rscript"]}, + {name: "reStructuredText", mime: "text/x-rst", mode: "rst", ext: ["rst"], alias: ["rst"]}, + {name: "RPM Changes", mime: "text/x-rpm-changes", mode: "rpm"}, + {name: "RPM Spec", mime: "text/x-rpm-spec", mode: "rpm", ext: ["spec"]}, + {name: "Ruby", mime: "text/x-ruby", mode: "ruby", ext: ["rb"], alias: ["jruby", "macruby", "rake", "rb", "rbx"]}, + {name: "Rust", mime: "text/x-rustsrc", mode: "rust", ext: ["rs"]}, + {name: "Sass", mime: "text/x-sass", mode: "sass", ext: ["sass"]}, + {name: "Scala", mime: "text/x-scala", mode: "clike", ext: ["scala"]}, + {name: "Scheme", mime: "text/x-scheme", mode: "scheme", ext: ["scm", "ss"]}, + {name: "SCSS", mime: "text/x-scss", mode: "css", ext: ["scss"]}, + {name: "Shell", mime: "text/x-sh", mode: "shell", ext: ["sh", "ksh", "bash"], alias: ["bash", "sh", "zsh"]}, + {name: "Sieve", mime: "application/sieve", mode: "sieve", ext: ["siv", "sieve"]}, + {name: "Slim", mimes: ["text/x-slim", "application/x-slim"], mode: "slim", ext: ["slim"]}, + {name: "Smalltalk", mime: "text/x-stsrc", mode: "smalltalk", ext: ["st"]}, + {name: "Smarty", mime: "text/x-smarty", mode: "smarty", ext: ["tpl"]}, + {name: "SmartyMixed", mime: "text/x-smarty", mode: "smartymixed"}, + {name: "Solr", mime: "text/x-solr", mode: "solr"}, + {name: "Soy", mime: "text/x-soy", mode: "soy", ext: ["soy"], alias: ["closure template"]}, + {name: "SPARQL", mime: "application/sparql-query", mode: "sparql", ext: ["rq", "sparql"], alias: ["sparul"]}, + {name: "Spreadsheet", mime: "text/x-spreadsheet", mode: "spreadsheet", alias: ["excel", "formula"]}, + {name: "SQL", mime: "text/x-sql", mode: "sql", ext: ["sql"]}, + {name: "MariaDB", mime: "text/x-mariadb", mode: "sql"}, + {name: "sTeX", mime: "text/x-stex", mode: "stex"}, + {name: "LaTeX", mime: "text/x-latex", mode: "stex", ext: ["text", "ltx"], alias: ["tex"]}, + {name: "SystemVerilog", mime: "text/x-systemverilog", mode: "verilog", ext: ["v"]}, + {name: "Tcl", mime: "text/x-tcl", mode: "tcl", ext: ["tcl"]}, + {name: "Textile", mime: "text/x-textile", mode: "textile", ext: ["textile"]}, + {name: "TiddlyWiki ", mime: "text/x-tiddlywiki", mode: "tiddlywiki"}, + {name: "Tiki wiki", mime: "text/tiki", mode: "tiki"}, + {name: "TOML", mime: "text/x-toml", mode: "toml", ext: ["toml"]}, + {name: "Tornado", mime: "text/x-tornado", mode: "tornado"}, + {name: "Turtle", mime: "text/turtle", mode: "turtle", ext: ["ttl"]}, + {name: "TypeScript", mime: "application/typescript", mode: "javascript", ext: ["ts"], alias: ["ts"]}, + {name: "VB.NET", mime: "text/x-vb", mode: "vb", ext: ["vb"]}, + {name: "VBScript", mime: "text/vbscript", mode: "vbscript", ext: ["vbs"]}, + {name: "Velocity", mime: "text/velocity", mode: "velocity", ext: ["vtl"]}, + {name: "Verilog", mime: "text/x-verilog", mode: "verilog", ext: ["v"]}, + {name: "XML", mimes: ["application/xml", "text/xml"], mode: "xml", ext: ["xml", "xsl", "xsd"], alias: ["rss", "wsdl", "xsd"]}, + {name: "XQuery", mime: "application/xquery", mode: "xquery", ext: ["xy", "xquery"]}, + {name: "YAML", mime: "text/x-yaml", mode: "yaml", ext: ["yaml"], alias: ["yml"]}, + {name: "Z80", mime: "text/x-z80", mode: "z80", ext: ["z80"]} + ]; + // Ensure all modes have a mime property for backwards compatibility + for (var i = 0; i < CodeMirror.modeInfo.length; i++) { + var info = CodeMirror.modeInfo[i]; + if (info.mimes) info.mime = info.mimes[0]; + } + + CodeMirror.findModeByMIME = function(mime) { + mime = mime.toLowerCase(); + for (var i = 0; i < CodeMirror.modeInfo.length; i++) { + var info = CodeMirror.modeInfo[i]; + if (info.mime == mime) return info; + if (info.mimes) for (var j = 0; j < info.mimes.length; j++) + if (info.mimes[j] == mime) return info; + } + }; + + CodeMirror.findModeByExtension = function(ext) { + for (var i = 0; i < CodeMirror.modeInfo.length; i++) { + var info = CodeMirror.modeInfo[i]; + if (info.ext) for (var j = 0; j < info.ext.length; j++) + if (info.ext[j] == ext) return info; + } + }; + + CodeMirror.findModeByFileName = function(filename) { + for (var i = 0; i < CodeMirror.modeInfo.length; i++) { + var info = CodeMirror.modeInfo[i]; + if (info.file && info.file.test(filename)) return info; + } + var dot = filename.lastIndexOf("."); + var ext = dot > -1 && filename.substring(dot + 1, filename.length); + if (ext) return CodeMirror.findModeByExtension(ext); + }; + + CodeMirror.findModeByName = function(name) { + name = name.toLowerCase(); + for (var i = 0; i < CodeMirror.modeInfo.length; i++) { + var info = CodeMirror.modeInfo[i]; + if (info.name.toLowerCase() == name) return info; + if (info.alias) for (var j = 0; j < info.alias.length; j++) + if (info.alias[j].toLowerCase() == name) return info; + } + }; +}); diff --git a/static/js/mdeditor/lib/codemirror/mode/mirc/index.html b/static/js/mdeditor/lib/codemirror/mode/mirc/index.html new file mode 100644 index 00000000..fd2f34e4 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/mirc/index.html @@ -0,0 +1,160 @@ + + +CodeMirror: mIRC mode + + + + + + + + + + +
+

mIRC mode

+
+ + +

MIME types defined: text/mirc.

+ +
diff --git a/static/js/mdeditor/lib/codemirror/mode/mirc/mirc.js b/static/js/mdeditor/lib/codemirror/mode/mirc/mirc.js new file mode 100644 index 00000000..f0d5c6ad --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/mirc/mirc.js @@ -0,0 +1,193 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +//mIRC mode by Ford_Lawnmower :: Based on Velocity mode by Steve O'Hara + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMIME("text/mirc", "mirc"); +CodeMirror.defineMode("mirc", function() { + function parseWords(str) { + var obj = {}, words = str.split(" "); + for (var i = 0; i < words.length; ++i) obj[words[i]] = true; + return obj; + } + var specials = parseWords("$! $$ $& $? $+ $abook $abs $active $activecid " + + "$activewid $address $addtok $agent $agentname $agentstat $agentver " + + "$alias $and $anick $ansi2mirc $aop $appactive $appstate $asc $asctime " + + "$asin $atan $avoice $away $awaymsg $awaytime $banmask $base $bfind " + + "$binoff $biton $bnick $bvar $bytes $calc $cb $cd $ceil $chan $chanmodes " + + "$chantypes $chat $chr $cid $clevel $click $cmdbox $cmdline $cnick $color " + + "$com $comcall $comchan $comerr $compact $compress $comval $cos $count " + + "$cr $crc $creq $crlf $ctime $ctimer $ctrlenter $date $day $daylight " + + "$dbuh $dbuw $dccignore $dccport $dde $ddename $debug $decode $decompress " + + "$deltok $devent $dialog $did $didreg $didtok $didwm $disk $dlevel $dll " + + "$dllcall $dname $dns $duration $ebeeps $editbox $emailaddr $encode $error " + + "$eval $event $exist $feof $ferr $fgetc $file $filename $filtered $finddir " + + "$finddirn $findfile $findfilen $findtok $fline $floor $fopen $fread $fserve " + + "$fulladdress $fulldate $fullname $fullscreen $get $getdir $getdot $gettok $gmt " + + "$group $halted $hash $height $hfind $hget $highlight $hnick $hotline " + + "$hotlinepos $ial $ialchan $ibl $idle $iel $ifmatch $ignore $iif $iil " + + "$inelipse $ini $inmidi $inpaste $inpoly $input $inrect $inroundrect " + + "$insong $instok $int $inwave $ip $isalias $isbit $isdde $isdir $isfile " + + "$isid $islower $istok $isupper $keychar $keyrpt $keyval $knick $lactive " + + "$lactivecid $lactivewid $left $len $level $lf $line $lines $link $lock " + + "$lock $locked $log $logstamp $logstampfmt $longfn $longip $lower $ltimer " + + "$maddress $mask $matchkey $matchtok $md5 $me $menu $menubar $menucontext " + + "$menutype $mid $middir $mircdir $mircexe $mircini $mklogfn $mnick $mode " + + "$modefirst $modelast $modespl $mouse $msfile $network $newnick $nick $nofile " + + "$nopath $noqt $not $notags $notify $null $numeric $numok $oline $onpoly " + + "$opnick $or $ord $os $passivedcc $pic $play $pnick $port $portable $portfree " + + "$pos $prefix $prop $protect $puttok $qt $query $rand $r $rawmsg $read $readomo " + + "$readn $regex $regml $regsub $regsubex $remove $remtok $replace $replacex " + + "$reptok $result $rgb $right $round $scid $scon $script $scriptdir $scriptline " + + "$sdir $send $server $serverip $sfile $sha1 $shortfn $show $signal $sin " + + "$site $sline $snick $snicks $snotify $sock $sockbr $sockerr $sockname " + + "$sorttok $sound $sqrt $ssl $sreq $sslready $status $strip $str $stripped " + + "$syle $submenu $switchbar $tan $target $ticks $time $timer $timestamp " + + "$timestampfmt $timezone $tip $titlebar $toolbar $treebar $trust $ulevel " + + "$ulist $upper $uptime $url $usermode $v1 $v2 $var $vcmd $vcmdstat $vcmdver " + + "$version $vnick $vol $wid $width $wildsite $wildtok $window $wrap $xor"); + var keywords = parseWords("abook ajinvite alias aline ame amsg anick aop auser autojoin avoice " + + "away background ban bcopy beep bread break breplace bset btrunc bunset bwrite " + + "channel clear clearall cline clipboard close cnick color comclose comopen " + + "comreg continue copy creq ctcpreply ctcps dcc dccserver dde ddeserver " + + "debug dec describe dialog did didtok disable disconnect dlevel dline dll " + + "dns dqwindow drawcopy drawdot drawfill drawline drawpic drawrect drawreplace " + + "drawrot drawsave drawscroll drawtext ebeeps echo editbox emailaddr enable " + + "events exit fclose filter findtext finger firewall flash flist flood flush " + + "flushini font fopen fseek fsend fserve fullname fwrite ghide gload gmove " + + "gopts goto gplay gpoint gqreq groups gshow gsize gstop gtalk gunload hadd " + + "halt haltdef hdec hdel help hfree hinc hload hmake hop hsave ial ialclear " + + "ialmark identd if ignore iline inc invite iuser join kick linesep links list " + + "load loadbuf localinfo log mdi me menubar mkdir mnick mode msg nick noop notice " + + "notify omsg onotice part partall pdcc perform play playctrl pop protect pvoice " + + "qme qmsg query queryn quit raw reload remini remote remove rename renwin " + + "reseterror resetidle return rlevel rline rmdir run ruser save savebuf saveini " + + "say scid scon server set showmirc signam sline sockaccept sockclose socklist " + + "socklisten sockmark sockopen sockpause sockread sockrename sockudp sockwrite " + + "sound speak splay sreq strip switchbar timer timestamp titlebar tnick tokenize " + + "toolbar topic tray treebar ulist unload unset unsetall updatenl url uwho " + + "var vcadd vcmd vcrem vol while whois window winhelp write writeint if isalnum " + + "isalpha isaop isavoice isban ischan ishop isignore isin isincs isletter islower " + + "isnotify isnum ison isop isprotect isreg isupper isvoice iswm iswmcs " + + "elseif else goto menu nicklist status title icon size option text edit " + + "button check radio box scroll list combo link tab item"); + var functions = parseWords("if elseif else and not or eq ne in ni for foreach while switch"); + var isOperatorChar = /[+\-*&%=<>!?^\/\|]/; + function chain(stream, state, f) { + state.tokenize = f; + return f(stream, state); + } + function tokenBase(stream, state) { + var beforeParams = state.beforeParams; + state.beforeParams = false; + var ch = stream.next(); + if (/[\[\]{}\(\),\.]/.test(ch)) { + if (ch == "(" && beforeParams) state.inParams = true; + else if (ch == ")") state.inParams = false; + return null; + } + else if (/\d/.test(ch)) { + stream.eatWhile(/[\w\.]/); + return "number"; + } + else if (ch == "\\") { + stream.eat("\\"); + stream.eat(/./); + return "number"; + } + else if (ch == "/" && stream.eat("*")) { + return chain(stream, state, tokenComment); + } + else if (ch == ";" && stream.match(/ *\( *\(/)) { + return chain(stream, state, tokenUnparsed); + } + else if (ch == ";" && !state.inParams) { + stream.skipToEnd(); + return "comment"; + } + else if (ch == '"') { + stream.eat(/"/); + return "keyword"; + } + else if (ch == "$") { + stream.eatWhile(/[$_a-z0-9A-Z\.:]/); + if (specials && specials.propertyIsEnumerable(stream.current().toLowerCase())) { + return "keyword"; + } + else { + state.beforeParams = true; + return "builtin"; + } + } + else if (ch == "%") { + stream.eatWhile(/[^,^\s^\(^\)]/); + state.beforeParams = true; + return "string"; + } + else if (isOperatorChar.test(ch)) { + stream.eatWhile(isOperatorChar); + return "operator"; + } + else { + stream.eatWhile(/[\w\$_{}]/); + var word = stream.current().toLowerCase(); + if (keywords && keywords.propertyIsEnumerable(word)) + return "keyword"; + if (functions && functions.propertyIsEnumerable(word)) { + state.beforeParams = true; + return "keyword"; + } + return null; + } + } + function tokenComment(stream, state) { + var maybeEnd = false, ch; + while (ch = stream.next()) { + if (ch == "/" && maybeEnd) { + state.tokenize = tokenBase; + break; + } + maybeEnd = (ch == "*"); + } + return "comment"; + } + function tokenUnparsed(stream, state) { + var maybeEnd = 0, ch; + while (ch = stream.next()) { + if (ch == ";" && maybeEnd == 2) { + state.tokenize = tokenBase; + break; + } + if (ch == ")") + maybeEnd++; + else if (ch != " ") + maybeEnd = 0; + } + return "meta"; + } + return { + startState: function() { + return { + tokenize: tokenBase, + beforeParams: false, + inParams: false + }; + }, + token: function(stream, state) { + if (stream.eatSpace()) return null; + return state.tokenize(stream, state); + } + }; +}); + +}); diff --git a/static/js/mdeditor/lib/codemirror/mode/mllike/index.html b/static/js/mdeditor/lib/codemirror/mode/mllike/index.html new file mode 100644 index 00000000..5923af8f --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/mllike/index.html @@ -0,0 +1,179 @@ + + +CodeMirror: ML-like mode + + + + + + + + + + +
+

OCaml mode

+ + + + +

F# mode

+ + + + + +

MIME types defined: text/x-ocaml (OCaml) and text/x-fsharp (F#).

+
diff --git a/static/js/mdeditor/lib/codemirror/mode/mllike/mllike.js b/static/js/mdeditor/lib/codemirror/mode/mllike/mllike.js new file mode 100644 index 00000000..04ab1c98 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/mllike/mllike.js @@ -0,0 +1,205 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode('mllike', function(_config, parserConfig) { + var words = { + 'let': 'keyword', + 'rec': 'keyword', + 'in': 'keyword', + 'of': 'keyword', + 'and': 'keyword', + 'if': 'keyword', + 'then': 'keyword', + 'else': 'keyword', + 'for': 'keyword', + 'to': 'keyword', + 'while': 'keyword', + 'do': 'keyword', + 'done': 'keyword', + 'fun': 'keyword', + 'function': 'keyword', + 'val': 'keyword', + 'type': 'keyword', + 'mutable': 'keyword', + 'match': 'keyword', + 'with': 'keyword', + 'try': 'keyword', + 'open': 'builtin', + 'ignore': 'builtin', + 'begin': 'keyword', + 'end': 'keyword' + }; + + var extraWords = parserConfig.extraWords || {}; + for (var prop in extraWords) { + if (extraWords.hasOwnProperty(prop)) { + words[prop] = parserConfig.extraWords[prop]; + } + } + + function tokenBase(stream, state) { + var ch = stream.next(); + + if (ch === '"') { + state.tokenize = tokenString; + return state.tokenize(stream, state); + } + if (ch === '(') { + if (stream.eat('*')) { + state.commentLevel++; + state.tokenize = tokenComment; + return state.tokenize(stream, state); + } + } + if (ch === '~') { + stream.eatWhile(/\w/); + return 'variable-2'; + } + if (ch === '`') { + stream.eatWhile(/\w/); + return 'quote'; + } + if (ch === '/' && parserConfig.slashComments && stream.eat('/')) { + stream.skipToEnd(); + return 'comment'; + } + if (/\d/.test(ch)) { + stream.eatWhile(/[\d]/); + if (stream.eat('.')) { + stream.eatWhile(/[\d]/); + } + return 'number'; + } + if ( /[+\-*&%=<>!?|]/.test(ch)) { + return 'operator'; + } + stream.eatWhile(/\w/); + var cur = stream.current(); + return words[cur] || 'variable'; + } + + function tokenString(stream, state) { + var next, end = false, escaped = false; + while ((next = stream.next()) != null) { + if (next === '"' && !escaped) { + end = true; + break; + } + escaped = !escaped && next === '\\'; + } + if (end && !escaped) { + state.tokenize = tokenBase; + } + return 'string'; + }; + + function tokenComment(stream, state) { + var prev, next; + while(state.commentLevel > 0 && (next = stream.next()) != null) { + if (prev === '(' && next === '*') state.commentLevel++; + if (prev === '*' && next === ')') state.commentLevel--; + prev = next; + } + if (state.commentLevel <= 0) { + state.tokenize = tokenBase; + } + return 'comment'; + } + + return { + startState: function() {return {tokenize: tokenBase, commentLevel: 0};}, + token: function(stream, state) { + if (stream.eatSpace()) return null; + return state.tokenize(stream, state); + }, + + blockCommentStart: "(*", + blockCommentEnd: "*)", + lineComment: parserConfig.slashComments ? "//" : null + }; +}); + +CodeMirror.defineMIME('text/x-ocaml', { + name: 'mllike', + extraWords: { + 'succ': 'keyword', + 'trace': 'builtin', + 'exit': 'builtin', + 'print_string': 'builtin', + 'print_endline': 'builtin', + 'true': 'atom', + 'false': 'atom', + 'raise': 'keyword' + } +}); + +CodeMirror.defineMIME('text/x-fsharp', { + name: 'mllike', + extraWords: { + 'abstract': 'keyword', + 'as': 'keyword', + 'assert': 'keyword', + 'base': 'keyword', + 'class': 'keyword', + 'default': 'keyword', + 'delegate': 'keyword', + 'downcast': 'keyword', + 'downto': 'keyword', + 'elif': 'keyword', + 'exception': 'keyword', + 'extern': 'keyword', + 'finally': 'keyword', + 'global': 'keyword', + 'inherit': 'keyword', + 'inline': 'keyword', + 'interface': 'keyword', + 'internal': 'keyword', + 'lazy': 'keyword', + 'let!': 'keyword', + 'member' : 'keyword', + 'module': 'keyword', + 'namespace': 'keyword', + 'new': 'keyword', + 'null': 'keyword', + 'override': 'keyword', + 'private': 'keyword', + 'public': 'keyword', + 'return': 'keyword', + 'return!': 'keyword', + 'select': 'keyword', + 'static': 'keyword', + 'struct': 'keyword', + 'upcast': 'keyword', + 'use': 'keyword', + 'use!': 'keyword', + 'val': 'keyword', + 'when': 'keyword', + 'yield': 'keyword', + 'yield!': 'keyword', + + 'List': 'builtin', + 'Seq': 'builtin', + 'Map': 'builtin', + 'Set': 'builtin', + 'int': 'builtin', + 'string': 'builtin', + 'raise': 'builtin', + 'failwith': 'builtin', + 'not': 'builtin', + 'true': 'builtin', + 'false': 'builtin' + }, + slashComments: true +}); + +}); diff --git a/static/js/mdeditor/lib/codemirror/mode/modelica/index.html b/static/js/mdeditor/lib/codemirror/mode/modelica/index.html new file mode 100644 index 00000000..408c3b17 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/modelica/index.html @@ -0,0 +1,67 @@ + + +CodeMirror: Modelica mode + + + + + + + + + + + + +
+

Modelica mode

+ +
+ + + +

Simple mode that tries to handle Modelica as well as it can.

+ +

MIME types defined: text/x-modelica + (Modlica code).

+
diff --git a/static/js/mdeditor/lib/codemirror/mode/modelica/modelica.js b/static/js/mdeditor/lib/codemirror/mode/modelica/modelica.js new file mode 100644 index 00000000..77ec7a3c --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/modelica/modelica.js @@ -0,0 +1,245 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// Modelica support for CodeMirror, copyright (c) by Lennart Ochel + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +}) + +(function(CodeMirror) { + "use strict"; + + CodeMirror.defineMode("modelica", function(config, parserConfig) { + + var indentUnit = config.indentUnit; + var keywords = parserConfig.keywords || {}; + var builtin = parserConfig.builtin || {}; + var atoms = parserConfig.atoms || {}; + + var isSingleOperatorChar = /[;=\(:\),{}.*<>+\-\/^\[\]]/; + var isDoubleOperatorChar = /(:=|<=|>=|==|<>|\.\+|\.\-|\.\*|\.\/|\.\^)/; + var isDigit = /[0-9]/; + var isNonDigit = /[_a-zA-Z]/; + + function tokenLineComment(stream, state) { + stream.skipToEnd(); + state.tokenize = null; + return "comment"; + } + + function tokenBlockComment(stream, state) { + var maybeEnd = false, ch; + while (ch = stream.next()) { + if (maybeEnd && ch == "/") { + state.tokenize = null; + break; + } + maybeEnd = (ch == "*"); + } + return "comment"; + } + + function tokenString(stream, state) { + var escaped = false, ch; + while ((ch = stream.next()) != null) { + if (ch == '"' && !escaped) { + state.tokenize = null; + state.sol = false; + break; + } + escaped = !escaped && ch == "\\"; + } + + return "string"; + } + + function tokenIdent(stream, state) { + stream.eatWhile(isDigit); + while (stream.eat(isDigit) || stream.eat(isNonDigit)) { } + + + var cur = stream.current(); + + if(state.sol && (cur == "package" || cur == "model" || cur == "when" || cur == "connector")) state.level++; + else if(state.sol && cur == "end" && state.level > 0) state.level--; + + state.tokenize = null; + state.sol = false; + + if (keywords.propertyIsEnumerable(cur)) return "keyword"; + else if (builtin.propertyIsEnumerable(cur)) return "builtin"; + else if (atoms.propertyIsEnumerable(cur)) return "atom"; + else return "variable"; + } + + function tokenQIdent(stream, state) { + while (stream.eat(/[^']/)) { } + + state.tokenize = null; + state.sol = false; + + if(stream.eat("'")) + return "variable"; + else + return "error"; + } + + function tokenUnsignedNuber(stream, state) { + stream.eatWhile(isDigit); + if (stream.eat('.')) { + stream.eatWhile(isDigit); + } + if (stream.eat('e') || stream.eat('E')) { + if (!stream.eat('-')) + stream.eat('+'); + stream.eatWhile(isDigit); + } + + state.tokenize = null; + state.sol = false; + return "number"; + } + + // Interface + return { + startState: function() { + return { + tokenize: null, + level: 0, + sol: true + }; + }, + + token: function(stream, state) { + if(state.tokenize != null) { + return state.tokenize(stream, state); + } + + if(stream.sol()) { + state.sol = true; + } + + // WHITESPACE + if(stream.eatSpace()) { + state.tokenize = null; + return null; + } + + var ch = stream.next(); + + // LINECOMMENT + if(ch == '/' && stream.eat('/')) { + state.tokenize = tokenLineComment; + } + // BLOCKCOMMENT + else if(ch == '/' && stream.eat('*')) { + state.tokenize = tokenBlockComment; + } + // TWO SYMBOL TOKENS + else if(isDoubleOperatorChar.test(ch+stream.peek())) { + stream.next(); + state.tokenize = null; + return "operator"; + } + // SINGLE SYMBOL TOKENS + else if(isSingleOperatorChar.test(ch)) { + state.tokenize = null; + return "operator"; + } + // IDENT + else if(isNonDigit.test(ch)) { + state.tokenize = tokenIdent; + } + // Q-IDENT + else if(ch == "'" && stream.peek() && stream.peek() != "'") { + state.tokenize = tokenQIdent; + } + // STRING + else if(ch == '"') { + state.tokenize = tokenString; + } + // UNSIGNED_NUBER + else if(isDigit.test(ch)) { + state.tokenize = tokenUnsignedNuber; + } + // ERROR + else { + state.tokenize = null; + return "error"; + } + + return state.tokenize(stream, state); + }, + + indent: function(state, textAfter) { + if (state.tokenize != null) return CodeMirror.Pass; + + var level = state.level; + if(/(algorithm)/.test(textAfter)) level--; + if(/(equation)/.test(textAfter)) level--; + if(/(initial algorithm)/.test(textAfter)) level--; + if(/(initial equation)/.test(textAfter)) level--; + if(/(end)/.test(textAfter)) level--; + + if(level > 0) + return indentUnit*level; + else + return 0; + }, + + blockCommentStart: "/*", + blockCommentEnd: "*/", + lineComment: "//" + }; + }); + + function words(str) { + var obj = {}, words = str.split(" "); + for (var i=0; i + +CodeMirror: NGINX mode + + + + + + + + + + + + + +
+

NGINX mode

+
+ + +

MIME types defined: text/nginx.

+ +
diff --git a/static/js/mdeditor/lib/codemirror/mode/nginx/nginx.js b/static/js/mdeditor/lib/codemirror/mode/nginx/nginx.js new file mode 100644 index 00000000..135b9cc7 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/nginx/nginx.js @@ -0,0 +1,178 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("nginx", function(config) { + + function words(str) { + var obj = {}, words = str.split(" "); + for (var i = 0; i < words.length; ++i) obj[words[i]] = true; + return obj; + } + + var keywords = words( + /* ngxDirectiveControl */ "break return rewrite set" + + /* ngxDirective */ " accept_mutex accept_mutex_delay access_log add_after_body add_before_body add_header addition_types aio alias allow ancient_browser ancient_browser_value auth_basic auth_basic_user_file auth_http auth_http_header auth_http_timeout autoindex autoindex_exact_size autoindex_localtime charset charset_types client_body_buffer_size client_body_in_file_only client_body_in_single_buffer client_body_temp_path client_body_timeout client_header_buffer_size client_header_timeout client_max_body_size connection_pool_size create_full_put_path daemon dav_access dav_methods debug_connection debug_points default_type degradation degrade deny devpoll_changes devpoll_events directio directio_alignment empty_gif env epoll_events error_log eventport_events expires fastcgi_bind fastcgi_buffer_size fastcgi_buffers fastcgi_busy_buffers_size fastcgi_cache fastcgi_cache_key fastcgi_cache_methods fastcgi_cache_min_uses fastcgi_cache_path fastcgi_cache_use_stale fastcgi_cache_valid fastcgi_catch_stderr fastcgi_connect_timeout fastcgi_hide_header fastcgi_ignore_client_abort fastcgi_ignore_headers fastcgi_index fastcgi_intercept_errors fastcgi_max_temp_file_size fastcgi_next_upstream fastcgi_param fastcgi_pass_header fastcgi_pass_request_body fastcgi_pass_request_headers fastcgi_read_timeout fastcgi_send_lowat fastcgi_send_timeout fastcgi_split_path_info fastcgi_store fastcgi_store_access fastcgi_temp_file_write_size fastcgi_temp_path fastcgi_upstream_fail_timeout fastcgi_upstream_max_fails flv geoip_city geoip_country google_perftools_profiles gzip gzip_buffers gzip_comp_level gzip_disable gzip_hash gzip_http_version gzip_min_length gzip_no_buffer gzip_proxied gzip_static gzip_types gzip_vary gzip_window if_modified_since ignore_invalid_headers image_filter image_filter_buffer image_filter_jpeg_quality image_filter_transparency imap_auth imap_capabilities imap_client_buffer index ip_hash keepalive_requests keepalive_timeout kqueue_changes kqueue_events large_client_header_buffers limit_conn limit_conn_log_level limit_rate limit_rate_after limit_req limit_req_log_level limit_req_zone limit_zone lingering_time lingering_timeout lock_file log_format log_not_found log_subrequest map_hash_bucket_size map_hash_max_size master_process memcached_bind memcached_buffer_size memcached_connect_timeout memcached_next_upstream memcached_read_timeout memcached_send_timeout memcached_upstream_fail_timeout memcached_upstream_max_fails merge_slashes min_delete_depth modern_browser modern_browser_value msie_padding msie_refresh multi_accept open_file_cache open_file_cache_errors open_file_cache_events open_file_cache_min_uses open_file_cache_valid open_log_file_cache output_buffers override_charset perl perl_modules perl_require perl_set pid pop3_auth pop3_capabilities port_in_redirect postpone_gzipping postpone_output protocol proxy proxy_bind proxy_buffer proxy_buffer_size proxy_buffering proxy_buffers proxy_busy_buffers_size proxy_cache proxy_cache_key proxy_cache_methods proxy_cache_min_uses proxy_cache_path proxy_cache_use_stale proxy_cache_valid proxy_connect_timeout proxy_headers_hash_bucket_size proxy_headers_hash_max_size proxy_hide_header proxy_ignore_client_abort proxy_ignore_headers proxy_intercept_errors proxy_max_temp_file_size proxy_method proxy_next_upstream proxy_pass_error_message proxy_pass_header proxy_pass_request_body proxy_pass_request_headers proxy_read_timeout proxy_redirect proxy_send_lowat proxy_send_timeout proxy_set_body proxy_set_header proxy_ssl_session_reuse proxy_store proxy_store_access proxy_temp_file_write_size proxy_temp_path proxy_timeout proxy_upstream_fail_timeout proxy_upstream_max_fails random_index read_ahead real_ip_header recursive_error_pages request_pool_size reset_timedout_connection resolver resolver_timeout rewrite_log rtsig_overflow_events rtsig_overflow_test rtsig_overflow_threshold rtsig_signo satisfy secure_link_secret send_lowat send_timeout sendfile sendfile_max_chunk server_name_in_redirect server_names_hash_bucket_size server_names_hash_max_size server_tokens set_real_ip_from smtp_auth smtp_capabilities smtp_client_buffer smtp_greeting_delay so_keepalive source_charset ssi ssi_ignore_recycled_buffers ssi_min_file_chunk ssi_silent_errors ssi_types ssi_value_length ssl ssl_certificate ssl_certificate_key ssl_ciphers ssl_client_certificate ssl_crl ssl_dhparam ssl_engine ssl_prefer_server_ciphers ssl_protocols ssl_session_cache ssl_session_timeout ssl_verify_client ssl_verify_depth starttls stub_status sub_filter sub_filter_once sub_filter_types tcp_nodelay tcp_nopush thread_stack_size timeout timer_resolution types_hash_bucket_size types_hash_max_size underscores_in_headers uninitialized_variable_warn use user userid userid_domain userid_expires userid_mark userid_name userid_p3p userid_path userid_service valid_referers variables_hash_bucket_size variables_hash_max_size worker_connections worker_cpu_affinity worker_priority worker_processes worker_rlimit_core worker_rlimit_nofile worker_rlimit_sigpending worker_threads working_directory xclient xml_entities xslt_stylesheet xslt_typesdrew@li229-23" + ); + + var keywords_block = words( + /* ngxDirectiveBlock */ "http mail events server types location upstream charset_map limit_except if geo map" + ); + + var keywords_important = words( + /* ngxDirectiveImportant */ "include root server server_name listen internal proxy_pass memcached_pass fastcgi_pass try_files" + ); + + var indentUnit = config.indentUnit, type; + function ret(style, tp) {type = tp; return style;} + + function tokenBase(stream, state) { + + + stream.eatWhile(/[\w\$_]/); + + var cur = stream.current(); + + + if (keywords.propertyIsEnumerable(cur)) { + return "keyword"; + } + else if (keywords_block.propertyIsEnumerable(cur)) { + return "variable-2"; + } + else if (keywords_important.propertyIsEnumerable(cur)) { + return "string-2"; + } + /**/ + + var ch = stream.next(); + if (ch == "@") {stream.eatWhile(/[\w\\\-]/); return ret("meta", stream.current());} + else if (ch == "/" && stream.eat("*")) { + state.tokenize = tokenCComment; + return tokenCComment(stream, state); + } + else if (ch == "<" && stream.eat("!")) { + state.tokenize = tokenSGMLComment; + return tokenSGMLComment(stream, state); + } + else if (ch == "=") ret(null, "compare"); + else if ((ch == "~" || ch == "|") && stream.eat("=")) return ret(null, "compare"); + else if (ch == "\"" || ch == "'") { + state.tokenize = tokenString(ch); + return state.tokenize(stream, state); + } + else if (ch == "#") { + stream.skipToEnd(); + return ret("comment", "comment"); + } + else if (ch == "!") { + stream.match(/^\s*\w*/); + return ret("keyword", "important"); + } + else if (/\d/.test(ch)) { + stream.eatWhile(/[\w.%]/); + return ret("number", "unit"); + } + else if (/[,.+>*\/]/.test(ch)) { + return ret(null, "select-op"); + } + else if (/[;{}:\[\]]/.test(ch)) { + return ret(null, ch); + } + else { + stream.eatWhile(/[\w\\\-]/); + return ret("variable", "variable"); + } + } + + function tokenCComment(stream, state) { + var maybeEnd = false, ch; + while ((ch = stream.next()) != null) { + if (maybeEnd && ch == "/") { + state.tokenize = tokenBase; + break; + } + maybeEnd = (ch == "*"); + } + return ret("comment", "comment"); + } + + function tokenSGMLComment(stream, state) { + var dashes = 0, ch; + while ((ch = stream.next()) != null) { + if (dashes >= 2 && ch == ">") { + state.tokenize = tokenBase; + break; + } + dashes = (ch == "-") ? dashes + 1 : 0; + } + return ret("comment", "comment"); + } + + function tokenString(quote) { + return function(stream, state) { + var escaped = false, ch; + while ((ch = stream.next()) != null) { + if (ch == quote && !escaped) + break; + escaped = !escaped && ch == "\\"; + } + if (!escaped) state.tokenize = tokenBase; + return ret("string", "string"); + }; + } + + return { + startState: function(base) { + return {tokenize: tokenBase, + baseIndent: base || 0, + stack: []}; + }, + + token: function(stream, state) { + if (stream.eatSpace()) return null; + type = null; + var style = state.tokenize(stream, state); + + var context = state.stack[state.stack.length-1]; + if (type == "hash" && context == "rule") style = "atom"; + else if (style == "variable") { + if (context == "rule") style = "number"; + else if (!context || context == "@media{") style = "tag"; + } + + if (context == "rule" && /^[\{\};]$/.test(type)) + state.stack.pop(); + if (type == "{") { + if (context == "@media") state.stack[state.stack.length-1] = "@media{"; + else state.stack.push("{"); + } + else if (type == "}") state.stack.pop(); + else if (type == "@media") state.stack.push("@media"); + else if (context == "{" && type != "comment") state.stack.push("rule"); + return style; + }, + + indent: function(state, textAfter) { + var n = state.stack.length; + if (/^\}/.test(textAfter)) + n -= state.stack[state.stack.length-1] == "rule" ? 2 : 1; + return state.baseIndent + n * indentUnit; + }, + + electricChars: "}" + }; +}); + +CodeMirror.defineMIME("text/nginx", "text/x-nginx-conf"); + +}); diff --git a/static/js/mdeditor/lib/codemirror/mode/ntriples/index.html b/static/js/mdeditor/lib/codemirror/mode/ntriples/index.html new file mode 100644 index 00000000..1355e718 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/ntriples/index.html @@ -0,0 +1,45 @@ + + +CodeMirror: NTriples mode + + + + + + + + + +
+

NTriples mode

+
+ +
+ + +

MIME types defined: text/n-triples.

+
diff --git a/static/js/mdeditor/lib/codemirror/mode/ntriples/ntriples.js b/static/js/mdeditor/lib/codemirror/mode/ntriples/ntriples.js new file mode 100644 index 00000000..0524b1e8 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/ntriples/ntriples.js @@ -0,0 +1,186 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +/********************************************************** +* This script provides syntax highlighting support for +* the Ntriples format. +* Ntriples format specification: +* http://www.w3.org/TR/rdf-testcases/#ntriples +***********************************************************/ + +/* + The following expression defines the defined ASF grammar transitions. + + pre_subject -> + { + ( writing_subject_uri | writing_bnode_uri ) + -> pre_predicate + -> writing_predicate_uri + -> pre_object + -> writing_object_uri | writing_object_bnode | + ( + writing_object_literal + -> writing_literal_lang | writing_literal_type + ) + -> post_object + -> BEGIN + } otherwise { + -> ERROR + } +*/ + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("ntriples", function() { + + var Location = { + PRE_SUBJECT : 0, + WRITING_SUB_URI : 1, + WRITING_BNODE_URI : 2, + PRE_PRED : 3, + WRITING_PRED_URI : 4, + PRE_OBJ : 5, + WRITING_OBJ_URI : 6, + WRITING_OBJ_BNODE : 7, + WRITING_OBJ_LITERAL : 8, + WRITING_LIT_LANG : 9, + WRITING_LIT_TYPE : 10, + POST_OBJ : 11, + ERROR : 12 + }; + function transitState(currState, c) { + var currLocation = currState.location; + var ret; + + // Opening. + if (currLocation == Location.PRE_SUBJECT && c == '<') ret = Location.WRITING_SUB_URI; + else if(currLocation == Location.PRE_SUBJECT && c == '_') ret = Location.WRITING_BNODE_URI; + else if(currLocation == Location.PRE_PRED && c == '<') ret = Location.WRITING_PRED_URI; + else if(currLocation == Location.PRE_OBJ && c == '<') ret = Location.WRITING_OBJ_URI; + else if(currLocation == Location.PRE_OBJ && c == '_') ret = Location.WRITING_OBJ_BNODE; + else if(currLocation == Location.PRE_OBJ && c == '"') ret = Location.WRITING_OBJ_LITERAL; + + // Closing. + else if(currLocation == Location.WRITING_SUB_URI && c == '>') ret = Location.PRE_PRED; + else if(currLocation == Location.WRITING_BNODE_URI && c == ' ') ret = Location.PRE_PRED; + else if(currLocation == Location.WRITING_PRED_URI && c == '>') ret = Location.PRE_OBJ; + else if(currLocation == Location.WRITING_OBJ_URI && c == '>') ret = Location.POST_OBJ; + else if(currLocation == Location.WRITING_OBJ_BNODE && c == ' ') ret = Location.POST_OBJ; + else if(currLocation == Location.WRITING_OBJ_LITERAL && c == '"') ret = Location.POST_OBJ; + else if(currLocation == Location.WRITING_LIT_LANG && c == ' ') ret = Location.POST_OBJ; + else if(currLocation == Location.WRITING_LIT_TYPE && c == '>') ret = Location.POST_OBJ; + + // Closing typed and language literal. + else if(currLocation == Location.WRITING_OBJ_LITERAL && c == '@') ret = Location.WRITING_LIT_LANG; + else if(currLocation == Location.WRITING_OBJ_LITERAL && c == '^') ret = Location.WRITING_LIT_TYPE; + + // Spaces. + else if( c == ' ' && + ( + currLocation == Location.PRE_SUBJECT || + currLocation == Location.PRE_PRED || + currLocation == Location.PRE_OBJ || + currLocation == Location.POST_OBJ + ) + ) ret = currLocation; + + // Reset. + else if(currLocation == Location.POST_OBJ && c == '.') ret = Location.PRE_SUBJECT; + + // Error + else ret = Location.ERROR; + + currState.location=ret; + } + + return { + startState: function() { + return { + location : Location.PRE_SUBJECT, + uris : [], + anchors : [], + bnodes : [], + langs : [], + types : [] + }; + }, + token: function(stream, state) { + var ch = stream.next(); + if(ch == '<') { + transitState(state, ch); + var parsedURI = ''; + stream.eatWhile( function(c) { if( c != '#' && c != '>' ) { parsedURI += c; return true; } return false;} ); + state.uris.push(parsedURI); + if( stream.match('#', false) ) return 'variable'; + stream.next(); + transitState(state, '>'); + return 'variable'; + } + if(ch == '#') { + var parsedAnchor = ''; + stream.eatWhile(function(c) { if(c != '>' && c != ' ') { parsedAnchor+= c; return true; } return false;}); + state.anchors.push(parsedAnchor); + return 'variable-2'; + } + if(ch == '>') { + transitState(state, '>'); + return 'variable'; + } + if(ch == '_') { + transitState(state, ch); + var parsedBNode = ''; + stream.eatWhile(function(c) { if( c != ' ' ) { parsedBNode += c; return true; } return false;}); + state.bnodes.push(parsedBNode); + stream.next(); + transitState(state, ' '); + return 'builtin'; + } + if(ch == '"') { + transitState(state, ch); + stream.eatWhile( function(c) { return c != '"'; } ); + stream.next(); + if( stream.peek() != '@' && stream.peek() != '^' ) { + transitState(state, '"'); + } + return 'string'; + } + if( ch == '@' ) { + transitState(state, '@'); + var parsedLang = ''; + stream.eatWhile(function(c) { if( c != ' ' ) { parsedLang += c; return true; } return false;}); + state.langs.push(parsedLang); + stream.next(); + transitState(state, ' '); + return 'string-2'; + } + if( ch == '^' ) { + stream.next(); + transitState(state, '^'); + var parsedType = ''; + stream.eatWhile(function(c) { if( c != '>' ) { parsedType += c; return true; } return false;} ); + state.types.push(parsedType); + stream.next(); + transitState(state, '>'); + return 'variable'; + } + if( ch == ' ' ) { + transitState(state, ch); + } + if( ch == '.' ) { + transitState(state, ch); + } + } + }; +}); + +CodeMirror.defineMIME("text/n-triples", "ntriples"); + +}); diff --git a/static/js/mdeditor/lib/codemirror/mode/octave/index.html b/static/js/mdeditor/lib/codemirror/mode/octave/index.html new file mode 100644 index 00000000..79df5811 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/octave/index.html @@ -0,0 +1,83 @@ + + +CodeMirror: Octave mode + + + + + + + + + +
+

Octave mode

+ +
+ + +

MIME types defined: text/x-octave.

+
diff --git a/static/js/mdeditor/lib/codemirror/mode/octave/octave.js b/static/js/mdeditor/lib/codemirror/mode/octave/octave.js new file mode 100644 index 00000000..a7bec030 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/octave/octave.js @@ -0,0 +1,135 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("octave", function() { + function wordRegexp(words) { + return new RegExp("^((" + words.join(")|(") + "))\\b"); + } + + var singleOperators = new RegExp("^[\\+\\-\\*/&|\\^~<>!@'\\\\]"); + var singleDelimiters = new RegExp('^[\\(\\[\\{\\},:=;]'); + var doubleOperators = new RegExp("^((==)|(~=)|(<=)|(>=)|(<<)|(>>)|(\\.[\\+\\-\\*/\\^\\\\]))"); + var doubleDelimiters = new RegExp("^((!=)|(\\+=)|(\\-=)|(\\*=)|(/=)|(&=)|(\\|=)|(\\^=))"); + var tripleDelimiters = new RegExp("^((>>=)|(<<=))"); + var expressionEnd = new RegExp("^[\\]\\)]"); + var identifiers = new RegExp("^[_A-Za-z\xa1-\uffff][_A-Za-z0-9\xa1-\uffff]*"); + + var builtins = wordRegexp([ + 'error', 'eval', 'function', 'abs', 'acos', 'atan', 'asin', 'cos', + 'cosh', 'exp', 'log', 'prod', 'sum', 'log10', 'max', 'min', 'sign', 'sin', 'sinh', + 'sqrt', 'tan', 'reshape', 'break', 'zeros', 'default', 'margin', 'round', 'ones', + 'rand', 'syn', 'ceil', 'floor', 'size', 'clear', 'zeros', 'eye', 'mean', 'std', 'cov', + 'det', 'eig', 'inv', 'norm', 'rank', 'trace', 'expm', 'logm', 'sqrtm', 'linspace', 'plot', + 'title', 'xlabel', 'ylabel', 'legend', 'text', 'grid', 'meshgrid', 'mesh', 'num2str', + 'fft', 'ifft', 'arrayfun', 'cellfun', 'input', 'fliplr', 'flipud', 'ismember' + ]); + + var keywords = wordRegexp([ + 'return', 'case', 'switch', 'else', 'elseif', 'end', 'endif', 'endfunction', + 'if', 'otherwise', 'do', 'for', 'while', 'try', 'catch', 'classdef', 'properties', 'events', + 'methods', 'global', 'persistent', 'endfor', 'endwhile', 'printf', 'sprintf', 'disp', 'until', + 'continue', 'pkg' + ]); + + + // tokenizers + function tokenTranspose(stream, state) { + if (!stream.sol() && stream.peek() === '\'') { + stream.next(); + state.tokenize = tokenBase; + return 'operator'; + } + state.tokenize = tokenBase; + return tokenBase(stream, state); + } + + + function tokenComment(stream, state) { + if (stream.match(/^.*%}/)) { + state.tokenize = tokenBase; + return 'comment'; + }; + stream.skipToEnd(); + return 'comment'; + } + + function tokenBase(stream, state) { + // whitespaces + if (stream.eatSpace()) return null; + + // Handle one line Comments + if (stream.match('%{')){ + state.tokenize = tokenComment; + stream.skipToEnd(); + return 'comment'; + } + + if (stream.match(/^[%#]/)){ + stream.skipToEnd(); + return 'comment'; + } + + // Handle Number Literals + if (stream.match(/^[0-9\.+-]/, false)) { + if (stream.match(/^[+-]?0x[0-9a-fA-F]+[ij]?/)) { + stream.tokenize = tokenBase; + return 'number'; }; + if (stream.match(/^[+-]?\d*\.\d+([EeDd][+-]?\d+)?[ij]?/)) { return 'number'; }; + if (stream.match(/^[+-]?\d+([EeDd][+-]?\d+)?[ij]?/)) { return 'number'; }; + } + if (stream.match(wordRegexp(['nan','NaN','inf','Inf']))) { return 'number'; }; + + // Handle Strings + if (stream.match(/^"([^"]|(""))*"/)) { return 'string'; } ; + if (stream.match(/^'([^']|(''))*'/)) { return 'string'; } ; + + // Handle words + if (stream.match(keywords)) { return 'keyword'; } ; + if (stream.match(builtins)) { return 'builtin'; } ; + if (stream.match(identifiers)) { return 'variable'; } ; + + if (stream.match(singleOperators) || stream.match(doubleOperators)) { return 'operator'; }; + if (stream.match(singleDelimiters) || stream.match(doubleDelimiters) || stream.match(tripleDelimiters)) { return null; }; + + if (stream.match(expressionEnd)) { + state.tokenize = tokenTranspose; + return null; + }; + + + // Handle non-detected items + stream.next(); + return 'error'; + }; + + + return { + startState: function() { + return { + tokenize: tokenBase + }; + }, + + token: function(stream, state) { + var style = state.tokenize(stream, state); + if (style === 'number' || style === 'variable'){ + state.tokenize = tokenTranspose; + } + return style; + } + }; +}); + +CodeMirror.defineMIME("text/x-octave", "octave"); + +}); diff --git a/static/js/mdeditor/lib/codemirror/mode/pascal/index.html b/static/js/mdeditor/lib/codemirror/mode/pascal/index.html new file mode 100644 index 00000000..f8a99ad0 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/pascal/index.html @@ -0,0 +1,61 @@ + + +CodeMirror: Pascal mode + + + + + + + + + +
+

Pascal mode

+ + +
+ + + +

MIME types defined: text/x-pascal.

+
diff --git a/static/js/mdeditor/lib/codemirror/mode/pascal/pascal.js b/static/js/mdeditor/lib/codemirror/mode/pascal/pascal.js new file mode 100644 index 00000000..2d0c3d42 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/pascal/pascal.js @@ -0,0 +1,109 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("pascal", function() { + function words(str) { + var obj = {}, words = str.split(" "); + for (var i = 0; i < words.length; ++i) obj[words[i]] = true; + return obj; + } + var keywords = words("and array begin case const div do downto else end file for forward integer " + + "boolean char function goto if in label mod nil not of or packed procedure " + + "program record repeat set string then to type until var while with"); + var atoms = {"null": true}; + + var isOperatorChar = /[+\-*&%=<>!?|\/]/; + + function tokenBase(stream, state) { + var ch = stream.next(); + if (ch == "#" && state.startOfLine) { + stream.skipToEnd(); + return "meta"; + } + if (ch == '"' || ch == "'") { + state.tokenize = tokenString(ch); + return state.tokenize(stream, state); + } + if (ch == "(" && stream.eat("*")) { + state.tokenize = tokenComment; + return tokenComment(stream, state); + } + if (/[\[\]{}\(\),;\:\.]/.test(ch)) { + return null; + } + if (/\d/.test(ch)) { + stream.eatWhile(/[\w\.]/); + return "number"; + } + if (ch == "/") { + if (stream.eat("/")) { + stream.skipToEnd(); + return "comment"; + } + } + if (isOperatorChar.test(ch)) { + stream.eatWhile(isOperatorChar); + return "operator"; + } + stream.eatWhile(/[\w\$_]/); + var cur = stream.current(); + if (keywords.propertyIsEnumerable(cur)) return "keyword"; + if (atoms.propertyIsEnumerable(cur)) return "atom"; + return "variable"; + } + + function tokenString(quote) { + return function(stream, state) { + var escaped = false, next, end = false; + while ((next = stream.next()) != null) { + if (next == quote && !escaped) {end = true; break;} + escaped = !escaped && next == "\\"; + } + if (end || !escaped) state.tokenize = null; + return "string"; + }; + } + + function tokenComment(stream, state) { + var maybeEnd = false, ch; + while (ch = stream.next()) { + if (ch == ")" && maybeEnd) { + state.tokenize = null; + break; + } + maybeEnd = (ch == "*"); + } + return "comment"; + } + + // Interface + + return { + startState: function() { + return {tokenize: null}; + }, + + token: function(stream, state) { + if (stream.eatSpace()) return null; + var style = (state.tokenize || tokenBase)(stream, state); + if (style == "comment" || style == "meta") return style; + return style; + }, + + electricChars: "{}" + }; +}); + +CodeMirror.defineMIME("text/x-pascal", "pascal"); + +}); diff --git a/static/js/mdeditor/lib/codemirror/mode/pegjs/index.html b/static/js/mdeditor/lib/codemirror/mode/pegjs/index.html new file mode 100644 index 00000000..0c746048 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/pegjs/index.html @@ -0,0 +1,66 @@ + + + + CodeMirror: PEG.js Mode + + + + + + + + + + + + +
+

PEG.js Mode

+
+ +

The PEG.js Mode

+

Created by Forbes Lindesay.

+
+ + diff --git a/static/js/mdeditor/lib/codemirror/mode/pegjs/pegjs.js b/static/js/mdeditor/lib/codemirror/mode/pegjs/pegjs.js new file mode 100644 index 00000000..306e3768 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/pegjs/pegjs.js @@ -0,0 +1,114 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../javascript/javascript")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../javascript/javascript"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("pegjs", function (config) { + var jsMode = CodeMirror.getMode(config, "javascript"); + + function identifier(stream) { + return stream.match(/^[a-zA-Z_][a-zA-Z0-9_]*/); + } + + return { + startState: function () { + return { + inString: false, + stringType: null, + inComment: false, + inChracterClass: false, + braced: 0, + lhs: true, + localState: null + }; + }, + token: function (stream, state) { + if (stream) + + //check for state changes + if (!state.inString && !state.inComment && ((stream.peek() == '"') || (stream.peek() == "'"))) { + state.stringType = stream.peek(); + stream.next(); // Skip quote + state.inString = true; // Update state + } + if (!state.inString && !state.inComment && stream.match(/^\/\*/)) { + state.inComment = true; + } + + //return state + if (state.inString) { + while (state.inString && !stream.eol()) { + if (stream.peek() === state.stringType) { + stream.next(); // Skip quote + state.inString = false; // Clear flag + } else if (stream.peek() === '\\') { + stream.next(); + stream.next(); + } else { + stream.match(/^.[^\\\"\']*/); + } + } + return state.lhs ? "property string" : "string"; // Token style + } else if (state.inComment) { + while (state.inComment && !stream.eol()) { + if (stream.match(/\*\//)) { + state.inComment = false; // Clear flag + } else { + stream.match(/^.[^\*]*/); + } + } + return "comment"; + } else if (state.inChracterClass) { + while (state.inChracterClass && !stream.eol()) { + if (!(stream.match(/^[^\]\\]+/) || stream.match(/^\\./))) { + state.inChracterClass = false; + } + } + } else if (stream.peek() === '[') { + stream.next(); + state.inChracterClass = true; + return 'bracket'; + } else if (stream.match(/^\/\//)) { + stream.skipToEnd(); + return "comment"; + } else if (state.braced || stream.peek() === '{') { + if (state.localState === null) { + state.localState = jsMode.startState(); + } + var token = jsMode.token(stream, state.localState); + var text = stream.current(); + if (!token) { + for (var i = 0; i < text.length; i++) { + if (text[i] === '{') { + state.braced++; + } else if (text[i] === '}') { + state.braced--; + } + }; + } + return token; + } else if (identifier(stream)) { + if (stream.peek() === ':') { + return 'variable'; + } + return 'variable-2'; + } else if (['[', ']', '(', ')'].indexOf(stream.peek()) != -1) { + stream.next(); + return 'bracket'; + } else if (!stream.eatSpace()) { + stream.next(); + } + return null; + } + }; +}, "javascript"); + +}); diff --git a/static/js/mdeditor/lib/codemirror/mode/perl/index.html b/static/js/mdeditor/lib/codemirror/mode/perl/index.html new file mode 100644 index 00000000..8c1021c4 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/perl/index.html @@ -0,0 +1,75 @@ + + +CodeMirror: Perl mode + + + + + + + + + +
+

Perl mode

+ + +
+ + + +

MIME types defined: text/x-perl.

+
diff --git a/static/js/mdeditor/lib/codemirror/mode/perl/perl.js b/static/js/mdeditor/lib/codemirror/mode/perl/perl.js new file mode 100644 index 00000000..bef62bc7 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/perl/perl.js @@ -0,0 +1,837 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// CodeMirror2 mode/perl/perl.js (text/x-perl) beta 0.10 (2011-11-08) +// This is a part of CodeMirror from https://github.com/sabaca/CodeMirror_mode_perl (mail@sabaca.com) + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("perl",function(){ + // http://perldoc.perl.org + var PERL={ // null - magic touch + // 1 - keyword + // 2 - def + // 3 - atom + // 4 - operator + // 5 - variable-2 (predefined) + // [x,y] - x=1,2,3; y=must be defined if x{...} + // PERL operators + '->' : 4, + '++' : 4, + '--' : 4, + '**' : 4, + // ! ~ \ and unary + and - + '=~' : 4, + '!~' : 4, + '*' : 4, + '/' : 4, + '%' : 4, + 'x' : 4, + '+' : 4, + '-' : 4, + '.' : 4, + '<<' : 4, + '>>' : 4, + // named unary operators + '<' : 4, + '>' : 4, + '<=' : 4, + '>=' : 4, + 'lt' : 4, + 'gt' : 4, + 'le' : 4, + 'ge' : 4, + '==' : 4, + '!=' : 4, + '<=>' : 4, + 'eq' : 4, + 'ne' : 4, + 'cmp' : 4, + '~~' : 4, + '&' : 4, + '|' : 4, + '^' : 4, + '&&' : 4, + '||' : 4, + '//' : 4, + '..' : 4, + '...' : 4, + '?' : 4, + ':' : 4, + '=' : 4, + '+=' : 4, + '-=' : 4, + '*=' : 4, // etc. ??? + ',' : 4, + '=>' : 4, + '::' : 4, + // list operators (rightward) + 'not' : 4, + 'and' : 4, + 'or' : 4, + 'xor' : 4, + // PERL predefined variables (I know, what this is a paranoid idea, but may be needed for people, who learn PERL, and for me as well, ...and may be for you?;) + 'BEGIN' : [5,1], + 'END' : [5,1], + 'PRINT' : [5,1], + 'PRINTF' : [5,1], + 'GETC' : [5,1], + 'READ' : [5,1], + 'READLINE' : [5,1], + 'DESTROY' : [5,1], + 'TIE' : [5,1], + 'TIEHANDLE' : [5,1], + 'UNTIE' : [5,1], + 'STDIN' : 5, + 'STDIN_TOP' : 5, + 'STDOUT' : 5, + 'STDOUT_TOP' : 5, + 'STDERR' : 5, + 'STDERR_TOP' : 5, + '$ARG' : 5, + '$_' : 5, + '@ARG' : 5, + '@_' : 5, + '$LIST_SEPARATOR' : 5, + '$"' : 5, + '$PROCESS_ID' : 5, + '$PID' : 5, + '$$' : 5, + '$REAL_GROUP_ID' : 5, + '$GID' : 5, + '$(' : 5, + '$EFFECTIVE_GROUP_ID' : 5, + '$EGID' : 5, + '$)' : 5, + '$PROGRAM_NAME' : 5, + '$0' : 5, + '$SUBSCRIPT_SEPARATOR' : 5, + '$SUBSEP' : 5, + '$;' : 5, + '$REAL_USER_ID' : 5, + '$UID' : 5, + '$<' : 5, + '$EFFECTIVE_USER_ID' : 5, + '$EUID' : 5, + '$>' : 5, + '$a' : 5, + '$b' : 5, + '$COMPILING' : 5, + '$^C' : 5, + '$DEBUGGING' : 5, + '$^D' : 5, + '${^ENCODING}' : 5, + '$ENV' : 5, + '%ENV' : 5, + '$SYSTEM_FD_MAX' : 5, + '$^F' : 5, + '@F' : 5, + '${^GLOBAL_PHASE}' : 5, + '$^H' : 5, + '%^H' : 5, + '@INC' : 5, + '%INC' : 5, + '$INPLACE_EDIT' : 5, + '$^I' : 5, + '$^M' : 5, + '$OSNAME' : 5, + '$^O' : 5, + '${^OPEN}' : 5, + '$PERLDB' : 5, + '$^P' : 5, + '$SIG' : 5, + '%SIG' : 5, + '$BASETIME' : 5, + '$^T' : 5, + '${^TAINT}' : 5, + '${^UNICODE}' : 5, + '${^UTF8CACHE}' : 5, + '${^UTF8LOCALE}' : 5, + '$PERL_VERSION' : 5, + '$^V' : 5, + '${^WIN32_SLOPPY_STAT}' : 5, + '$EXECUTABLE_NAME' : 5, + '$^X' : 5, + '$1' : 5, // - regexp $1, $2... + '$MATCH' : 5, + '$&' : 5, + '${^MATCH}' : 5, + '$PREMATCH' : 5, + '$`' : 5, + '${^PREMATCH}' : 5, + '$POSTMATCH' : 5, + "$'" : 5, + '${^POSTMATCH}' : 5, + '$LAST_PAREN_MATCH' : 5, + '$+' : 5, + '$LAST_SUBMATCH_RESULT' : 5, + '$^N' : 5, + '@LAST_MATCH_END' : 5, + '@+' : 5, + '%LAST_PAREN_MATCH' : 5, + '%+' : 5, + '@LAST_MATCH_START' : 5, + '@-' : 5, + '%LAST_MATCH_START' : 5, + '%-' : 5, + '$LAST_REGEXP_CODE_RESULT' : 5, + '$^R' : 5, + '${^RE_DEBUG_FLAGS}' : 5, + '${^RE_TRIE_MAXBUF}' : 5, + '$ARGV' : 5, + '@ARGV' : 5, + 'ARGV' : 5, + 'ARGVOUT' : 5, + '$OUTPUT_FIELD_SEPARATOR' : 5, + '$OFS' : 5, + '$,' : 5, + '$INPUT_LINE_NUMBER' : 5, + '$NR' : 5, + '$.' : 5, + '$INPUT_RECORD_SEPARATOR' : 5, + '$RS' : 5, + '$/' : 5, + '$OUTPUT_RECORD_SEPARATOR' : 5, + '$ORS' : 5, + '$\\' : 5, + '$OUTPUT_AUTOFLUSH' : 5, + '$|' : 5, + '$ACCUMULATOR' : 5, + '$^A' : 5, + '$FORMAT_FORMFEED' : 5, + '$^L' : 5, + '$FORMAT_PAGE_NUMBER' : 5, + '$%' : 5, + '$FORMAT_LINES_LEFT' : 5, + '$-' : 5, + '$FORMAT_LINE_BREAK_CHARACTERS' : 5, + '$:' : 5, + '$FORMAT_LINES_PER_PAGE' : 5, + '$=' : 5, + '$FORMAT_TOP_NAME' : 5, + '$^' : 5, + '$FORMAT_NAME' : 5, + '$~' : 5, + '${^CHILD_ERROR_NATIVE}' : 5, + '$EXTENDED_OS_ERROR' : 5, + '$^E' : 5, + '$EXCEPTIONS_BEING_CAUGHT' : 5, + '$^S' : 5, + '$WARNING' : 5, + '$^W' : 5, + '${^WARNING_BITS}' : 5, + '$OS_ERROR' : 5, + '$ERRNO' : 5, + '$!' : 5, + '%OS_ERROR' : 5, + '%ERRNO' : 5, + '%!' : 5, + '$CHILD_ERROR' : 5, + '$?' : 5, + '$EVAL_ERROR' : 5, + '$@' : 5, + '$OFMT' : 5, + '$#' : 5, + '$*' : 5, + '$ARRAY_BASE' : 5, + '$[' : 5, + '$OLD_PERL_VERSION' : 5, + '$]' : 5, + // PERL blocks + 'if' :[1,1], + elsif :[1,1], + 'else' :[1,1], + 'while' :[1,1], + unless :[1,1], + 'for' :[1,1], + foreach :[1,1], + // PERL functions + 'abs' :1, // - absolute value function + accept :1, // - accept an incoming socket connect + alarm :1, // - schedule a SIGALRM + 'atan2' :1, // - arctangent of Y/X in the range -PI to PI + bind :1, // - binds an address to a socket + binmode :1, // - prepare binary files for I/O + bless :1, // - create an object + bootstrap :1, // + 'break' :1, // - break out of a "given" block + caller :1, // - get context of the current subroutine call + chdir :1, // - change your current working directory + chmod :1, // - changes the permissions on a list of files + chomp :1, // - remove a trailing record separator from a string + chop :1, // - remove the last character from a string + chown :1, // - change the owership on a list of files + chr :1, // - get character this number represents + chroot :1, // - make directory new root for path lookups + close :1, // - close file (or pipe or socket) handle + closedir :1, // - close directory handle + connect :1, // - connect to a remote socket + 'continue' :[1,1], // - optional trailing block in a while or foreach + 'cos' :1, // - cosine function + crypt :1, // - one-way passwd-style encryption + dbmclose :1, // - breaks binding on a tied dbm file + dbmopen :1, // - create binding on a tied dbm file + 'default' :1, // + defined :1, // - test whether a value, variable, or function is defined + 'delete' :1, // - deletes a value from a hash + die :1, // - raise an exception or bail out + 'do' :1, // - turn a BLOCK into a TERM + dump :1, // - create an immediate core dump + each :1, // - retrieve the next key/value pair from a hash + endgrent :1, // - be done using group file + endhostent :1, // - be done using hosts file + endnetent :1, // - be done using networks file + endprotoent :1, // - be done using protocols file + endpwent :1, // - be done using passwd file + endservent :1, // - be done using services file + eof :1, // - test a filehandle for its end + 'eval' :1, // - catch exceptions or compile and run code + 'exec' :1, // - abandon this program to run another + exists :1, // - test whether a hash key is present + exit :1, // - terminate this program + 'exp' :1, // - raise I to a power + fcntl :1, // - file control system call + fileno :1, // - return file descriptor from filehandle + flock :1, // - lock an entire file with an advisory lock + fork :1, // - create a new process just like this one + format :1, // - declare a picture format with use by the write() function + formline :1, // - internal function used for formats + getc :1, // - get the next character from the filehandle + getgrent :1, // - get next group record + getgrgid :1, // - get group record given group user ID + getgrnam :1, // - get group record given group name + gethostbyaddr :1, // - get host record given its address + gethostbyname :1, // - get host record given name + gethostent :1, // - get next hosts record + getlogin :1, // - return who logged in at this tty + getnetbyaddr :1, // - get network record given its address + getnetbyname :1, // - get networks record given name + getnetent :1, // - get next networks record + getpeername :1, // - find the other end of a socket connection + getpgrp :1, // - get process group + getppid :1, // - get parent process ID + getpriority :1, // - get current nice value + getprotobyname :1, // - get protocol record given name + getprotobynumber :1, // - get protocol record numeric protocol + getprotoent :1, // - get next protocols record + getpwent :1, // - get next passwd record + getpwnam :1, // - get passwd record given user login name + getpwuid :1, // - get passwd record given user ID + getservbyname :1, // - get services record given its name + getservbyport :1, // - get services record given numeric port + getservent :1, // - get next services record + getsockname :1, // - retrieve the sockaddr for a given socket + getsockopt :1, // - get socket options on a given socket + given :1, // + glob :1, // - expand filenames using wildcards + gmtime :1, // - convert UNIX time into record or string using Greenwich time + 'goto' :1, // - create spaghetti code + grep :1, // - locate elements in a list test true against a given criterion + hex :1, // - convert a string to a hexadecimal number + 'import' :1, // - patch a module's namespace into your own + index :1, // - find a substring within a string + 'int' :1, // - get the integer portion of a number + ioctl :1, // - system-dependent device control system call + 'join' :1, // - join a list into a string using a separator + keys :1, // - retrieve list of indices from a hash + kill :1, // - send a signal to a process or process group + last :1, // - exit a block prematurely + lc :1, // - return lower-case version of a string + lcfirst :1, // - return a string with just the next letter in lower case + length :1, // - return the number of bytes in a string + 'link' :1, // - create a hard link in the filesytem + listen :1, // - register your socket as a server + local : 2, // - create a temporary value for a global variable (dynamic scoping) + localtime :1, // - convert UNIX time into record or string using local time + lock :1, // - get a thread lock on a variable, subroutine, or method + 'log' :1, // - retrieve the natural logarithm for a number + lstat :1, // - stat a symbolic link + m :null, // - match a string with a regular expression pattern + map :1, // - apply a change to a list to get back a new list with the changes + mkdir :1, // - create a directory + msgctl :1, // - SysV IPC message control operations + msgget :1, // - get SysV IPC message queue + msgrcv :1, // - receive a SysV IPC message from a message queue + msgsnd :1, // - send a SysV IPC message to a message queue + my : 2, // - declare and assign a local variable (lexical scoping) + 'new' :1, // + next :1, // - iterate a block prematurely + no :1, // - unimport some module symbols or semantics at compile time + oct :1, // - convert a string to an octal number + open :1, // - open a file, pipe, or descriptor + opendir :1, // - open a directory + ord :1, // - find a character's numeric representation + our : 2, // - declare and assign a package variable (lexical scoping) + pack :1, // - convert a list into a binary representation + 'package' :1, // - declare a separate global namespace + pipe :1, // - open a pair of connected filehandles + pop :1, // - remove the last element from an array and return it + pos :1, // - find or set the offset for the last/next m//g search + print :1, // - output a list to a filehandle + printf :1, // - output a formatted list to a filehandle + prototype :1, // - get the prototype (if any) of a subroutine + push :1, // - append one or more elements to an array + q :null, // - singly quote a string + qq :null, // - doubly quote a string + qr :null, // - Compile pattern + quotemeta :null, // - quote regular expression magic characters + qw :null, // - quote a list of words + qx :null, // - backquote quote a string + rand :1, // - retrieve the next pseudorandom number + read :1, // - fixed-length buffered input from a filehandle + readdir :1, // - get a directory from a directory handle + readline :1, // - fetch a record from a file + readlink :1, // - determine where a symbolic link is pointing + readpipe :1, // - execute a system command and collect standard output + recv :1, // - receive a message over a Socket + redo :1, // - start this loop iteration over again + ref :1, // - find out the type of thing being referenced + rename :1, // - change a filename + require :1, // - load in external functions from a library at runtime + reset :1, // - clear all variables of a given name + 'return' :1, // - get out of a function early + reverse :1, // - flip a string or a list + rewinddir :1, // - reset directory handle + rindex :1, // - right-to-left substring search + rmdir :1, // - remove a directory + s :null, // - replace a pattern with a string + say :1, // - print with newline + scalar :1, // - force a scalar context + seek :1, // - reposition file pointer for random-access I/O + seekdir :1, // - reposition directory pointer + select :1, // - reset default output or do I/O multiplexing + semctl :1, // - SysV semaphore control operations + semget :1, // - get set of SysV semaphores + semop :1, // - SysV semaphore operations + send :1, // - send a message over a socket + setgrent :1, // - prepare group file for use + sethostent :1, // - prepare hosts file for use + setnetent :1, // - prepare networks file for use + setpgrp :1, // - set the process group of a process + setpriority :1, // - set a process's nice value + setprotoent :1, // - prepare protocols file for use + setpwent :1, // - prepare passwd file for use + setservent :1, // - prepare services file for use + setsockopt :1, // - set some socket options + shift :1, // - remove the first element of an array, and return it + shmctl :1, // - SysV shared memory operations + shmget :1, // - get SysV shared memory segment identifier + shmread :1, // - read SysV shared memory + shmwrite :1, // - write SysV shared memory + shutdown :1, // - close down just half of a socket connection + 'sin' :1, // - return the sine of a number + sleep :1, // - block for some number of seconds + socket :1, // - create a socket + socketpair :1, // - create a pair of sockets + 'sort' :1, // - sort a list of values + splice :1, // - add or remove elements anywhere in an array + 'split' :1, // - split up a string using a regexp delimiter + sprintf :1, // - formatted print into a string + 'sqrt' :1, // - square root function + srand :1, // - seed the random number generator + stat :1, // - get a file's status information + state :1, // - declare and assign a state variable (persistent lexical scoping) + study :1, // - optimize input data for repeated searches + 'sub' :1, // - declare a subroutine, possibly anonymously + 'substr' :1, // - get or alter a portion of a stirng + symlink :1, // - create a symbolic link to a file + syscall :1, // - execute an arbitrary system call + sysopen :1, // - open a file, pipe, or descriptor + sysread :1, // - fixed-length unbuffered input from a filehandle + sysseek :1, // - position I/O pointer on handle used with sysread and syswrite + system :1, // - run a separate program + syswrite :1, // - fixed-length unbuffered output to a filehandle + tell :1, // - get current seekpointer on a filehandle + telldir :1, // - get current seekpointer on a directory handle + tie :1, // - bind a variable to an object class + tied :1, // - get a reference to the object underlying a tied variable + time :1, // - return number of seconds since 1970 + times :1, // - return elapsed time for self and child processes + tr :null, // - transliterate a string + truncate :1, // - shorten a file + uc :1, // - return upper-case version of a string + ucfirst :1, // - return a string with just the next letter in upper case + umask :1, // - set file creation mode mask + undef :1, // - remove a variable or function definition + unlink :1, // - remove one link to a file + unpack :1, // - convert binary structure into normal perl variables + unshift :1, // - prepend more elements to the beginning of a list + untie :1, // - break a tie binding to a variable + use :1, // - load in a module at compile time + utime :1, // - set a file's last access and modify times + values :1, // - return a list of the values in a hash + vec :1, // - test or set particular bits in a string + wait :1, // - wait for any child process to die + waitpid :1, // - wait for a particular child process to die + wantarray :1, // - get void vs scalar vs list context of current subroutine call + warn :1, // - print debugging info + when :1, // + write :1, // - print a picture record + y :null}; // - transliterate a string + + var RXstyle="string-2"; + var RXmodifiers=/[goseximacplud]/; // NOTE: "m", "s", "y" and "tr" need to correct real modifiers for each regexp type + + function tokenChain(stream,state,chain,style,tail){ // NOTE: chain.length > 2 is not working now (it's for s[...][...]geos;) + state.chain=null; // 12 3tail + state.style=null; + state.tail=null; + state.tokenize=function(stream,state){ + var e=false,c,i=0; + while(c=stream.next()){ + if(c===chain[i]&&!e){ + if(chain[++i]!==undefined){ + state.chain=chain[i]; + state.style=style; + state.tail=tail;} + else if(tail) + stream.eatWhile(tail); + state.tokenize=tokenPerl; + return style;} + e=!e&&c=="\\";} + return style;}; + return state.tokenize(stream,state);} + + function tokenSOMETHING(stream,state,string){ + state.tokenize=function(stream,state){ + if(stream.string==string) + state.tokenize=tokenPerl; + stream.skipToEnd(); + return "string";}; + return state.tokenize(stream,state);} + + function tokenPerl(stream,state){ + if(stream.eatSpace()) + return null; + if(state.chain) + return tokenChain(stream,state,state.chain,state.style,state.tail); + if(stream.match(/^\-?[\d\.]/,false)) + if(stream.match(/^(\-?(\d*\.\d+(e[+-]?\d+)?|\d+\.\d*)|0x[\da-fA-F]+|0b[01]+|\d+(e[+-]?\d+)?)/)) + return 'number'; + if(stream.match(/^<<(?=\w)/)){ // NOTE: <"],RXstyle,RXmodifiers);} + if(/[\^'"!~\/]/.test(c)){ + eatSuffix(stream, 1); + return tokenChain(stream,state,[stream.eat(c)],RXstyle,RXmodifiers);}} + else if(c=="q"){ + c=look(stream, 1); + if(c=="("){ + eatSuffix(stream, 2); + return tokenChain(stream,state,[")"],"string");} + if(c=="["){ + eatSuffix(stream, 2); + return tokenChain(stream,state,["]"],"string");} + if(c=="{"){ + eatSuffix(stream, 2); + return tokenChain(stream,state,["}"],"string");} + if(c=="<"){ + eatSuffix(stream, 2); + return tokenChain(stream,state,[">"],"string");} + if(/[\^'"!~\/]/.test(c)){ + eatSuffix(stream, 1); + return tokenChain(stream,state,[stream.eat(c)],"string");}} + else if(c=="w"){ + c=look(stream, 1); + if(c=="("){ + eatSuffix(stream, 2); + return tokenChain(stream,state,[")"],"bracket");} + if(c=="["){ + eatSuffix(stream, 2); + return tokenChain(stream,state,["]"],"bracket");} + if(c=="{"){ + eatSuffix(stream, 2); + return tokenChain(stream,state,["}"],"bracket");} + if(c=="<"){ + eatSuffix(stream, 2); + return tokenChain(stream,state,[">"],"bracket");} + if(/[\^'"!~\/]/.test(c)){ + eatSuffix(stream, 1); + return tokenChain(stream,state,[stream.eat(c)],"bracket");}} + else if(c=="r"){ + c=look(stream, 1); + if(c=="("){ + eatSuffix(stream, 2); + return tokenChain(stream,state,[")"],RXstyle,RXmodifiers);} + if(c=="["){ + eatSuffix(stream, 2); + return tokenChain(stream,state,["]"],RXstyle,RXmodifiers);} + if(c=="{"){ + eatSuffix(stream, 2); + return tokenChain(stream,state,["}"],RXstyle,RXmodifiers);} + if(c=="<"){ + eatSuffix(stream, 2); + return tokenChain(stream,state,[">"],RXstyle,RXmodifiers);} + if(/[\^'"!~\/]/.test(c)){ + eatSuffix(stream, 1); + return tokenChain(stream,state,[stream.eat(c)],RXstyle,RXmodifiers);}} + else if(/[\^'"!~\/(\[{<]/.test(c)){ + if(c=="("){ + eatSuffix(stream, 1); + return tokenChain(stream,state,[")"],"string");} + if(c=="["){ + eatSuffix(stream, 1); + return tokenChain(stream,state,["]"],"string");} + if(c=="{"){ + eatSuffix(stream, 1); + return tokenChain(stream,state,["}"],"string");} + if(c=="<"){ + eatSuffix(stream, 1); + return tokenChain(stream,state,[">"],"string");} + if(/[\^'"!~\/]/.test(c)){ + return tokenChain(stream,state,[stream.eat(c)],"string");}}}} + if(ch=="m"){ + var c=look(stream, -2); + if(!(c&&/\w/.test(c))){ + c=stream.eat(/[(\[{<\^'"!~\/]/); + if(c){ + if(/[\^'"!~\/]/.test(c)){ + return tokenChain(stream,state,[c],RXstyle,RXmodifiers);} + if(c=="("){ + return tokenChain(stream,state,[")"],RXstyle,RXmodifiers);} + if(c=="["){ + return tokenChain(stream,state,["]"],RXstyle,RXmodifiers);} + if(c=="{"){ + return tokenChain(stream,state,["}"],RXstyle,RXmodifiers);} + if(c=="<"){ + return tokenChain(stream,state,[">"],RXstyle,RXmodifiers);}}}} + if(ch=="s"){ + var c=/[\/>\]})\w]/.test(look(stream, -2)); + if(!c){ + c=stream.eat(/[(\[{<\^'"!~\/]/); + if(c){ + if(c=="[") + return tokenChain(stream,state,["]","]"],RXstyle,RXmodifiers); + if(c=="{") + return tokenChain(stream,state,["}","}"],RXstyle,RXmodifiers); + if(c=="<") + return tokenChain(stream,state,[">",">"],RXstyle,RXmodifiers); + if(c=="(") + return tokenChain(stream,state,[")",")"],RXstyle,RXmodifiers); + return tokenChain(stream,state,[c,c],RXstyle,RXmodifiers);}}} + if(ch=="y"){ + var c=/[\/>\]})\w]/.test(look(stream, -2)); + if(!c){ + c=stream.eat(/[(\[{<\^'"!~\/]/); + if(c){ + if(c=="[") + return tokenChain(stream,state,["]","]"],RXstyle,RXmodifiers); + if(c=="{") + return tokenChain(stream,state,["}","}"],RXstyle,RXmodifiers); + if(c=="<") + return tokenChain(stream,state,[">",">"],RXstyle,RXmodifiers); + if(c=="(") + return tokenChain(stream,state,[")",")"],RXstyle,RXmodifiers); + return tokenChain(stream,state,[c,c],RXstyle,RXmodifiers);}}} + if(ch=="t"){ + var c=/[\/>\]})\w]/.test(look(stream, -2)); + if(!c){ + c=stream.eat("r");if(c){ + c=stream.eat(/[(\[{<\^'"!~\/]/); + if(c){ + if(c=="[") + return tokenChain(stream,state,["]","]"],RXstyle,RXmodifiers); + if(c=="{") + return tokenChain(stream,state,["}","}"],RXstyle,RXmodifiers); + if(c=="<") + return tokenChain(stream,state,[">",">"],RXstyle,RXmodifiers); + if(c=="(") + return tokenChain(stream,state,[")",")"],RXstyle,RXmodifiers); + return tokenChain(stream,state,[c,c],RXstyle,RXmodifiers);}}}} + if(ch=="`"){ + return tokenChain(stream,state,[ch],"variable-2");} + if(ch=="/"){ + if(!/~\s*$/.test(prefix(stream))) + return "operator"; + else + return tokenChain(stream,state,[ch],RXstyle,RXmodifiers);} + if(ch=="$"){ + var p=stream.pos; + if(stream.eatWhile(/\d/)||stream.eat("{")&&stream.eatWhile(/\d/)&&stream.eat("}")) + return "variable-2"; + else + stream.pos=p;} + if(/[$@%]/.test(ch)){ + var p=stream.pos; + if(stream.eat("^")&&stream.eat(/[A-Z]/)||!/[@$%&]/.test(look(stream, -2))&&stream.eat(/[=|\\\-#?@;:&`~\^!\[\]*'"$+.,\/<>()]/)){ + var c=stream.current(); + if(PERL[c]) + return "variable-2";} + stream.pos=p;} + if(/[$@%&]/.test(ch)){ + if(stream.eatWhile(/[\w$\[\]]/)||stream.eat("{")&&stream.eatWhile(/[\w$\[\]]/)&&stream.eat("}")){ + var c=stream.current(); + if(PERL[c]) + return "variable-2"; + else + return "variable";}} + if(ch=="#"){ + if(look(stream, -2)!="$"){ + stream.skipToEnd(); + return "comment";}} + if(/[:+\-\^*$&%@=<>!?|\/~\.]/.test(ch)){ + var p=stream.pos; + stream.eatWhile(/[:+\-\^*$&%@=<>!?|\/~\.]/); + if(PERL[stream.current()]) + return "operator"; + else + stream.pos=p;} + if(ch=="_"){ + if(stream.pos==1){ + if(suffix(stream, 6)=="_END__"){ + return tokenChain(stream,state,['\0'],"comment");} + else if(suffix(stream, 7)=="_DATA__"){ + return tokenChain(stream,state,['\0'],"variable-2");} + else if(suffix(stream, 7)=="_C__"){ + return tokenChain(stream,state,['\0'],"string");}}} + if(/\w/.test(ch)){ + var p=stream.pos; + if(look(stream, -2)=="{"&&(look(stream, 0)=="}"||stream.eatWhile(/\w/)&&look(stream, 0)=="}")) + return "string"; + else + stream.pos=p;} + if(/[A-Z]/.test(ch)){ + var l=look(stream, -2); + var p=stream.pos; + stream.eatWhile(/[A-Z_]/); + if(/[\da-z]/.test(look(stream, 0))){ + stream.pos=p;} + else{ + var c=PERL[stream.current()]; + if(!c) + return "meta"; + if(c[1]) + c=c[0]; + if(l!=":"){ + if(c==1) + return "keyword"; + else if(c==2) + return "def"; + else if(c==3) + return "atom"; + else if(c==4) + return "operator"; + else if(c==5) + return "variable-2"; + else + return "meta";} + else + return "meta";}} + if(/[a-zA-Z_]/.test(ch)){ + var l=look(stream, -2); + stream.eatWhile(/\w/); + var c=PERL[stream.current()]; + if(!c) + return "meta"; + if(c[1]) + c=c[0]; + if(l!=":"){ + if(c==1) + return "keyword"; + else if(c==2) + return "def"; + else if(c==3) + return "atom"; + else if(c==4) + return "operator"; + else if(c==5) + return "variable-2"; + else + return "meta";} + else + return "meta";} + return null;} + + return { + startState: function() { + return { + tokenize: tokenPerl, + chain: null, + style: null, + tail: null + }; + }, + token: function(stream, state) { + return (state.tokenize || tokenPerl)(stream, state); + }, + lineComment: '#' + }; +}); + +CodeMirror.registerHelper("wordChars", "perl", /[\w$]/); + +CodeMirror.defineMIME("text/x-perl", "perl"); + +// it's like "peek", but need for look-ahead or look-behind if index < 0 +function look(stream, c){ + return stream.string.charAt(stream.pos+(c||0)); +} + +// return a part of prefix of current stream from current position +function prefix(stream, c){ + if(c){ + var x=stream.pos-c; + return stream.string.substr((x>=0?x:0),c);} + else{ + return stream.string.substr(0,stream.pos-1); + } +} + +// return a part of suffix of current stream from current position +function suffix(stream, c){ + var y=stream.string.length; + var x=y-stream.pos+1; + return stream.string.substr(stream.pos,(c&&c=(y=stream.string.length-1)) + stream.pos=y; + else + stream.pos=x; +} + +}); diff --git a/static/js/mdeditor/lib/codemirror/mode/php/index.html b/static/js/mdeditor/lib/codemirror/mode/php/index.html new file mode 100644 index 00000000..adf6b1be --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/php/index.html @@ -0,0 +1,64 @@ + + +CodeMirror: PHP mode + + + + + + + + + + + + + + + +
+

PHP mode

+
+ + + +

Simple HTML/PHP mode based on + the C-like mode. Depends on XML, + JavaScript, CSS, HTMLMixed, and C-like modes.

+ +

MIME types defined: application/x-httpd-php (HTML with PHP code), text/x-php (plain, non-wrapped PHP code).

+
diff --git a/static/js/mdeditor/lib/codemirror/mode/php/php.js b/static/js/mdeditor/lib/codemirror/mode/php/php.js new file mode 100644 index 00000000..e112d911 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/php/php.js @@ -0,0 +1,226 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../htmlmixed/htmlmixed"), require("../clike/clike")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../htmlmixed/htmlmixed", "../clike/clike"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + function keywords(str) { + var obj = {}, words = str.split(" "); + for (var i = 0; i < words.length; ++i) obj[words[i]] = true; + return obj; + } + + // Helper for stringWithEscapes + function matchSequence(list, end) { + if (list.length == 0) return stringWithEscapes(end); + return function (stream, state) { + var patterns = list[0]; + for (var i = 0; i < patterns.length; i++) if (stream.match(patterns[i][0])) { + state.tokenize = matchSequence(list.slice(1), end); + return patterns[i][1]; + } + state.tokenize = stringWithEscapes(end); + return "string"; + }; + } + function stringWithEscapes(closing) { + return function(stream, state) { return stringWithEscapes_(stream, state, closing); }; + } + function stringWithEscapes_(stream, state, closing) { + // "Complex" syntax + if (stream.match("${", false) || stream.match("{$", false)) { + state.tokenize = null; + return "string"; + } + + // Simple syntax + if (stream.match(/^\$[a-zA-Z_][a-zA-Z0-9_]*/)) { + // After the variable name there may appear array or object operator. + if (stream.match("[", false)) { + // Match array operator + state.tokenize = matchSequence([ + [["[", null]], + [[/\d[\w\.]*/, "number"], + [/\$[a-zA-Z_][a-zA-Z0-9_]*/, "variable-2"], + [/[\w\$]+/, "variable"]], + [["]", null]] + ], closing); + } + if (stream.match(/\-\>\w/, false)) { + // Match object operator + state.tokenize = matchSequence([ + [["->", null]], + [[/[\w]+/, "variable"]] + ], closing); + } + return "variable-2"; + } + + var escaped = false; + // Normal string + while (!stream.eol() && + (escaped || (!stream.match("{$", false) && + !stream.match(/^(\$[a-zA-Z_][a-zA-Z0-9_]*|\$\{)/, false)))) { + if (!escaped && stream.match(closing)) { + state.tokenize = null; + state.tokStack.pop(); state.tokStack.pop(); + break; + } + escaped = stream.next() == "\\" && !escaped; + } + return "string"; + } + + var phpKeywords = "abstract and array as break case catch class clone const continue declare default " + + "do else elseif enddeclare endfor endforeach endif endswitch endwhile extends final " + + "for foreach function global goto if implements interface instanceof namespace " + + "new or private protected public static switch throw trait try use var while xor " + + "die echo empty exit eval include include_once isset list require require_once return " + + "print unset __halt_compiler self static parent yield insteadof finally"; + var phpAtoms = "true false null TRUE FALSE NULL __CLASS__ __DIR__ __FILE__ __LINE__ __METHOD__ __FUNCTION__ __NAMESPACE__ __TRAIT__"; + var phpBuiltin = "func_num_args func_get_arg func_get_args strlen strcmp strncmp strcasecmp strncasecmp each error_reporting define defined trigger_error user_error set_error_handler restore_error_handler get_declared_classes get_loaded_extensions extension_loaded get_extension_funcs debug_backtrace constant bin2hex hex2bin sleep usleep time mktime gmmktime strftime gmstrftime strtotime date gmdate getdate localtime checkdate flush wordwrap htmlspecialchars htmlentities html_entity_decode md5 md5_file crc32 getimagesize image_type_to_mime_type phpinfo phpversion phpcredits strnatcmp strnatcasecmp substr_count strspn strcspn strtok strtoupper strtolower strpos strrpos strrev hebrev hebrevc nl2br basename dirname pathinfo stripslashes stripcslashes strstr stristr strrchr str_shuffle str_word_count strcoll substr substr_replace quotemeta ucfirst ucwords strtr addslashes addcslashes rtrim str_replace str_repeat count_chars chunk_split trim ltrim strip_tags similar_text explode implode setlocale localeconv parse_str str_pad chop strchr sprintf printf vprintf vsprintf sscanf fscanf parse_url urlencode urldecode rawurlencode rawurldecode readlink linkinfo link unlink exec system escapeshellcmd escapeshellarg passthru shell_exec proc_open proc_close rand srand getrandmax mt_rand mt_srand mt_getrandmax base64_decode base64_encode abs ceil floor round is_finite is_nan is_infinite bindec hexdec octdec decbin decoct dechex base_convert number_format fmod ip2long long2ip getenv putenv getopt microtime gettimeofday getrusage uniqid quoted_printable_decode set_time_limit get_cfg_var magic_quotes_runtime set_magic_quotes_runtime get_magic_quotes_gpc get_magic_quotes_runtime import_request_variables error_log serialize unserialize memory_get_usage var_dump var_export debug_zval_dump print_r highlight_file show_source highlight_string ini_get ini_get_all ini_set ini_alter ini_restore get_include_path set_include_path restore_include_path setcookie header headers_sent connection_aborted connection_status ignore_user_abort parse_ini_file is_uploaded_file move_uploaded_file intval floatval doubleval strval gettype settype is_null is_resource is_bool is_long is_float is_int is_integer is_double is_real is_numeric is_string is_array is_object is_scalar ereg ereg_replace eregi eregi_replace split spliti join sql_regcase dl pclose popen readfile rewind rmdir umask fclose feof fgetc fgets fgetss fread fopen fpassthru ftruncate fstat fseek ftell fflush fwrite fputs mkdir rename copy tempnam tmpfile file file_get_contents stream_select stream_context_create stream_context_set_params stream_context_set_option stream_context_get_options stream_filter_prepend stream_filter_append fgetcsv flock get_meta_tags stream_set_write_buffer set_file_buffer set_socket_blocking stream_set_blocking socket_set_blocking stream_get_meta_data stream_register_wrapper stream_wrapper_register stream_set_timeout socket_set_timeout socket_get_status realpath fnmatch fsockopen pfsockopen pack unpack get_browser crypt opendir closedir chdir getcwd rewinddir readdir dir glob fileatime filectime filegroup fileinode filemtime fileowner fileperms filesize filetype file_exists is_writable is_writeable is_readable is_executable is_file is_dir is_link stat lstat chown touch clearstatcache mail ob_start ob_flush ob_clean ob_end_flush ob_end_clean ob_get_flush ob_get_clean ob_get_length ob_get_level ob_get_status ob_get_contents ob_implicit_flush ob_list_handlers ksort krsort natsort natcasesort asort arsort sort rsort usort uasort uksort shuffle array_walk count end prev next reset current key min max in_array array_search extract compact array_fill range array_multisort array_push array_pop array_shift array_unshift array_splice array_slice array_merge array_merge_recursive array_keys array_values array_count_values array_reverse array_reduce array_pad array_flip array_change_key_case array_rand array_unique array_intersect array_intersect_assoc array_diff array_diff_assoc array_sum array_filter array_map array_chunk array_key_exists pos sizeof key_exists assert assert_options version_compare ftok str_rot13 aggregate session_name session_module_name session_save_path session_id session_regenerate_id session_decode session_register session_unregister session_is_registered session_encode session_start session_destroy session_unset session_set_save_handler session_cache_limiter session_cache_expire session_set_cookie_params session_get_cookie_params session_write_close preg_match preg_match_all preg_replace preg_replace_callback preg_split preg_quote preg_grep overload ctype_alnum ctype_alpha ctype_cntrl ctype_digit ctype_lower ctype_graph ctype_print ctype_punct ctype_space ctype_upper ctype_xdigit virtual apache_request_headers apache_note apache_lookup_uri apache_child_terminate apache_setenv apache_response_headers apache_get_version getallheaders mysql_connect mysql_pconnect mysql_close mysql_select_db mysql_create_db mysql_drop_db mysql_query mysql_unbuffered_query mysql_db_query mysql_list_dbs mysql_list_tables mysql_list_fields mysql_list_processes mysql_error mysql_errno mysql_affected_rows mysql_insert_id mysql_result mysql_num_rows mysql_num_fields mysql_fetch_row mysql_fetch_array mysql_fetch_assoc mysql_fetch_object mysql_data_seek mysql_fetch_lengths mysql_fetch_field mysql_field_seek mysql_free_result mysql_field_name mysql_field_table mysql_field_len mysql_field_type mysql_field_flags mysql_escape_string mysql_real_escape_string mysql_stat mysql_thread_id mysql_client_encoding mysql_get_client_info mysql_get_host_info mysql_get_proto_info mysql_get_server_info mysql_info mysql mysql_fieldname mysql_fieldtable mysql_fieldlen mysql_fieldtype mysql_fieldflags mysql_selectdb mysql_createdb mysql_dropdb mysql_freeresult mysql_numfields mysql_numrows mysql_listdbs mysql_listtables mysql_listfields mysql_db_name mysql_dbname mysql_tablename mysql_table_name pg_connect pg_pconnect pg_close pg_connection_status pg_connection_busy pg_connection_reset pg_host pg_dbname pg_port pg_tty pg_options pg_ping pg_query pg_send_query pg_cancel_query pg_fetch_result pg_fetch_row pg_fetch_assoc pg_fetch_array pg_fetch_object pg_fetch_all pg_affected_rows pg_get_result pg_result_seek pg_result_status pg_free_result pg_last_oid pg_num_rows pg_num_fields pg_field_name pg_field_num pg_field_size pg_field_type pg_field_prtlen pg_field_is_null pg_get_notify pg_get_pid pg_result_error pg_last_error pg_last_notice pg_put_line pg_end_copy pg_copy_to pg_copy_from pg_trace pg_untrace pg_lo_create pg_lo_unlink pg_lo_open pg_lo_close pg_lo_read pg_lo_write pg_lo_read_all pg_lo_import pg_lo_export pg_lo_seek pg_lo_tell pg_escape_string pg_escape_bytea pg_unescape_bytea pg_client_encoding pg_set_client_encoding pg_meta_data pg_convert pg_insert pg_update pg_delete pg_select pg_exec pg_getlastoid pg_cmdtuples pg_errormessage pg_numrows pg_numfields pg_fieldname pg_fieldsize pg_fieldtype pg_fieldnum pg_fieldprtlen pg_fieldisnull pg_freeresult pg_result pg_loreadall pg_locreate pg_lounlink pg_loopen pg_loclose pg_loread pg_lowrite pg_loimport pg_loexport http_response_code get_declared_traits getimagesizefromstring socket_import_stream stream_set_chunk_size trait_exists header_register_callback class_uses session_status session_register_shutdown echo print global static exit array empty eval isset unset die include require include_once require_once json_decode json_encode json_last_error json_last_error_msg curl_close curl_copy_handle curl_errno curl_error curl_escape curl_exec curl_file_create curl_getinfo curl_init curl_multi_add_handle curl_multi_close curl_multi_exec curl_multi_getcontent curl_multi_info_read curl_multi_init curl_multi_remove_handle curl_multi_select curl_multi_setopt curl_multi_strerror curl_pause curl_reset curl_setopt_array curl_setopt curl_share_close curl_share_init curl_share_setopt curl_strerror curl_unescape curl_version mysqli_affected_rows mysqli_autocommit mysqli_change_user mysqli_character_set_name mysqli_close mysqli_commit mysqli_connect_errno mysqli_connect_error mysqli_connect mysqli_data_seek mysqli_debug mysqli_dump_debug_info mysqli_errno mysqli_error_list mysqli_error mysqli_fetch_all mysqli_fetch_array mysqli_fetch_assoc mysqli_fetch_field_direct mysqli_fetch_field mysqli_fetch_fields mysqli_fetch_lengths mysqli_fetch_object mysqli_fetch_row mysqli_field_count mysqli_field_seek mysqli_field_tell mysqli_free_result mysqli_get_charset mysqli_get_client_info mysqli_get_client_stats mysqli_get_client_version mysqli_get_connection_stats mysqli_get_host_info mysqli_get_proto_info mysqli_get_server_info mysqli_get_server_version mysqli_info mysqli_init mysqli_insert_id mysqli_kill mysqli_more_results mysqli_multi_query mysqli_next_result mysqli_num_fields mysqli_num_rows mysqli_options mysqli_ping mysqli_prepare mysqli_query mysqli_real_connect mysqli_real_escape_string mysqli_real_query mysqli_reap_async_query mysqli_refresh mysqli_rollback mysqli_select_db mysqli_set_charset mysqli_set_local_infile_default mysqli_set_local_infile_handler mysqli_sqlstate mysqli_ssl_set mysqli_stat mysqli_stmt_init mysqli_store_result mysqli_thread_id mysqli_thread_safe mysqli_use_result mysqli_warning_count"; + CodeMirror.registerHelper("hintWords", "php", [phpKeywords, phpAtoms, phpBuiltin].join(" ").split(" ")); + CodeMirror.registerHelper("wordChars", "php", /[\w$]/); + + var phpConfig = { + name: "clike", + helperType: "php", + keywords: keywords(phpKeywords), + blockKeywords: keywords("catch do else elseif for foreach if switch try while finally"), + atoms: keywords(phpAtoms), + builtin: keywords(phpBuiltin), + multiLineStrings: true, + hooks: { + "$": function(stream) { + stream.eatWhile(/[\w\$_]/); + return "variable-2"; + }, + "<": function(stream, state) { + if (stream.match(/<", false)) stream.next(); + return "comment"; + }, + "/": function(stream) { + if (stream.eat("/")) { + while (!stream.eol() && !stream.match("?>", false)) stream.next(); + return "comment"; + } + return false; + }, + '"': function(_stream, state) { + (state.tokStack || (state.tokStack = [])).push('"', 0); + state.tokenize = stringWithEscapes('"'); + return "string"; + }, + "{": function(_stream, state) { + if (state.tokStack && state.tokStack.length) + state.tokStack[state.tokStack.length - 1]++; + return false; + }, + "}": function(_stream, state) { + if (state.tokStack && state.tokStack.length > 0 && + !--state.tokStack[state.tokStack.length - 1]) { + state.tokenize = stringWithEscapes(state.tokStack[state.tokStack.length - 2]); + } + return false; + } + } + }; + + CodeMirror.defineMode("php", function(config, parserConfig) { + var htmlMode = CodeMirror.getMode(config, "text/html"); + var phpMode = CodeMirror.getMode(config, phpConfig); + + function dispatch(stream, state) { + var isPHP = state.curMode == phpMode; + if (stream.sol() && state.pending && state.pending != '"' && state.pending != "'") state.pending = null; + if (!isPHP) { + if (stream.match(/^<\?\w*/)) { + state.curMode = phpMode; + state.curState = state.php; + return "meta"; + } + if (state.pending == '"' || state.pending == "'") { + while (!stream.eol() && stream.next() != state.pending) {} + var style = "string"; + } else if (state.pending && stream.pos < state.pending.end) { + stream.pos = state.pending.end; + var style = state.pending.style; + } else { + var style = htmlMode.token(stream, state.curState); + } + if (state.pending) state.pending = null; + var cur = stream.current(), openPHP = cur.search(/<\?/), m; + if (openPHP != -1) { + if (style == "string" && (m = cur.match(/[\'\"]$/)) && !/\?>/.test(cur)) state.pending = m[0]; + else state.pending = {end: stream.pos, style: style}; + stream.backUp(cur.length - openPHP); + } + return style; + } else if (isPHP && state.php.tokenize == null && stream.match("?>")) { + state.curMode = htmlMode; + state.curState = state.html; + return "meta"; + } else { + return phpMode.token(stream, state.curState); + } + } + + return { + startState: function() { + var html = CodeMirror.startState(htmlMode), php = CodeMirror.startState(phpMode); + return {html: html, + php: php, + curMode: parserConfig.startOpen ? phpMode : htmlMode, + curState: parserConfig.startOpen ? php : html, + pending: null}; + }, + + copyState: function(state) { + var html = state.html, htmlNew = CodeMirror.copyState(htmlMode, html), + php = state.php, phpNew = CodeMirror.copyState(phpMode, php), cur; + if (state.curMode == htmlMode) cur = htmlNew; + else cur = phpNew; + return {html: htmlNew, php: phpNew, curMode: state.curMode, curState: cur, + pending: state.pending}; + }, + + token: dispatch, + + indent: function(state, textAfter) { + if ((state.curMode != phpMode && /^\s*<\//.test(textAfter)) || + (state.curMode == phpMode && /^\?>/.test(textAfter))) + return htmlMode.indent(state.html, textAfter); + return state.curMode.indent(state.curState, textAfter); + }, + + blockCommentStart: "/*", + blockCommentEnd: "*/", + lineComment: "//", + + innerMode: function(state) { return {state: state.curState, mode: state.curMode}; } + }; + }, "htmlmixed", "clike"); + + CodeMirror.defineMIME("application/x-httpd-php", "php"); + CodeMirror.defineMIME("application/x-httpd-php-open", {name: "php", startOpen: true}); + CodeMirror.defineMIME("text/x-php", phpConfig); +}); diff --git a/static/js/mdeditor/lib/codemirror/mode/php/test.js b/static/js/mdeditor/lib/codemirror/mode/php/test.js new file mode 100644 index 00000000..e2ecefc1 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/php/test.js @@ -0,0 +1,154 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function() { + var mode = CodeMirror.getMode({indentUnit: 2}, "php"); + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); } + + MT('simple_test', + '[meta ]'); + + MT('variable_interpolation_non_alphanumeric', + '[meta $/$\\$}$\\\"$:$;$?$|$[[$]]$+$=aaa"]', + '[meta ?>]'); + + MT('variable_interpolation_digits', + '[meta ]'); + + MT('variable_interpolation_simple_syntax_1', + '[meta ]'); + + MT('variable_interpolation_simple_syntax_2', + '[meta ]'); + + MT('variable_interpolation_simple_syntax_3', + '[meta [variable aaaaa][string .aaaaaa"];', + '[keyword echo] [string "aaa][variable-2 $aaaa][string ->][variable-2 $aaaaa][string .aaaaaa"];', + '[keyword echo] [string "aaa][variable-2 $aaaa]->[variable aaaaa][string [[2]].aaaaaa"];', + '[keyword echo] [string "aaa][variable-2 $aaaa]->[variable aaaaa][string ->aaaa2.aaaaaa"];', + '[meta ?>]'); + + MT('variable_interpolation_escaping', + '[meta aaa.aaa"];', + '[keyword echo] [string "aaa\\$aaaa[[2]]aaa.aaa"];', + '[keyword echo] [string "aaa\\$aaaa[[asd]]aaa.aaa"];', + '[keyword echo] [string "aaa{\\$aaaa->aaa.aaa"];', + '[keyword echo] [string "aaa{\\$aaaa[[2]]aaa.aaa"];', + '[keyword echo] [string "aaa{\\aaaaa[[asd]]aaa.aaa"];', + '[keyword echo] [string "aaa\\${aaaa->aaa.aaa"];', + '[keyword echo] [string "aaa\\${aaaa[[2]]aaa.aaa"];', + '[keyword echo] [string "aaa\\${aaaa[[asd]]aaa.aaa"];', + '[meta ?>]'); + + MT('variable_interpolation_complex_syntax_1', + '[meta aaa.aaa"];', + '[keyword echo] [string "aaa][variable-2 $]{[variable-2 $aaaa]}[string ->aaa.aaa"];', + '[keyword echo] [string "aaa][variable-2 $]{[variable-2 $aaaa][[',' [number 42]',']]}[string ->aaa.aaa"];', + '[keyword echo] [string "aaa][variable-2 $]{[variable aaaa][meta ?>]aaaaaa'); + + MT('variable_interpolation_complex_syntax_2', + '[meta } $aaaaaa.aaa"];', + '[keyword echo] [string "][variable-2 $]{[variable aaa][comment /*}?>*/][[',' [string "aaa][variable-2 $aaa][string {}][variable-2 $]{[variable aaa]}[string "]',']]}[string ->aaa.aaa"];', + '[keyword echo] [string "][variable-2 $]{[variable aaa][comment /*} } $aaa } */]}[string ->aaa.aaa"];'); + + + function build_recursive_monsters(nt, t, n){ + var monsters = [t]; + for (var i = 1; i <= n; ++i) + monsters[i] = nt.join(monsters[i - 1]); + return monsters; + } + + var m1 = build_recursive_monsters( + ['[string "][variable-2 $]{[variable aaa] [operator +] ', '}[string "]'], + '[comment /* }?>} */] [string "aaa][variable-2 $aaa][string .aaa"]', + 10 + ); + + MT('variable_interpolation_complex_syntax_3_1', + '[meta ]'); + + var m2 = build_recursive_monsters( + ['[string "a][variable-2 $]{[variable aaa] [operator +] ', ' [operator +] ', '}[string .a"]'], + '[comment /* }?>{{ */] [string "a?>}{{aa][variable-2 $aaa][string .a}a?>a"]', + 5 + ); + + MT('variable_interpolation_complex_syntax_3_2', + '[meta ]'); + + function build_recursive_monsters_2(mf1, mf2, nt, t, n){ + var monsters = [t]; + for (var i = 1; i <= n; ++i) + monsters[i] = nt[0] + mf1[i - 1] + nt[1] + mf2[i - 1] + nt[2] + monsters[i - 1] + nt[3]; + return monsters; + } + + var m3 = build_recursive_monsters_2( + m1, + m2, + ['[string "a][variable-2 $]{[variable aaa] [operator +] ', ' [operator +] ', ' [operator +] ', '}[string .a"]'], + '[comment /* }?>{{ */] [string "a?>}{{aa][variable-2 $aaa][string .a}a?>a"]', + 4 + ); + + MT('variable_interpolation_complex_syntax_3_3', + '[meta ]'); + + MT("variable_interpolation_heredoc", + "[meta + +CodeMirror: Pig Latin mode + + + + + + + + + +
+

Pig Latin mode

+
+ + + +

+ Simple mode that handles Pig Latin language. +

+ +

MIME type defined: text/x-pig + (PIG code) + +

diff --git a/static/js/mdeditor/lib/codemirror/mode/pig/pig.js b/static/js/mdeditor/lib/codemirror/mode/pig/pig.js new file mode 100644 index 00000000..c74b2cc8 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/pig/pig.js @@ -0,0 +1,188 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +/* + * Pig Latin Mode for CodeMirror 2 + * @author Prasanth Jayachandran + * @link https://github.com/prasanthj/pig-codemirror-2 + * This implementation is adapted from PL/SQL mode in CodeMirror 2. + */ +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("pig", function(_config, parserConfig) { + var keywords = parserConfig.keywords, + builtins = parserConfig.builtins, + types = parserConfig.types, + multiLineStrings = parserConfig.multiLineStrings; + + var isOperatorChar = /[*+\-%<>=&?:\/!|]/; + + function chain(stream, state, f) { + state.tokenize = f; + return f(stream, state); + } + + var type; + function ret(tp, style) { + type = tp; + return style; + } + + function tokenComment(stream, state) { + var isEnd = false; + var ch; + while(ch = stream.next()) { + if(ch == "/" && isEnd) { + state.tokenize = tokenBase; + break; + } + isEnd = (ch == "*"); + } + return ret("comment", "comment"); + } + + function tokenString(quote) { + return function(stream, state) { + var escaped = false, next, end = false; + while((next = stream.next()) != null) { + if (next == quote && !escaped) { + end = true; break; + } + escaped = !escaped && next == "\\"; + } + if (end || !(escaped || multiLineStrings)) + state.tokenize = tokenBase; + return ret("string", "error"); + }; + } + + function tokenBase(stream, state) { + var ch = stream.next(); + + // is a start of string? + if (ch == '"' || ch == "'") + return chain(stream, state, tokenString(ch)); + // is it one of the special chars + else if(/[\[\]{}\(\),;\.]/.test(ch)) + return ret(ch); + // is it a number? + else if(/\d/.test(ch)) { + stream.eatWhile(/[\w\.]/); + return ret("number", "number"); + } + // multi line comment or operator + else if (ch == "/") { + if (stream.eat("*")) { + return chain(stream, state, tokenComment); + } + else { + stream.eatWhile(isOperatorChar); + return ret("operator", "operator"); + } + } + // single line comment or operator + else if (ch=="-") { + if(stream.eat("-")){ + stream.skipToEnd(); + return ret("comment", "comment"); + } + else { + stream.eatWhile(isOperatorChar); + return ret("operator", "operator"); + } + } + // is it an operator + else if (isOperatorChar.test(ch)) { + stream.eatWhile(isOperatorChar); + return ret("operator", "operator"); + } + else { + // get the while word + stream.eatWhile(/[\w\$_]/); + // is it one of the listed keywords? + if (keywords && keywords.propertyIsEnumerable(stream.current().toUpperCase())) { + if (stream.eat(")") || stream.eat(".")) { + //keywords can be used as variables like flatten(group), group.$0 etc.. + } + else { + return ("keyword", "keyword"); + } + } + // is it one of the builtin functions? + if (builtins && builtins.propertyIsEnumerable(stream.current().toUpperCase())) + { + return ("keyword", "variable-2"); + } + // is it one of the listed types? + if (types && types.propertyIsEnumerable(stream.current().toUpperCase())) + return ("keyword", "variable-3"); + // default is a 'variable' + return ret("variable", "pig-word"); + } + } + + // Interface + return { + startState: function() { + return { + tokenize: tokenBase, + startOfLine: true + }; + }, + + token: function(stream, state) { + if(stream.eatSpace()) return null; + var style = state.tokenize(stream, state); + return style; + } + }; +}); + +(function() { + function keywords(str) { + var obj = {}, words = str.split(" "); + for (var i = 0; i < words.length; ++i) obj[words[i]] = true; + return obj; + } + + // builtin funcs taken from trunk revision 1303237 + var pBuiltins = "ABS ACOS ARITY ASIN ATAN AVG BAGSIZE BINSTORAGE BLOOM BUILDBLOOM CBRT CEIL " + + "CONCAT COR COS COSH COUNT COUNT_STAR COV CONSTANTSIZE CUBEDIMENSIONS DIFF DISTINCT DOUBLEABS " + + "DOUBLEAVG DOUBLEBASE DOUBLEMAX DOUBLEMIN DOUBLEROUND DOUBLESUM EXP FLOOR FLOATABS FLOATAVG " + + "FLOATMAX FLOATMIN FLOATROUND FLOATSUM GENERICINVOKER INDEXOF INTABS INTAVG INTMAX INTMIN " + + "INTSUM INVOKEFORDOUBLE INVOKEFORFLOAT INVOKEFORINT INVOKEFORLONG INVOKEFORSTRING INVOKER " + + "ISEMPTY JSONLOADER JSONMETADATA JSONSTORAGE LAST_INDEX_OF LCFIRST LOG LOG10 LOWER LONGABS " + + "LONGAVG LONGMAX LONGMIN LONGSUM MAX MIN MAPSIZE MONITOREDUDF NONDETERMINISTIC OUTPUTSCHEMA " + + "PIGSTORAGE PIGSTREAMING RANDOM REGEX_EXTRACT REGEX_EXTRACT_ALL REPLACE ROUND SIN SINH SIZE " + + "SQRT STRSPLIT SUBSTRING SUM STRINGCONCAT STRINGMAX STRINGMIN STRINGSIZE TAN TANH TOBAG " + + "TOKENIZE TOMAP TOP TOTUPLE TRIM TEXTLOADER TUPLESIZE UCFIRST UPPER UTF8STORAGECONVERTER "; + + // taken from QueryLexer.g + var pKeywords = "VOID IMPORT RETURNS DEFINE LOAD FILTER FOREACH ORDER CUBE DISTINCT COGROUP " + + "JOIN CROSS UNION SPLIT INTO IF OTHERWISE ALL AS BY USING INNER OUTER ONSCHEMA PARALLEL " + + "PARTITION GROUP AND OR NOT GENERATE FLATTEN ASC DESC IS STREAM THROUGH STORE MAPREDUCE " + + "SHIP CACHE INPUT OUTPUT STDERROR STDIN STDOUT LIMIT SAMPLE LEFT RIGHT FULL EQ GT LT GTE LTE " + + "NEQ MATCHES TRUE FALSE DUMP"; + + // data types + var pTypes = "BOOLEAN INT LONG FLOAT DOUBLE CHARARRAY BYTEARRAY BAG TUPLE MAP "; + + CodeMirror.defineMIME("text/x-pig", { + name: "pig", + builtins: keywords(pBuiltins), + keywords: keywords(pKeywords), + types: keywords(pTypes) + }); + + CodeMirror.registerHelper("hintWords", "pig", (pBuiltins + pTypes + pKeywords).split(" ")); +}()); + +}); diff --git a/static/js/mdeditor/lib/codemirror/mode/properties/index.html b/static/js/mdeditor/lib/codemirror/mode/properties/index.html new file mode 100644 index 00000000..f885302d --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/properties/index.html @@ -0,0 +1,53 @@ + + +CodeMirror: Properties files mode + + + + + + + + + +
+

Properties files mode

+
+ + +

MIME types defined: text/x-properties, + text/x-ini.

+ +
diff --git a/static/js/mdeditor/lib/codemirror/mode/properties/properties.js b/static/js/mdeditor/lib/codemirror/mode/properties/properties.js new file mode 100644 index 00000000..07400842 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/properties/properties.js @@ -0,0 +1,78 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("properties", function() { + return { + token: function(stream, state) { + var sol = stream.sol() || state.afterSection; + var eol = stream.eol(); + + state.afterSection = false; + + if (sol) { + if (state.nextMultiline) { + state.inMultiline = true; + state.nextMultiline = false; + } else { + state.position = "def"; + } + } + + if (eol && ! state.nextMultiline) { + state.inMultiline = false; + state.position = "def"; + } + + if (sol) { + while(stream.eatSpace()); + } + + var ch = stream.next(); + + if (sol && (ch === "#" || ch === "!" || ch === ";")) { + state.position = "comment"; + stream.skipToEnd(); + return "comment"; + } else if (sol && ch === "[") { + state.afterSection = true; + stream.skipTo("]"); stream.eat("]"); + return "header"; + } else if (ch === "=" || ch === ":") { + state.position = "quote"; + return null; + } else if (ch === "\\" && state.position === "quote") { + if (stream.next() !== "u") { // u = Unicode sequence \u1234 + // Multiline value + state.nextMultiline = true; + } + } + + return state.position; + }, + + startState: function() { + return { + position : "def", // Current position, "def", "quote" or "comment" + nextMultiline : false, // Is the next line multiline value + inMultiline : false, // Is the current line a multiline value + afterSection : false // Did we just open a section + }; + } + + }; +}); + +CodeMirror.defineMIME("text/x-properties", "properties"); +CodeMirror.defineMIME("text/x-ini", "properties"); + +}); diff --git a/static/js/mdeditor/lib/codemirror/mode/puppet/index.html b/static/js/mdeditor/lib/codemirror/mode/puppet/index.html new file mode 100644 index 00000000..5614c369 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/puppet/index.html @@ -0,0 +1,121 @@ + + +CodeMirror: Puppet mode + + + + + + + + + + +
+

Puppet mode

+
+ + +

MIME types defined: text/x-puppet.

+ +
diff --git a/static/js/mdeditor/lib/codemirror/mode/puppet/puppet.js b/static/js/mdeditor/lib/codemirror/mode/puppet/puppet.js new file mode 100644 index 00000000..e7f799f7 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/puppet/puppet.js @@ -0,0 +1,220 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("puppet", function () { + // Stores the words from the define method + var words = {}; + // Taken, mostly, from the Puppet official variable standards regex + var variable_regex = /({)?([a-z][a-z0-9_]*)?((::[a-z][a-z0-9_]*)*::)?[a-zA-Z0-9_]+(})?/; + + // Takes a string of words separated by spaces and adds them as + // keys with the value of the first argument 'style' + function define(style, string) { + var split = string.split(' '); + for (var i = 0; i < split.length; i++) { + words[split[i]] = style; + } + } + + // Takes commonly known puppet types/words and classifies them to a style + define('keyword', 'class define site node include import inherits'); + define('keyword', 'case if else in and elsif default or'); + define('atom', 'false true running present absent file directory undef'); + define('builtin', 'action augeas burst chain computer cron destination dport exec ' + + 'file filebucket group host icmp iniface interface jump k5login limit log_level ' + + 'log_prefix macauthorization mailalias maillist mcx mount nagios_command ' + + 'nagios_contact nagios_contactgroup nagios_host nagios_hostdependency ' + + 'nagios_hostescalation nagios_hostextinfo nagios_hostgroup nagios_service ' + + 'nagios_servicedependency nagios_serviceescalation nagios_serviceextinfo ' + + 'nagios_servicegroup nagios_timeperiod name notify outiface package proto reject ' + + 'resources router schedule scheduled_task selboolean selmodule service source ' + + 'sport ssh_authorized_key sshkey stage state table tidy todest toports tosource ' + + 'user vlan yumrepo zfs zone zpool'); + + // After finding a start of a string ('|") this function attempts to find the end; + // If a variable is encountered along the way, we display it differently when it + // is encapsulated in a double-quoted string. + function tokenString(stream, state) { + var current, prev, found_var = false; + while (!stream.eol() && (current = stream.next()) != state.pending) { + if (current === '$' && prev != '\\' && state.pending == '"') { + found_var = true; + break; + } + prev = current; + } + if (found_var) { + stream.backUp(1); + } + if (current == state.pending) { + state.continueString = false; + } else { + state.continueString = true; + } + return "string"; + } + + // Main function + function tokenize(stream, state) { + // Matches one whole word + var word = stream.match(/[\w]+/, false); + // Matches attributes (i.e. ensure => present ; 'ensure' would be matched) + var attribute = stream.match(/(\s+)?\w+\s+=>.*/, false); + // Matches non-builtin resource declarations + // (i.e. "apache::vhost {" or "mycustomclasss {" would be matched) + var resource = stream.match(/(\s+)?[\w:_]+(\s+)?{/, false); + // Matches virtual and exported resources (i.e. @@user { ; and the like) + var special_resource = stream.match(/(\s+)?[@]{1,2}[\w:_]+(\s+)?{/, false); + + // Finally advance the stream + var ch = stream.next(); + + // Have we found a variable? + if (ch === '$') { + if (stream.match(variable_regex)) { + // If so, and its in a string, assign it a different color + return state.continueString ? 'variable-2' : 'variable'; + } + // Otherwise return an invalid variable + return "error"; + } + // Should we still be looking for the end of a string? + if (state.continueString) { + // If so, go through the loop again + stream.backUp(1); + return tokenString(stream, state); + } + // Are we in a definition (class, node, define)? + if (state.inDefinition) { + // If so, return def (i.e. for 'class myclass {' ; 'myclass' would be matched) + if (stream.match(/(\s+)?[\w:_]+(\s+)?/)) { + return 'def'; + } + // Match the rest it the next time around + stream.match(/\s+{/); + state.inDefinition = false; + } + // Are we in an 'include' statement? + if (state.inInclude) { + // Match and return the included class + stream.match(/(\s+)?\S+(\s+)?/); + state.inInclude = false; + return 'def'; + } + // Do we just have a function on our hands? + // In 'ensure_resource("myclass")', 'ensure_resource' is matched + if (stream.match(/(\s+)?\w+\(/)) { + stream.backUp(1); + return 'def'; + } + // Have we matched the prior attribute regex? + if (attribute) { + stream.match(/(\s+)?\w+/); + return 'tag'; + } + // Do we have Puppet specific words? + if (word && words.hasOwnProperty(word)) { + // Negates the initial next() + stream.backUp(1); + // Acutally move the stream + stream.match(/[\w]+/); + // We want to process these words differently + // do to the importance they have in Puppet + if (stream.match(/\s+\S+\s+{/, false)) { + state.inDefinition = true; + } + if (word == 'include') { + state.inInclude = true; + } + // Returns their value as state in the prior define methods + return words[word]; + } + // Is there a match on a reference? + if (/(^|\s+)[A-Z][\w:_]+/.test(word)) { + // Negate the next() + stream.backUp(1); + // Match the full reference + stream.match(/(^|\s+)[A-Z][\w:_]+/); + return 'def'; + } + // Have we matched the prior resource regex? + if (resource) { + stream.match(/(\s+)?[\w:_]+/); + return 'def'; + } + // Have we matched the prior special_resource regex? + if (special_resource) { + stream.match(/(\s+)?[@]{1,2}/); + return 'special'; + } + // Match all the comments. All of them. + if (ch == "#") { + stream.skipToEnd(); + return "comment"; + } + // Have we found a string? + if (ch == "'" || ch == '"') { + // Store the type (single or double) + state.pending = ch; + // Perform the looping function to find the end + return tokenString(stream, state); + } + // Match all the brackets + if (ch == '{' || ch == '}') { + return 'bracket'; + } + // Match characters that we are going to assume + // are trying to be regex + if (ch == '/') { + stream.match(/.*?\//); + return 'variable-3'; + } + // Match all the numbers + if (ch.match(/[0-9]/)) { + stream.eatWhile(/[0-9]+/); + return 'number'; + } + // Match the '=' and '=>' operators + if (ch == '=') { + if (stream.peek() == '>') { + stream.next(); + } + return "operator"; + } + // Keep advancing through all the rest + stream.eatWhile(/[\w-]/); + // Return a blank line for everything else + return null; + } + // Start it all + return { + startState: function () { + var state = {}; + state.inDefinition = false; + state.inInclude = false; + state.continueString = false; + state.pending = false; + return state; + }, + token: function (stream, state) { + // Strip the spaces, but regex will account for them eitherway + if (stream.eatSpace()) return null; + // Go through the main process + return tokenize(stream, state); + } + }; +}); + +CodeMirror.defineMIME("text/x-puppet", "puppet"); + +}); diff --git a/static/js/mdeditor/lib/codemirror/mode/python/index.html b/static/js/mdeditor/lib/codemirror/mode/python/index.html new file mode 100644 index 00000000..86eb3d52 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/python/index.html @@ -0,0 +1,198 @@ + + +CodeMirror: Python mode + + + + + + + + + + +
+

Python mode

+ +
+ + +

Cython mode

+ +
+ + +

Configuration Options for Python mode:

+
    +
  • version - 2/3 - The version of Python to recognize. Default is 2.
  • +
  • singleLineStringErrors - true/false - If you have a single-line string that is not terminated at the end of the line, this will show subsequent lines as errors if true, otherwise it will consider the newline as the end of the string. Default is false.
  • +
  • hangingIndent - int - If you want to write long arguments to a function starting on a new line, how much that line should be indented. Defaults to one normal indentation unit.
  • +
+

Advanced Configuration Options:

+

Usefull for superset of python syntax like Enthought enaml, IPython magics and questionmark help

+
    +
  • singleOperators - RegEx - Regular Expression for single operator matching, default :
    ^[\\+\\-\\*/%&|\\^~<>!]
    including
    @
    on Python 3
  • +
  • singleDelimiters - RegEx - Regular Expression for single delimiter matching, default :
    ^[\\(\\)\\[\\]\\{\\}@,:`=;\\.]
  • +
  • doubleOperators - RegEx - Regular Expression for double operators matching, default :
    ^((==)|(!=)|(<=)|(>=)|(<>)|(<<)|(>>)|(//)|(\\*\\*))
  • +
  • doubleDelimiters - RegEx - Regular Expressoin for double delimiters matching, default :
    ^((\\+=)|(\\-=)|(\\*=)|(%=)|(/=)|(&=)|(\\|=)|(\\^=))
  • +
  • tripleDelimiters - RegEx - Regular Expression for triple delimiters matching, default :
    ^((//=)|(>>=)|(<<=)|(\\*\\*=))
  • +
  • identifiers - RegEx - Regular Expression for identifier, default :
    ^[_A-Za-z][_A-Za-z0-9]*
    on Python 2 and
    ^[_A-Za-z\u00A1-\uFFFF][_A-Za-z0-9\u00A1-\uFFFF]*
    on Python 3.
  • +
  • extra_keywords - list of string - List of extra words ton consider as keywords
  • +
  • extra_builtins - list of string - List of extra words ton consider as builtins
  • +
+ + +

MIME types defined: text/x-python and text/x-cython.

+
diff --git a/static/js/mdeditor/lib/codemirror/mode/python/python.js b/static/js/mdeditor/lib/codemirror/mode/python/python.js new file mode 100644 index 00000000..98c0409a --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/python/python.js @@ -0,0 +1,359 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + function wordRegexp(words) { + return new RegExp("^((" + words.join(")|(") + "))\\b"); + } + + var wordOperators = wordRegexp(["and", "or", "not", "is"]); + var commonKeywords = ["as", "assert", "break", "class", "continue", + "def", "del", "elif", "else", "except", "finally", + "for", "from", "global", "if", "import", + "lambda", "pass", "raise", "return", + "try", "while", "with", "yield", "in"]; + var commonBuiltins = ["abs", "all", "any", "bin", "bool", "bytearray", "callable", "chr", + "classmethod", "compile", "complex", "delattr", "dict", "dir", "divmod", + "enumerate", "eval", "filter", "float", "format", "frozenset", + "getattr", "globals", "hasattr", "hash", "help", "hex", "id", + "input", "int", "isinstance", "issubclass", "iter", "len", + "list", "locals", "map", "max", "memoryview", "min", "next", + "object", "oct", "open", "ord", "pow", "property", "range", + "repr", "reversed", "round", "set", "setattr", "slice", + "sorted", "staticmethod", "str", "sum", "super", "tuple", + "type", "vars", "zip", "__import__", "NotImplemented", + "Ellipsis", "__debug__"]; + var py2 = {builtins: ["apply", "basestring", "buffer", "cmp", "coerce", "execfile", + "file", "intern", "long", "raw_input", "reduce", "reload", + "unichr", "unicode", "xrange", "False", "True", "None"], + keywords: ["exec", "print"]}; + var py3 = {builtins: ["ascii", "bytes", "exec", "print"], + keywords: ["nonlocal", "False", "True", "None"]}; + + CodeMirror.registerHelper("hintWords", "python", commonKeywords.concat(commonBuiltins)); + + function top(state) { + return state.scopes[state.scopes.length - 1]; + } + + CodeMirror.defineMode("python", function(conf, parserConf) { + var ERRORCLASS = "error"; + + var singleDelimiters = parserConf.singleDelimiters || new RegExp("^[\\(\\)\\[\\]\\{\\}@,:`=;\\.]"); + var doubleOperators = parserConf.doubleOperators || new RegExp("^((==)|(!=)|(<=)|(>=)|(<>)|(<<)|(>>)|(//)|(\\*\\*))"); + var doubleDelimiters = parserConf.doubleDelimiters || new RegExp("^((\\+=)|(\\-=)|(\\*=)|(%=)|(/=)|(&=)|(\\|=)|(\\^=))"); + var tripleDelimiters = parserConf.tripleDelimiters || new RegExp("^((//=)|(>>=)|(<<=)|(\\*\\*=))"); + + if (parserConf.version && parseInt(parserConf.version, 10) == 3){ + // since http://legacy.python.org/dev/peps/pep-0465/ @ is also an operator + var singleOperators = parserConf.singleOperators || new RegExp("^[\\+\\-\\*/%&|\\^~<>!@]"); + var identifiers = parserConf.identifiers|| new RegExp("^[_A-Za-z\u00A1-\uFFFF][_A-Za-z0-9\u00A1-\uFFFF]*"); + } else { + var singleOperators = parserConf.singleOperators || new RegExp("^[\\+\\-\\*/%&|\\^~<>!]"); + var identifiers = parserConf.identifiers|| new RegExp("^[_A-Za-z][_A-Za-z0-9]*"); + } + + var hangingIndent = parserConf.hangingIndent || conf.indentUnit; + + var myKeywords = commonKeywords, myBuiltins = commonBuiltins; + if(parserConf.extra_keywords != undefined){ + myKeywords = myKeywords.concat(parserConf.extra_keywords); + } + if(parserConf.extra_builtins != undefined){ + myBuiltins = myBuiltins.concat(parserConf.extra_builtins); + } + if (parserConf.version && parseInt(parserConf.version, 10) == 3) { + myKeywords = myKeywords.concat(py3.keywords); + myBuiltins = myBuiltins.concat(py3.builtins); + var stringPrefixes = new RegExp("^(([rb]|(br))?('{3}|\"{3}|['\"]))", "i"); + } else { + myKeywords = myKeywords.concat(py2.keywords); + myBuiltins = myBuiltins.concat(py2.builtins); + var stringPrefixes = new RegExp("^(([rub]|(ur)|(br))?('{3}|\"{3}|['\"]))", "i"); + } + var keywords = wordRegexp(myKeywords); + var builtins = wordRegexp(myBuiltins); + + // tokenizers + function tokenBase(stream, state) { + // Handle scope changes + if (stream.sol() && top(state).type == "py") { + var scopeOffset = top(state).offset; + if (stream.eatSpace()) { + var lineOffset = stream.indentation(); + if (lineOffset > scopeOffset) + pushScope(stream, state, "py"); + else if (lineOffset < scopeOffset && dedent(stream, state)) + state.errorToken = true; + return null; + } else { + var style = tokenBaseInner(stream, state); + if (scopeOffset > 0 && dedent(stream, state)) + style += " " + ERRORCLASS; + return style; + } + } + return tokenBaseInner(stream, state); + } + + function tokenBaseInner(stream, state) { + if (stream.eatSpace()) return null; + + var ch = stream.peek(); + + // Handle Comments + if (ch == "#") { + stream.skipToEnd(); + return "comment"; + } + + // Handle Number Literals + if (stream.match(/^[0-9\.]/, false)) { + var floatLiteral = false; + // Floats + if (stream.match(/^\d*\.\d+(e[\+\-]?\d+)?/i)) { floatLiteral = true; } + if (stream.match(/^\d+\.\d*/)) { floatLiteral = true; } + if (stream.match(/^\.\d+/)) { floatLiteral = true; } + if (floatLiteral) { + // Float literals may be "imaginary" + stream.eat(/J/i); + return "number"; + } + // Integers + var intLiteral = false; + // Hex + if (stream.match(/^0x[0-9a-f]+/i)) intLiteral = true; + // Binary + if (stream.match(/^0b[01]+/i)) intLiteral = true; + // Octal + if (stream.match(/^0o[0-7]+/i)) intLiteral = true; + // Decimal + if (stream.match(/^[1-9]\d*(e[\+\-]?\d+)?/)) { + // Decimal literals may be "imaginary" + stream.eat(/J/i); + // TODO - Can you have imaginary longs? + intLiteral = true; + } + // Zero by itself with no other piece of number. + if (stream.match(/^0(?![\dx])/i)) intLiteral = true; + if (intLiteral) { + // Integer literals may be "long" + stream.eat(/L/i); + return "number"; + } + } + + // Handle Strings + if (stream.match(stringPrefixes)) { + state.tokenize = tokenStringFactory(stream.current()); + return state.tokenize(stream, state); + } + + // Handle operators and Delimiters + if (stream.match(tripleDelimiters) || stream.match(doubleDelimiters)) + return null; + + if (stream.match(doubleOperators) + || stream.match(singleOperators) + || stream.match(wordOperators)) + return "operator"; + + if (stream.match(singleDelimiters)) + return null; + + if (stream.match(keywords)) + return "keyword"; + + if (stream.match(builtins)) + return "builtin"; + + if (stream.match(/^(self|cls)\b/)) + return "variable-2"; + + if (stream.match(identifiers)) { + if (state.lastToken == "def" || state.lastToken == "class") + return "def"; + return "variable"; + } + + // Handle non-detected items + stream.next(); + return ERRORCLASS; + } + + function tokenStringFactory(delimiter) { + while ("rub".indexOf(delimiter.charAt(0).toLowerCase()) >= 0) + delimiter = delimiter.substr(1); + + var singleline = delimiter.length == 1; + var OUTCLASS = "string"; + + function tokenString(stream, state) { + while (!stream.eol()) { + stream.eatWhile(/[^'"\\]/); + if (stream.eat("\\")) { + stream.next(); + if (singleline && stream.eol()) + return OUTCLASS; + } else if (stream.match(delimiter)) { + state.tokenize = tokenBase; + return OUTCLASS; + } else { + stream.eat(/['"]/); + } + } + if (singleline) { + if (parserConf.singleLineStringErrors) + return ERRORCLASS; + else + state.tokenize = tokenBase; + } + return OUTCLASS; + } + tokenString.isString = true; + return tokenString; + } + + function pushScope(stream, state, type) { + var offset = 0, align = null; + if (type == "py") { + while (top(state).type != "py") + state.scopes.pop(); + } + offset = top(state).offset + (type == "py" ? conf.indentUnit : hangingIndent); + if (type != "py" && !stream.match(/^(\s|#.*)*$/, false)) + align = stream.column() + 1; + state.scopes.push({offset: offset, type: type, align: align}); + } + + function dedent(stream, state) { + var indented = stream.indentation(); + while (top(state).offset > indented) { + if (top(state).type != "py") return true; + state.scopes.pop(); + } + return top(state).offset != indented; + } + + function tokenLexer(stream, state) { + var style = state.tokenize(stream, state); + var current = stream.current(); + + // Handle '.' connected identifiers + if (current == ".") { + style = stream.match(identifiers, false) ? null : ERRORCLASS; + if (style == null && state.lastStyle == "meta") { + // Apply 'meta' style to '.' connected identifiers when + // appropriate. + style = "meta"; + } + return style; + } + + // Handle decorators + if (current == "@"){ + if(parserConf.version && parseInt(parserConf.version, 10) == 3){ + return stream.match(identifiers, false) ? "meta" : "operator"; + } else { + return stream.match(identifiers, false) ? "meta" : ERRORCLASS; + } + } + + if ((style == "variable" || style == "builtin") + && state.lastStyle == "meta") + style = "meta"; + + // Handle scope changes. + if (current == "pass" || current == "return") + state.dedent += 1; + + if (current == "lambda") state.lambda = true; + if (current == ":" && !state.lambda && top(state).type == "py") + pushScope(stream, state, "py"); + + var delimiter_index = current.length == 1 ? "[({".indexOf(current) : -1; + if (delimiter_index != -1) + pushScope(stream, state, "])}".slice(delimiter_index, delimiter_index+1)); + + delimiter_index = "])}".indexOf(current); + if (delimiter_index != -1) { + if (top(state).type == current) state.scopes.pop(); + else return ERRORCLASS; + } + if (state.dedent > 0 && stream.eol() && top(state).type == "py") { + if (state.scopes.length > 1) state.scopes.pop(); + state.dedent -= 1; + } + + return style; + } + + var external = { + startState: function(basecolumn) { + return { + tokenize: tokenBase, + scopes: [{offset: basecolumn || 0, type: "py", align: null}], + lastStyle: null, + lastToken: null, + lambda: false, + dedent: 0 + }; + }, + + token: function(stream, state) { + var addErr = state.errorToken; + if (addErr) state.errorToken = false; + var style = tokenLexer(stream, state); + + state.lastStyle = style; + + var current = stream.current(); + if (current && style) + state.lastToken = current; + + if (stream.eol() && state.lambda) + state.lambda = false; + return addErr ? style + " " + ERRORCLASS : style; + }, + + indent: function(state, textAfter) { + if (state.tokenize != tokenBase) + return state.tokenize.isString ? CodeMirror.Pass : 0; + + var scope = top(state); + var closing = textAfter && textAfter.charAt(0) == scope.type; + if (scope.align != null) + return scope.align - (closing ? 1 : 0); + else if (closing && state.scopes.length > 1) + return state.scopes[state.scopes.length - 2].offset; + else + return scope.offset; + }, + + lineComment: "#", + fold: "indent" + }; + return external; + }); + + CodeMirror.defineMIME("text/x-python", "python"); + + var words = function(str) { return str.split(" "); }; + + CodeMirror.defineMIME("text/x-cython", { + name: "python", + extra_keywords: words("by cdef cimport cpdef ctypedef enum except"+ + "extern gil include nogil property public"+ + "readonly struct union DEF IF ELIF ELSE") + }); + +}); diff --git a/static/js/mdeditor/lib/codemirror/mode/q/index.html b/static/js/mdeditor/lib/codemirror/mode/q/index.html new file mode 100644 index 00000000..72785ba3 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/q/index.html @@ -0,0 +1,144 @@ + + +CodeMirror: Q mode + + + + + + + + + + +
+

Q mode

+ + +
+ + + +

MIME type defined: text/x-q.

+
diff --git a/static/js/mdeditor/lib/codemirror/mode/q/q.js b/static/js/mdeditor/lib/codemirror/mode/q/q.js new file mode 100644 index 00000000..a4af9383 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/q/q.js @@ -0,0 +1,139 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("q",function(config){ + var indentUnit=config.indentUnit, + curPunc, + keywords=buildRE(["abs","acos","aj","aj0","all","and","any","asc","asin","asof","atan","attr","avg","avgs","bin","by","ceiling","cols","cor","cos","count","cov","cross","csv","cut","delete","deltas","desc","dev","differ","distinct","div","do","each","ej","enlist","eval","except","exec","exit","exp","fby","fills","first","fkeys","flip","floor","from","get","getenv","group","gtime","hclose","hcount","hdel","hopen","hsym","iasc","idesc","if","ij","in","insert","inter","inv","key","keys","last","like","list","lj","load","log","lower","lsq","ltime","ltrim","mavg","max","maxs","mcount","md5","mdev","med","meta","min","mins","mmax","mmin","mmu","mod","msum","neg","next","not","null","or","over","parse","peach","pj","plist","prd","prds","prev","prior","rand","rank","ratios","raze","read0","read1","reciprocal","reverse","rload","rotate","rsave","rtrim","save","scan","select","set","setenv","show","signum","sin","sqrt","ss","ssr","string","sublist","sum","sums","sv","system","tables","tan","til","trim","txf","type","uj","ungroup","union","update","upper","upsert","value","var","view","views","vs","wavg","where","where","while","within","wj","wj1","wsum","xasc","xbar","xcol","xcols","xdesc","xexp","xgroup","xkey","xlog","xprev","xrank"]), + E=/[|/&^!+:\\\-*%$=~#;@><,?_\'\"\[\(\]\)\s{}]/; + function buildRE(w){return new RegExp("^("+w.join("|")+")$");} + function tokenBase(stream,state){ + var sol=stream.sol(),c=stream.next(); + curPunc=null; + if(sol) + if(c=="/") + return(state.tokenize=tokenLineComment)(stream,state); + else if(c=="\\"){ + if(stream.eol()||/\s/.test(stream.peek())) + return stream.skipToEnd(),/^\\\s*$/.test(stream.current())?(state.tokenize=tokenCommentToEOF)(stream, state):state.tokenize=tokenBase,"comment"; + else + return state.tokenize=tokenBase,"builtin"; + } + if(/\s/.test(c)) + return stream.peek()=="/"?(stream.skipToEnd(),"comment"):"whitespace"; + if(c=='"') + return(state.tokenize=tokenString)(stream,state); + if(c=='`') + return stream.eatWhile(/[A-Z|a-z|\d|_|:|\/|\.]/),"symbol"; + if(("."==c&&/\d/.test(stream.peek()))||/\d/.test(c)){ + var t=null; + stream.backUp(1); + if(stream.match(/^\d{4}\.\d{2}(m|\.\d{2}([D|T](\d{2}(:\d{2}(:\d{2}(\.\d{1,9})?)?)?)?)?)/) + || stream.match(/^\d+D(\d{2}(:\d{2}(:\d{2}(\.\d{1,9})?)?)?)/) + || stream.match(/^\d{2}:\d{2}(:\d{2}(\.\d{1,9})?)?/) + || stream.match(/^\d+[ptuv]{1}/)) + t="temporal"; + else if(stream.match(/^0[NwW]{1}/) + || stream.match(/^0x[\d|a-f|A-F]*/) + || stream.match(/^[0|1]+[b]{1}/) + || stream.match(/^\d+[chijn]{1}/) + || stream.match(/-?\d*(\.\d*)?(e[+\-]?\d+)?(e|f)?/)) + t="number"; + return(t&&(!(c=stream.peek())||E.test(c)))?t:(stream.next(),"error"); + } + if(/[A-Z|a-z]|\./.test(c)) + return stream.eatWhile(/[A-Z|a-z|\.|_|\d]/),keywords.test(stream.current())?"keyword":"variable"; + if(/[|/&^!+:\\\-*%$=~#;@><\.,?_\']/.test(c)) + return null; + if(/[{}\(\[\]\)]/.test(c)) + return null; + return"error"; + } + function tokenLineComment(stream,state){ + return stream.skipToEnd(),/\/\s*$/.test(stream.current())?(state.tokenize=tokenBlockComment)(stream,state):(state.tokenize=tokenBase),"comment"; + } + function tokenBlockComment(stream,state){ + var f=stream.sol()&&stream.peek()=="\\"; + stream.skipToEnd(); + if(f&&/^\\\s*$/.test(stream.current())) + state.tokenize=tokenBase; + return"comment"; + } + function tokenCommentToEOF(stream){return stream.skipToEnd(),"comment";} + function tokenString(stream,state){ + var escaped=false,next,end=false; + while((next=stream.next())){ + if(next=="\""&&!escaped){end=true;break;} + escaped=!escaped&&next=="\\"; + } + if(end)state.tokenize=tokenBase; + return"string"; + } + function pushContext(state,type,col){state.context={prev:state.context,indent:state.indent,col:col,type:type};} + function popContext(state){state.indent=state.context.indent;state.context=state.context.prev;} + return{ + startState:function(){ + return{tokenize:tokenBase, + context:null, + indent:0, + col:0}; + }, + token:function(stream,state){ + if(stream.sol()){ + if(state.context&&state.context.align==null) + state.context.align=false; + state.indent=stream.indentation(); + } + //if (stream.eatSpace()) return null; + var style=state.tokenize(stream,state); + if(style!="comment"&&state.context&&state.context.align==null&&state.context.type!="pattern"){ + state.context.align=true; + } + if(curPunc=="(")pushContext(state,")",stream.column()); + else if(curPunc=="[")pushContext(state,"]",stream.column()); + else if(curPunc=="{")pushContext(state,"}",stream.column()); + else if(/[\]\}\)]/.test(curPunc)){ + while(state.context&&state.context.type=="pattern")popContext(state); + if(state.context&&curPunc==state.context.type)popContext(state); + } + else if(curPunc=="."&&state.context&&state.context.type=="pattern")popContext(state); + else if(/atom|string|variable/.test(style)&&state.context){ + if(/[\}\]]/.test(state.context.type)) + pushContext(state,"pattern",stream.column()); + else if(state.context.type=="pattern"&&!state.context.align){ + state.context.align=true; + state.context.col=stream.column(); + } + } + return style; + }, + indent:function(state,textAfter){ + var firstChar=textAfter&&textAfter.charAt(0); + var context=state.context; + if(/[\]\}]/.test(firstChar)) + while (context&&context.type=="pattern")context=context.prev; + var closing=context&&firstChar==context.type; + if(!context) + return 0; + else if(context.type=="pattern") + return context.col; + else if(context.align) + return context.col+(closing?0:1); + else + return context.indent+(closing?0:indentUnit); + } + }; +}); +CodeMirror.defineMIME("text/x-q","q"); + +}); diff --git a/static/js/mdeditor/lib/codemirror/mode/r/index.html b/static/js/mdeditor/lib/codemirror/mode/r/index.html new file mode 100644 index 00000000..6dd96346 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/r/index.html @@ -0,0 +1,85 @@ + + +CodeMirror: R mode + + + + + + + + + +
+

R mode

+
+ + +

MIME types defined: text/x-rsrc.

+ +

Development of the CodeMirror R mode was kindly sponsored + by Ubalo.

+ +
diff --git a/static/js/mdeditor/lib/codemirror/mode/r/r.js b/static/js/mdeditor/lib/codemirror/mode/r/r.js new file mode 100644 index 00000000..1ab4a956 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/r/r.js @@ -0,0 +1,162 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("r", function(config) { + function wordObj(str) { + var words = str.split(" "), res = {}; + for (var i = 0; i < words.length; ++i) res[words[i]] = true; + return res; + } + var atoms = wordObj("NULL NA Inf NaN NA_integer_ NA_real_ NA_complex_ NA_character_"); + var builtins = wordObj("list quote bquote eval return call parse deparse"); + var keywords = wordObj("if else repeat while function for in next break"); + var blockkeywords = wordObj("if else repeat while function for"); + var opChars = /[+\-*\/^<>=!&|~$:]/; + var curPunc; + + function tokenBase(stream, state) { + curPunc = null; + var ch = stream.next(); + if (ch == "#") { + stream.skipToEnd(); + return "comment"; + } else if (ch == "0" && stream.eat("x")) { + stream.eatWhile(/[\da-f]/i); + return "number"; + } else if (ch == "." && stream.eat(/\d/)) { + stream.match(/\d*(?:e[+\-]?\d+)?/); + return "number"; + } else if (/\d/.test(ch)) { + stream.match(/\d*(?:\.\d+)?(?:e[+\-]\d+)?L?/); + return "number"; + } else if (ch == "'" || ch == '"') { + state.tokenize = tokenString(ch); + return "string"; + } else if (ch == "." && stream.match(/.[.\d]+/)) { + return "keyword"; + } else if (/[\w\.]/.test(ch) && ch != "_") { + stream.eatWhile(/[\w\.]/); + var word = stream.current(); + if (atoms.propertyIsEnumerable(word)) return "atom"; + if (keywords.propertyIsEnumerable(word)) { + // Block keywords start new blocks, except 'else if', which only starts + // one new block for the 'if', no block for the 'else'. + if (blockkeywords.propertyIsEnumerable(word) && + !stream.match(/\s*if(\s+|$)/, false)) + curPunc = "block"; + return "keyword"; + } + if (builtins.propertyIsEnumerable(word)) return "builtin"; + return "variable"; + } else if (ch == "%") { + if (stream.skipTo("%")) stream.next(); + return "variable-2"; + } else if (ch == "<" && stream.eat("-")) { + return "arrow"; + } else if (ch == "=" && state.ctx.argList) { + return "arg-is"; + } else if (opChars.test(ch)) { + if (ch == "$") return "dollar"; + stream.eatWhile(opChars); + return "operator"; + } else if (/[\(\){}\[\];]/.test(ch)) { + curPunc = ch; + if (ch == ";") return "semi"; + return null; + } else { + return null; + } + } + + function tokenString(quote) { + return function(stream, state) { + if (stream.eat("\\")) { + var ch = stream.next(); + if (ch == "x") stream.match(/^[a-f0-9]{2}/i); + else if ((ch == "u" || ch == "U") && stream.eat("{") && stream.skipTo("}")) stream.next(); + else if (ch == "u") stream.match(/^[a-f0-9]{4}/i); + else if (ch == "U") stream.match(/^[a-f0-9]{8}/i); + else if (/[0-7]/.test(ch)) stream.match(/^[0-7]{1,2}/); + return "string-2"; + } else { + var next; + while ((next = stream.next()) != null) { + if (next == quote) { state.tokenize = tokenBase; break; } + if (next == "\\") { stream.backUp(1); break; } + } + return "string"; + } + }; + } + + function push(state, type, stream) { + state.ctx = {type: type, + indent: state.indent, + align: null, + column: stream.column(), + prev: state.ctx}; + } + function pop(state) { + state.indent = state.ctx.indent; + state.ctx = state.ctx.prev; + } + + return { + startState: function() { + return {tokenize: tokenBase, + ctx: {type: "top", + indent: -config.indentUnit, + align: false}, + indent: 0, + afterIdent: false}; + }, + + token: function(stream, state) { + if (stream.sol()) { + if (state.ctx.align == null) state.ctx.align = false; + state.indent = stream.indentation(); + } + if (stream.eatSpace()) return null; + var style = state.tokenize(stream, state); + if (style != "comment" && state.ctx.align == null) state.ctx.align = true; + + var ctype = state.ctx.type; + if ((curPunc == ";" || curPunc == "{" || curPunc == "}") && ctype == "block") pop(state); + if (curPunc == "{") push(state, "}", stream); + else if (curPunc == "(") { + push(state, ")", stream); + if (state.afterIdent) state.ctx.argList = true; + } + else if (curPunc == "[") push(state, "]", stream); + else if (curPunc == "block") push(state, "block", stream); + else if (curPunc == ctype) pop(state); + state.afterIdent = style == "variable" || style == "keyword"; + return style; + }, + + indent: function(state, textAfter) { + if (state.tokenize != tokenBase) return 0; + var firstChar = textAfter && textAfter.charAt(0), ctx = state.ctx, + closing = firstChar == ctx.type; + if (ctx.type == "block") return ctx.indent + (firstChar == "{" ? 0 : config.indentUnit); + else if (ctx.align) return ctx.column + (closing ? 0 : 1); + else return ctx.indent + (closing ? 0 : config.indentUnit); + }, + + lineComment: "#" + }; +}); + +CodeMirror.defineMIME("text/x-rsrc", "r"); + +}); diff --git a/static/js/mdeditor/lib/codemirror/mode/rpm/changes/index.html b/static/js/mdeditor/lib/codemirror/mode/rpm/changes/index.html new file mode 100644 index 00000000..6e5031bd --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/rpm/changes/index.html @@ -0,0 +1,66 @@ + + +CodeMirror: RPM changes mode + + + + + + + + + + + +
+

RPM changes mode

+ +
+ + +

MIME types defined: text/x-rpm-changes.

+
diff --git a/static/js/mdeditor/lib/codemirror/mode/rpm/index.html b/static/js/mdeditor/lib/codemirror/mode/rpm/index.html new file mode 100644 index 00000000..9a34e6df --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/rpm/index.html @@ -0,0 +1,149 @@ + + +CodeMirror: RPM changes mode + + + + + + + + + + + +
+

RPM changes mode

+ +
+ + +

RPM spec mode

+ +
+ + +

MIME types defined: text/x-rpm-spec, text/x-rpm-changes.

+
diff --git a/static/js/mdeditor/lib/codemirror/mode/rpm/rpm.js b/static/js/mdeditor/lib/codemirror/mode/rpm/rpm.js new file mode 100644 index 00000000..3bb7cd2f --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/rpm/rpm.js @@ -0,0 +1,101 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("rpm-changes", function() { + var headerSeperator = /^-+$/; + var headerLine = /^(Mon|Tue|Wed|Thu|Fri|Sat|Sun) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) ?\d{1,2} \d{2}:\d{2}(:\d{2})? [A-Z]{3,4} \d{4} - /; + var simpleEmail = /^[\w+.-]+@[\w.-]+/; + + return { + token: function(stream) { + if (stream.sol()) { + if (stream.match(headerSeperator)) { return 'tag'; } + if (stream.match(headerLine)) { return 'tag'; } + } + if (stream.match(simpleEmail)) { return 'string'; } + stream.next(); + return null; + } + }; +}); + +CodeMirror.defineMIME("text/x-rpm-changes", "rpm-changes"); + +// Quick and dirty spec file highlighting + +CodeMirror.defineMode("rpm-spec", function() { + var arch = /^(i386|i586|i686|x86_64|ppc64|ppc|ia64|s390x|s390|sparc64|sparcv9|sparc|noarch|alphaev6|alpha|hppa|mipsel)/; + + var preamble = /^(Name|Version|Release|License|Summary|Url|Group|Source|BuildArch|BuildRequires|BuildRoot|AutoReqProv|Provides|Requires(\(\w+\))?|Obsoletes|Conflicts|Recommends|Source\d*|Patch\d*|ExclusiveArch|NoSource|Supplements):/; + var section = /^%(debug_package|package|description|prep|build|install|files|clean|changelog|preinstall|preun|postinstall|postun|pre|post|triggerin|triggerun|pretrans|posttrans|verifyscript|check|triggerpostun|triggerprein|trigger)/; + var control_flow_complex = /^%(ifnarch|ifarch|if)/; // rpm control flow macros + var control_flow_simple = /^%(else|endif)/; // rpm control flow macros + var operators = /^(\!|\?|\<\=|\<|\>\=|\>|\=\=|\&\&|\|\|)/; // operators in control flow macros + + return { + startState: function () { + return { + controlFlow: false, + macroParameters: false, + section: false + }; + }, + token: function (stream, state) { + var ch = stream.peek(); + if (ch == "#") { stream.skipToEnd(); return "comment"; } + + if (stream.sol()) { + if (stream.match(preamble)) { return "preamble"; } + if (stream.match(section)) { return "section"; } + } + + if (stream.match(/^\$\w+/)) { return "def"; } // Variables like '$RPM_BUILD_ROOT' + if (stream.match(/^\$\{\w+\}/)) { return "def"; } // Variables like '${RPM_BUILD_ROOT}' + + if (stream.match(control_flow_simple)) { return "keyword"; } + if (stream.match(control_flow_complex)) { + state.controlFlow = true; + return "keyword"; + } + if (state.controlFlow) { + if (stream.match(operators)) { return "operator"; } + if (stream.match(/^(\d+)/)) { return "number"; } + if (stream.eol()) { state.controlFlow = false; } + } + + if (stream.match(arch)) { return "number"; } + + // Macros like '%make_install' or '%attr(0775,root,root)' + if (stream.match(/^%[\w]+/)) { + if (stream.match(/^\(/)) { state.macroParameters = true; } + return "macro"; + } + if (state.macroParameters) { + if (stream.match(/^\d+/)) { return "number";} + if (stream.match(/^\)/)) { + state.macroParameters = false; + return "macro"; + } + } + if (stream.match(/^%\{\??[\w \-]+\}/)) { return "macro"; } // Macros like '%{defined fedora}' + + //TODO: Include bash script sub-parser (CodeMirror supports that) + stream.next(); + return null; + } + }; +}); + +CodeMirror.defineMIME("text/x-rpm-spec", "rpm-spec"); + +}); diff --git a/static/js/mdeditor/lib/codemirror/mode/rst/index.html b/static/js/mdeditor/lib/codemirror/mode/rst/index.html new file mode 100644 index 00000000..2902dea2 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/rst/index.html @@ -0,0 +1,535 @@ + + +CodeMirror: reStructuredText mode + + + + + + + + + + +
+

reStructuredText mode

+
+ + +

+ The python mode will be used for highlighting blocks + containing Python/IPython terminal sessions: blocks starting with + >>> (for Python) or In [num]: (for + IPython). + + Further, the stex mode will be used for highlighting + blocks containing LaTex code. +

+ +

MIME types defined: text/x-rst.

+
diff --git a/static/js/mdeditor/lib/codemirror/mode/rst/rst.js b/static/js/mdeditor/lib/codemirror/mode/rst/rst.js new file mode 100644 index 00000000..bcf110c1 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/rst/rst.js @@ -0,0 +1,557 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../python/python"), require("../stex/stex"), require("../../addon/mode/overlay")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../python/python", "../stex/stex", "../../addon/mode/overlay"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode('rst', function (config, options) { + + var rx_strong = /^\*\*[^\*\s](?:[^\*]*[^\*\s])?\*\*/; + var rx_emphasis = /^\*[^\*\s](?:[^\*]*[^\*\s])?\*/; + var rx_literal = /^``[^`\s](?:[^`]*[^`\s])``/; + + var rx_number = /^(?:[\d]+(?:[\.,]\d+)*)/; + var rx_positive = /^(?:\s\+[\d]+(?:[\.,]\d+)*)/; + var rx_negative = /^(?:\s\-[\d]+(?:[\.,]\d+)*)/; + + var rx_uri_protocol = "[Hh][Tt][Tt][Pp][Ss]?://"; + var rx_uri_domain = "(?:[\\d\\w.-]+)\\.(?:\\w{2,6})"; + var rx_uri_path = "(?:/[\\d\\w\\#\\%\\&\\-\\.\\,\\/\\:\\=\\?\\~]+)*"; + var rx_uri = new RegExp("^" + rx_uri_protocol + rx_uri_domain + rx_uri_path); + + var overlay = { + token: function (stream) { + + if (stream.match(rx_strong) && stream.match (/\W+|$/, false)) + return 'strong'; + if (stream.match(rx_emphasis) && stream.match (/\W+|$/, false)) + return 'em'; + if (stream.match(rx_literal) && stream.match (/\W+|$/, false)) + return 'string-2'; + if (stream.match(rx_number)) + return 'number'; + if (stream.match(rx_positive)) + return 'positive'; + if (stream.match(rx_negative)) + return 'negative'; + if (stream.match(rx_uri)) + return 'link'; + + while (stream.next() != null) { + if (stream.match(rx_strong, false)) break; + if (stream.match(rx_emphasis, false)) break; + if (stream.match(rx_literal, false)) break; + if (stream.match(rx_number, false)) break; + if (stream.match(rx_positive, false)) break; + if (stream.match(rx_negative, false)) break; + if (stream.match(rx_uri, false)) break; + } + + return null; + } + }; + + var mode = CodeMirror.getMode( + config, options.backdrop || 'rst-base' + ); + + return CodeMirror.overlayMode(mode, overlay, true); // combine +}, 'python', 'stex'); + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +CodeMirror.defineMode('rst-base', function (config) { + + /////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + + function format(string) { + var args = Array.prototype.slice.call(arguments, 1); + return string.replace(/{(\d+)}/g, function (match, n) { + return typeof args[n] != 'undefined' ? args[n] : match; + }); + } + + /////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + + var mode_python = CodeMirror.getMode(config, 'python'); + var mode_stex = CodeMirror.getMode(config, 'stex'); + + /////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + + var SEPA = "\\s+"; + var TAIL = "(?:\\s*|\\W|$)", + rx_TAIL = new RegExp(format('^{0}', TAIL)); + + var NAME = + "(?:[^\\W\\d_](?:[\\w!\"#$%&'()\\*\\+,\\-\\.\/:;<=>\\?]*[^\\W_])?)", + rx_NAME = new RegExp(format('^{0}', NAME)); + var NAME_WWS = + "(?:[^\\W\\d_](?:[\\w\\s!\"#$%&'()\\*\\+,\\-\\.\/:;<=>\\?]*[^\\W_])?)"; + var REF_NAME = format('(?:{0}|`{1}`)', NAME, NAME_WWS); + + var TEXT1 = "(?:[^\\s\\|](?:[^\\|]*[^\\s\\|])?)"; + var TEXT2 = "(?:[^\\`]+)", + rx_TEXT2 = new RegExp(format('^{0}', TEXT2)); + + var rx_section = new RegExp( + "^([!'#$%&\"()*+,-./:;<=>?@\\[\\\\\\]^_`{|}~])\\1{3,}\\s*$"); + var rx_explicit = new RegExp( + format('^\\.\\.{0}', SEPA)); + var rx_link = new RegExp( + format('^_{0}:{1}|^__:{1}', REF_NAME, TAIL)); + var rx_directive = new RegExp( + format('^{0}::{1}', REF_NAME, TAIL)); + var rx_substitution = new RegExp( + format('^\\|{0}\\|{1}{2}::{3}', TEXT1, SEPA, REF_NAME, TAIL)); + var rx_footnote = new RegExp( + format('^\\[(?:\\d+|#{0}?|\\*)]{1}', REF_NAME, TAIL)); + var rx_citation = new RegExp( + format('^\\[{0}\\]{1}', REF_NAME, TAIL)); + + var rx_substitution_ref = new RegExp( + format('^\\|{0}\\|', TEXT1)); + var rx_footnote_ref = new RegExp( + format('^\\[(?:\\d+|#{0}?|\\*)]_', REF_NAME)); + var rx_citation_ref = new RegExp( + format('^\\[{0}\\]_', REF_NAME)); + var rx_link_ref1 = new RegExp( + format('^{0}__?', REF_NAME)); + var rx_link_ref2 = new RegExp( + format('^`{0}`_', TEXT2)); + + var rx_role_pre = new RegExp( + format('^:{0}:`{1}`{2}', NAME, TEXT2, TAIL)); + var rx_role_suf = new RegExp( + format('^`{1}`:{0}:{2}', NAME, TEXT2, TAIL)); + var rx_role = new RegExp( + format('^:{0}:{1}', NAME, TAIL)); + + var rx_directive_name = new RegExp(format('^{0}', REF_NAME)); + var rx_directive_tail = new RegExp(format('^::{0}', TAIL)); + var rx_substitution_text = new RegExp(format('^\\|{0}\\|', TEXT1)); + var rx_substitution_sepa = new RegExp(format('^{0}', SEPA)); + var rx_substitution_name = new RegExp(format('^{0}', REF_NAME)); + var rx_substitution_tail = new RegExp(format('^::{0}', TAIL)); + var rx_link_head = new RegExp("^_"); + var rx_link_name = new RegExp(format('^{0}|_', REF_NAME)); + var rx_link_tail = new RegExp(format('^:{0}', TAIL)); + + var rx_verbatim = new RegExp('^::\\s*$'); + var rx_examples = new RegExp('^\\s+(?:>>>|In \\[\\d+\\]:)\\s'); + + /////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + + function to_normal(stream, state) { + var token = null; + + if (stream.sol() && stream.match(rx_examples, false)) { + change(state, to_mode, { + mode: mode_python, local: CodeMirror.startState(mode_python) + }); + } else if (stream.sol() && stream.match(rx_explicit)) { + change(state, to_explicit); + token = 'meta'; + } else if (stream.sol() && stream.match(rx_section)) { + change(state, to_normal); + token = 'header'; + } else if (phase(state) == rx_role_pre || + stream.match(rx_role_pre, false)) { + + switch (stage(state)) { + case 0: + change(state, to_normal, context(rx_role_pre, 1)); + stream.match(/^:/); + token = 'meta'; + break; + case 1: + change(state, to_normal, context(rx_role_pre, 2)); + stream.match(rx_NAME); + token = 'keyword'; + + if (stream.current().match(/^(?:math|latex)/)) { + state.tmp_stex = true; + } + break; + case 2: + change(state, to_normal, context(rx_role_pre, 3)); + stream.match(/^:`/); + token = 'meta'; + break; + case 3: + if (state.tmp_stex) { + state.tmp_stex = undefined; state.tmp = { + mode: mode_stex, local: CodeMirror.startState(mode_stex) + }; + } + + if (state.tmp) { + if (stream.peek() == '`') { + change(state, to_normal, context(rx_role_pre, 4)); + state.tmp = undefined; + break; + } + + token = state.tmp.mode.token(stream, state.tmp.local); + break; + } + + change(state, to_normal, context(rx_role_pre, 4)); + stream.match(rx_TEXT2); + token = 'string'; + break; + case 4: + change(state, to_normal, context(rx_role_pre, 5)); + stream.match(/^`/); + token = 'meta'; + break; + case 5: + change(state, to_normal, context(rx_role_pre, 6)); + stream.match(rx_TAIL); + break; + default: + change(state, to_normal); + } + } else if (phase(state) == rx_role_suf || + stream.match(rx_role_suf, false)) { + + switch (stage(state)) { + case 0: + change(state, to_normal, context(rx_role_suf, 1)); + stream.match(/^`/); + token = 'meta'; + break; + case 1: + change(state, to_normal, context(rx_role_suf, 2)); + stream.match(rx_TEXT2); + token = 'string'; + break; + case 2: + change(state, to_normal, context(rx_role_suf, 3)); + stream.match(/^`:/); + token = 'meta'; + break; + case 3: + change(state, to_normal, context(rx_role_suf, 4)); + stream.match(rx_NAME); + token = 'keyword'; + break; + case 4: + change(state, to_normal, context(rx_role_suf, 5)); + stream.match(/^:/); + token = 'meta'; + break; + case 5: + change(state, to_normal, context(rx_role_suf, 6)); + stream.match(rx_TAIL); + break; + default: + change(state, to_normal); + } + } else if (phase(state) == rx_role || stream.match(rx_role, false)) { + + switch (stage(state)) { + case 0: + change(state, to_normal, context(rx_role, 1)); + stream.match(/^:/); + token = 'meta'; + break; + case 1: + change(state, to_normal, context(rx_role, 2)); + stream.match(rx_NAME); + token = 'keyword'; + break; + case 2: + change(state, to_normal, context(rx_role, 3)); + stream.match(/^:/); + token = 'meta'; + break; + case 3: + change(state, to_normal, context(rx_role, 4)); + stream.match(rx_TAIL); + break; + default: + change(state, to_normal); + } + } else if (phase(state) == rx_substitution_ref || + stream.match(rx_substitution_ref, false)) { + + switch (stage(state)) { + case 0: + change(state, to_normal, context(rx_substitution_ref, 1)); + stream.match(rx_substitution_text); + token = 'variable-2'; + break; + case 1: + change(state, to_normal, context(rx_substitution_ref, 2)); + if (stream.match(/^_?_?/)) token = 'link'; + break; + default: + change(state, to_normal); + } + } else if (stream.match(rx_footnote_ref)) { + change(state, to_normal); + token = 'quote'; + } else if (stream.match(rx_citation_ref)) { + change(state, to_normal); + token = 'quote'; + } else if (stream.match(rx_link_ref1)) { + change(state, to_normal); + if (!stream.peek() || stream.peek().match(/^\W$/)) { + token = 'link'; + } + } else if (phase(state) == rx_link_ref2 || + stream.match(rx_link_ref2, false)) { + + switch (stage(state)) { + case 0: + if (!stream.peek() || stream.peek().match(/^\W$/)) { + change(state, to_normal, context(rx_link_ref2, 1)); + } else { + stream.match(rx_link_ref2); + } + break; + case 1: + change(state, to_normal, context(rx_link_ref2, 2)); + stream.match(/^`/); + token = 'link'; + break; + case 2: + change(state, to_normal, context(rx_link_ref2, 3)); + stream.match(rx_TEXT2); + break; + case 3: + change(state, to_normal, context(rx_link_ref2, 4)); + stream.match(/^`_/); + token = 'link'; + break; + default: + change(state, to_normal); + } + } else if (stream.match(rx_verbatim)) { + change(state, to_verbatim); + } + + else { + if (stream.next()) change(state, to_normal); + } + + return token; + } + + /////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + + function to_explicit(stream, state) { + var token = null; + + if (phase(state) == rx_substitution || + stream.match(rx_substitution, false)) { + + switch (stage(state)) { + case 0: + change(state, to_explicit, context(rx_substitution, 1)); + stream.match(rx_substitution_text); + token = 'variable-2'; + break; + case 1: + change(state, to_explicit, context(rx_substitution, 2)); + stream.match(rx_substitution_sepa); + break; + case 2: + change(state, to_explicit, context(rx_substitution, 3)); + stream.match(rx_substitution_name); + token = 'keyword'; + break; + case 3: + change(state, to_explicit, context(rx_substitution, 4)); + stream.match(rx_substitution_tail); + token = 'meta'; + break; + default: + change(state, to_normal); + } + } else if (phase(state) == rx_directive || + stream.match(rx_directive, false)) { + + switch (stage(state)) { + case 0: + change(state, to_explicit, context(rx_directive, 1)); + stream.match(rx_directive_name); + token = 'keyword'; + + if (stream.current().match(/^(?:math|latex)/)) + state.tmp_stex = true; + else if (stream.current().match(/^python/)) + state.tmp_py = true; + break; + case 1: + change(state, to_explicit, context(rx_directive, 2)); + stream.match(rx_directive_tail); + token = 'meta'; + + if (stream.match(/^latex\s*$/) || state.tmp_stex) { + state.tmp_stex = undefined; change(state, to_mode, { + mode: mode_stex, local: CodeMirror.startState(mode_stex) + }); + } + break; + case 2: + change(state, to_explicit, context(rx_directive, 3)); + if (stream.match(/^python\s*$/) || state.tmp_py) { + state.tmp_py = undefined; change(state, to_mode, { + mode: mode_python, local: CodeMirror.startState(mode_python) + }); + } + break; + default: + change(state, to_normal); + } + } else if (phase(state) == rx_link || stream.match(rx_link, false)) { + + switch (stage(state)) { + case 0: + change(state, to_explicit, context(rx_link, 1)); + stream.match(rx_link_head); + stream.match(rx_link_name); + token = 'link'; + break; + case 1: + change(state, to_explicit, context(rx_link, 2)); + stream.match(rx_link_tail); + token = 'meta'; + break; + default: + change(state, to_normal); + } + } else if (stream.match(rx_footnote)) { + change(state, to_normal); + token = 'quote'; + } else if (stream.match(rx_citation)) { + change(state, to_normal); + token = 'quote'; + } + + else { + stream.eatSpace(); + if (stream.eol()) { + change(state, to_normal); + } else { + stream.skipToEnd(); + change(state, to_comment); + token = 'comment'; + } + } + + return token; + } + + /////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + + function to_comment(stream, state) { + return as_block(stream, state, 'comment'); + } + + function to_verbatim(stream, state) { + return as_block(stream, state, 'meta'); + } + + function as_block(stream, state, token) { + if (stream.eol() || stream.eatSpace()) { + stream.skipToEnd(); + return token; + } else { + change(state, to_normal); + return null; + } + } + + /////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + + function to_mode(stream, state) { + + if (state.ctx.mode && state.ctx.local) { + + if (stream.sol()) { + if (!stream.eatSpace()) change(state, to_normal); + return null; + } + + return state.ctx.mode.token(stream, state.ctx.local); + } + + change(state, to_normal); + return null; + } + + /////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + + function context(phase, stage, mode, local) { + return {phase: phase, stage: stage, mode: mode, local: local}; + } + + function change(state, tok, ctx) { + state.tok = tok; + state.ctx = ctx || {}; + } + + function stage(state) { + return state.ctx.stage || 0; + } + + function phase(state) { + return state.ctx.phase; + } + + /////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + + return { + startState: function () { + return {tok: to_normal, ctx: context(undefined, 0)}; + }, + + copyState: function (state) { + var ctx = state.ctx, tmp = state.tmp; + if (ctx.local) + ctx = {mode: ctx.mode, local: CodeMirror.copyState(ctx.mode, ctx.local)}; + if (tmp) + tmp = {mode: tmp.mode, local: CodeMirror.copyState(tmp.mode, tmp.local)}; + return {tok: state.tok, ctx: ctx, tmp: tmp}; + }, + + innerMode: function (state) { + return state.tmp ? {state: state.tmp.local, mode: state.tmp.mode} + : state.ctx.mode ? {state: state.ctx.local, mode: state.ctx.mode} + : null; + }, + + token: function (stream, state) { + return state.tok(stream, state); + } + }; +}, 'python', 'stex'); + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +CodeMirror.defineMIME('text/x-rst', 'rst'); + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +}); diff --git a/static/js/mdeditor/lib/codemirror/mode/ruby/index.html b/static/js/mdeditor/lib/codemirror/mode/ruby/index.html new file mode 100644 index 00000000..97544bab --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/ruby/index.html @@ -0,0 +1,183 @@ + + +CodeMirror: Ruby mode + + + + + + + + + + +
+

Ruby mode

+
+ + +

MIME types defined: text/x-ruby.

+ +

Development of the CodeMirror Ruby mode was kindly sponsored + by Ubalo.

+ +
diff --git a/static/js/mdeditor/lib/codemirror/mode/ruby/ruby.js b/static/js/mdeditor/lib/codemirror/mode/ruby/ruby.js new file mode 100644 index 00000000..eab9d9da --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/ruby/ruby.js @@ -0,0 +1,285 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("ruby", function(config) { + function wordObj(words) { + var o = {}; + for (var i = 0, e = words.length; i < e; ++i) o[words[i]] = true; + return o; + } + var keywords = wordObj([ + "alias", "and", "BEGIN", "begin", "break", "case", "class", "def", "defined?", "do", "else", + "elsif", "END", "end", "ensure", "false", "for", "if", "in", "module", "next", "not", "or", + "redo", "rescue", "retry", "return", "self", "super", "then", "true", "undef", "unless", + "until", "when", "while", "yield", "nil", "raise", "throw", "catch", "fail", "loop", "callcc", + "caller", "lambda", "proc", "public", "protected", "private", "require", "load", + "require_relative", "extend", "autoload", "__END__", "__FILE__", "__LINE__", "__dir__" + ]); + var indentWords = wordObj(["def", "class", "case", "for", "while", "module", "then", + "catch", "loop", "proc", "begin"]); + var dedentWords = wordObj(["end", "until"]); + var matching = {"[": "]", "{": "}", "(": ")"}; + var curPunc; + + function chain(newtok, stream, state) { + state.tokenize.push(newtok); + return newtok(stream, state); + } + + function tokenBase(stream, state) { + curPunc = null; + if (stream.sol() && stream.match("=begin") && stream.eol()) { + state.tokenize.push(readBlockComment); + return "comment"; + } + if (stream.eatSpace()) return null; + var ch = stream.next(), m; + if (ch == "`" || ch == "'" || ch == '"') { + return chain(readQuoted(ch, "string", ch == '"' || ch == "`"), stream, state); + } else if (ch == "/") { + var currentIndex = stream.current().length; + if (stream.skipTo("/")) { + var search_till = stream.current().length; + stream.backUp(stream.current().length - currentIndex); + var balance = 0; // balance brackets + while (stream.current().length < search_till) { + var chchr = stream.next(); + if (chchr == "(") balance += 1; + else if (chchr == ")") balance -= 1; + if (balance < 0) break; + } + stream.backUp(stream.current().length - currentIndex); + if (balance == 0) + return chain(readQuoted(ch, "string-2", true), stream, state); + } + return "operator"; + } else if (ch == "%") { + var style = "string", embed = true; + if (stream.eat("s")) style = "atom"; + else if (stream.eat(/[WQ]/)) style = "string"; + else if (stream.eat(/[r]/)) style = "string-2"; + else if (stream.eat(/[wxq]/)) { style = "string"; embed = false; } + var delim = stream.eat(/[^\w\s=]/); + if (!delim) return "operator"; + if (matching.propertyIsEnumerable(delim)) delim = matching[delim]; + return chain(readQuoted(delim, style, embed, true), stream, state); + } else if (ch == "#") { + stream.skipToEnd(); + return "comment"; + } else if (ch == "<" && (m = stream.match(/^<-?[\`\"\']?([a-zA-Z_?]\w*)[\`\"\']?(?:;|$)/))) { + return chain(readHereDoc(m[1]), stream, state); + } else if (ch == "0") { + if (stream.eat("x")) stream.eatWhile(/[\da-fA-F]/); + else if (stream.eat("b")) stream.eatWhile(/[01]/); + else stream.eatWhile(/[0-7]/); + return "number"; + } else if (/\d/.test(ch)) { + stream.match(/^[\d_]*(?:\.[\d_]+)?(?:[eE][+\-]?[\d_]+)?/); + return "number"; + } else if (ch == "?") { + while (stream.match(/^\\[CM]-/)) {} + if (stream.eat("\\")) stream.eatWhile(/\w/); + else stream.next(); + return "string"; + } else if (ch == ":") { + if (stream.eat("'")) return chain(readQuoted("'", "atom", false), stream, state); + if (stream.eat('"')) return chain(readQuoted('"', "atom", true), stream, state); + + // :> :>> :< :<< are valid symbols + if (stream.eat(/[\<\>]/)) { + stream.eat(/[\<\>]/); + return "atom"; + } + + // :+ :- :/ :* :| :& :! are valid symbols + if (stream.eat(/[\+\-\*\/\&\|\:\!]/)) { + return "atom"; + } + + // Symbols can't start by a digit + if (stream.eat(/[a-zA-Z$@_\xa1-\uffff]/)) { + stream.eatWhile(/[\w$\xa1-\uffff]/); + // Only one ? ! = is allowed and only as the last character + stream.eat(/[\?\!\=]/); + return "atom"; + } + return "operator"; + } else if (ch == "@" && stream.match(/^@?[a-zA-Z_\xa1-\uffff]/)) { + stream.eat("@"); + stream.eatWhile(/[\w\xa1-\uffff]/); + return "variable-2"; + } else if (ch == "$") { + if (stream.eat(/[a-zA-Z_]/)) { + stream.eatWhile(/[\w]/); + } else if (stream.eat(/\d/)) { + stream.eat(/\d/); + } else { + stream.next(); // Must be a special global like $: or $! + } + return "variable-3"; + } else if (/[a-zA-Z_\xa1-\uffff]/.test(ch)) { + stream.eatWhile(/[\w\xa1-\uffff]/); + stream.eat(/[\?\!]/); + if (stream.eat(":")) return "atom"; + return "ident"; + } else if (ch == "|" && (state.varList || state.lastTok == "{" || state.lastTok == "do")) { + curPunc = "|"; + return null; + } else if (/[\(\)\[\]{}\\;]/.test(ch)) { + curPunc = ch; + return null; + } else if (ch == "-" && stream.eat(">")) { + return "arrow"; + } else if (/[=+\-\/*:\.^%<>~|]/.test(ch)) { + var more = stream.eatWhile(/[=+\-\/*:\.^%<>~|]/); + if (ch == "." && !more) curPunc = "."; + return "operator"; + } else { + return null; + } + } + + function tokenBaseUntilBrace(depth) { + if (!depth) depth = 1; + return function(stream, state) { + if (stream.peek() == "}") { + if (depth == 1) { + state.tokenize.pop(); + return state.tokenize[state.tokenize.length-1](stream, state); + } else { + state.tokenize[state.tokenize.length - 1] = tokenBaseUntilBrace(depth - 1); + } + } else if (stream.peek() == "{") { + state.tokenize[state.tokenize.length - 1] = tokenBaseUntilBrace(depth + 1); + } + return tokenBase(stream, state); + }; + } + function tokenBaseOnce() { + var alreadyCalled = false; + return function(stream, state) { + if (alreadyCalled) { + state.tokenize.pop(); + return state.tokenize[state.tokenize.length-1](stream, state); + } + alreadyCalled = true; + return tokenBase(stream, state); + }; + } + function readQuoted(quote, style, embed, unescaped) { + return function(stream, state) { + var escaped = false, ch; + + if (state.context.type === 'read-quoted-paused') { + state.context = state.context.prev; + stream.eat("}"); + } + + while ((ch = stream.next()) != null) { + if (ch == quote && (unescaped || !escaped)) { + state.tokenize.pop(); + break; + } + if (embed && ch == "#" && !escaped) { + if (stream.eat("{")) { + if (quote == "}") { + state.context = {prev: state.context, type: 'read-quoted-paused'}; + } + state.tokenize.push(tokenBaseUntilBrace()); + break; + } else if (/[@\$]/.test(stream.peek())) { + state.tokenize.push(tokenBaseOnce()); + break; + } + } + escaped = !escaped && ch == "\\"; + } + return style; + }; + } + function readHereDoc(phrase) { + return function(stream, state) { + if (stream.match(phrase)) state.tokenize.pop(); + else stream.skipToEnd(); + return "string"; + }; + } + function readBlockComment(stream, state) { + if (stream.sol() && stream.match("=end") && stream.eol()) + state.tokenize.pop(); + stream.skipToEnd(); + return "comment"; + } + + return { + startState: function() { + return {tokenize: [tokenBase], + indented: 0, + context: {type: "top", indented: -config.indentUnit}, + continuedLine: false, + lastTok: null, + varList: false}; + }, + + token: function(stream, state) { + if (stream.sol()) state.indented = stream.indentation(); + var style = state.tokenize[state.tokenize.length-1](stream, state), kwtype; + var thisTok = curPunc; + if (style == "ident") { + var word = stream.current(); + style = state.lastTok == "." ? "property" + : keywords.propertyIsEnumerable(stream.current()) ? "keyword" + : /^[A-Z]/.test(word) ? "tag" + : (state.lastTok == "def" || state.lastTok == "class" || state.varList) ? "def" + : "variable"; + if (style == "keyword") { + thisTok = word; + if (indentWords.propertyIsEnumerable(word)) kwtype = "indent"; + else if (dedentWords.propertyIsEnumerable(word)) kwtype = "dedent"; + else if ((word == "if" || word == "unless") && stream.column() == stream.indentation()) + kwtype = "indent"; + else if (word == "do" && state.context.indented < state.indented) + kwtype = "indent"; + } + } + if (curPunc || (style && style != "comment")) state.lastTok = thisTok; + if (curPunc == "|") state.varList = !state.varList; + + if (kwtype == "indent" || /[\(\[\{]/.test(curPunc)) + state.context = {prev: state.context, type: curPunc || style, indented: state.indented}; + else if ((kwtype == "dedent" || /[\)\]\}]/.test(curPunc)) && state.context.prev) + state.context = state.context.prev; + + if (stream.eol()) + state.continuedLine = (curPunc == "\\" || style == "operator"); + return style; + }, + + indent: function(state, textAfter) { + if (state.tokenize[state.tokenize.length-1] != tokenBase) return 0; + var firstChar = textAfter && textAfter.charAt(0); + var ct = state.context; + var closing = ct.type == matching[firstChar] || + ct.type == "keyword" && /^(?:end|until|else|elsif|when|rescue)\b/.test(textAfter); + return ct.indented + (closing ? 0 : config.indentUnit) + + (state.continuedLine ? config.indentUnit : 0); + }, + + electricChars: "}de", // enD and rescuE + lineComment: "#" + }; +}); + +CodeMirror.defineMIME("text/x-ruby", "ruby"); + +}); diff --git a/static/js/mdeditor/lib/codemirror/mode/ruby/test.js b/static/js/mdeditor/lib/codemirror/mode/ruby/test.js new file mode 100644 index 00000000..cade864f --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/ruby/test.js @@ -0,0 +1,14 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function() { + var mode = CodeMirror.getMode({indentUnit: 2}, "ruby"); + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); } + + MT("divide_equal_operator", + "[variable bar] [operator /=] [variable foo]"); + + MT("divide_equal_operator_no_spacing", + "[variable foo][operator /=][number 42]"); + +})(); diff --git a/static/js/mdeditor/lib/codemirror/mode/rust/index.html b/static/js/mdeditor/lib/codemirror/mode/rust/index.html new file mode 100644 index 00000000..407e84f2 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/rust/index.html @@ -0,0 +1,60 @@ + + +CodeMirror: Rust mode + + + + + + + + + +
+

Rust mode

+ + +
+ + + +

MIME types defined: text/x-rustsrc.

+
diff --git a/static/js/mdeditor/lib/codemirror/mode/rust/rust.js b/static/js/mdeditor/lib/codemirror/mode/rust/rust.js new file mode 100644 index 00000000..2bffa9a6 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/rust/rust.js @@ -0,0 +1,451 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("rust", function() { + var indentUnit = 4, altIndentUnit = 2; + var valKeywords = { + "if": "if-style", "while": "if-style", "loop": "else-style", "else": "else-style", + "do": "else-style", "ret": "else-style", "fail": "else-style", + "break": "atom", "cont": "atom", "const": "let", "resource": "fn", + "let": "let", "fn": "fn", "for": "for", "alt": "alt", "iface": "iface", + "impl": "impl", "type": "type", "enum": "enum", "mod": "mod", + "as": "op", "true": "atom", "false": "atom", "assert": "op", "check": "op", + "claim": "op", "native": "ignore", "unsafe": "ignore", "import": "else-style", + "export": "else-style", "copy": "op", "log": "op", "log_err": "op", + "use": "op", "bind": "op", "self": "atom", "struct": "enum" + }; + var typeKeywords = function() { + var keywords = {"fn": "fn", "block": "fn", "obj": "obj"}; + var atoms = "bool uint int i8 i16 i32 i64 u8 u16 u32 u64 float f32 f64 str char".split(" "); + for (var i = 0, e = atoms.length; i < e; ++i) keywords[atoms[i]] = "atom"; + return keywords; + }(); + var operatorChar = /[+\-*&%=<>!?|\.@]/; + + // Tokenizer + + // Used as scratch variable to communicate multiple values without + // consing up tons of objects. + var tcat, content; + function r(tc, style) { + tcat = tc; + return style; + } + + function tokenBase(stream, state) { + var ch = stream.next(); + if (ch == '"') { + state.tokenize = tokenString; + return state.tokenize(stream, state); + } + if (ch == "'") { + tcat = "atom"; + if (stream.eat("\\")) { + if (stream.skipTo("'")) { stream.next(); return "string"; } + else { return "error"; } + } else { + stream.next(); + return stream.eat("'") ? "string" : "error"; + } + } + if (ch == "/") { + if (stream.eat("/")) { stream.skipToEnd(); return "comment"; } + if (stream.eat("*")) { + state.tokenize = tokenComment(1); + return state.tokenize(stream, state); + } + } + if (ch == "#") { + if (stream.eat("[")) { tcat = "open-attr"; return null; } + stream.eatWhile(/\w/); + return r("macro", "meta"); + } + if (ch == ":" && stream.match(":<")) { + return r("op", null); + } + if (ch.match(/\d/) || (ch == "." && stream.eat(/\d/))) { + var flp = false; + if (!stream.match(/^x[\da-f]+/i) && !stream.match(/^b[01]+/)) { + stream.eatWhile(/\d/); + if (stream.eat(".")) { flp = true; stream.eatWhile(/\d/); } + if (stream.match(/^e[+\-]?\d+/i)) { flp = true; } + } + if (flp) stream.match(/^f(?:32|64)/); + else stream.match(/^[ui](?:8|16|32|64)/); + return r("atom", "number"); + } + if (ch.match(/[()\[\]{}:;,]/)) return r(ch, null); + if (ch == "-" && stream.eat(">")) return r("->", null); + if (ch.match(operatorChar)) { + stream.eatWhile(operatorChar); + return r("op", null); + } + stream.eatWhile(/\w/); + content = stream.current(); + if (stream.match(/^::\w/)) { + stream.backUp(1); + return r("prefix", "variable-2"); + } + if (state.keywords.propertyIsEnumerable(content)) + return r(state.keywords[content], content.match(/true|false/) ? "atom" : "keyword"); + return r("name", "variable"); + } + + function tokenString(stream, state) { + var ch, escaped = false; + while (ch = stream.next()) { + if (ch == '"' && !escaped) { + state.tokenize = tokenBase; + return r("atom", "string"); + } + escaped = !escaped && ch == "\\"; + } + // Hack to not confuse the parser when a string is split in + // pieces. + return r("op", "string"); + } + + function tokenComment(depth) { + return function(stream, state) { + var lastCh = null, ch; + while (ch = stream.next()) { + if (ch == "/" && lastCh == "*") { + if (depth == 1) { + state.tokenize = tokenBase; + break; + } else { + state.tokenize = tokenComment(depth - 1); + return state.tokenize(stream, state); + } + } + if (ch == "*" && lastCh == "/") { + state.tokenize = tokenComment(depth + 1); + return state.tokenize(stream, state); + } + lastCh = ch; + } + return "comment"; + }; + } + + // Parser + + var cx = {state: null, stream: null, marked: null, cc: null}; + function pass() { + for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]); + } + function cont() { + pass.apply(null, arguments); + return true; + } + + function pushlex(type, info) { + var result = function() { + var state = cx.state; + state.lexical = {indented: state.indented, column: cx.stream.column(), + type: type, prev: state.lexical, info: info}; + }; + result.lex = true; + return result; + } + function poplex() { + var state = cx.state; + if (state.lexical.prev) { + if (state.lexical.type == ")") + state.indented = state.lexical.indented; + state.lexical = state.lexical.prev; + } + } + function typecx() { cx.state.keywords = typeKeywords; } + function valcx() { cx.state.keywords = valKeywords; } + poplex.lex = typecx.lex = valcx.lex = true; + + function commasep(comb, end) { + function more(type) { + if (type == ",") return cont(comb, more); + if (type == end) return cont(); + return cont(more); + } + return function(type) { + if (type == end) return cont(); + return pass(comb, more); + }; + } + + function stat_of(comb, tag) { + return cont(pushlex("stat", tag), comb, poplex, block); + } + function block(type) { + if (type == "}") return cont(); + if (type == "let") return stat_of(letdef1, "let"); + if (type == "fn") return stat_of(fndef); + if (type == "type") return cont(pushlex("stat"), tydef, endstatement, poplex, block); + if (type == "enum") return stat_of(enumdef); + if (type == "mod") return stat_of(mod); + if (type == "iface") return stat_of(iface); + if (type == "impl") return stat_of(impl); + if (type == "open-attr") return cont(pushlex("]"), commasep(expression, "]"), poplex); + if (type == "ignore" || type.match(/[\]\);,]/)) return cont(block); + return pass(pushlex("stat"), expression, poplex, endstatement, block); + } + function endstatement(type) { + if (type == ";") return cont(); + return pass(); + } + function expression(type) { + if (type == "atom" || type == "name") return cont(maybeop); + if (type == "{") return cont(pushlex("}"), exprbrace, poplex); + if (type.match(/[\[\(]/)) return matchBrackets(type, expression); + if (type.match(/[\]\)\};,]/)) return pass(); + if (type == "if-style") return cont(expression, expression); + if (type == "else-style" || type == "op") return cont(expression); + if (type == "for") return cont(pattern, maybetype, inop, expression, expression); + if (type == "alt") return cont(expression, altbody); + if (type == "fn") return cont(fndef); + if (type == "macro") return cont(macro); + return cont(); + } + function maybeop(type) { + if (content == ".") return cont(maybeprop); + if (content == "::<"){return cont(typarams, maybeop);} + if (type == "op" || content == ":") return cont(expression); + if (type == "(" || type == "[") return matchBrackets(type, expression); + return pass(); + } + function maybeprop() { + if (content.match(/^\w+$/)) {cx.marked = "variable"; return cont(maybeop);} + return pass(expression); + } + function exprbrace(type) { + if (type == "op") { + if (content == "|") return cont(blockvars, poplex, pushlex("}", "block"), block); + if (content == "||") return cont(poplex, pushlex("}", "block"), block); + } + if (content == "mutable" || (content.match(/^\w+$/) && cx.stream.peek() == ":" + && !cx.stream.match("::", false))) + return pass(record_of(expression)); + return pass(block); + } + function record_of(comb) { + function ro(type) { + if (content == "mutable" || content == "with") {cx.marked = "keyword"; return cont(ro);} + if (content.match(/^\w*$/)) {cx.marked = "variable"; return cont(ro);} + if (type == ":") return cont(comb, ro); + if (type == "}") return cont(); + return cont(ro); + } + return ro; + } + function blockvars(type) { + if (type == "name") {cx.marked = "def"; return cont(blockvars);} + if (type == "op" && content == "|") return cont(); + return cont(blockvars); + } + + function letdef1(type) { + if (type.match(/[\]\)\};]/)) return cont(); + if (content == "=") return cont(expression, letdef2); + if (type == ",") return cont(letdef1); + return pass(pattern, maybetype, letdef1); + } + function letdef2(type) { + if (type.match(/[\]\)\};,]/)) return pass(letdef1); + else return pass(expression, letdef2); + } + function maybetype(type) { + if (type == ":") return cont(typecx, rtype, valcx); + return pass(); + } + function inop(type) { + if (type == "name" && content == "in") {cx.marked = "keyword"; return cont();} + return pass(); + } + function fndef(type) { + if (content == "@" || content == "~") {cx.marked = "keyword"; return cont(fndef);} + if (type == "name") {cx.marked = "def"; return cont(fndef);} + if (content == "<") return cont(typarams, fndef); + if (type == "{") return pass(expression); + if (type == "(") return cont(pushlex(")"), commasep(argdef, ")"), poplex, fndef); + if (type == "->") return cont(typecx, rtype, valcx, fndef); + if (type == ";") return cont(); + return cont(fndef); + } + function tydef(type) { + if (type == "name") {cx.marked = "def"; return cont(tydef);} + if (content == "<") return cont(typarams, tydef); + if (content == "=") return cont(typecx, rtype, valcx); + return cont(tydef); + } + function enumdef(type) { + if (type == "name") {cx.marked = "def"; return cont(enumdef);} + if (content == "<") return cont(typarams, enumdef); + if (content == "=") return cont(typecx, rtype, valcx, endstatement); + if (type == "{") return cont(pushlex("}"), typecx, enumblock, valcx, poplex); + return cont(enumdef); + } + function enumblock(type) { + if (type == "}") return cont(); + if (type == "(") return cont(pushlex(")"), commasep(rtype, ")"), poplex, enumblock); + if (content.match(/^\w+$/)) cx.marked = "def"; + return cont(enumblock); + } + function mod(type) { + if (type == "name") {cx.marked = "def"; return cont(mod);} + if (type == "{") return cont(pushlex("}"), block, poplex); + return pass(); + } + function iface(type) { + if (type == "name") {cx.marked = "def"; return cont(iface);} + if (content == "<") return cont(typarams, iface); + if (type == "{") return cont(pushlex("}"), block, poplex); + return pass(); + } + function impl(type) { + if (content == "<") return cont(typarams, impl); + if (content == "of" || content == "for") {cx.marked = "keyword"; return cont(rtype, impl);} + if (type == "name") {cx.marked = "def"; return cont(impl);} + if (type == "{") return cont(pushlex("}"), block, poplex); + return pass(); + } + function typarams() { + if (content == ">") return cont(); + if (content == ",") return cont(typarams); + if (content == ":") return cont(rtype, typarams); + return pass(rtype, typarams); + } + function argdef(type) { + if (type == "name") {cx.marked = "def"; return cont(argdef);} + if (type == ":") return cont(typecx, rtype, valcx); + return pass(); + } + function rtype(type) { + if (type == "name") {cx.marked = "variable-3"; return cont(rtypemaybeparam); } + if (content == "mutable") {cx.marked = "keyword"; return cont(rtype);} + if (type == "atom") return cont(rtypemaybeparam); + if (type == "op" || type == "obj") return cont(rtype); + if (type == "fn") return cont(fntype); + if (type == "{") return cont(pushlex("{"), record_of(rtype), poplex); + return matchBrackets(type, rtype); + } + function rtypemaybeparam() { + if (content == "<") return cont(typarams); + return pass(); + } + function fntype(type) { + if (type == "(") return cont(pushlex("("), commasep(rtype, ")"), poplex, fntype); + if (type == "->") return cont(rtype); + return pass(); + } + function pattern(type) { + if (type == "name") {cx.marked = "def"; return cont(patternmaybeop);} + if (type == "atom") return cont(patternmaybeop); + if (type == "op") return cont(pattern); + if (type.match(/[\]\)\};,]/)) return pass(); + return matchBrackets(type, pattern); + } + function patternmaybeop(type) { + if (type == "op" && content == ".") return cont(); + if (content == "to") {cx.marked = "keyword"; return cont(pattern);} + else return pass(); + } + function altbody(type) { + if (type == "{") return cont(pushlex("}", "alt"), altblock1, poplex); + return pass(); + } + function altblock1(type) { + if (type == "}") return cont(); + if (type == "|") return cont(altblock1); + if (content == "when") {cx.marked = "keyword"; return cont(expression, altblock2);} + if (type.match(/[\]\);,]/)) return cont(altblock1); + return pass(pattern, altblock2); + } + function altblock2(type) { + if (type == "{") return cont(pushlex("}", "alt"), block, poplex, altblock1); + else return pass(altblock1); + } + + function macro(type) { + if (type.match(/[\[\(\{]/)) return matchBrackets(type, expression); + return pass(); + } + function matchBrackets(type, comb) { + if (type == "[") return cont(pushlex("]"), commasep(comb, "]"), poplex); + if (type == "(") return cont(pushlex(")"), commasep(comb, ")"), poplex); + if (type == "{") return cont(pushlex("}"), commasep(comb, "}"), poplex); + return cont(); + } + + function parse(state, stream, style) { + var cc = state.cc; + // Communicate our context to the combinators. + // (Less wasteful than consing up a hundred closures on every call.) + cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc; + + while (true) { + var combinator = cc.length ? cc.pop() : block; + if (combinator(tcat)) { + while(cc.length && cc[cc.length - 1].lex) + cc.pop()(); + return cx.marked || style; + } + } + } + + return { + startState: function() { + return { + tokenize: tokenBase, + cc: [], + lexical: {indented: -indentUnit, column: 0, type: "top", align: false}, + keywords: valKeywords, + indented: 0 + }; + }, + + token: function(stream, state) { + if (stream.sol()) { + if (!state.lexical.hasOwnProperty("align")) + state.lexical.align = false; + state.indented = stream.indentation(); + } + if (stream.eatSpace()) return null; + tcat = content = null; + var style = state.tokenize(stream, state); + if (style == "comment") return style; + if (!state.lexical.hasOwnProperty("align")) + state.lexical.align = true; + if (tcat == "prefix") return style; + if (!content) content = stream.current(); + return parse(state, stream, style); + }, + + indent: function(state, textAfter) { + if (state.tokenize != tokenBase) return 0; + var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical, + type = lexical.type, closing = firstChar == type; + if (type == "stat") return lexical.indented + indentUnit; + if (lexical.align) return lexical.column + (closing ? 0 : 1); + return lexical.indented + (closing ? 0 : (lexical.info == "alt" ? altIndentUnit : indentUnit)); + }, + + electricChars: "{}", + blockCommentStart: "/*", + blockCommentEnd: "*/", + lineComment: "//", + fold: "brace" + }; +}); + +CodeMirror.defineMIME("text/x-rustsrc", "rust"); + +}); diff --git a/static/js/mdeditor/lib/codemirror/mode/sass/index.html b/static/js/mdeditor/lib/codemirror/mode/sass/index.html new file mode 100644 index 00000000..9f4a7902 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/sass/index.html @@ -0,0 +1,66 @@ + + +CodeMirror: Sass mode + + + + + + + + + + +
+

Sass mode

+
+ + +

MIME types defined: text/x-sass.

+
diff --git a/static/js/mdeditor/lib/codemirror/mode/sass/sass.js b/static/js/mdeditor/lib/codemirror/mode/sass/sass.js new file mode 100644 index 00000000..52a66829 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/sass/sass.js @@ -0,0 +1,414 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("sass", function(config) { + function tokenRegexp(words) { + return new RegExp("^" + words.join("|")); + } + + var keywords = ["true", "false", "null", "auto"]; + var keywordsRegexp = new RegExp("^" + keywords.join("|")); + + var operators = ["\\(", "\\)", "=", ">", "<", "==", ">=", "<=", "\\+", "-", + "\\!=", "/", "\\*", "%", "and", "or", "not", ";","\\{","\\}",":"]; + var opRegexp = tokenRegexp(operators); + + var pseudoElementsRegexp = /^::?[a-zA-Z_][\w\-]*/; + + function urlTokens(stream, state) { + var ch = stream.peek(); + + if (ch === ")") { + stream.next(); + state.tokenizer = tokenBase; + return "operator"; + } else if (ch === "(") { + stream.next(); + stream.eatSpace(); + + return "operator"; + } else if (ch === "'" || ch === '"') { + state.tokenizer = buildStringTokenizer(stream.next()); + return "string"; + } else { + state.tokenizer = buildStringTokenizer(")", false); + return "string"; + } + } + function comment(indentation, multiLine) { + return function(stream, state) { + if (stream.sol() && stream.indentation() <= indentation) { + state.tokenizer = tokenBase; + return tokenBase(stream, state); + } + + if (multiLine && stream.skipTo("*/")) { + stream.next(); + stream.next(); + state.tokenizer = tokenBase; + } else { + stream.skipToEnd(); + } + + return "comment"; + }; + } + + function buildStringTokenizer(quote, greedy) { + if (greedy == null) { greedy = true; } + + function stringTokenizer(stream, state) { + var nextChar = stream.next(); + var peekChar = stream.peek(); + var previousChar = stream.string.charAt(stream.pos-2); + + var endingString = ((nextChar !== "\\" && peekChar === quote) || (nextChar === quote && previousChar !== "\\")); + + if (endingString) { + if (nextChar !== quote && greedy) { stream.next(); } + state.tokenizer = tokenBase; + return "string"; + } else if (nextChar === "#" && peekChar === "{") { + state.tokenizer = buildInterpolationTokenizer(stringTokenizer); + stream.next(); + return "operator"; + } else { + return "string"; + } + } + + return stringTokenizer; + } + + function buildInterpolationTokenizer(currentTokenizer) { + return function(stream, state) { + if (stream.peek() === "}") { + stream.next(); + state.tokenizer = currentTokenizer; + return "operator"; + } else { + return tokenBase(stream, state); + } + }; + } + + function indent(state) { + if (state.indentCount == 0) { + state.indentCount++; + var lastScopeOffset = state.scopes[0].offset; + var currentOffset = lastScopeOffset + config.indentUnit; + state.scopes.unshift({ offset:currentOffset }); + } + } + + function dedent(state) { + if (state.scopes.length == 1) return; + + state.scopes.shift(); + } + + function tokenBase(stream, state) { + var ch = stream.peek(); + + // Comment + if (stream.match("/*")) { + state.tokenizer = comment(stream.indentation(), true); + return state.tokenizer(stream, state); + } + if (stream.match("//")) { + state.tokenizer = comment(stream.indentation(), false); + return state.tokenizer(stream, state); + } + + // Interpolation + if (stream.match("#{")) { + state.tokenizer = buildInterpolationTokenizer(tokenBase); + return "operator"; + } + + // Strings + if (ch === '"' || ch === "'") { + stream.next(); + state.tokenizer = buildStringTokenizer(ch); + return "string"; + } + + if(!state.cursorHalf){// state.cursorHalf === 0 + // first half i.e. before : for key-value pairs + // including selectors + + if (ch === ".") { + stream.next(); + if (stream.match(/^[\w-]+/)) { + indent(state); + return "atom"; + } else if (stream.peek() === "#") { + indent(state); + return "atom"; + } + } + + if (ch === "#") { + stream.next(); + // ID selectors + if (stream.match(/^[\w-]+/)) { + indent(state); + return "atom"; + } + if (stream.peek() === "#") { + indent(state); + return "atom"; + } + } + + // Variables + if (ch === "$") { + stream.next(); + stream.eatWhile(/[\w-]/); + return "variable-2"; + } + + // Numbers + if (stream.match(/^-?[0-9\.]+/)) + return "number"; + + // Units + if (stream.match(/^(px|em|in)\b/)) + return "unit"; + + if (stream.match(keywordsRegexp)) + return "keyword"; + + if (stream.match(/^url/) && stream.peek() === "(") { + state.tokenizer = urlTokens; + return "atom"; + } + + if (ch === "=") { + // Match shortcut mixin definition + if (stream.match(/^=[\w-]+/)) { + indent(state); + return "meta"; + } + } + + if (ch === "+") { + // Match shortcut mixin definition + if (stream.match(/^\+[\w-]+/)){ + return "variable-3"; + } + } + + if(ch === "@"){ + if(stream.match(/@extend/)){ + if(!stream.match(/\s*[\w]/)) + dedent(state); + } + } + + + // Indent Directives + if (stream.match(/^@(else if|if|media|else|for|each|while|mixin|function)/)) { + indent(state); + return "meta"; + } + + // Other Directives + if (ch === "@") { + stream.next(); + stream.eatWhile(/[\w-]/); + return "meta"; + } + + if (stream.eatWhile(/[\w-]/)){ + if(stream.match(/ *: *[\w-\+\$#!\("']/,false)){ + return "propery"; + } + else if(stream.match(/ *:/,false)){ + indent(state); + state.cursorHalf = 1; + return "atom"; + } + else if(stream.match(/ *,/,false)){ + return "atom"; + } + else{ + indent(state); + return "atom"; + } + } + + if(ch === ":"){ + if (stream.match(pseudoElementsRegexp)){ // could be a pseudo-element + return "keyword"; + } + stream.next(); + state.cursorHalf=1; + return "operator"; + } + + } // cursorHalf===0 ends here + else{ + + if (ch === "#") { + stream.next(); + // Hex numbers + if (stream.match(/[0-9a-fA-F]{6}|[0-9a-fA-F]{3}/)){ + if(!stream.peek()){ + state.cursorHalf = 0; + } + return "number"; + } + } + + // Numbers + if (stream.match(/^-?[0-9\.]+/)){ + if(!stream.peek()){ + state.cursorHalf = 0; + } + return "number"; + } + + // Units + if (stream.match(/^(px|em|in)\b/)){ + if(!stream.peek()){ + state.cursorHalf = 0; + } + return "unit"; + } + + if (stream.match(keywordsRegexp)){ + if(!stream.peek()){ + state.cursorHalf = 0; + } + return "keyword"; + } + + if (stream.match(/^url/) && stream.peek() === "(") { + state.tokenizer = urlTokens; + if(!stream.peek()){ + state.cursorHalf = 0; + } + return "atom"; + } + + // Variables + if (ch === "$") { + stream.next(); + stream.eatWhile(/[\w-]/); + if(!stream.peek()){ + state.cursorHalf = 0; + } + return "variable-3"; + } + + // bang character for !important, !default, etc. + if (ch === "!") { + stream.next(); + if(!stream.peek()){ + state.cursorHalf = 0; + } + return stream.match(/^[\w]+/) ? "keyword": "operator"; + } + + if (stream.match(opRegexp)){ + if(!stream.peek()){ + state.cursorHalf = 0; + } + return "operator"; + } + + // attributes + if (stream.eatWhile(/[\w-]/)) { + if(!stream.peek()){ + state.cursorHalf = 0; + } + return "attribute"; + } + + //stream.eatSpace(); + if(!stream.peek()){ + state.cursorHalf = 0; + return null; + } + + } // else ends here + + if (stream.match(opRegexp)) + return "operator"; + + // If we haven't returned by now, we move 1 character + // and return an error + stream.next(); + return null; + } + + function tokenLexer(stream, state) { + if (stream.sol()) state.indentCount = 0; + var style = state.tokenizer(stream, state); + var current = stream.current(); + + if (current === "@return" || current === "}"){ + dedent(state); + } + + if (style !== null) { + var startOfToken = stream.pos - current.length; + + var withCurrentIndent = startOfToken + (config.indentUnit * state.indentCount); + + var newScopes = []; + + for (var i = 0; i < state.scopes.length; i++) { + var scope = state.scopes[i]; + + if (scope.offset <= withCurrentIndent) + newScopes.push(scope); + } + + state.scopes = newScopes; + } + + + return style; + } + + return { + startState: function() { + return { + tokenizer: tokenBase, + scopes: [{offset: 0, type: "sass"}], + indentCount: 0, + cursorHalf: 0, // cursor half tells us if cursor lies after (1) + // or before (0) colon (well... more or less) + definedVars: [], + definedMixins: [] + }; + }, + token: function(stream, state) { + var style = tokenLexer(stream, state); + + state.lastToken = { style: style, content: stream.current() }; + + return style; + }, + + indent: function(state) { + return state.scopes[0].offset; + } + }; +}); + +CodeMirror.defineMIME("text/x-sass", "sass"); + +}); diff --git a/static/js/mdeditor/lib/codemirror/mode/scheme/index.html b/static/js/mdeditor/lib/codemirror/mode/scheme/index.html new file mode 100644 index 00000000..04d5c6a2 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/scheme/index.html @@ -0,0 +1,77 @@ + + +CodeMirror: Scheme mode + + + + + + + + + +
+

Scheme mode

+
+ + +

MIME types defined: text/x-scheme.

+ +
diff --git a/static/js/mdeditor/lib/codemirror/mode/scheme/scheme.js b/static/js/mdeditor/lib/codemirror/mode/scheme/scheme.js new file mode 100644 index 00000000..979edc09 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/scheme/scheme.js @@ -0,0 +1,248 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +/** + * Author: Koh Zi Han, based on implementation by Koh Zi Chun + */ + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("scheme", function () { + var BUILTIN = "builtin", COMMENT = "comment", STRING = "string", + ATOM = "atom", NUMBER = "number", BRACKET = "bracket"; + var INDENT_WORD_SKIP = 2; + + function makeKeywords(str) { + var obj = {}, words = str.split(" "); + for (var i = 0; i < words.length; ++i) obj[words[i]] = true; + return obj; + } + + var keywords = makeKeywords("λ case-lambda call/cc class define-class exit-handler field import inherit init-field interface let*-values let-values let/ec mixin opt-lambda override protect provide public rename require require-for-syntax syntax syntax-case syntax-error unit/sig unless when with-syntax and begin call-with-current-continuation call-with-input-file call-with-output-file case cond define define-syntax delay do dynamic-wind else for-each if lambda let let* let-syntax letrec letrec-syntax map or syntax-rules abs acos angle append apply asin assoc assq assv atan boolean? caar cadr call-with-input-file call-with-output-file call-with-values car cdddar cddddr cdr ceiling char->integer char-alphabetic? char-ci<=? char-ci=? char-ci>? char-downcase char-lower-case? char-numeric? char-ready? char-upcase char-upper-case? char-whitespace? char<=? char=? char>? char? close-input-port close-output-port complex? cons cos current-input-port current-output-port denominator display eof-object? eq? equal? eqv? eval even? exact->inexact exact? exp expt #f floor force gcd imag-part inexact->exact inexact? input-port? integer->char integer? interaction-environment lcm length list list->string list->vector list-ref list-tail list? load log magnitude make-polar make-rectangular make-string make-vector max member memq memv min modulo negative? newline not null-environment null? number->string number? numerator odd? open-input-file open-output-file output-port? pair? peek-char port? positive? procedure? quasiquote quote quotient rational? rationalize read read-char real-part real? remainder reverse round scheme-report-environment set! set-car! set-cdr! sin sqrt string string->list string->number string->symbol string-append string-ci<=? string-ci=? string-ci>? string-copy string-fill! string-length string-ref string-set! string<=? string=? string>? string? substring symbol->string symbol? #t tan transcript-off transcript-on truncate values vector vector->list vector-fill! vector-length vector-ref vector-set! with-input-from-file with-output-to-file write write-char zero?"); + var indentKeys = makeKeywords("define let letrec let* lambda"); + + function stateStack(indent, type, prev) { // represents a state stack object + this.indent = indent; + this.type = type; + this.prev = prev; + } + + function pushStack(state, indent, type) { + state.indentStack = new stateStack(indent, type, state.indentStack); + } + + function popStack(state) { + state.indentStack = state.indentStack.prev; + } + + var binaryMatcher = new RegExp(/^(?:[-+]i|[-+][01]+#*(?:\/[01]+#*)?i|[-+]?[01]+#*(?:\/[01]+#*)?@[-+]?[01]+#*(?:\/[01]+#*)?|[-+]?[01]+#*(?:\/[01]+#*)?[-+](?:[01]+#*(?:\/[01]+#*)?)?i|[-+]?[01]+#*(?:\/[01]+#*)?)(?=[()\s;"]|$)/i); + var octalMatcher = new RegExp(/^(?:[-+]i|[-+][0-7]+#*(?:\/[0-7]+#*)?i|[-+]?[0-7]+#*(?:\/[0-7]+#*)?@[-+]?[0-7]+#*(?:\/[0-7]+#*)?|[-+]?[0-7]+#*(?:\/[0-7]+#*)?[-+](?:[0-7]+#*(?:\/[0-7]+#*)?)?i|[-+]?[0-7]+#*(?:\/[0-7]+#*)?)(?=[()\s;"]|$)/i); + var hexMatcher = new RegExp(/^(?:[-+]i|[-+][\da-f]+#*(?:\/[\da-f]+#*)?i|[-+]?[\da-f]+#*(?:\/[\da-f]+#*)?@[-+]?[\da-f]+#*(?:\/[\da-f]+#*)?|[-+]?[\da-f]+#*(?:\/[\da-f]+#*)?[-+](?:[\da-f]+#*(?:\/[\da-f]+#*)?)?i|[-+]?[\da-f]+#*(?:\/[\da-f]+#*)?)(?=[()\s;"]|$)/i); + var decimalMatcher = new RegExp(/^(?:[-+]i|[-+](?:(?:(?:\d+#+\.?#*|\d+\.\d*#*|\.\d+#*|\d+)(?:[esfdl][-+]?\d+)?)|\d+#*\/\d+#*)i|[-+]?(?:(?:(?:\d+#+\.?#*|\d+\.\d*#*|\.\d+#*|\d+)(?:[esfdl][-+]?\d+)?)|\d+#*\/\d+#*)@[-+]?(?:(?:(?:\d+#+\.?#*|\d+\.\d*#*|\.\d+#*|\d+)(?:[esfdl][-+]?\d+)?)|\d+#*\/\d+#*)|[-+]?(?:(?:(?:\d+#+\.?#*|\d+\.\d*#*|\.\d+#*|\d+)(?:[esfdl][-+]?\d+)?)|\d+#*\/\d+#*)[-+](?:(?:(?:\d+#+\.?#*|\d+\.\d*#*|\.\d+#*|\d+)(?:[esfdl][-+]?\d+)?)|\d+#*\/\d+#*)?i|(?:(?:(?:\d+#+\.?#*|\d+\.\d*#*|\.\d+#*|\d+)(?:[esfdl][-+]?\d+)?)|\d+#*\/\d+#*))(?=[()\s;"]|$)/i); + + function isBinaryNumber (stream) { + return stream.match(binaryMatcher); + } + + function isOctalNumber (stream) { + return stream.match(octalMatcher); + } + + function isDecimalNumber (stream, backup) { + if (backup === true) { + stream.backUp(1); + } + return stream.match(decimalMatcher); + } + + function isHexNumber (stream) { + return stream.match(hexMatcher); + } + + return { + startState: function () { + return { + indentStack: null, + indentation: 0, + mode: false, + sExprComment: false + }; + }, + + token: function (stream, state) { + if (state.indentStack == null && stream.sol()) { + // update indentation, but only if indentStack is empty + state.indentation = stream.indentation(); + } + + // skip spaces + if (stream.eatSpace()) { + return null; + } + var returnType = null; + + switch(state.mode){ + case "string": // multi-line string parsing mode + var next, escaped = false; + while ((next = stream.next()) != null) { + if (next == "\"" && !escaped) { + + state.mode = false; + break; + } + escaped = !escaped && next == "\\"; + } + returnType = STRING; // continue on in scheme-string mode + break; + case "comment": // comment parsing mode + var next, maybeEnd = false; + while ((next = stream.next()) != null) { + if (next == "#" && maybeEnd) { + + state.mode = false; + break; + } + maybeEnd = (next == "|"); + } + returnType = COMMENT; + break; + case "s-expr-comment": // s-expr commenting mode + state.mode = false; + if(stream.peek() == "(" || stream.peek() == "["){ + // actually start scheme s-expr commenting mode + state.sExprComment = 0; + }else{ + // if not we just comment the entire of the next token + stream.eatWhile(/[^/s]/); // eat non spaces + returnType = COMMENT; + break; + } + default: // default parsing mode + var ch = stream.next(); + + if (ch == "\"") { + state.mode = "string"; + returnType = STRING; + + } else if (ch == "'") { + returnType = ATOM; + } else if (ch == '#') { + if (stream.eat("|")) { // Multi-line comment + state.mode = "comment"; // toggle to comment mode + returnType = COMMENT; + } else if (stream.eat(/[tf]/i)) { // #t/#f (atom) + returnType = ATOM; + } else if (stream.eat(';')) { // S-Expr comment + state.mode = "s-expr-comment"; + returnType = COMMENT; + } else { + var numTest = null, hasExactness = false, hasRadix = true; + if (stream.eat(/[ei]/i)) { + hasExactness = true; + } else { + stream.backUp(1); // must be radix specifier + } + if (stream.match(/^#b/i)) { + numTest = isBinaryNumber; + } else if (stream.match(/^#o/i)) { + numTest = isOctalNumber; + } else if (stream.match(/^#x/i)) { + numTest = isHexNumber; + } else if (stream.match(/^#d/i)) { + numTest = isDecimalNumber; + } else if (stream.match(/^[-+0-9.]/, false)) { + hasRadix = false; + numTest = isDecimalNumber; + // re-consume the intial # if all matches failed + } else if (!hasExactness) { + stream.eat('#'); + } + if (numTest != null) { + if (hasRadix && !hasExactness) { + // consume optional exactness after radix + stream.match(/^#[ei]/i); + } + if (numTest(stream)) + returnType = NUMBER; + } + } + } else if (/^[-+0-9.]/.test(ch) && isDecimalNumber(stream, true)) { // match non-prefixed number, must be decimal + returnType = NUMBER; + } else if (ch == ";") { // comment + stream.skipToEnd(); // rest of the line is a comment + returnType = COMMENT; + } else if (ch == "(" || ch == "[") { + var keyWord = ''; var indentTemp = stream.column(), letter; + /** + Either + (indent-word .. + (non-indent-word .. + (;something else, bracket, etc. + */ + + while ((letter = stream.eat(/[^\s\(\[\;\)\]]/)) != null) { + keyWord += letter; + } + + if (keyWord.length > 0 && indentKeys.propertyIsEnumerable(keyWord)) { // indent-word + + pushStack(state, indentTemp + INDENT_WORD_SKIP, ch); + } else { // non-indent word + // we continue eating the spaces + stream.eatSpace(); + if (stream.eol() || stream.peek() == ";") { + // nothing significant after + // we restart indentation 1 space after + pushStack(state, indentTemp + 1, ch); + } else { + pushStack(state, indentTemp + stream.current().length, ch); // else we match + } + } + stream.backUp(stream.current().length - 1); // undo all the eating + + if(typeof state.sExprComment == "number") state.sExprComment++; + + returnType = BRACKET; + } else if (ch == ")" || ch == "]") { + returnType = BRACKET; + if (state.indentStack != null && state.indentStack.type == (ch == ")" ? "(" : "[")) { + popStack(state); + + if(typeof state.sExprComment == "number"){ + if(--state.sExprComment == 0){ + returnType = COMMENT; // final closing bracket + state.sExprComment = false; // turn off s-expr commenting mode + } + } + } + } else { + stream.eatWhile(/[\w\$_\-!$%&*+\.\/:<=>?@\^~]/); + + if (keywords && keywords.propertyIsEnumerable(stream.current())) { + returnType = BUILTIN; + } else returnType = "variable"; + } + } + return (typeof state.sExprComment == "number") ? COMMENT : returnType; + }, + + indent: function (state) { + if (state.indentStack == null) return state.indentation; + return state.indentStack.indent; + }, + + lineComment: ";;" + }; +}); + +CodeMirror.defineMIME("text/x-scheme", "scheme"); + +}); diff --git a/static/js/mdeditor/lib/codemirror/mode/shell/index.html b/static/js/mdeditor/lib/codemirror/mode/shell/index.html new file mode 100644 index 00000000..0b56300b --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/shell/index.html @@ -0,0 +1,66 @@ + + +CodeMirror: Shell mode + + + + + + + + + + +
+

Shell mode

+ + + + + + +

MIME types defined: text/x-sh.

+
diff --git a/static/js/mdeditor/lib/codemirror/mode/shell/shell.js b/static/js/mdeditor/lib/codemirror/mode/shell/shell.js new file mode 100644 index 00000000..a684e8c2 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/shell/shell.js @@ -0,0 +1,139 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode('shell', function() { + + var words = {}; + function define(style, string) { + var split = string.split(' '); + for(var i = 0; i < split.length; i++) { + words[split[i]] = style; + } + }; + + // Atoms + define('atom', 'true false'); + + // Keywords + define('keyword', 'if then do else elif while until for in esac fi fin ' + + 'fil done exit set unset export function'); + + // Commands + define('builtin', 'ab awk bash beep cat cc cd chown chmod chroot clear cp ' + + 'curl cut diff echo find gawk gcc get git grep kill killall ln ls make ' + + 'mkdir openssl mv nc node npm ping ps restart rm rmdir sed service sh ' + + 'shopt shred source sort sleep ssh start stop su sudo tee telnet top ' + + 'touch vi vim wall wc wget who write yes zsh'); + + function tokenBase(stream, state) { + if (stream.eatSpace()) return null; + + var sol = stream.sol(); + var ch = stream.next(); + + if (ch === '\\') { + stream.next(); + return null; + } + if (ch === '\'' || ch === '"' || ch === '`') { + state.tokens.unshift(tokenString(ch)); + return tokenize(stream, state); + } + if (ch === '#') { + if (sol && stream.eat('!')) { + stream.skipToEnd(); + return 'meta'; // 'comment'? + } + stream.skipToEnd(); + return 'comment'; + } + if (ch === '$') { + state.tokens.unshift(tokenDollar); + return tokenize(stream, state); + } + if (ch === '+' || ch === '=') { + return 'operator'; + } + if (ch === '-') { + stream.eat('-'); + stream.eatWhile(/\w/); + return 'attribute'; + } + if (/\d/.test(ch)) { + stream.eatWhile(/\d/); + if(stream.eol() || !/\w/.test(stream.peek())) { + return 'number'; + } + } + stream.eatWhile(/[\w-]/); + var cur = stream.current(); + if (stream.peek() === '=' && /\w+/.test(cur)) return 'def'; + return words.hasOwnProperty(cur) ? words[cur] : null; + } + + function tokenString(quote) { + return function(stream, state) { + var next, end = false, escaped = false; + while ((next = stream.next()) != null) { + if (next === quote && !escaped) { + end = true; + break; + } + if (next === '$' && !escaped && quote !== '\'') { + escaped = true; + stream.backUp(1); + state.tokens.unshift(tokenDollar); + break; + } + escaped = !escaped && next === '\\'; + } + if (end || !escaped) { + state.tokens.shift(); + } + return (quote === '`' || quote === ')' ? 'quote' : 'string'); + }; + }; + + var tokenDollar = function(stream, state) { + if (state.tokens.length > 1) stream.eat('$'); + var ch = stream.next(), hungry = /\w/; + if (ch === '{') hungry = /[^}]/; + if (ch === '(') { + state.tokens[0] = tokenString(')'); + return tokenize(stream, state); + } + if (!/\d/.test(ch)) { + stream.eatWhile(hungry); + stream.eat('}'); + } + state.tokens.shift(); + return 'def'; + }; + + function tokenize(stream, state) { + return (state.tokens[0] || tokenBase) (stream, state); + }; + + return { + startState: function() {return {tokens:[]};}, + token: function(stream, state) { + return tokenize(stream, state); + }, + lineComment: '#', + fold: "brace" + }; +}); + +CodeMirror.defineMIME('text/x-sh', 'shell'); + +}); diff --git a/static/js/mdeditor/lib/codemirror/mode/shell/test.js b/static/js/mdeditor/lib/codemirror/mode/shell/test.js new file mode 100644 index 00000000..a413b5a4 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/shell/test.js @@ -0,0 +1,58 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function() { + var mode = CodeMirror.getMode({}, "shell"); + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); } + + MT("var", + "text [def $var] text"); + MT("varBraces", + "text[def ${var}]text"); + MT("varVar", + "text [def $a$b] text"); + MT("varBracesVarBraces", + "text[def ${a}${b}]text"); + + MT("singleQuotedVar", + "[string 'text $var text']"); + MT("singleQuotedVarBraces", + "[string 'text ${var} text']"); + + MT("doubleQuotedVar", + '[string "text ][def $var][string text"]'); + MT("doubleQuotedVarBraces", + '[string "text][def ${var}][string text"]'); + MT("doubleQuotedVarPunct", + '[string "text ][def $@][string text"]'); + MT("doubleQuotedVarVar", + '[string "][def $a$b][string "]'); + MT("doubleQuotedVarBracesVarBraces", + '[string "][def ${a}${b}][string "]'); + + MT("notAString", + "text\\'text"); + MT("escapes", + "outside\\'\\\"\\`\\\\[string \"inside\\`\\'\\\"\\\\`\\$notAVar\"]outside\\$\\(notASubShell\\)"); + + MT("subshell", + "[builtin echo] [quote $(whoami)] s log, stardate [quote `date`]."); + MT("doubleQuotedSubshell", + "[builtin echo] [string \"][quote $(whoami)][string 's log, stardate `date`.\"]"); + + MT("hashbang", + "[meta #!/bin/bash]"); + MT("comment", + "text [comment # Blurb]"); + + MT("numbers", + "[number 0] [number 1] [number 2]"); + MT("keywords", + "[keyword while] [atom true]; [keyword do]", + " [builtin sleep] [number 3]", + "[keyword done]"); + MT("options", + "[builtin ls] [attribute -l] [attribute --human-readable]"); + MT("operator", + "[def var][operator =]value"); +})(); diff --git a/static/js/mdeditor/lib/codemirror/mode/sieve/index.html b/static/js/mdeditor/lib/codemirror/mode/sieve/index.html new file mode 100644 index 00000000..6f029b62 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/sieve/index.html @@ -0,0 +1,93 @@ + + +CodeMirror: Sieve (RFC5228) mode + + + + + + + + + +
+

Sieve (RFC5228) mode

+
+ + +

MIME types defined: application/sieve.

+ +
diff --git a/static/js/mdeditor/lib/codemirror/mode/sieve/sieve.js b/static/js/mdeditor/lib/codemirror/mode/sieve/sieve.js new file mode 100644 index 00000000..f67db2f5 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/sieve/sieve.js @@ -0,0 +1,193 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("sieve", function(config) { + function words(str) { + var obj = {}, words = str.split(" "); + for (var i = 0; i < words.length; ++i) obj[words[i]] = true; + return obj; + } + + var keywords = words("if elsif else stop require"); + var atoms = words("true false not"); + var indentUnit = config.indentUnit; + + function tokenBase(stream, state) { + + var ch = stream.next(); + if (ch == "/" && stream.eat("*")) { + state.tokenize = tokenCComment; + return tokenCComment(stream, state); + } + + if (ch === '#') { + stream.skipToEnd(); + return "comment"; + } + + if (ch == "\"") { + state.tokenize = tokenString(ch); + return state.tokenize(stream, state); + } + + if (ch == "(") { + state._indent.push("("); + // add virtual angel wings so that editor behaves... + // ...more sane incase of broken brackets + state._indent.push("{"); + return null; + } + + if (ch === "{") { + state._indent.push("{"); + return null; + } + + if (ch == ")") { + state._indent.pop(); + state._indent.pop(); + } + + if (ch === "}") { + state._indent.pop(); + return null; + } + + if (ch == ",") + return null; + + if (ch == ";") + return null; + + + if (/[{}\(\),;]/.test(ch)) + return null; + + // 1*DIGIT "K" / "M" / "G" + if (/\d/.test(ch)) { + stream.eatWhile(/[\d]/); + stream.eat(/[KkMmGg]/); + return "number"; + } + + // ":" (ALPHA / "_") *(ALPHA / DIGIT / "_") + if (ch == ":") { + stream.eatWhile(/[a-zA-Z_]/); + stream.eatWhile(/[a-zA-Z0-9_]/); + + return "operator"; + } + + stream.eatWhile(/\w/); + var cur = stream.current(); + + // "text:" *(SP / HTAB) (hash-comment / CRLF) + // *(multiline-literal / multiline-dotstart) + // "." CRLF + if ((cur == "text") && stream.eat(":")) + { + state.tokenize = tokenMultiLineString; + return "string"; + } + + if (keywords.propertyIsEnumerable(cur)) + return "keyword"; + + if (atoms.propertyIsEnumerable(cur)) + return "atom"; + + return null; + } + + function tokenMultiLineString(stream, state) + { + state._multiLineString = true; + // the first line is special it may contain a comment + if (!stream.sol()) { + stream.eatSpace(); + + if (stream.peek() == "#") { + stream.skipToEnd(); + return "comment"; + } + + stream.skipToEnd(); + return "string"; + } + + if ((stream.next() == ".") && (stream.eol())) + { + state._multiLineString = false; + state.tokenize = tokenBase; + } + + return "string"; + } + + function tokenCComment(stream, state) { + var maybeEnd = false, ch; + while ((ch = stream.next()) != null) { + if (maybeEnd && ch == "/") { + state.tokenize = tokenBase; + break; + } + maybeEnd = (ch == "*"); + } + return "comment"; + } + + function tokenString(quote) { + return function(stream, state) { + var escaped = false, ch; + while ((ch = stream.next()) != null) { + if (ch == quote && !escaped) + break; + escaped = !escaped && ch == "\\"; + } + if (!escaped) state.tokenize = tokenBase; + return "string"; + }; + } + + return { + startState: function(base) { + return {tokenize: tokenBase, + baseIndent: base || 0, + _indent: []}; + }, + + token: function(stream, state) { + if (stream.eatSpace()) + return null; + + return (state.tokenize || tokenBase)(stream, state);; + }, + + indent: function(state, _textAfter) { + var length = state._indent.length; + if (_textAfter && (_textAfter[0] == "}")) + length--; + + if (length <0) + length = 0; + + return length * indentUnit; + }, + + electricChars: "}" + }; +}); + +CodeMirror.defineMIME("application/sieve", "sieve"); + +}); diff --git a/static/js/mdeditor/lib/codemirror/mode/slim/index.html b/static/js/mdeditor/lib/codemirror/mode/slim/index.html new file mode 100644 index 00000000..7fa4e50d --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/slim/index.html @@ -0,0 +1,96 @@ + + +CodeMirror: SLIM mode + + + + + + + + + + + + + + + + + + + + +
+

SLIM mode

+
+ + +

MIME types defined: application/x-slim.

+ +

+ Parsing/Highlighting Tests: + normal, + verbose. +

+
diff --git a/static/js/mdeditor/lib/codemirror/mode/slim/slim.js b/static/js/mdeditor/lib/codemirror/mode/slim/slim.js new file mode 100644 index 00000000..164464d0 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/slim/slim.js @@ -0,0 +1,575 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// Slim Highlighting for CodeMirror copyright (c) HicknHack Software Gmbh + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../htmlmixed/htmlmixed"), require("../ruby/ruby")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../htmlmixed/htmlmixed", "../ruby/ruby"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + + CodeMirror.defineMode("slim", function(config) { + var htmlMode = CodeMirror.getMode(config, {name: "htmlmixed"}); + var rubyMode = CodeMirror.getMode(config, "ruby"); + var modes = { html: htmlMode, ruby: rubyMode }; + var embedded = { + ruby: "ruby", + javascript: "javascript", + css: "text/css", + sass: "text/x-sass", + scss: "text/x-scss", + less: "text/x-less", + styl: "text/x-styl", // no highlighting so far + coffee: "coffeescript", + asciidoc: "text/x-asciidoc", + markdown: "text/x-markdown", + textile: "text/x-textile", // no highlighting so far + creole: "text/x-creole", // no highlighting so far + wiki: "text/x-wiki", // no highlighting so far + mediawiki: "text/x-mediawiki", // no highlighting so far + rdoc: "text/x-rdoc", // no highlighting so far + builder: "text/x-builder", // no highlighting so far + nokogiri: "text/x-nokogiri", // no highlighting so far + erb: "application/x-erb" + }; + var embeddedRegexp = function(map){ + var arr = []; + for(var key in map) arr.push(key); + return new RegExp("^("+arr.join('|')+"):"); + }(embedded); + + var styleMap = { + "commentLine": "comment", + "slimSwitch": "operator special", + "slimTag": "tag", + "slimId": "attribute def", + "slimClass": "attribute qualifier", + "slimAttribute": "attribute", + "slimSubmode": "keyword special", + "closeAttributeTag": null, + "slimDoctype": null, + "lineContinuation": null + }; + var closing = { + "{": "}", + "[": "]", + "(": ")" + }; + + var nameStartChar = "_a-zA-Z\xC0-\xD6\xD8-\xF6\xF8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD"; + var nameChar = nameStartChar + "\\-0-9\xB7\u0300-\u036F\u203F-\u2040"; + var nameRegexp = new RegExp("^[:"+nameStartChar+"](?::["+nameChar+"]|["+nameChar+"]*)"); + var attributeNameRegexp = new RegExp("^[:"+nameStartChar+"][:\\."+nameChar+"]*(?=\\s*=)"); + var wrappedAttributeNameRegexp = new RegExp("^[:"+nameStartChar+"][:\\."+nameChar+"]*"); + var classNameRegexp = /^\.-?[_a-zA-Z]+[\w\-]*/; + var classIdRegexp = /^#[_a-zA-Z]+[\w\-]*/; + + function backup(pos, tokenize, style) { + var restore = function(stream, state) { + state.tokenize = tokenize; + if (stream.pos < pos) { + stream.pos = pos; + return style; + } + return state.tokenize(stream, state); + }; + return function(stream, state) { + state.tokenize = restore; + return tokenize(stream, state); + }; + } + + function maybeBackup(stream, state, pat, offset, style) { + var cur = stream.current(); + var idx = cur.search(pat); + if (idx > -1) { + state.tokenize = backup(stream.pos, state.tokenize, style); + stream.backUp(cur.length - idx - offset); + } + return style; + } + + function continueLine(state, column) { + state.stack = { + parent: state.stack, + style: "continuation", + indented: column, + tokenize: state.line + }; + state.line = state.tokenize; + } + function finishContinue(state) { + if (state.line == state.tokenize) { + state.line = state.stack.tokenize; + state.stack = state.stack.parent; + } + } + + function lineContinuable(column, tokenize) { + return function(stream, state) { + finishContinue(state); + if (stream.match(/^\\$/)) { + continueLine(state, column); + return "lineContinuation"; + } + var style = tokenize(stream, state); + if (stream.eol() && stream.current().match(/(?:^|[^\\])(?:\\\\)*\\$/)) { + stream.backUp(1); + } + return style; + }; + } + function commaContinuable(column, tokenize) { + return function(stream, state) { + finishContinue(state); + var style = tokenize(stream, state); + if (stream.eol() && stream.current().match(/,$/)) { + continueLine(state, column); + } + return style; + }; + } + + function rubyInQuote(endQuote, tokenize) { + // TODO: add multi line support + return function(stream, state) { + var ch = stream.peek(); + if (ch == endQuote && state.rubyState.tokenize.length == 1) { + // step out of ruby context as it seems to complete processing all the braces + stream.next(); + state.tokenize = tokenize; + return "closeAttributeTag"; + } else { + return ruby(stream, state); + } + }; + } + function startRubySplat(tokenize) { + var rubyState; + var runSplat = function(stream, state) { + if (state.rubyState.tokenize.length == 1 && !state.rubyState.context.prev) { + stream.backUp(1); + if (stream.eatSpace()) { + state.rubyState = rubyState; + state.tokenize = tokenize; + return tokenize(stream, state); + } + stream.next(); + } + return ruby(stream, state); + }; + return function(stream, state) { + rubyState = state.rubyState; + state.rubyState = rubyMode.startState(); + state.tokenize = runSplat; + return ruby(stream, state); + }; + } + + function ruby(stream, state) { + return rubyMode.token(stream, state.rubyState); + } + + function htmlLine(stream, state) { + if (stream.match(/^\\$/)) { + return "lineContinuation"; + } + return html(stream, state); + } + function html(stream, state) { + if (stream.match(/^#\{/)) { + state.tokenize = rubyInQuote("}", state.tokenize); + return null; + } + return maybeBackup(stream, state, /[^\\]#\{/, 1, htmlMode.token(stream, state.htmlState)); + } + + function startHtmlLine(lastTokenize) { + return function(stream, state) { + var style = htmlLine(stream, state); + if (stream.eol()) state.tokenize = lastTokenize; + return style; + }; + } + + function startHtmlMode(stream, state, offset) { + state.stack = { + parent: state.stack, + style: "html", + indented: stream.column() + offset, // pipe + space + tokenize: state.line + }; + state.line = state.tokenize = html; + return null; + } + + function comment(stream, state) { + stream.skipToEnd(); + return state.stack.style; + } + + function commentMode(stream, state) { + state.stack = { + parent: state.stack, + style: "comment", + indented: state.indented + 1, + tokenize: state.line + }; + state.line = comment; + return comment(stream, state); + } + + function attributeWrapper(stream, state) { + if (stream.eat(state.stack.endQuote)) { + state.line = state.stack.line; + state.tokenize = state.stack.tokenize; + state.stack = state.stack.parent; + return null; + } + if (stream.match(wrappedAttributeNameRegexp)) { + state.tokenize = attributeWrapperAssign; + return "slimAttribute"; + } + stream.next(); + return null; + } + function attributeWrapperAssign(stream, state) { + if (stream.match(/^==?/)) { + state.tokenize = attributeWrapperValue; + return null; + } + return attributeWrapper(stream, state); + } + function attributeWrapperValue(stream, state) { + var ch = stream.peek(); + if (ch == '"' || ch == "\'") { + state.tokenize = readQuoted(ch, "string", true, false, attributeWrapper); + stream.next(); + return state.tokenize(stream, state); + } + if (ch == '[') { + return startRubySplat(attributeWrapper)(stream, state); + } + if (stream.match(/^(true|false|nil)\b/)) { + state.tokenize = attributeWrapper; + return "keyword"; + } + return startRubySplat(attributeWrapper)(stream, state); + } + + function startAttributeWrapperMode(state, endQuote, tokenize) { + state.stack = { + parent: state.stack, + style: "wrapper", + indented: state.indented + 1, + tokenize: tokenize, + line: state.line, + endQuote: endQuote + }; + state.line = state.tokenize = attributeWrapper; + return null; + } + + function sub(stream, state) { + if (stream.match(/^#\{/)) { + state.tokenize = rubyInQuote("}", state.tokenize); + return null; + } + var subStream = new CodeMirror.StringStream(stream.string.slice(state.stack.indented), stream.tabSize); + subStream.pos = stream.pos - state.stack.indented; + subStream.start = stream.start - state.stack.indented; + subStream.lastColumnPos = stream.lastColumnPos - state.stack.indented; + subStream.lastColumnValue = stream.lastColumnValue - state.stack.indented; + var style = state.subMode.token(subStream, state.subState); + stream.pos = subStream.pos + state.stack.indented; + return style; + } + function firstSub(stream, state) { + state.stack.indented = stream.column(); + state.line = state.tokenize = sub; + return state.tokenize(stream, state); + } + + function createMode(mode) { + var query = embedded[mode]; + var spec = CodeMirror.mimeModes[query]; + if (spec) { + return CodeMirror.getMode(config, spec); + } + var factory = CodeMirror.modes[query]; + if (factory) { + return factory(config, {name: query}); + } + return CodeMirror.getMode(config, "null"); + } + + function getMode(mode) { + if (!modes.hasOwnProperty(mode)) { + return modes[mode] = createMode(mode); + } + return modes[mode]; + } + + function startSubMode(mode, state) { + var subMode = getMode(mode); + var subState = subMode.startState && subMode.startState(); + + state.subMode = subMode; + state.subState = subState; + + state.stack = { + parent: state.stack, + style: "sub", + indented: state.indented + 1, + tokenize: state.line + }; + state.line = state.tokenize = firstSub; + return "slimSubmode"; + } + + function doctypeLine(stream, _state) { + stream.skipToEnd(); + return "slimDoctype"; + } + + function startLine(stream, state) { + var ch = stream.peek(); + if (ch == '<') { + return (state.tokenize = startHtmlLine(state.tokenize))(stream, state); + } + if (stream.match(/^[|']/)) { + return startHtmlMode(stream, state, 1); + } + if (stream.match(/^\/(!|\[\w+])?/)) { + return commentMode(stream, state); + } + if (stream.match(/^(-|==?[<>]?)/)) { + state.tokenize = lineContinuable(stream.column(), commaContinuable(stream.column(), ruby)); + return "slimSwitch"; + } + if (stream.match(/^doctype\b/)) { + state.tokenize = doctypeLine; + return "keyword"; + } + + var m = stream.match(embeddedRegexp); + if (m) { + return startSubMode(m[1], state); + } + + return slimTag(stream, state); + } + + function slim(stream, state) { + if (state.startOfLine) { + return startLine(stream, state); + } + return slimTag(stream, state); + } + + function slimTag(stream, state) { + if (stream.eat('*')) { + state.tokenize = startRubySplat(slimTagExtras); + return null; + } + if (stream.match(nameRegexp)) { + state.tokenize = slimTagExtras; + return "slimTag"; + } + return slimClass(stream, state); + } + function slimTagExtras(stream, state) { + if (stream.match(/^(<>?|> state.indented && state.last != "slimSubmode") { + state.line = state.tokenize = state.stack.tokenize; + state.stack = state.stack.parent; + state.subMode = null; + state.subState = null; + } + } + if (stream.eatSpace()) return null; + var style = state.tokenize(stream, state); + state.startOfLine = false; + if (style) state.last = style; + return styleMap.hasOwnProperty(style) ? styleMap[style] : style; + }, + + blankLine: function(state) { + if (state.subMode && state.subMode.blankLine) { + return state.subMode.blankLine(state.subState); + } + }, + + innerMode: function(state) { + if (state.subMode) return {state: state.subState, mode: state.subMode}; + return {state: state, mode: mode}; + } + + //indent: function(state) { + // return state.indented; + //} + }; + return mode; + }, "htmlmixed", "ruby"); + + CodeMirror.defineMIME("text/x-slim", "slim"); + CodeMirror.defineMIME("application/x-slim", "slim"); +}); diff --git a/static/js/mdeditor/lib/codemirror/mode/slim/test.js b/static/js/mdeditor/lib/codemirror/mode/slim/test.js new file mode 100644 index 00000000..be4ddacb --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/slim/test.js @@ -0,0 +1,96 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// Slim Highlighting for CodeMirror copyright (c) HicknHack Software Gmbh + +(function() { + var mode = CodeMirror.getMode({tabSize: 4, indentUnit: 2}, "slim"); + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); } + + // Requires at least one media query + MT("elementName", + "[tag h1] Hey There"); + + MT("oneElementPerLine", + "[tag h1] Hey There .h2"); + + MT("idShortcut", + "[attribute&def #test] Hey There"); + + MT("tagWithIdShortcuts", + "[tag h1][attribute&def #test] Hey There"); + + MT("classShortcut", + "[attribute&qualifier .hello] Hey There"); + + MT("tagWithIdAndClassShortcuts", + "[tag h1][attribute&def #test][attribute&qualifier .hello] Hey There"); + + MT("docType", + "[keyword doctype] xml"); + + MT("comment", + "[comment / Hello WORLD]"); + + MT("notComment", + "[tag h1] This is not a / comment "); + + MT("attributes", + "[tag a]([attribute title]=[string \"test\"]) [attribute href]=[string \"link\"]}"); + + MT("multiLineAttributes", + "[tag a]([attribute title]=[string \"test\"]", + " ) [attribute href]=[string \"link\"]}"); + + MT("htmlCode", + "[tag&bracket <][tag h1][tag&bracket >]Title[tag&bracket ]"); + + MT("rubyBlock", + "[operator&special =][variable-2 @item]"); + + MT("selectorRubyBlock", + "[tag a][attribute&qualifier .test][operator&special =] [variable-2 @item]"); + + MT("nestedRubyBlock", + "[tag a]", + " [operator&special =][variable puts] [string \"test\"]"); + + MT("multilinePlaintext", + "[tag p]", + " | Hello,", + " World"); + + MT("multilineRuby", + "[tag p]", + " [comment /# this is a comment]", + " [comment and this is a comment too]", + " | Date/Time", + " [operator&special -] [variable now] [operator =] [tag DateTime][operator .][property now]", + " [tag strong][operator&special =] [variable now]", + " [operator&special -] [keyword if] [variable now] [operator >] [tag DateTime][operator .][property parse]([string \"December 31, 2006\"])", + " [operator&special =][string \"Happy\"]", + " [operator&special =][string \"Belated\"]", + " [operator&special =][string \"Birthday\"]"); + + MT("multilineComment", + "[comment /]", + " [comment Multiline]", + " [comment Comment]"); + + MT("hamlAfterRubyTag", + "[attribute&qualifier .block]", + " [tag strong][operator&special =] [variable now]", + " [attribute&qualifier .test]", + " [operator&special =][variable now]", + " [attribute&qualifier .right]"); + + MT("stretchedRuby", + "[operator&special =] [variable puts] [string \"Hello\"],", + " [string \"World\"]"); + + MT("interpolationInHashAttribute", + "[tag div]{[attribute id] = [string \"]#{[variable test]}[string _]#{[variable ting]}[string \"]} test"); + + MT("interpolationInHTMLAttribute", + "[tag div]([attribute title]=[string \"]#{[variable test]}[string _]#{[variable ting]()}[string \"]) Test"); +})(); diff --git a/static/js/mdeditor/lib/codemirror/mode/smalltalk/index.html b/static/js/mdeditor/lib/codemirror/mode/smalltalk/index.html new file mode 100644 index 00000000..2155ebc2 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/smalltalk/index.html @@ -0,0 +1,68 @@ + + +CodeMirror: Smalltalk mode + + + + + + + + + + +
+

Smalltalk mode

+
+ + + +

Simple Smalltalk mode.

+ +

MIME types defined: text/x-stsrc.

+
diff --git a/static/js/mdeditor/lib/codemirror/mode/smalltalk/smalltalk.js b/static/js/mdeditor/lib/codemirror/mode/smalltalk/smalltalk.js new file mode 100644 index 00000000..bb510ba2 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/smalltalk/smalltalk.js @@ -0,0 +1,168 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode('smalltalk', function(config) { + + var specialChars = /[+\-\/\\*~<>=@%|&?!.,:;^]/; + var keywords = /true|false|nil|self|super|thisContext/; + + var Context = function(tokenizer, parent) { + this.next = tokenizer; + this.parent = parent; + }; + + var Token = function(name, context, eos) { + this.name = name; + this.context = context; + this.eos = eos; + }; + + var State = function() { + this.context = new Context(next, null); + this.expectVariable = true; + this.indentation = 0; + this.userIndentationDelta = 0; + }; + + State.prototype.userIndent = function(indentation) { + this.userIndentationDelta = indentation > 0 ? (indentation / config.indentUnit - this.indentation) : 0; + }; + + var next = function(stream, context, state) { + var token = new Token(null, context, false); + var aChar = stream.next(); + + if (aChar === '"') { + token = nextComment(stream, new Context(nextComment, context)); + + } else if (aChar === '\'') { + token = nextString(stream, new Context(nextString, context)); + + } else if (aChar === '#') { + if (stream.peek() === '\'') { + stream.next(); + token = nextSymbol(stream, new Context(nextSymbol, context)); + } else { + if (stream.eatWhile(/[^\s.{}\[\]()]/)) + token.name = 'string-2'; + else + token.name = 'meta'; + } + + } else if (aChar === '$') { + if (stream.next() === '<') { + stream.eatWhile(/[^\s>]/); + stream.next(); + } + token.name = 'string-2'; + + } else if (aChar === '|' && state.expectVariable) { + token.context = new Context(nextTemporaries, context); + + } else if (/[\[\]{}()]/.test(aChar)) { + token.name = 'bracket'; + token.eos = /[\[{(]/.test(aChar); + + if (aChar === '[') { + state.indentation++; + } else if (aChar === ']') { + state.indentation = Math.max(0, state.indentation - 1); + } + + } else if (specialChars.test(aChar)) { + stream.eatWhile(specialChars); + token.name = 'operator'; + token.eos = aChar !== ';'; // ; cascaded message expression + + } else if (/\d/.test(aChar)) { + stream.eatWhile(/[\w\d]/); + token.name = 'number'; + + } else if (/[\w_]/.test(aChar)) { + stream.eatWhile(/[\w\d_]/); + token.name = state.expectVariable ? (keywords.test(stream.current()) ? 'keyword' : 'variable') : null; + + } else { + token.eos = state.expectVariable; + } + + return token; + }; + + var nextComment = function(stream, context) { + stream.eatWhile(/[^"]/); + return new Token('comment', stream.eat('"') ? context.parent : context, true); + }; + + var nextString = function(stream, context) { + stream.eatWhile(/[^']/); + return new Token('string', stream.eat('\'') ? context.parent : context, false); + }; + + var nextSymbol = function(stream, context) { + stream.eatWhile(/[^']/); + return new Token('string-2', stream.eat('\'') ? context.parent : context, false); + }; + + var nextTemporaries = function(stream, context) { + var token = new Token(null, context, false); + var aChar = stream.next(); + + if (aChar === '|') { + token.context = context.parent; + token.eos = true; + + } else { + stream.eatWhile(/[^|]/); + token.name = 'variable'; + } + + return token; + }; + + return { + startState: function() { + return new State; + }, + + token: function(stream, state) { + state.userIndent(stream.indentation()); + + if (stream.eatSpace()) { + return null; + } + + var token = state.context.next(stream, state.context, state); + state.context = token.context; + state.expectVariable = token.eos; + + return token.name; + }, + + blankLine: function(state) { + state.userIndent(0); + }, + + indent: function(state, textAfter) { + var i = state.context.next === next && textAfter && textAfter.charAt(0) === ']' ? -1 : state.userIndentationDelta; + return (state.indentation + i) * config.indentUnit; + }, + + electricChars: ']' + }; + +}); + +CodeMirror.defineMIME('text/x-stsrc', {name: 'smalltalk'}); + +}); diff --git a/static/js/mdeditor/lib/codemirror/mode/smarty/index.html b/static/js/mdeditor/lib/codemirror/mode/smarty/index.html new file mode 100644 index 00000000..8d88c9a3 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/smarty/index.html @@ -0,0 +1,136 @@ + + +CodeMirror: Smarty mode + + + + + + + + + +
+

Smarty mode

+
+ + + +
+ +

Smarty 2, custom delimiters

+
+ + + +
+ +

Smarty 3

+ + + + + + +

A plain text/Smarty version 2 or 3 mode, which allows for custom delimiter tags.

+ +

MIME types defined: text/x-smarty

+
diff --git a/static/js/mdeditor/lib/codemirror/mode/smarty/smarty.js b/static/js/mdeditor/lib/codemirror/mode/smarty/smarty.js new file mode 100644 index 00000000..bb053245 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/smarty/smarty.js @@ -0,0 +1,221 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +/** + * Smarty 2 and 3 mode. + */ + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("smarty", function(config) { + "use strict"; + + // our default settings; check to see if they're overridden + var settings = { + rightDelimiter: '}', + leftDelimiter: '{', + smartyVersion: 2 // for backward compatibility + }; + if (config.hasOwnProperty("leftDelimiter")) { + settings.leftDelimiter = config.leftDelimiter; + } + if (config.hasOwnProperty("rightDelimiter")) { + settings.rightDelimiter = config.rightDelimiter; + } + if (config.hasOwnProperty("smartyVersion") && config.smartyVersion === 3) { + settings.smartyVersion = 3; + } + + var keyFunctions = ["debug", "extends", "function", "include", "literal"]; + var last; + var regs = { + operatorChars: /[+\-*&%=<>!?]/, + validIdentifier: /[a-zA-Z0-9_]/, + stringChar: /['"]/ + }; + + var helpers = { + cont: function(style, lastType) { + last = lastType; + return style; + }, + chain: function(stream, state, parser) { + state.tokenize = parser; + return parser(stream, state); + } + }; + + + // our various parsers + var parsers = { + + // the main tokenizer + tokenizer: function(stream, state) { + if (stream.match(settings.leftDelimiter, true)) { + if (stream.eat("*")) { + return helpers.chain(stream, state, parsers.inBlock("comment", "*" + settings.rightDelimiter)); + } else { + // Smarty 3 allows { and } surrounded by whitespace to NOT slip into Smarty mode + state.depth++; + var isEol = stream.eol(); + var isFollowedByWhitespace = /\s/.test(stream.peek()); + if (settings.smartyVersion === 3 && settings.leftDelimiter === "{" && (isEol || isFollowedByWhitespace)) { + state.depth--; + return null; + } else { + state.tokenize = parsers.smarty; + last = "startTag"; + return "tag"; + } + } + } else { + stream.next(); + return null; + } + }, + + // parsing Smarty content + smarty: function(stream, state) { + if (stream.match(settings.rightDelimiter, true)) { + if (settings.smartyVersion === 3) { + state.depth--; + if (state.depth <= 0) { + state.tokenize = parsers.tokenizer; + } + } else { + state.tokenize = parsers.tokenizer; + } + return helpers.cont("tag", null); + } + + if (stream.match(settings.leftDelimiter, true)) { + state.depth++; + return helpers.cont("tag", "startTag"); + } + + var ch = stream.next(); + if (ch == "$") { + stream.eatWhile(regs.validIdentifier); + return helpers.cont("variable-2", "variable"); + } else if (ch == "|") { + return helpers.cont("operator", "pipe"); + } else if (ch == ".") { + return helpers.cont("operator", "property"); + } else if (regs.stringChar.test(ch)) { + state.tokenize = parsers.inAttribute(ch); + return helpers.cont("string", "string"); + } else if (regs.operatorChars.test(ch)) { + stream.eatWhile(regs.operatorChars); + return helpers.cont("operator", "operator"); + } else if (ch == "[" || ch == "]") { + return helpers.cont("bracket", "bracket"); + } else if (ch == "(" || ch == ")") { + return helpers.cont("bracket", "operator"); + } else if (/\d/.test(ch)) { + stream.eatWhile(/\d/); + return helpers.cont("number", "number"); + } else { + + if (state.last == "variable") { + if (ch == "@") { + stream.eatWhile(regs.validIdentifier); + return helpers.cont("property", "property"); + } else if (ch == "|") { + stream.eatWhile(regs.validIdentifier); + return helpers.cont("qualifier", "modifier"); + } + } else if (state.last == "pipe") { + stream.eatWhile(regs.validIdentifier); + return helpers.cont("qualifier", "modifier"); + } else if (state.last == "whitespace") { + stream.eatWhile(regs.validIdentifier); + return helpers.cont("attribute", "modifier"); + } if (state.last == "property") { + stream.eatWhile(regs.validIdentifier); + return helpers.cont("property", null); + } else if (/\s/.test(ch)) { + last = "whitespace"; + return null; + } + + var str = ""; + if (ch != "/") { + str += ch; + } + var c = null; + while (c = stream.eat(regs.validIdentifier)) { + str += c; + } + for (var i=0, j=keyFunctions.length; i + +CodeMirror: Smarty mixed mode + + + + + + + + + + + + + +
+

Smarty mixed mode

+
+ + + +

The Smarty mixed mode depends on the Smarty and HTML mixed modes. HTML + mixed mode itself depends on XML, JavaScript, and CSS modes.

+ +

It takes the same options, as Smarty and HTML mixed modes.

+ +

MIME types defined: text/x-smarty.

+
diff --git a/static/js/mdeditor/lib/codemirror/mode/smartymixed/smartymixed.js b/static/js/mdeditor/lib/codemirror/mode/smartymixed/smartymixed.js new file mode 100644 index 00000000..4fc7ca4b --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/smartymixed/smartymixed.js @@ -0,0 +1,197 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +/** +* @file smartymixed.js +* @brief Smarty Mixed Codemirror mode (Smarty + Mixed HTML) +* @author Ruslan Osmanov +* @version 3.0 +* @date 05.07.2013 +*/ + +// Warning: Don't base other modes on this one. This here is a +// terrible way to write a mixed mode. + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../htmlmixed/htmlmixed"), require("../smarty/smarty")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../htmlmixed/htmlmixed", "../smarty/smarty"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("smartymixed", function(config) { + var htmlMixedMode = CodeMirror.getMode(config, "htmlmixed"); + var smartyMode = CodeMirror.getMode(config, "smarty"); + + var settings = { + rightDelimiter: '}', + leftDelimiter: '{' + }; + + if (config.hasOwnProperty("leftDelimiter")) { + settings.leftDelimiter = config.leftDelimiter; + } + if (config.hasOwnProperty("rightDelimiter")) { + settings.rightDelimiter = config.rightDelimiter; + } + + function reEsc(str) { return str.replace(/[^\s\w]/g, "\\$&"); } + + var reLeft = reEsc(settings.leftDelimiter), reRight = reEsc(settings.rightDelimiter); + var regs = { + smartyComment: new RegExp("^" + reRight + "\\*"), + literalOpen: new RegExp(reLeft + "literal" + reRight), + literalClose: new RegExp(reLeft + "\/literal" + reRight), + hasLeftDelimeter: new RegExp(".*" + reLeft), + htmlHasLeftDelimeter: new RegExp("[^<>]*" + reLeft) + }; + + var helpers = { + chain: function(stream, state, parser) { + state.tokenize = parser; + return parser(stream, state); + }, + + cleanChain: function(stream, state, parser) { + state.tokenize = null; + state.localState = null; + state.localMode = null; + return (typeof parser == "string") ? (parser ? parser : null) : parser(stream, state); + }, + + maybeBackup: function(stream, pat, style) { + var cur = stream.current(); + var close = cur.search(pat), + m; + if (close > - 1) stream.backUp(cur.length - close); + else if (m = cur.match(/<\/?$/)) { + stream.backUp(cur.length); + if (!stream.match(pat, false)) stream.match(cur[0]); + } + return style; + } + }; + + var parsers = { + html: function(stream, state) { + var htmlTagName = state.htmlMixedState.htmlState.context && state.htmlMixedState.htmlState.context.tagName + ? state.htmlMixedState.htmlState.context.tagName + : null; + + if (!state.inLiteral && stream.match(regs.htmlHasLeftDelimeter, false) && htmlTagName === null) { + state.tokenize = parsers.smarty; + state.localMode = smartyMode; + state.localState = smartyMode.startState(htmlMixedMode.indent(state.htmlMixedState, "")); + return helpers.maybeBackup(stream, settings.leftDelimiter, smartyMode.token(stream, state.localState)); + } else if (!state.inLiteral && stream.match(settings.leftDelimiter, false)) { + state.tokenize = parsers.smarty; + state.localMode = smartyMode; + state.localState = smartyMode.startState(htmlMixedMode.indent(state.htmlMixedState, "")); + return helpers.maybeBackup(stream, settings.leftDelimiter, smartyMode.token(stream, state.localState)); + } + return htmlMixedMode.token(stream, state.htmlMixedState); + }, + + smarty: function(stream, state) { + if (stream.match(settings.leftDelimiter, false)) { + if (stream.match(regs.smartyComment, false)) { + return helpers.chain(stream, state, parsers.inBlock("comment", "*" + settings.rightDelimiter)); + } + } else if (stream.match(settings.rightDelimiter, false)) { + stream.eat(settings.rightDelimiter); + state.tokenize = parsers.html; + state.localMode = htmlMixedMode; + state.localState = state.htmlMixedState; + return "tag"; + } + + return helpers.maybeBackup(stream, settings.rightDelimiter, smartyMode.token(stream, state.localState)); + }, + + inBlock: function(style, terminator) { + return function(stream, state) { + while (!stream.eol()) { + if (stream.match(terminator)) { + helpers.cleanChain(stream, state, ""); + break; + } + stream.next(); + } + return style; + }; + } + }; + + return { + startState: function() { + var state = htmlMixedMode.startState(); + return { + token: parsers.html, + localMode: null, + localState: null, + htmlMixedState: state, + tokenize: null, + inLiteral: false + }; + }, + + copyState: function(state) { + var local = null, tok = (state.tokenize || state.token); + if (state.localState) { + local = CodeMirror.copyState((tok != parsers.html ? smartyMode : htmlMixedMode), state.localState); + } + return { + token: state.token, + tokenize: state.tokenize, + localMode: state.localMode, + localState: local, + htmlMixedState: CodeMirror.copyState(htmlMixedMode, state.htmlMixedState), + inLiteral: state.inLiteral + }; + }, + + token: function(stream, state) { + if (stream.match(settings.leftDelimiter, false)) { + if (!state.inLiteral && stream.match(regs.literalOpen, true)) { + state.inLiteral = true; + return "keyword"; + } else if (state.inLiteral && stream.match(regs.literalClose, true)) { + state.inLiteral = false; + return "keyword"; + } + } + if (state.inLiteral && state.localState != state.htmlMixedState) { + state.tokenize = parsers.html; + state.localMode = htmlMixedMode; + state.localState = state.htmlMixedState; + } + + var style = (state.tokenize || state.token)(stream, state); + return style; + }, + + indent: function(state, textAfter) { + if (state.localMode == smartyMode + || (state.inLiteral && !state.localMode) + || regs.hasLeftDelimeter.test(textAfter)) { + return CodeMirror.Pass; + } + return htmlMixedMode.indent(state.htmlMixedState, textAfter); + }, + + innerMode: function(state) { + return { + state: state.localState || state.htmlMixedState, + mode: state.localMode || htmlMixedMode + }; + } + }; +}, "htmlmixed", "smarty"); + +CodeMirror.defineMIME("text/x-smarty", "smartymixed"); +// vim: et ts=2 sts=2 sw=2 + +}); diff --git a/static/js/mdeditor/lib/codemirror/mode/solr/index.html b/static/js/mdeditor/lib/codemirror/mode/solr/index.html new file mode 100644 index 00000000..4b18c25b --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/solr/index.html @@ -0,0 +1,57 @@ + + +CodeMirror: Solr mode + + + + + + + + + +
+

Solr mode

+ +
+ +
+ + + +

MIME types defined: text/x-solr.

+
diff --git a/static/js/mdeditor/lib/codemirror/mode/solr/solr.js b/static/js/mdeditor/lib/codemirror/mode/solr/solr.js new file mode 100644 index 00000000..f7f70878 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/solr/solr.js @@ -0,0 +1,104 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("solr", function() { + "use strict"; + + var isStringChar = /[^\s\|\!\+\-\*\?\~\^\&\:\(\)\[\]\{\}\^\"\\]/; + var isOperatorChar = /[\|\!\+\-\*\?\~\^\&]/; + var isOperatorString = /^(OR|AND|NOT|TO)$/i; + + function isNumber(word) { + return parseFloat(word, 10).toString() === word; + } + + function tokenString(quote) { + return function(stream, state) { + var escaped = false, next; + while ((next = stream.next()) != null) { + if (next == quote && !escaped) break; + escaped = !escaped && next == "\\"; + } + + if (!escaped) state.tokenize = tokenBase; + return "string"; + }; + } + + function tokenOperator(operator) { + return function(stream, state) { + var style = "operator"; + if (operator == "+") + style += " positive"; + else if (operator == "-") + style += " negative"; + else if (operator == "|") + stream.eat(/\|/); + else if (operator == "&") + stream.eat(/\&/); + else if (operator == "^") + style += " boost"; + + state.tokenize = tokenBase; + return style; + }; + } + + function tokenWord(ch) { + return function(stream, state) { + var word = ch; + while ((ch = stream.peek()) && ch.match(isStringChar) != null) { + word += stream.next(); + } + + state.tokenize = tokenBase; + if (isOperatorString.test(word)) + return "operator"; + else if (isNumber(word)) + return "number"; + else if (stream.peek() == ":") + return "field"; + else + return "string"; + }; + } + + function tokenBase(stream, state) { + var ch = stream.next(); + if (ch == '"') + state.tokenize = tokenString(ch); + else if (isOperatorChar.test(ch)) + state.tokenize = tokenOperator(ch); + else if (isStringChar.test(ch)) + state.tokenize = tokenWord(ch); + + return (state.tokenize != tokenBase) ? state.tokenize(stream, state) : null; + } + + return { + startState: function() { + return { + tokenize: tokenBase + }; + }, + + token: function(stream, state) { + if (stream.eatSpace()) return null; + return state.tokenize(stream, state); + } + }; +}); + +CodeMirror.defineMIME("text/x-solr", "solr"); + +}); diff --git a/static/js/mdeditor/lib/codemirror/mode/soy/index.html b/static/js/mdeditor/lib/codemirror/mode/soy/index.html new file mode 100644 index 00000000..f0216f09 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/soy/index.html @@ -0,0 +1,68 @@ + + +CodeMirror: Soy (Closure Template) mode + + + + + + + + + + + + + + +
+

Soy (Closure Template) mode

+
+ + + +

A mode for Closure Templates (Soy).

+

MIME type defined: text/x-soy.

+
diff --git a/static/js/mdeditor/lib/codemirror/mode/soy/soy.js b/static/js/mdeditor/lib/codemirror/mode/soy/soy.js new file mode 100644 index 00000000..7e81e8dd --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/soy/soy.js @@ -0,0 +1,198 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../htmlmixed/htmlmixed")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../htmlmixed/htmlmixed"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var indentingTags = ["template", "literal", "msg", "fallbackmsg", "let", "if", "elseif", + "else", "switch", "case", "default", "foreach", "ifempty", "for", + "call", "param", "deltemplate", "delcall", "log"]; + + CodeMirror.defineMode("soy", function(config) { + var textMode = CodeMirror.getMode(config, "text/plain"); + var modes = { + html: CodeMirror.getMode(config, {name: "text/html", multilineTagIndentFactor: 2, multilineTagIndentPastTag: false}), + attributes: textMode, + text: textMode, + uri: textMode, + css: CodeMirror.getMode(config, "text/css"), + js: CodeMirror.getMode(config, {name: "text/javascript", statementIndent: 2 * config.indentUnit}) + }; + + function last(array) { + return array[array.length - 1]; + } + + function tokenUntil(stream, state, untilRegExp) { + var oldString = stream.string; + var match = untilRegExp.exec(oldString.substr(stream.pos)); + if (match) { + // We don't use backUp because it backs up just the position, not the state. + // This uses an undocumented API. + stream.string = oldString.substr(0, stream.pos + match.index); + } + var result = stream.hideFirstChars(state.indent, function() { + return state.localMode.token(stream, state.localState); + }); + stream.string = oldString; + return result; + } + + return { + startState: function() { + return { + kind: [], + kindTag: [], + soyState: [], + indent: 0, + localMode: modes.html, + localState: CodeMirror.startState(modes.html) + }; + }, + + copyState: function(state) { + return { + tag: state.tag, // Last seen Soy tag. + kind: state.kind.concat([]), // Values of kind="" attributes. + kindTag: state.kindTag.concat([]), // Opened tags with kind="" attributes. + soyState: state.soyState.concat([]), + indent: state.indent, // Indentation of the following line. + localMode: state.localMode, + localState: CodeMirror.copyState(state.localMode, state.localState) + }; + }, + + token: function(stream, state) { + var match; + + switch (last(state.soyState)) { + case "comment": + if (stream.match(/^.*?\*\//)) { + state.soyState.pop(); + } else { + stream.skipToEnd(); + } + return "comment"; + + case "variable": + if (stream.match(/^}/)) { + state.indent -= 2 * config.indentUnit; + state.soyState.pop(); + return "variable-2"; + } + stream.next(); + return null; + + case "tag": + if (stream.match(/^\/?}/)) { + if (state.tag == "/template" || state.tag == "/deltemplate") state.indent = 0; + else state.indent -= (stream.current() == "/}" || indentingTags.indexOf(state.tag) == -1 ? 2 : 1) * config.indentUnit; + state.soyState.pop(); + return "keyword"; + } else if (stream.match(/^(\w+)(?==)/)) { + if (stream.current() == "kind" && (match = stream.match(/^="([^"]+)/, false))) { + var kind = match[1]; + state.kind.push(kind); + state.kindTag.push(state.tag); + state.localMode = modes[kind] || modes.html; + state.localState = CodeMirror.startState(state.localMode); + } + return "attribute"; + } else if (stream.match(/^"/)) { + state.soyState.push("string"); + return "string"; + } + stream.next(); + return null; + + case "literal": + if (stream.match(/^(?=\{\/literal})/)) { + state.indent -= config.indentUnit; + state.soyState.pop(); + return this.token(stream, state); + } + return tokenUntil(stream, state, /\{\/literal}/); + + case "string": + if (stream.match(/^.*?"/)) { + state.soyState.pop(); + } else { + stream.skipToEnd(); + } + return "string"; + } + + if (stream.match(/^\/\*/)) { + state.soyState.push("comment"); + return "comment"; + } else if (stream.match(stream.sol() ? /^\s*\/\/.*/ : /^\s+\/\/.*/)) { + return "comment"; + } else if (stream.match(/^\{\$\w*/)) { + state.indent += 2 * config.indentUnit; + state.soyState.push("variable"); + return "variable-2"; + } else if (stream.match(/^\{literal}/)) { + state.indent += config.indentUnit; + state.soyState.push("literal"); + return "keyword"; + } else if (match = stream.match(/^\{([\/@\\]?\w*)/)) { + if (match[1] != "/switch") + state.indent += (/^(\/|(else|elseif|case|default)$)/.test(match[1]) && state.tag != "switch" ? 1 : 2) * config.indentUnit; + state.tag = match[1]; + if (state.tag == "/" + last(state.kindTag)) { + // We found the tag that opened the current kind="". + state.kind.pop(); + state.kindTag.pop(); + state.localMode = modes[last(state.kind)] || modes.html; + state.localState = CodeMirror.startState(state.localMode); + } + state.soyState.push("tag"); + return "keyword"; + } + + return tokenUntil(stream, state, /\{|\s+\/\/|\/\*/); + }, + + indent: function(state, textAfter) { + var indent = state.indent, top = last(state.soyState); + if (top == "comment") return CodeMirror.Pass; + + if (top == "literal") { + if (/^\{\/literal}/.test(textAfter)) indent -= config.indentUnit; + } else { + if (/^\s*\{\/(template|deltemplate)\b/.test(textAfter)) return 0; + if (/^\{(\/|(fallbackmsg|elseif|else|ifempty)\b)/.test(textAfter)) indent -= config.indentUnit; + if (state.tag != "switch" && /^\{(case|default)\b/.test(textAfter)) indent -= config.indentUnit; + if (/^\{\/switch\b/.test(textAfter)) indent -= config.indentUnit; + } + if (indent && state.localMode.indent) + indent += state.localMode.indent(state.localState, textAfter); + return indent; + }, + + innerMode: function(state) { + if (state.soyState.length && last(state.soyState) != "literal") return null; + else return {state: state.localState, mode: state.localMode}; + }, + + electricInput: /^\s*\{(\/|\/template|\/deltemplate|\/switch|fallbackmsg|elseif|else|case|default|ifempty|\/literal\})$/, + lineComment: "//", + blockCommentStart: "/*", + blockCommentEnd: "*/", + blockCommentContinue: " * ", + fold: "indent" + }; + }, "htmlmixed"); + + CodeMirror.registerHelper("hintWords", "soy", indentingTags.concat( + ["delpackage", "namespace", "alias", "print", "css", "debugger"])); + + CodeMirror.defineMIME("text/x-soy", "soy"); +}); diff --git a/static/js/mdeditor/lib/codemirror/mode/sparql/index.html b/static/js/mdeditor/lib/codemirror/mode/sparql/index.html new file mode 100644 index 00000000..84ef4d36 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/sparql/index.html @@ -0,0 +1,61 @@ + + +CodeMirror: SPARQL mode + + + + + + + + + + +
+

SPARQL mode

+
+ + +

MIME types defined: application/sparql-query.

+ +
diff --git a/static/js/mdeditor/lib/codemirror/mode/sparql/sparql.js b/static/js/mdeditor/lib/codemirror/mode/sparql/sparql.js new file mode 100644 index 00000000..bbf8a76a --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/sparql/sparql.js @@ -0,0 +1,174 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("sparql", function(config) { + var indentUnit = config.indentUnit; + var curPunc; + + function wordRegexp(words) { + return new RegExp("^(?:" + words.join("|") + ")$", "i"); + } + var ops = wordRegexp(["str", "lang", "langmatches", "datatype", "bound", "sameterm", "isiri", "isuri", + "iri", "uri", "bnode", "count", "sum", "min", "max", "avg", "sample", + "group_concat", "rand", "abs", "ceil", "floor", "round", "concat", "substr", "strlen", + "replace", "ucase", "lcase", "encode_for_uri", "contains", "strstarts", "strends", + "strbefore", "strafter", "year", "month", "day", "hours", "minutes", "seconds", + "timezone", "tz", "now", "uuid", "struuid", "md5", "sha1", "sha256", "sha384", + "sha512", "coalesce", "if", "strlang", "strdt", "isnumeric", "regex", "exists", + "isblank", "isliteral", "a"]); + var keywords = wordRegexp(["base", "prefix", "select", "distinct", "reduced", "construct", "describe", + "ask", "from", "named", "where", "order", "limit", "offset", "filter", "optional", + "graph", "by", "asc", "desc", "as", "having", "undef", "values", "group", + "minus", "in", "not", "service", "silent", "using", "insert", "delete", "union", + "true", "false", "with", + "data", "copy", "to", "move", "add", "create", "drop", "clear", "load"]); + var operatorChars = /[*+\-<>=&|\^\/!\?]/; + + function tokenBase(stream, state) { + var ch = stream.next(); + curPunc = null; + if (ch == "$" || ch == "?") { + if(ch == "?" && stream.match(/\s/, false)){ + return "operator"; + } + stream.match(/^[\w\d]*/); + return "variable-2"; + } + else if (ch == "<" && !stream.match(/^[\s\u00a0=]/, false)) { + stream.match(/^[^\s\u00a0>]*>?/); + return "atom"; + } + else if (ch == "\"" || ch == "'") { + state.tokenize = tokenLiteral(ch); + return state.tokenize(stream, state); + } + else if (/[{}\(\),\.;\[\]]/.test(ch)) { + curPunc = ch; + return "bracket"; + } + else if (ch == "#") { + stream.skipToEnd(); + return "comment"; + } + else if (operatorChars.test(ch)) { + stream.eatWhile(operatorChars); + return "operator"; + } + else if (ch == ":") { + stream.eatWhile(/[\w\d\._\-]/); + return "atom"; + } + else if (ch == "@") { + stream.eatWhile(/[a-z\d\-]/i); + return "meta"; + } + else { + stream.eatWhile(/[_\w\d]/); + if (stream.eat(":")) { + stream.eatWhile(/[\w\d_\-]/); + return "atom"; + } + var word = stream.current(); + if (ops.test(word)) + return "builtin"; + else if (keywords.test(word)) + return "keyword"; + else + return "variable"; + } + } + + function tokenLiteral(quote) { + return function(stream, state) { + var escaped = false, ch; + while ((ch = stream.next()) != null) { + if (ch == quote && !escaped) { + state.tokenize = tokenBase; + break; + } + escaped = !escaped && ch == "\\"; + } + return "string"; + }; + } + + function pushContext(state, type, col) { + state.context = {prev: state.context, indent: state.indent, col: col, type: type}; + } + function popContext(state) { + state.indent = state.context.indent; + state.context = state.context.prev; + } + + return { + startState: function() { + return {tokenize: tokenBase, + context: null, + indent: 0, + col: 0}; + }, + + token: function(stream, state) { + if (stream.sol()) { + if (state.context && state.context.align == null) state.context.align = false; + state.indent = stream.indentation(); + } + if (stream.eatSpace()) return null; + var style = state.tokenize(stream, state); + + if (style != "comment" && state.context && state.context.align == null && state.context.type != "pattern") { + state.context.align = true; + } + + if (curPunc == "(") pushContext(state, ")", stream.column()); + else if (curPunc == "[") pushContext(state, "]", stream.column()); + else if (curPunc == "{") pushContext(state, "}", stream.column()); + else if (/[\]\}\)]/.test(curPunc)) { + while (state.context && state.context.type == "pattern") popContext(state); + if (state.context && curPunc == state.context.type) popContext(state); + } + else if (curPunc == "." && state.context && state.context.type == "pattern") popContext(state); + else if (/atom|string|variable/.test(style) && state.context) { + if (/[\}\]]/.test(state.context.type)) + pushContext(state, "pattern", stream.column()); + else if (state.context.type == "pattern" && !state.context.align) { + state.context.align = true; + state.context.col = stream.column(); + } + } + + return style; + }, + + indent: function(state, textAfter) { + var firstChar = textAfter && textAfter.charAt(0); + var context = state.context; + if (/[\]\}]/.test(firstChar)) + while (context && context.type == "pattern") context = context.prev; + + var closing = context && firstChar == context.type; + if (!context) + return 0; + else if (context.type == "pattern") + return context.col; + else if (context.align) + return context.col + (closing ? 0 : 1); + else + return context.indent + (closing ? 0 : indentUnit); + } + }; +}); + +CodeMirror.defineMIME("application/sparql-query", "sparql"); + +}); diff --git a/static/js/mdeditor/lib/codemirror/mode/spreadsheet/index.html b/static/js/mdeditor/lib/codemirror/mode/spreadsheet/index.html new file mode 100644 index 00000000..a52f76f0 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/spreadsheet/index.html @@ -0,0 +1,42 @@ + + +CodeMirror: Spreadsheet mode + + + + + + + + + + +
+

Spreadsheet mode

+
+ + + +

MIME types defined: text/x-spreadsheet.

+ +

The Spreadsheet Mode

+

Created by Robert Plummer

+
diff --git a/static/js/mdeditor/lib/codemirror/mode/spreadsheet/spreadsheet.js b/static/js/mdeditor/lib/codemirror/mode/spreadsheet/spreadsheet.js new file mode 100644 index 00000000..6fab00fd --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/spreadsheet/spreadsheet.js @@ -0,0 +1,109 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineMode("spreadsheet", function () { + return { + startState: function () { + return { + stringType: null, + stack: [] + }; + }, + token: function (stream, state) { + if (!stream) return; + + //check for state changes + if (state.stack.length === 0) { + //strings + if ((stream.peek() == '"') || (stream.peek() == "'")) { + state.stringType = stream.peek(); + stream.next(); // Skip quote + state.stack.unshift("string"); + } + } + + //return state + //stack has + switch (state.stack[0]) { + case "string": + while (state.stack[0] === "string" && !stream.eol()) { + if (stream.peek() === state.stringType) { + stream.next(); // Skip quote + state.stack.shift(); // Clear flag + } else if (stream.peek() === "\\") { + stream.next(); + stream.next(); + } else { + stream.match(/^.[^\\\"\']*/); + } + } + return "string"; + + case "characterClass": + while (state.stack[0] === "characterClass" && !stream.eol()) { + if (!(stream.match(/^[^\]\\]+/) || stream.match(/^\\./))) + state.stack.shift(); + } + return "operator"; + } + + var peek = stream.peek(); + + //no stack + switch (peek) { + case "[": + stream.next(); + state.stack.unshift("characterClass"); + return "bracket"; + case ":": + stream.next(); + return "operator"; + case "\\": + if (stream.match(/\\[a-z]+/)) return "string-2"; + else return null; + case ".": + case ",": + case ";": + case "*": + case "-": + case "+": + case "^": + case "<": + case "/": + case "=": + stream.next(); + return "atom"; + case "$": + stream.next(); + return "builtin"; + } + + if (stream.match(/\d+/)) { + if (stream.match(/^\w+/)) return "error"; + return "number"; + } else if (stream.match(/^[a-zA-Z_]\w*/)) { + if (stream.match(/(?=[\(.])/, false)) return "keyword"; + return "variable-2"; + } else if (["[", "]", "(", ")", "{", "}"].indexOf(peek) != -1) { + stream.next(); + return "bracket"; + } else if (!stream.eatSpace()) { + stream.next(); + } + return null; + } + }; + }); + + CodeMirror.defineMIME("text/x-spreadsheet", "spreadsheet"); +}); diff --git a/static/js/mdeditor/lib/codemirror/mode/sql/index.html b/static/js/mdeditor/lib/codemirror/mode/sql/index.html new file mode 100644 index 00000000..a0d8d9e1 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/sql/index.html @@ -0,0 +1,84 @@ + + +CodeMirror: SQL Mode for CodeMirror + + + + + + + + + + + + +
+

SQL Mode for CodeMirror

+
+ +
+

MIME types defined: + text/x-sql, + text/x-mysql, + text/x-mariadb, + text/x-cassandra, + text/x-plsql, + text/x-mssql, + text/x-hive. +

+ + +
diff --git a/static/js/mdeditor/lib/codemirror/mode/sql/sql.js b/static/js/mdeditor/lib/codemirror/mode/sql/sql.js new file mode 100644 index 00000000..ee6c194b --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/sql/sql.js @@ -0,0 +1,391 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("sql", function(config, parserConfig) { + "use strict"; + + var client = parserConfig.client || {}, + atoms = parserConfig.atoms || {"false": true, "true": true, "null": true}, + builtin = parserConfig.builtin || {}, + keywords = parserConfig.keywords || {}, + operatorChars = parserConfig.operatorChars || /^[*+\-%<>!=&|~^]/, + support = parserConfig.support || {}, + hooks = parserConfig.hooks || {}, + dateSQL = parserConfig.dateSQL || {"date" : true, "time" : true, "timestamp" : true}; + + function tokenBase(stream, state) { + var ch = stream.next(); + + // call hooks from the mime type + if (hooks[ch]) { + var result = hooks[ch](stream, state); + if (result !== false) return result; + } + + if (support.hexNumber == true && + ((ch == "0" && stream.match(/^[xX][0-9a-fA-F]+/)) + || (ch == "x" || ch == "X") && stream.match(/^'[0-9a-fA-F]+'/))) { + // hex + // ref: http://dev.mysql.com/doc/refman/5.5/en/hexadecimal-literals.html + return "number"; + } else if (support.binaryNumber == true && + (((ch == "b" || ch == "B") && stream.match(/^'[01]+'/)) + || (ch == "0" && stream.match(/^b[01]+/)))) { + // bitstring + // ref: http://dev.mysql.com/doc/refman/5.5/en/bit-field-literals.html + return "number"; + } else if (ch.charCodeAt(0) > 47 && ch.charCodeAt(0) < 58) { + // numbers + // ref: http://dev.mysql.com/doc/refman/5.5/en/number-literals.html + stream.match(/^[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?/); + support.decimallessFloat == true && stream.eat('.'); + return "number"; + } else if (ch == "?" && (stream.eatSpace() || stream.eol() || stream.eat(";"))) { + // placeholders + return "variable-3"; + } else if (ch == "'" || (ch == '"' && support.doubleQuote)) { + // strings + // ref: http://dev.mysql.com/doc/refman/5.5/en/string-literals.html + state.tokenize = tokenLiteral(ch); + return state.tokenize(stream, state); + } else if ((((support.nCharCast == true && (ch == "n" || ch == "N")) + || (support.charsetCast == true && ch == "_" && stream.match(/[a-z][a-z0-9]*/i))) + && (stream.peek() == "'" || stream.peek() == '"'))) { + // charset casting: _utf8'str', N'str', n'str' + // ref: http://dev.mysql.com/doc/refman/5.5/en/string-literals.html + return "keyword"; + } else if (/^[\(\),\;\[\]]/.test(ch)) { + // no highlightning + return null; + } else if (support.commentSlashSlash && ch == "/" && stream.eat("/")) { + // 1-line comment + stream.skipToEnd(); + return "comment"; + } else if ((support.commentHash && ch == "#") + || (ch == "-" && stream.eat("-") && (!support.commentSpaceRequired || stream.eat(" ")))) { + // 1-line comments + // ref: https://kb.askmonty.org/en/comment-syntax/ + stream.skipToEnd(); + return "comment"; + } else if (ch == "/" && stream.eat("*")) { + // multi-line comments + // ref: https://kb.askmonty.org/en/comment-syntax/ + state.tokenize = tokenComment; + return state.tokenize(stream, state); + } else if (ch == ".") { + // .1 for 0.1 + if (support.zerolessFloat == true && stream.match(/^(?:\d+(?:e[+-]?\d+)?)/i)) { + return "number"; + } + // .table_name (ODBC) + // // ref: http://dev.mysql.com/doc/refman/5.6/en/identifier-qualifiers.html + if (support.ODBCdotTable == true && stream.match(/^[a-zA-Z_]+/)) { + return "variable-2"; + } + } else if (operatorChars.test(ch)) { + // operators + stream.eatWhile(operatorChars); + return null; + } else if (ch == '{' && + (stream.match(/^( )*(d|D|t|T|ts|TS)( )*'[^']*'( )*}/) || stream.match(/^( )*(d|D|t|T|ts|TS)( )*"[^"]*"( )*}/))) { + // dates (weird ODBC syntax) + // ref: http://dev.mysql.com/doc/refman/5.5/en/date-and-time-literals.html + return "number"; + } else { + stream.eatWhile(/^[_\w\d]/); + var word = stream.current().toLowerCase(); + // dates (standard SQL syntax) + // ref: http://dev.mysql.com/doc/refman/5.5/en/date-and-time-literals.html + if (dateSQL.hasOwnProperty(word) && (stream.match(/^( )+'[^']*'/) || stream.match(/^( )+"[^"]*"/))) + return "number"; + if (atoms.hasOwnProperty(word)) return "atom"; + if (builtin.hasOwnProperty(word)) return "builtin"; + if (keywords.hasOwnProperty(word)) return "keyword"; + if (client.hasOwnProperty(word)) return "string-2"; + return null; + } + } + + // 'string', with char specified in quote escaped by '\' + function tokenLiteral(quote) { + return function(stream, state) { + var escaped = false, ch; + while ((ch = stream.next()) != null) { + if (ch == quote && !escaped) { + state.tokenize = tokenBase; + break; + } + escaped = !escaped && ch == "\\"; + } + return "string"; + }; + } + function tokenComment(stream, state) { + while (true) { + if (stream.skipTo("*")) { + stream.next(); + if (stream.eat("/")) { + state.tokenize = tokenBase; + break; + } + } else { + stream.skipToEnd(); + break; + } + } + return "comment"; + } + + function pushContext(stream, state, type) { + state.context = { + prev: state.context, + indent: stream.indentation(), + col: stream.column(), + type: type + }; + } + + function popContext(state) { + state.indent = state.context.indent; + state.context = state.context.prev; + } + + return { + startState: function() { + return {tokenize: tokenBase, context: null}; + }, + + token: function(stream, state) { + if (stream.sol()) { + if (state.context && state.context.align == null) + state.context.align = false; + } + if (stream.eatSpace()) return null; + + var style = state.tokenize(stream, state); + if (style == "comment") return style; + + if (state.context && state.context.align == null) + state.context.align = true; + + var tok = stream.current(); + if (tok == "(") + pushContext(stream, state, ")"); + else if (tok == "[") + pushContext(stream, state, "]"); + else if (state.context && state.context.type == tok) + popContext(state); + return style; + }, + + indent: function(state, textAfter) { + var cx = state.context; + if (!cx) return CodeMirror.Pass; + var closing = textAfter.charAt(0) == cx.type; + if (cx.align) return cx.col + (closing ? 0 : 1); + else return cx.indent + (closing ? 0 : config.indentUnit); + }, + + blockCommentStart: "/*", + blockCommentEnd: "*/", + lineComment: support.commentSlashSlash ? "//" : support.commentHash ? "#" : null + }; +}); + +(function() { + "use strict"; + + // `identifier` + function hookIdentifier(stream) { + // MySQL/MariaDB identifiers + // ref: http://dev.mysql.com/doc/refman/5.6/en/identifier-qualifiers.html + var ch; + while ((ch = stream.next()) != null) { + if (ch == "`" && !stream.eat("`")) return "variable-2"; + } + stream.backUp(stream.current().length - 1); + return stream.eatWhile(/\w/) ? "variable-2" : null; + } + + // variable token + function hookVar(stream) { + // variables + // @@prefix.varName @varName + // varName can be quoted with ` or ' or " + // ref: http://dev.mysql.com/doc/refman/5.5/en/user-variables.html + if (stream.eat("@")) { + stream.match(/^session\./); + stream.match(/^local\./); + stream.match(/^global\./); + } + + if (stream.eat("'")) { + stream.match(/^.*'/); + return "variable-2"; + } else if (stream.eat('"')) { + stream.match(/^.*"/); + return "variable-2"; + } else if (stream.eat("`")) { + stream.match(/^.*`/); + return "variable-2"; + } else if (stream.match(/^[0-9a-zA-Z$\.\_]+/)) { + return "variable-2"; + } + return null; + }; + + // short client keyword token + function hookClient(stream) { + // \N means NULL + // ref: http://dev.mysql.com/doc/refman/5.5/en/null-values.html + if (stream.eat("N")) { + return "atom"; + } + // \g, etc + // ref: http://dev.mysql.com/doc/refman/5.5/en/mysql-commands.html + return stream.match(/^[a-zA-Z.#!?]/) ? "variable-2" : null; + } + + // these keywords are used by all SQL dialects (however, a mode can still overwrite it) + var sqlKeywords = "alter and as asc between by count create delete desc distinct drop from having in insert into is join like not on or order select set table union update values where "; + + // turn a space-separated list into an array + function set(str) { + var obj = {}, words = str.split(" "); + for (var i = 0; i < words.length; ++i) obj[words[i]] = true; + return obj; + } + + // A generic SQL Mode. It's not a standard, it just try to support what is generally supported + CodeMirror.defineMIME("text/x-sql", { + name: "sql", + keywords: set(sqlKeywords + "begin"), + builtin: set("bool boolean bit blob enum long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision real date datetime year unsigned signed decimal numeric"), + atoms: set("false true null unknown"), + operatorChars: /^[*+\-%<>!=]/, + dateSQL: set("date time timestamp"), + support: set("ODBCdotTable doubleQuote binaryNumber hexNumber") + }); + + CodeMirror.defineMIME("text/x-mssql", { + name: "sql", + client: set("charset clear connect edit ego exit go help nopager notee nowarning pager print prompt quit rehash source status system tee"), + keywords: set(sqlKeywords + "begin trigger proc view index for add constraint key primary foreign collate clustered nonclustered"), + builtin: set("bigint numeric bit smallint decimal smallmoney int tinyint money float real char varchar text nchar nvarchar ntext binary varbinary image cursor timestamp hierarchyid uniqueidentifier sql_variant xml table "), + atoms: set("false true null unknown"), + operatorChars: /^[*+\-%<>!=]/, + dateSQL: set("date datetimeoffset datetime2 smalldatetime datetime time"), + hooks: { + "@": hookVar + } + }); + + CodeMirror.defineMIME("text/x-mysql", { + name: "sql", + client: set("charset clear connect edit ego exit go help nopager notee nowarning pager print prompt quit rehash source status system tee"), + keywords: set(sqlKeywords + "accessible action add after algorithm all analyze asensitive at authors auto_increment autocommit avg avg_row_length before binary binlog both btree cache call cascade cascaded case catalog_name chain change changed character check checkpoint checksum class_origin client_statistics close coalesce code collate collation collations column columns comment commit committed completion concurrent condition connection consistent constraint contains continue contributors convert cross current current_date current_time current_timestamp current_user cursor data database databases day_hour day_microsecond day_minute day_second deallocate dec declare default delay_key_write delayed delimiter des_key_file describe deterministic dev_pop dev_samp deviance diagnostics directory disable discard distinctrow div dual dumpfile each elseif enable enclosed end ends engine engines enum errors escape escaped even event events every execute exists exit explain extended fast fetch field fields first flush for force foreign found_rows full fulltext function general get global grant grants group groupby_concat handler hash help high_priority hosts hour_microsecond hour_minute hour_second if ignore ignore_server_ids import index index_statistics infile inner innodb inout insensitive insert_method install interval invoker isolation iterate key keys kill language last leading leave left level limit linear lines list load local localtime localtimestamp lock logs low_priority master master_heartbeat_period master_ssl_verify_server_cert masters match max max_rows maxvalue message_text middleint migrate min min_rows minute_microsecond minute_second mod mode modifies modify mutex mysql_errno natural next no no_write_to_binlog offline offset one online open optimize option optionally out outer outfile pack_keys parser partition partitions password phase plugin plugins prepare preserve prev primary privileges procedure processlist profile profiles purge query quick range read read_write reads real rebuild recover references regexp relaylog release remove rename reorganize repair repeatable replace require resignal restrict resume return returns revoke right rlike rollback rollup row row_format rtree savepoint schedule schema schema_name schemas second_microsecond security sensitive separator serializable server session share show signal slave slow smallint snapshot soname spatial specific sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_no_cache sql_small_result sqlexception sqlstate sqlwarning ssl start starting starts status std stddev stddev_pop stddev_samp storage straight_join subclass_origin sum suspend table_name table_statistics tables tablespace temporary terminated to trailing transaction trigger triggers truncate uncommitted undo uninstall unique unlock upgrade usage use use_frm user user_resources user_statistics using utc_date utc_time utc_timestamp value variables varying view views warnings when while with work write xa xor year_month zerofill begin do then else loop repeat"), + builtin: set("bool boolean bit blob decimal double float long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision date datetime year unsigned signed numeric"), + atoms: set("false true null unknown"), + operatorChars: /^[*+\-%<>!=&|^]/, + dateSQL: set("date time timestamp"), + support: set("ODBCdotTable decimallessFloat zerolessFloat binaryNumber hexNumber doubleQuote nCharCast charsetCast commentHash commentSpaceRequired"), + hooks: { + "@": hookVar, + "`": hookIdentifier, + "\\": hookClient + } + }); + + CodeMirror.defineMIME("text/x-mariadb", { + name: "sql", + client: set("charset clear connect edit ego exit go help nopager notee nowarning pager print prompt quit rehash source status system tee"), + keywords: set(sqlKeywords + "accessible action add after algorithm all always analyze asensitive at authors auto_increment autocommit avg avg_row_length before binary binlog both btree cache call cascade cascaded case catalog_name chain change changed character check checkpoint checksum class_origin client_statistics close coalesce code collate collation collations column columns comment commit committed completion concurrent condition connection consistent constraint contains continue contributors convert cross current current_date current_time current_timestamp current_user cursor data database databases day_hour day_microsecond day_minute day_second deallocate dec declare default delay_key_write delayed delimiter des_key_file describe deterministic dev_pop dev_samp deviance diagnostics directory disable discard distinctrow div dual dumpfile each elseif enable enclosed end ends engine engines enum errors escape escaped even event events every execute exists exit explain extended fast fetch field fields first flush for force foreign found_rows full fulltext function general generated get global grant grants group groupby_concat handler hard hash help high_priority hosts hour_microsecond hour_minute hour_second if ignore ignore_server_ids import index index_statistics infile inner innodb inout insensitive insert_method install interval invoker isolation iterate key keys kill language last leading leave left level limit linear lines list load local localtime localtimestamp lock logs low_priority master master_heartbeat_period master_ssl_verify_server_cert masters match max max_rows maxvalue message_text middleint migrate min min_rows minute_microsecond minute_second mod mode modifies modify mutex mysql_errno natural next no no_write_to_binlog offline offset one online open optimize option optionally out outer outfile pack_keys parser partition partitions password persistent phase plugin plugins prepare preserve prev primary privileges procedure processlist profile profiles purge query quick range read read_write reads real rebuild recover references regexp relaylog release remove rename reorganize repair repeatable replace require resignal restrict resume return returns revoke right rlike rollback rollup row row_format rtree savepoint schedule schema schema_name schemas second_microsecond security sensitive separator serializable server session share show shutdown signal slave slow smallint snapshot soft soname spatial specific sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_no_cache sql_small_result sqlexception sqlstate sqlwarning ssl start starting starts status std stddev stddev_pop stddev_samp storage straight_join subclass_origin sum suspend table_name table_statistics tables tablespace temporary terminated to trailing transaction trigger triggers truncate uncommitted undo uninstall unique unlock upgrade usage use use_frm user user_resources user_statistics using utc_date utc_time utc_timestamp value variables varying view views virtual warnings when while with work write xa xor year_month zerofill begin do then else loop repeat"), + builtin: set("bool boolean bit blob decimal double float long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision date datetime year unsigned signed numeric"), + atoms: set("false true null unknown"), + operatorChars: /^[*+\-%<>!=&|^]/, + dateSQL: set("date time timestamp"), + support: set("ODBCdotTable decimallessFloat zerolessFloat binaryNumber hexNumber doubleQuote nCharCast charsetCast commentHash commentSpaceRequired"), + hooks: { + "@": hookVar, + "`": hookIdentifier, + "\\": hookClient + } + }); + + // the query language used by Apache Cassandra is called CQL, but this mime type + // is called Cassandra to avoid confusion with Contextual Query Language + CodeMirror.defineMIME("text/x-cassandra", { + name: "sql", + client: { }, + keywords: set("use select from using consistency where limit first reversed first and in insert into values using consistency ttl update set delete truncate begin batch apply create keyspace with columnfamily primary key index on drop alter type add any one quorum all local_quorum each_quorum"), + builtin: set("ascii bigint blob boolean counter decimal double float int text timestamp uuid varchar varint"), + atoms: set("false true"), + operatorChars: /^[<>=]/, + dateSQL: { }, + support: set("commentSlashSlash decimallessFloat"), + hooks: { } + }); + + // this is based on Peter Raganitsch's 'plsql' mode + CodeMirror.defineMIME("text/x-plsql", { + name: "sql", + client: set("appinfo arraysize autocommit autoprint autorecovery autotrace blockterminator break btitle cmdsep colsep compatibility compute concat copycommit copytypecheck define describe echo editfile embedded escape exec execute feedback flagger flush heading headsep instance linesize lno loboffset logsource long longchunksize markup native newpage numformat numwidth pagesize pause pno recsep recsepchar release repfooter repheader serveroutput shiftinout show showmode size spool sqlblanklines sqlcase sqlcode sqlcontinue sqlnumber sqlpluscompatibility sqlprefix sqlprompt sqlterminator suffix tab term termout time timing trimout trimspool ttitle underline verify version wrap"), + keywords: set("abort accept access add all alter and any array arraylen as asc assert assign at attributes audit authorization avg base_table begin between binary_integer body boolean by case cast char char_base check close cluster clusters colauth column comment commit compress connect connected constant constraint crash create current currval cursor data_base database date dba deallocate debugoff debugon decimal declare default definition delay delete desc digits dispose distinct do drop else elseif elsif enable end entry escape exception exception_init exchange exclusive exists exit external fast fetch file for force form from function generic goto grant group having identified if immediate in increment index indexes indicator initial initrans insert interface intersect into is key level library like limited local lock log logging long loop master maxextents maxtrans member minextents minus mislabel mode modify multiset new next no noaudit nocompress nologging noparallel not nowait number_base object of off offline on online only open option or order out package parallel partition pctfree pctincrease pctused pls_integer positive positiven pragma primary prior private privileges procedure public raise range raw read rebuild record ref references refresh release rename replace resource restrict return returning returns reverse revoke rollback row rowid rowlabel rownum rows run savepoint schema segment select separate session set share snapshot some space split sql start statement storage subtype successful synonym tabauth table tables tablespace task terminate then to trigger truncate type union unique unlimited unrecoverable unusable update use using validate value values variable view views when whenever where while with work"), + builtin: set("abs acos add_months ascii asin atan atan2 average bfile bfilename bigserial bit blob ceil character chartorowid chr clob concat convert cos cosh count dec decode deref dual dump dup_val_on_index empty error exp false float floor found glb greatest hextoraw initcap instr instrb int integer isopen last_day least lenght lenghtb ln lower lpad ltrim lub make_ref max min mlslabel mod months_between natural naturaln nchar nclob new_time next_day nextval nls_charset_decl_len nls_charset_id nls_charset_name nls_initcap nls_lower nls_sort nls_upper nlssort no_data_found notfound null number numeric nvarchar2 nvl others power rawtohex real reftohex round rowcount rowidtochar rowtype rpad rtrim serial sign signtype sin sinh smallint soundex sqlcode sqlerrm sqrt stddev string substr substrb sum sysdate tan tanh to_char text to_date to_label to_multi_byte to_number to_single_byte translate true trunc uid unlogged upper user userenv varchar varchar2 variance varying vsize xml"), + operatorChars: /^[*+\-%<>!=~]/, + dateSQL: set("date time timestamp"), + support: set("doubleQuote nCharCast zerolessFloat binaryNumber hexNumber") + }); + + // Created to support specific hive keywords + CodeMirror.defineMIME("text/x-hive", { + name: "sql", + keywords: set("select alter $elem$ $key$ $value$ add after all analyze and archive as asc before between binary both bucket buckets by cascade case cast change cluster clustered clusterstatus collection column columns comment compute concatenate continue create cross cursor data database databases dbproperties deferred delete delimited desc describe directory disable distinct distribute drop else enable end escaped exclusive exists explain export extended external false fetch fields fileformat first format formatted from full function functions grant group having hold_ddltime idxproperties if import in index indexes inpath inputdriver inputformat insert intersect into is items join keys lateral left like limit lines load local location lock locks mapjoin materialized minus msck no_drop nocompress not of offline on option or order out outer outputdriver outputformat overwrite partition partitioned partitions percent plus preserve procedure purge range rcfile read readonly reads rebuild recordreader recordwriter recover reduce regexp rename repair replace restrict revoke right rlike row schema schemas semi sequencefile serde serdeproperties set shared show show_database sort sorted ssl statistics stored streamtable table tables tablesample tblproperties temporary terminated textfile then tmp to touch transform trigger true unarchive undo union uniquejoin unlock update use using utc utc_tmestamp view when where while with"), + builtin: set("bool boolean long timestamp tinyint smallint bigint int float double date datetime unsigned string array struct map uniontype"), + atoms: set("false true null unknown"), + operatorChars: /^[*+\-%<>!=]/, + dateSQL: set("date timestamp"), + support: set("ODBCdotTable doubleQuote binaryNumber hexNumber") + }); +}()); + +}); + +/* + How Properties of Mime Types are used by SQL Mode + ================================================= + + keywords: + A list of keywords you want to be highlighted. + builtin: + A list of builtin types you want to be highlighted (if you want types to be of class "builtin" instead of "keyword"). + operatorChars: + All characters that must be handled as operators. + client: + Commands parsed and executed by the client (not the server). + support: + A list of supported syntaxes which are not common, but are supported by more than 1 DBMS. + * ODBCdotTable: .tableName + * zerolessFloat: .1 + * doubleQuote + * nCharCast: N'string' + * charsetCast: _utf8'string' + * commentHash: use # char for comments + * commentSlashSlash: use // for comments + * commentSpaceRequired: require a space after -- for comments + atoms: + Keywords that must be highlighted as atoms,. Some DBMS's support more atoms than others: + UNKNOWN, INFINITY, UNDERFLOW, NaN... + dateSQL: + Used for date/time SQL standard syntax, because not all DBMS's support same temporal types. +*/ diff --git a/static/js/mdeditor/lib/codemirror/mode/stex/index.html b/static/js/mdeditor/lib/codemirror/mode/stex/index.html new file mode 100644 index 00000000..14679da4 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/stex/index.html @@ -0,0 +1,110 @@ + + +CodeMirror: sTeX mode + + + + + + + + + +
+

sTeX mode

+
+ + +

MIME types defined: text/x-stex.

+ +

Parsing/Highlighting Tests: normal, verbose.

+ +
diff --git a/static/js/mdeditor/lib/codemirror/mode/stex/stex.js b/static/js/mdeditor/lib/codemirror/mode/stex/stex.js new file mode 100644 index 00000000..835ed46d --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/stex/stex.js @@ -0,0 +1,251 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +/* + * Author: Constantin Jucovschi (c.jucovschi@jacobs-university.de) + * Licence: MIT + */ + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineMode("stex", function() { + "use strict"; + + function pushCommand(state, command) { + state.cmdState.push(command); + } + + function peekCommand(state) { + if (state.cmdState.length > 0) { + return state.cmdState[state.cmdState.length - 1]; + } else { + return null; + } + } + + function popCommand(state) { + var plug = state.cmdState.pop(); + if (plug) { + plug.closeBracket(); + } + } + + // returns the non-default plugin closest to the end of the list + function getMostPowerful(state) { + var context = state.cmdState; + for (var i = context.length - 1; i >= 0; i--) { + var plug = context[i]; + if (plug.name == "DEFAULT") { + continue; + } + return plug; + } + return { styleIdentifier: function() { return null; } }; + } + + function addPluginPattern(pluginName, cmdStyle, styles) { + return function () { + this.name = pluginName; + this.bracketNo = 0; + this.style = cmdStyle; + this.styles = styles; + this.argument = null; // \begin and \end have arguments that follow. These are stored in the plugin + + this.styleIdentifier = function() { + return this.styles[this.bracketNo - 1] || null; + }; + this.openBracket = function() { + this.bracketNo++; + return "bracket"; + }; + this.closeBracket = function() {}; + }; + } + + var plugins = {}; + + plugins["importmodule"] = addPluginPattern("importmodule", "tag", ["string", "builtin"]); + plugins["documentclass"] = addPluginPattern("documentclass", "tag", ["", "atom"]); + plugins["usepackage"] = addPluginPattern("usepackage", "tag", ["atom"]); + plugins["begin"] = addPluginPattern("begin", "tag", ["atom"]); + plugins["end"] = addPluginPattern("end", "tag", ["atom"]); + + plugins["DEFAULT"] = function () { + this.name = "DEFAULT"; + this.style = "tag"; + + this.styleIdentifier = this.openBracket = this.closeBracket = function() {}; + }; + + function setState(state, f) { + state.f = f; + } + + // called when in a normal (no environment) context + function normal(source, state) { + var plug; + // Do we look like '\command' ? If so, attempt to apply the plugin 'command' + if (source.match(/^\\[a-zA-Z@]+/)) { + var cmdName = source.current().slice(1); + plug = plugins[cmdName] || plugins["DEFAULT"]; + plug = new plug(); + pushCommand(state, plug); + setState(state, beginParams); + return plug.style; + } + + // escape characters + if (source.match(/^\\[$&%#{}_]/)) { + return "tag"; + } + + // white space control characters + if (source.match(/^\\[,;!\/\\]/)) { + return "tag"; + } + + // find if we're starting various math modes + if (source.match("\\[")) { + setState(state, function(source, state){ return inMathMode(source, state, "\\]"); }); + return "keyword"; + } + if (source.match("$$")) { + setState(state, function(source, state){ return inMathMode(source, state, "$$"); }); + return "keyword"; + } + if (source.match("$")) { + setState(state, function(source, state){ return inMathMode(source, state, "$"); }); + return "keyword"; + } + + var ch = source.next(); + if (ch == "%") { + source.skipToEnd(); + return "comment"; + } else if (ch == '}' || ch == ']') { + plug = peekCommand(state); + if (plug) { + plug.closeBracket(ch); + setState(state, beginParams); + } else { + return "error"; + } + return "bracket"; + } else if (ch == '{' || ch == '[') { + plug = plugins["DEFAULT"]; + plug = new plug(); + pushCommand(state, plug); + return "bracket"; + } else if (/\d/.test(ch)) { + source.eatWhile(/[\w.%]/); + return "atom"; + } else { + source.eatWhile(/[\w\-_]/); + plug = getMostPowerful(state); + if (plug.name == 'begin') { + plug.argument = source.current(); + } + return plug.styleIdentifier(); + } + } + + function inMathMode(source, state, endModeSeq) { + if (source.eatSpace()) { + return null; + } + if (source.match(endModeSeq)) { + setState(state, normal); + return "keyword"; + } + if (source.match(/^\\[a-zA-Z@]+/)) { + return "tag"; + } + if (source.match(/^[a-zA-Z]+/)) { + return "variable-2"; + } + // escape characters + if (source.match(/^\\[$&%#{}_]/)) { + return "tag"; + } + // white space control characters + if (source.match(/^\\[,;!\/]/)) { + return "tag"; + } + // special math-mode characters + if (source.match(/^[\^_&]/)) { + return "tag"; + } + // non-special characters + if (source.match(/^[+\-<>|=,\/@!*:;'"`~#?]/)) { + return null; + } + if (source.match(/^(\d+\.\d*|\d*\.\d+|\d+)/)) { + return "number"; + } + var ch = source.next(); + if (ch == "{" || ch == "}" || ch == "[" || ch == "]" || ch == "(" || ch == ")") { + return "bracket"; + } + + if (ch == "%") { + source.skipToEnd(); + return "comment"; + } + return "error"; + } + + function beginParams(source, state) { + var ch = source.peek(), lastPlug; + if (ch == '{' || ch == '[') { + lastPlug = peekCommand(state); + lastPlug.openBracket(ch); + source.eat(ch); + setState(state, normal); + return "bracket"; + } + if (/[ \t\r]/.test(ch)) { + source.eat(ch); + return null; + } + setState(state, normal); + popCommand(state); + + return normal(source, state); + } + + return { + startState: function() { + return { + cmdState: [], + f: normal + }; + }, + copyState: function(s) { + return { + cmdState: s.cmdState.slice(), + f: s.f + }; + }, + token: function(stream, state) { + return state.f(stream, state); + }, + blankLine: function(state) { + state.f = normal; + state.cmdState.length = 0; + }, + lineComment: "%" + }; + }); + + CodeMirror.defineMIME("text/x-stex", "stex"); + CodeMirror.defineMIME("text/x-latex", "stex"); + +}); diff --git a/static/js/mdeditor/lib/codemirror/mode/stex/test.js b/static/js/mdeditor/lib/codemirror/mode/stex/test.js new file mode 100644 index 00000000..22f027ec --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/stex/test.js @@ -0,0 +1,123 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function() { + var mode = CodeMirror.getMode({tabSize: 4}, "stex"); + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); } + + MT("word", + "foo"); + + MT("twoWords", + "foo bar"); + + MT("beginEndDocument", + "[tag \\begin][bracket {][atom document][bracket }]", + "[tag \\end][bracket {][atom document][bracket }]"); + + MT("beginEndEquation", + "[tag \\begin][bracket {][atom equation][bracket }]", + " E=mc^2", + "[tag \\end][bracket {][atom equation][bracket }]"); + + MT("beginModule", + "[tag \\begin][bracket {][atom module][bracket }[[]]]"); + + MT("beginModuleId", + "[tag \\begin][bracket {][atom module][bracket }[[]id=bbt-size[bracket ]]]"); + + MT("importModule", + "[tag \\importmodule][bracket [[][string b-b-t][bracket ]]{][builtin b-b-t][bracket }]"); + + MT("importModulePath", + "[tag \\importmodule][bracket [[][tag \\KWARCslides][bracket {][string dmath/en/cardinality][bracket }]]{][builtin card][bracket }]"); + + MT("psForPDF", + "[tag \\PSforPDF][bracket [[][atom 1][bracket ]]{]#1[bracket }]"); + + MT("comment", + "[comment % foo]"); + + MT("tagComment", + "[tag \\item][comment % bar]"); + + MT("commentTag", + " [comment % \\item]"); + + MT("commentLineBreak", + "[comment %]", + "foo"); + + MT("tagErrorCurly", + "[tag \\begin][error }][bracket {]"); + + MT("tagErrorSquare", + "[tag \\item][error ]]][bracket {]"); + + MT("commentCurly", + "[comment % }]"); + + MT("tagHash", + "the [tag \\#] key"); + + MT("tagNumber", + "a [tag \\$][atom 5] stetson"); + + MT("tagPercent", + "[atom 100][tag \\%] beef"); + + MT("tagAmpersand", + "L [tag \\&] N"); + + MT("tagUnderscore", + "foo[tag \\_]bar"); + + MT("tagBracketOpen", + "[tag \\emph][bracket {][tag \\{][bracket }]"); + + MT("tagBracketClose", + "[tag \\emph][bracket {][tag \\}][bracket }]"); + + MT("tagLetterNumber", + "section [tag \\S][atom 1]"); + + MT("textTagNumber", + "para [tag \\P][atom 2]"); + + MT("thinspace", + "x[tag \\,]y"); + + MT("thickspace", + "x[tag \\;]y"); + + MT("negativeThinspace", + "x[tag \\!]y"); + + MT("periodNotSentence", + "J.\\ L.\\ is"); + + MT("periodSentence", + "X[tag \\@]. The"); + + MT("italicCorrection", + "[bracket {][tag \\em] If[tag \\/][bracket }] I"); + + MT("tagBracket", + "[tag \\newcommand][bracket {][tag \\pop][bracket }]"); + + MT("inlineMathTagFollowedByNumber", + "[keyword $][tag \\pi][number 2][keyword $]"); + + MT("inlineMath", + "[keyword $][number 3][variable-2 x][tag ^][number 2.45]-[tag \\sqrt][bracket {][tag \\$\\alpha][bracket }] = [number 2][keyword $] other text"); + + MT("displayMath", + "More [keyword $$]\t[variable-2 S][tag ^][variable-2 n][tag \\sum] [variable-2 i][keyword $$] other text"); + + MT("mathWithComment", + "[keyword $][variable-2 x] [comment % $]", + "[variable-2 y][keyword $] other text"); + + MT("lineBreakArgument", + "[tag \\\\][bracket [[][atom 1cm][bracket ]]]"); +})(); diff --git a/static/js/mdeditor/lib/codemirror/mode/stylus/index.html b/static/js/mdeditor/lib/codemirror/mode/stylus/index.html new file mode 100644 index 00000000..354bf303 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/stylus/index.html @@ -0,0 +1,104 @@ + + +CodeMirror: Stylus mode + + + + + + + + + + + +
+

Stylus mode

+
+
+ + +

MIME types defined: text/x-styl.

+ +
diff --git a/static/js/mdeditor/lib/codemirror/mode/stylus/stylus.js b/static/js/mdeditor/lib/codemirror/mode/stylus/stylus.js new file mode 100644 index 00000000..6f7c7544 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/stylus/stylus.js @@ -0,0 +1,444 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineMode("stylus", function(config) { + + var operatorsRegexp = /^(\?:?|\+[+=]?|-[\-=]?|\*[\*=]?|\/=?|[=!:\?]?=|<=?|>=?|%=?|&&|\|=?|\~|!|\^|\\)/, + delimitersRegexp = /^(?:[()\[\]{},:`=;]|\.\.?\.?)/, + wordOperatorsRegexp = wordRegexp(wordOperators), + commonKeywordsRegexp = wordRegexp(commonKeywords), + commonAtomsRegexp = wordRegexp(commonAtoms), + commonDefRegexp = wordRegexp(commonDef), + vendorPrefixesRegexp = new RegExp(/^\-(moz|ms|o|webkit)-/), + cssValuesWithBracketsRegexp = new RegExp("^(" + cssValuesWithBrackets_.join("|") + ")\\([\\w\-\\#\\,\\.\\%\\s\\(\\)]*\\)"); + + var tokenBase = function(stream, state) { + + if (stream.eatSpace()) return null; + + var ch = stream.peek(); + + // Single line Comment + if (stream.match('//')) { + stream.skipToEnd(); + return "comment"; + } + + // Multiline Comment + if (stream.match('/*')) { + state.tokenizer = multilineComment; + return state.tokenizer(stream, state); + } + + // Strings + if (ch === '"' || ch === "'") { + stream.next(); + state.tokenizer = buildStringTokenizer(ch); + return "string"; + } + + // Def + if (ch === "@") { + stream.next(); + if (stream.match(/extend/)) { + dedent(state); // remove indentation after selectors + } else if (stream.match(/media[\w-\s]*[\w-]/)) { + indent(state); + } else if(stream.eatWhile(/[\w-]/)) { + if(stream.current().match(commonDefRegexp)) { + indent(state); + } + } + return "def"; + } + + // Number + if (stream.match(/^-?[0-9\.]/, false)) { + + // Floats + if (stream.match(/^-?\d*\.\d+(e[\+\-]?\d+)?/i) || stream.match(/^-?\d+\.\d*/)) { + + // Prevent from getting extra . on 1.. + if (stream.peek() == ".") { + stream.backUp(1); + } + // Units + stream.eatWhile(/[a-z%]/i); + return "number"; + } + // Integers + if (stream.match(/^-?[1-9]\d*(e[\+\-]?\d+)?/) || stream.match(/^-?0(?![\dx])/i)) { + // Units + stream.eatWhile(/[a-z%]/i); + return "number"; + } + } + + // Hex color and id selector + if (ch === "#") { + stream.next(); + + // Hex color + if (stream.match(/^[0-9a-f]{6}|[0-9a-f]{3}/i)) { + return "atom"; + } + + // ID selector + if (stream.match(/^[\w-]+/i)) { + indent(state); + return "builtin"; + } + } + + // Vendor prefixes + if (stream.match(vendorPrefixesRegexp)) { + return "meta"; + } + + // Gradients and animation as CSS value + if (stream.match(cssValuesWithBracketsRegexp)) { + return "atom"; + } + + // Mixins / Functions with indentation + if (stream.sol() && stream.match(/^\.?[a-z][\w-]*\(/i)) { + stream.backUp(1); + indent(state); + return "keyword"; + } + + // Mixins / Functions + if (stream.match(/^\.?[a-z][\w-]*\(/i)) { + stream.backUp(1); + return "keyword"; + } + + // +Block mixins + if (stream.match(/^(\+|\-)[a-z][\w-]+\(/i)) { + stream.backUp(1); + indent(state); + return "keyword"; + } + + // url tokens + if (stream.match(/^url/) && stream.peek() === "(") { + state.tokenizer = urlTokens; + if(!stream.peek()) { + state.cursorHalf = 0; + } + return "atom"; + } + + // Class + if (stream.match(/^\.[a-z][\w-]*/i)) { + indent(state); + return "qualifier"; + } + + // & Parent Reference with BEM naming + if (stream.match(/^(_|__|-|--)[a-z0-9-]+/)) { + return "qualifier"; + } + + // Pseudo elements/classes + if (ch == ':' && stream.match(/^::?[\w-]+/)) { + indent(state); + return "variable-3"; + } + + // Conditionals + if (stream.match(wordRegexp(["for", "if", "else", "unless"]))) { + indent(state); + return "keyword"; + } + + // Keywords + if (stream.match(commonKeywordsRegexp)) { + return "keyword"; + } + + // Atoms + if (stream.match(commonAtomsRegexp)) { + return "atom"; + } + + // Variables + if (stream.match(/^\$?[a-z][\w-]+\s?=(\s|[\w-'"\$])/i)) { + stream.backUp(2); + var cssPropertie = stream.current().toLowerCase().match(/[\w-]+/)[0]; + return cssProperties[cssPropertie] === undefined ? "variable-2" : "property"; + } else if (stream.match(/\$[\w-\.]+/i)) { + return "variable-2"; + } else if (stream.match(/\$?[\w-]+\.[\w-]+/i)) { + var cssTypeSelector = stream.current().toLowerCase().match(/[\w]+/)[0]; + if(cssTypeSelectors[cssTypeSelector] === undefined) { + return "variable-2"; + } else stream.backUp(stream.current().length); + } + + // !important + if (ch === "!") { + stream.next(); + return stream.match(/^[\w]+/) ? "keyword": "operator"; + } + + // / Root Reference + if (stream.match(/^\/(:|\.|#|[a-z])/)) { + stream.backUp(1); + return "variable-3"; + } + + // Operators and delimiters + if (stream.match(operatorsRegexp) || stream.match(wordOperatorsRegexp)) { + return "operator"; + } + if (stream.match(delimitersRegexp)) { + return null; + } + + // & Parent Reference + if (ch === "&") { + stream.next(); + return "variable-3"; + } + + // Font family + if (stream.match(/^[A-Z][a-z0-9-]+/)) { + return "string"; + } + + // CSS rule + // NOTE: Some css selectors and property values have the same name + // (embed, menu, pre, progress, sub, table), + // so they will have the same color (.cm-atom). + if (stream.match(/[\w-]*/i)) { + + var word = stream.current().toLowerCase(); + + if(cssProperties[word] !== undefined) { + // CSS property + if(!stream.eol()) + return "property"; + else + return "variable-2"; + + } else if(cssValues[word] !== undefined) { + // CSS value + return "atom"; + + } else if(cssTypeSelectors[word] !== undefined) { + // CSS type selectors + indent(state); + return "tag"; + + } else if(word) { + // By default variable-2 + return "variable-2"; + } + } + + // Handle non-detected items + stream.next(); + return null; + + }; + + var tokenLexer = function(stream, state) { + + if (stream.sol()) { + state.indentCount = 0; + } + + var style = state.tokenizer(stream, state); + var current = stream.current(); + + if (stream.eol() && (current === "}" || current === ",")) { + dedent(state); + } + + if (style !== null) { + var startOfToken = stream.pos - current.length; + var withCurrentIndent = startOfToken + (config.indentUnit * state.indentCount); + + var newScopes = []; + + for (var i = 0; i < state.scopes.length; i++) { + var scope = state.scopes[i]; + + if (scope.offset <= withCurrentIndent) { + newScopes.push(scope); + } + } + + state.scopes = newScopes; + } + + return style; + }; + + return { + startState: function() { + return { + tokenizer: tokenBase, + scopes: [{offset: 0, type: 'styl'}] + }; + }, + + token: function(stream, state) { + var style = tokenLexer(stream, state); + state.lastToken = { style: style, content: stream.current() }; + return style; + }, + + indent: function(state) { + return state.scopes[0].offset; + }, + + lineComment: "//", + fold: "indent" + + }; + + function urlTokens(stream, state) { + var ch = stream.peek(); + + if (ch === ")") { + stream.next(); + state.tokenizer = tokenBase; + return "operator"; + } else if (ch === "(") { + stream.next(); + stream.eatSpace(); + + return "operator"; + } else if (ch === "'" || ch === '"') { + state.tokenizer = buildStringTokenizer(stream.next()); + return "string"; + } else { + state.tokenizer = buildStringTokenizer(")", false); + return "string"; + } + } + + function multilineComment(stream, state) { + if (stream.skipTo("*/")) { + stream.next(); + stream.next(); + state.tokenizer = tokenBase; + } else { + stream.next(); + } + return "comment"; + } + + function buildStringTokenizer(quote, greedy) { + + if(greedy == null) { + greedy = true; + } + + function stringTokenizer(stream, state) { + var nextChar = stream.next(); + var peekChar = stream.peek(); + var previousChar = stream.string.charAt(stream.pos-2); + + var endingString = ((nextChar !== "\\" && peekChar === quote) || + (nextChar === quote && previousChar !== "\\")); + + if (endingString) { + if (nextChar !== quote && greedy) { + stream.next(); + } + state.tokenizer = tokenBase; + return "string"; + } else if (nextChar === "#" && peekChar === "{") { + state.tokenizer = buildInterpolationTokenizer(stringTokenizer); + stream.next(); + return "operator"; + } else { + return "string"; + } + } + + return stringTokenizer; + } + + function buildInterpolationTokenizer(currentTokenizer) { + return function(stream, state) { + if (stream.peek() === "}") { + stream.next(); + state.tokenizer = currentTokenizer; + return "operator"; + } else { + return tokenBase(stream, state); + } + }; + } + + function indent(state) { + if (state.indentCount == 0) { + state.indentCount++; + var lastScopeOffset = state.scopes[0].offset; + var currentOffset = lastScopeOffset + config.indentUnit; + state.scopes.unshift({ offset:currentOffset }); + } + } + + function dedent(state) { + if (state.scopes.length == 1) { return true; } + state.scopes.shift(); + } + + }); + + // https://developer.mozilla.org/en-US/docs/Web/HTML/Element + var cssTypeSelectors_ = ["a","abbr","address","area","article","aside","audio", "b", "base","bdi","bdo","bgsound","blockquote","body","br","button","canvas","caption","cite","code","col","colgroup","data","datalist","dd","del","details","dfn","div","dl","dt","em","embed","fieldset","figcaption","figure","footer","form","h1","h2","h3","h4","h5","h6","head","header","hgroup","hr","html","i","iframe","img","input","ins","kbd","keygen","label","legend","li","link","main","map","mark","marquee","menu","menuitem","meta","meter","nav","nobr","noframes","noscript","object","ol","optgroup","option","output","p","param","pre","progress","q","rp","rt","ruby","s","samp","script","section","select","small","source","span","strong","style","sub","summary","sup","table","tbody","td","textarea","tfoot","th","thead","time","title","tr","track","u","ul","var","video","wbr"]; + // https://github.com/csscomb/csscomb.js/blob/master/config/zen.json + var cssProperties_ = ["position","top","right","bottom","left","z-index","display","visibility","flex-direction","flex-order","flex-pack","float","clear","flex-align","overflow","overflow-x","overflow-y","overflow-scrolling","clip","box-sizing","margin","margin-top","margin-right","margin-bottom","margin-left","padding","padding-top","padding-right","padding-bottom","padding-left","min-width","min-height","max-width","max-height","width","height","outline","outline-width","outline-style","outline-color","outline-offset","border","border-spacing","border-collapse","border-width","border-style","border-color","border-top","border-top-width","border-top-style","border-top-color","border-right","border-right-width","border-right-style","border-right-color","border-bottom","border-bottom-width","border-bottom-style","border-bottom-color","border-left","border-left-width","border-left-style","border-left-color","border-radius","border-top-left-radius","border-top-right-radius","border-bottom-right-radius","border-bottom-left-radius","border-image","border-image-source","border-image-slice","border-image-width","border-image-outset","border-image-repeat","border-top-image","border-right-image","border-bottom-image","border-left-image","border-corner-image","border-top-left-image","border-top-right-image","border-bottom-right-image","border-bottom-left-image","background","filter:progid:DXImageTransform\\.Microsoft\\.AlphaImageLoader","background-color","background-image","background-attachment","background-position","background-position-x","background-position-y","background-clip","background-origin","background-size","background-repeat","box-decoration-break","box-shadow","color","table-layout","caption-side","empty-cells","list-style","list-style-position","list-style-type","list-style-image","quotes","content","counter-increment","counter-reset","writing-mode","vertical-align","text-align","text-align-last","text-decoration","text-emphasis","text-emphasis-position","text-emphasis-style","text-emphasis-color","text-indent","-ms-text-justify","text-justify","text-outline","text-transform","text-wrap","text-overflow","text-overflow-ellipsis","text-overflow-mode","text-size-adjust","text-shadow","white-space","word-spacing","word-wrap","word-break","tab-size","hyphens","letter-spacing","font","font-weight","font-style","font-variant","font-size-adjust","font-stretch","font-size","font-family","src","line-height","opacity","filter:\\\\\\\\'progid:DXImageTransform.Microsoft.Alpha","filter:progid:DXImageTransform.Microsoft.Alpha\\(Opacity","interpolation-mode","filter","resize","cursor","nav-index","nav-up","nav-right","nav-down","nav-left","transition","transition-delay","transition-timing-function","transition-duration","transition-property","transform","transform-origin","animation","animation-name","animation-duration","animation-play-state","animation-timing-function","animation-delay","animation-iteration-count","animation-direction","pointer-events","unicode-bidi","direction","columns","column-span","column-width","column-count","column-fill","column-gap","column-rule","column-rule-width","column-rule-style","column-rule-color","break-before","break-inside","break-after","page-break-before","page-break-inside","page-break-after","orphans","widows","zoom","max-zoom","min-zoom","user-zoom","orientation","text-rendering","speak","animation-fill-mode","backface-visibility","user-drag","user-select","appearance"]; + // https://github.com/codemirror/CodeMirror/blob/master/mode/css/css.js#L501 + var cssValues_ = ["above","absolute","activeborder","activecaption","afar","after-white-space","ahead","alias","all","all-scroll","alternate","always","amharic","amharic-abegede","antialiased","appworkspace","arabic-indic","armenian","asterisks","auto","avoid","avoid-column","avoid-page","avoid-region","background","backwards","baseline","below","bidi-override","binary","bengali","block","block-axis","bold","bolder","border","border-box","both","bottom","break","break-all","break-word","button-bevel","buttonface","buttonhighlight","buttonshadow","buttontext","cambodian","capitalize","caps-lock-indicator","captiontext","caret","cell","center","checkbox","circle","cjk-earthly-branch","cjk-heavenly-stem","cjk-ideographic","clear","clip","close-quote","col-resize","collapse","column","compact","condensed","contain","content","content-box","context-menu","continuous","copy","cover","crop","cross","crosshair","currentcolor","cursive","dashed","decimal","decimal-leading-zero","default","default-button","destination-atop","destination-in","destination-out","destination-over","devanagari","disc","discard","document","dot-dash","dot-dot-dash","dotted","double","down","e-resize","ease","ease-in","ease-in-out","ease-out","element","ellipse","ellipsis","embed","end","ethiopic","ethiopic-abegede","ethiopic-abegede-am-et","ethiopic-abegede-gez","ethiopic-abegede-ti-er","ethiopic-abegede-ti-et","ethiopic-halehame-aa-er","ethiopic-halehame-aa-et","ethiopic-halehame-am-et","ethiopic-halehame-gez","ethiopic-halehame-om-et","ethiopic-halehame-sid-et","ethiopic-halehame-so-et","ethiopic-halehame-ti-er","ethiopic-halehame-ti-et","ethiopic-halehame-tig","ew-resize","expanded","extra-condensed","extra-expanded","fantasy","fast","fill","fixed","flat","footnotes","forwards","from","geometricPrecision","georgian","graytext","groove","gujarati","gurmukhi","hand","hangul","hangul-consonant","hebrew","help","hidden","hide","higher","highlight","highlighttext","hiragana","hiragana-iroha","horizontal","hsl","hsla","icon","ignore","inactiveborder","inactivecaption","inactivecaptiontext","infinite","infobackground","infotext","inherit","initial","inline","inline-axis","inline-block","inline-table","inset","inside","intrinsic","invert","italic","justify","kannada","katakana","katakana-iroha","keep-all","khmer","landscape","lao","large","larger","left","level","lighter","line-through","linear","lines","list-item","listbox","listitem","local","logical","loud","lower","lower-alpha","lower-armenian","lower-greek","lower-hexadecimal","lower-latin","lower-norwegian","lower-roman","lowercase","ltr","malayalam","match","media-controls-background","media-current-time-display","media-fullscreen-button","media-mute-button","media-play-button","media-return-to-realtime-button","media-rewind-button","media-seek-back-button","media-seek-forward-button","media-slider","media-sliderthumb","media-time-remaining-display","media-volume-slider","media-volume-slider-container","media-volume-sliderthumb","medium","menu","menulist","menulist-button","menulist-text","menulist-textfield","menutext","message-box","middle","min-intrinsic","mix","mongolian","monospace","move","multiple","myanmar","n-resize","narrower","ne-resize","nesw-resize","no-close-quote","no-drop","no-open-quote","no-repeat","none","normal","not-allowed","nowrap","ns-resize","nw-resize","nwse-resize","oblique","octal","open-quote","optimizeLegibility","optimizeSpeed","oriya","oromo","outset","outside","outside-shape","overlay","overline","padding","padding-box","painted","page","paused","persian","plus-darker","plus-lighter","pointer","polygon","portrait","pre","pre-line","pre-wrap","preserve-3d","progress","push-button","radio","read-only","read-write","read-write-plaintext-only","rectangle","region","relative","repeat","repeat-x","repeat-y","reset","reverse","rgb","rgba","ridge","right","round","row-resize","rtl","run-in","running","s-resize","sans-serif","scroll","scrollbar","se-resize","searchfield","searchfield-cancel-button","searchfield-decoration","searchfield-results-button","searchfield-results-decoration","semi-condensed","semi-expanded","separate","serif","show","sidama","single","skip-white-space","slide","slider-horizontal","slider-vertical","sliderthumb-horizontal","sliderthumb-vertical","slow","small-caps","small-caption","smaller","solid","somali","source-atop","source-in","source-out","source-over","space","square","square-button","start","static","status-bar","stretch","stroke","sub","subpixel-antialiased","super","sw-resize","table","table-caption","table-cell","table-column","table-column-group","table-footer-group","table-header-group","table-row","table-row-group","telugu","text","text-bottom","text-top","textfield","thai","thick","thin","threeddarkshadow","threedface","threedhighlight","threedlightshadow","threedshadow","tibetan","tigre","tigrinya-er","tigrinya-er-abegede","tigrinya-et","tigrinya-et-abegede","to","top","transparent","ultra-condensed","ultra-expanded","underline","up","upper-alpha","upper-armenian","upper-greek","upper-hexadecimal","upper-latin","upper-norwegian","upper-roman","uppercase","urdu","url","vertical","vertical-text","visible","visibleFill","visiblePainted","visibleStroke","visual","w-resize","wait","wave","wider","window","windowframe","windowtext","x-large","x-small","xor","xx-large","xx-small","bicubic","optimizespeed","grayscale"]; + var cssColorValues_ = ["aliceblue","antiquewhite","aqua","aquamarine","azure","beige","bisque","black","blanchedalmond","blue","blueviolet","brown","burlywood","cadetblue","chartreuse","chocolate","coral","cornflowerblue","cornsilk","crimson","cyan","darkblue","darkcyan","darkgoldenrod","darkgray","darkgreen","darkkhaki","darkmagenta","darkolivegreen","darkorange","darkorchid","darkred","darksalmon","darkseagreen","darkslateblue","darkslategray","darkturquoise","darkviolet","deeppink","deepskyblue","dimgray","dodgerblue","firebrick","floralwhite","forestgreen","fuchsia","gainsboro","ghostwhite","gold","goldenrod","gray","grey","green","greenyellow","honeydew","hotpink","indianred","indigo","ivory","khaki","lavender","lavenderblush","lawngreen","lemonchiffon","lightblue","lightcoral","lightcyan","lightgoldenrodyellow","lightgray","lightgreen","lightpink","lightsalmon","lightseagreen","lightskyblue","lightslategray","lightsteelblue","lightyellow","lime","limegreen","linen","magenta","maroon","mediumaquamarine","mediumblue","mediumorchid","mediumpurple","mediumseagreen","mediumslateblue","mediumspringgreen","mediumturquoise","mediumvioletred","midnightblue","mintcream","mistyrose","moccasin","navajowhite","navy","oldlace","olive","olivedrab","orange","orangered","orchid","palegoldenrod","palegreen","paleturquoise","palevioletred","papayawhip","peachpuff","peru","pink","plum","powderblue","purple","red","rosybrown","royalblue","saddlebrown","salmon","sandybrown","seagreen","seashell","sienna","silver","skyblue","slateblue","slategray","snow","springgreen","steelblue","tan","teal","thistle","tomato","turquoise","violet","wheat","white","whitesmoke","yellow","yellowgreen"]; + var cssValuesWithBrackets_ = ["gradient","linear-gradient","radial-gradient","repeating-linear-gradient","repeating-radial-gradient","cubic-bezier","translateX","translateY","translate3d","rotate3d","scale","scale3d","perspective","skewX"]; + + var wordOperators = ["in", "and", "or", "not", "is a", "is", "isnt", "defined", "if unless"], + commonKeywords = ["for", "if", "else", "unless", "return"], + commonAtoms = ["null", "true", "false", "href", "title", "type", "not-allowed", "readonly", "disabled"], + commonDef = ["@font-face", "@keyframes", "@media", "@viewport", "@page", "@host", "@supports", "@block", "@css"], + cssTypeSelectors = keySet(cssTypeSelectors_), + cssProperties = keySet(cssProperties_), + cssValues = keySet(cssValues_.concat(cssColorValues_)), + hintWords = wordOperators.concat(commonKeywords, + commonAtoms, + commonDef, + cssTypeSelectors_, + cssProperties_, + cssValues_, + cssValuesWithBrackets_, + cssColorValues_); + + function wordRegexp(words) { + return new RegExp("^((" + words.join(")|(") + "))\\b"); + }; + + function keySet(array) { + var keys = {}; + for (var i = 0; i < array.length; ++i) { + keys[array[i]] = true; + } + return keys; + }; + + CodeMirror.registerHelper("hintWords", "stylus", hintWords); + CodeMirror.defineMIME("text/x-styl", "stylus"); + +}); diff --git a/static/js/mdeditor/lib/codemirror/mode/tcl/index.html b/static/js/mdeditor/lib/codemirror/mode/tcl/index.html new file mode 100644 index 00000000..ce4ad342 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/tcl/index.html @@ -0,0 +1,142 @@ + + +CodeMirror: Tcl mode + + + + + + + + + + +
+

Tcl mode

+
+ + +

MIME types defined: text/x-tcl.

+ +
diff --git a/static/js/mdeditor/lib/codemirror/mode/tcl/tcl.js b/static/js/mdeditor/lib/codemirror/mode/tcl/tcl.js new file mode 100644 index 00000000..056accb2 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/tcl/tcl.js @@ -0,0 +1,147 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +//tcl mode by Ford_Lawnmower :: Based on Velocity mode by Steve O'Hara + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("tcl", function() { + function parseWords(str) { + var obj = {}, words = str.split(" "); + for (var i = 0; i < words.length; ++i) obj[words[i]] = true; + return obj; + } + var keywords = parseWords("Tcl safe after append array auto_execok auto_import auto_load " + + "auto_mkindex auto_mkindex_old auto_qualify auto_reset bgerror " + + "binary break catch cd close concat continue dde eof encoding error " + + "eval exec exit expr fblocked fconfigure fcopy file fileevent filename " + + "filename flush for foreach format gets glob global history http if " + + "incr info interp join lappend lindex linsert list llength load lrange " + + "lreplace lsearch lset lsort memory msgcat namespace open package parray " + + "pid pkg::create pkg_mkIndex proc puts pwd re_syntax read regex regexp " + + "registry regsub rename resource return scan seek set socket source split " + + "string subst switch tcl_endOfWord tcl_findLibrary tcl_startOfNextWord " + + "tcl_wordBreakAfter tcl_startOfPreviousWord tcl_wordBreakBefore tcltest " + + "tclvars tell time trace unknown unset update uplevel upvar variable " + + "vwait"); + var functions = parseWords("if elseif else and not or eq ne in ni for foreach while switch"); + var isOperatorChar = /[+\-*&%=<>!?^\/\|]/; + function chain(stream, state, f) { + state.tokenize = f; + return f(stream, state); + } + function tokenBase(stream, state) { + var beforeParams = state.beforeParams; + state.beforeParams = false; + var ch = stream.next(); + if ((ch == '"' || ch == "'") && state.inParams) + return chain(stream, state, tokenString(ch)); + else if (/[\[\]{}\(\),;\.]/.test(ch)) { + if (ch == "(" && beforeParams) state.inParams = true; + else if (ch == ")") state.inParams = false; + return null; + } + else if (/\d/.test(ch)) { + stream.eatWhile(/[\w\.]/); + return "number"; + } + else if (ch == "#" && stream.eat("*")) { + return chain(stream, state, tokenComment); + } + else if (ch == "#" && stream.match(/ *\[ *\[/)) { + return chain(stream, state, tokenUnparsed); + } + else if (ch == "#" && stream.eat("#")) { + stream.skipToEnd(); + return "comment"; + } + else if (ch == '"') { + stream.skipTo(/"/); + return "comment"; + } + else if (ch == "$") { + stream.eatWhile(/[$_a-z0-9A-Z\.{:]/); + stream.eatWhile(/}/); + state.beforeParams = true; + return "builtin"; + } + else if (isOperatorChar.test(ch)) { + stream.eatWhile(isOperatorChar); + return "comment"; + } + else { + stream.eatWhile(/[\w\$_{}\xa1-\uffff]/); + var word = stream.current().toLowerCase(); + if (keywords && keywords.propertyIsEnumerable(word)) + return "keyword"; + if (functions && functions.propertyIsEnumerable(word)) { + state.beforeParams = true; + return "keyword"; + } + return null; + } + } + function tokenString(quote) { + return function(stream, state) { + var escaped = false, next, end = false; + while ((next = stream.next()) != null) { + if (next == quote && !escaped) { + end = true; + break; + } + escaped = !escaped && next == "\\"; + } + if (end) state.tokenize = tokenBase; + return "string"; + }; + } + function tokenComment(stream, state) { + var maybeEnd = false, ch; + while (ch = stream.next()) { + if (ch == "#" && maybeEnd) { + state.tokenize = tokenBase; + break; + } + maybeEnd = (ch == "*"); + } + return "comment"; + } + function tokenUnparsed(stream, state) { + var maybeEnd = 0, ch; + while (ch = stream.next()) { + if (ch == "#" && maybeEnd == 2) { + state.tokenize = tokenBase; + break; + } + if (ch == "]") + maybeEnd++; + else if (ch != " ") + maybeEnd = 0; + } + return "meta"; + } + return { + startState: function() { + return { + tokenize: tokenBase, + beforeParams: false, + inParams: false + }; + }, + token: function(stream, state) { + if (stream.eatSpace()) return null; + return state.tokenize(stream, state); + } + }; +}); +CodeMirror.defineMIME("text/x-tcl", "tcl"); + +}); diff --git a/static/js/mdeditor/lib/codemirror/mode/textile/index.html b/static/js/mdeditor/lib/codemirror/mode/textile/index.html new file mode 100644 index 00000000..42b156b1 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/textile/index.html @@ -0,0 +1,191 @@ + + +CodeMirror: Textile mode + + + + + + + + + +
+

Textile mode

+
+ + +

MIME types defined: text/x-textile.

+ +

Parsing/Highlighting Tests: normal, verbose.

+ +
diff --git a/static/js/mdeditor/lib/codemirror/mode/textile/test.js b/static/js/mdeditor/lib/codemirror/mode/textile/test.js new file mode 100644 index 00000000..49cdaf9c --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/textile/test.js @@ -0,0 +1,417 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function() { + var mode = CodeMirror.getMode({tabSize: 4}, 'textile'); + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); } + + MT('simpleParagraphs', + 'Some text.', + '', + 'Some more text.'); + + /* + * Phrase Modifiers + */ + + MT('em', + 'foo [em _bar_]'); + + MT('emBoogus', + 'code_mirror'); + + MT('strong', + 'foo [strong *bar*]'); + + MT('strongBogus', + '3 * 3 = 9'); + + MT('italic', + 'foo [em __bar__]'); + + MT('italicBogus', + 'code__mirror'); + + MT('bold', + 'foo [strong **bar**]'); + + MT('boldBogus', + '3 ** 3 = 27'); + + MT('simpleLink', + '[link "CodeMirror":http://codemirror.net]'); + + MT('referenceLink', + '[link "CodeMirror":code_mirror]', + 'Normal Text.', + '[link [[code_mirror]]http://codemirror.net]'); + + MT('footCite', + 'foo bar[qualifier [[1]]]'); + + MT('footCiteBogus', + 'foo bar[[1a2]]'); + + MT('special-characters', + 'Registered [tag (r)], ' + + 'Trademark [tag (tm)], and ' + + 'Copyright [tag (c)] 2008'); + + MT('cite', + "A book is [keyword ??The Count of Monte Cristo??] by Dumas."); + + MT('additionAndDeletion', + 'The news networks declared [negative -Al Gore-] ' + + '[positive +George W. Bush+] the winner in Florida.'); + + MT('subAndSup', + 'f(x, n) = log [builtin ~4~] x [builtin ^n^]'); + + MT('spanAndCode', + 'A [quote %span element%] and [atom @code element@]'); + + MT('spanBogus', + 'Percentage 25% is not a span.'); + + MT('citeBogus', + 'Question? is not a citation.'); + + MT('codeBogus', + 'user@example.com'); + + MT('subBogus', + '~username'); + + MT('supBogus', + 'foo ^ bar'); + + MT('deletionBogus', + '3 - 3 = 0'); + + MT('additionBogus', + '3 + 3 = 6'); + + MT('image', + 'An image: [string !http://www.example.com/image.png!]'); + + MT('imageWithAltText', + 'An image: [string !http://www.example.com/image.png (Alt Text)!]'); + + MT('imageWithUrl', + 'An image: [string !http://www.example.com/image.png!:http://www.example.com/]'); + + /* + * Headers + */ + + MT('h1', + '[header&header-1 h1. foo]'); + + MT('h2', + '[header&header-2 h2. foo]'); + + MT('h3', + '[header&header-3 h3. foo]'); + + MT('h4', + '[header&header-4 h4. foo]'); + + MT('h5', + '[header&header-5 h5. foo]'); + + MT('h6', + '[header&header-6 h6. foo]'); + + MT('h7Bogus', + 'h7. foo'); + + MT('multipleHeaders', + '[header&header-1 h1. Heading 1]', + '', + 'Some text.', + '', + '[header&header-2 h2. Heading 2]', + '', + 'More text.'); + + MT('h1inline', + '[header&header-1 h1. foo ][header&header-1&em _bar_][header&header-1 baz]'); + + /* + * Lists + */ + + MT('ul', + 'foo', + 'bar', + '', + '[variable-2 * foo]', + '[variable-2 * bar]'); + + MT('ulNoBlank', + 'foo', + 'bar', + '[variable-2 * foo]', + '[variable-2 * bar]'); + + MT('ol', + 'foo', + 'bar', + '', + '[variable-2 # foo]', + '[variable-2 # bar]'); + + MT('olNoBlank', + 'foo', + 'bar', + '[variable-2 # foo]', + '[variable-2 # bar]'); + + MT('ulFormatting', + '[variable-2 * ][variable-2&em _foo_][variable-2 bar]', + '[variable-2 * ][variable-2&strong *][variable-2&em&strong _foo_]' + + '[variable-2&strong *][variable-2 bar]', + '[variable-2 * ][variable-2&strong *foo*][variable-2 bar]'); + + MT('olFormatting', + '[variable-2 # ][variable-2&em _foo_][variable-2 bar]', + '[variable-2 # ][variable-2&strong *][variable-2&em&strong _foo_]' + + '[variable-2&strong *][variable-2 bar]', + '[variable-2 # ][variable-2&strong *foo*][variable-2 bar]'); + + MT('ulNested', + '[variable-2 * foo]', + '[variable-3 ** bar]', + '[keyword *** bar]', + '[variable-2 **** bar]', + '[variable-3 ** bar]'); + + MT('olNested', + '[variable-2 # foo]', + '[variable-3 ## bar]', + '[keyword ### bar]', + '[variable-2 #### bar]', + '[variable-3 ## bar]'); + + MT('ulNestedWithOl', + '[variable-2 * foo]', + '[variable-3 ## bar]', + '[keyword *** bar]', + '[variable-2 #### bar]', + '[variable-3 ** bar]'); + + MT('olNestedWithUl', + '[variable-2 # foo]', + '[variable-3 ** bar]', + '[keyword ### bar]', + '[variable-2 **** bar]', + '[variable-3 ## bar]'); + + MT('definitionList', + '[number - coffee := Hot ][number&em _and_][number black]', + '', + 'Normal text.'); + + MT('definitionListSpan', + '[number - coffee :=]', + '', + '[number Hot ][number&em _and_][number black =:]', + '', + 'Normal text.'); + + MT('boo', + '[number - dog := woof woof]', + '[number - cat := meow meow]', + '[number - whale :=]', + '[number Whale noises.]', + '', + '[number Also, ][number&em _splashing_][number . =:]'); + + /* + * Attributes + */ + + MT('divWithAttribute', + '[punctuation div][punctuation&attribute (#my-id)][punctuation . foo bar]'); + + MT('divWithAttributeAnd2emRightPadding', + '[punctuation div][punctuation&attribute (#my-id)((][punctuation . foo bar]'); + + MT('divWithClassAndId', + '[punctuation div][punctuation&attribute (my-class#my-id)][punctuation . foo bar]'); + + MT('paragraphWithCss', + 'p[attribute {color:red;}]. foo bar'); + + MT('paragraphNestedStyles', + 'p. [strong *foo ][strong&em _bar_][strong *]'); + + MT('paragraphWithLanguage', + 'p[attribute [[fr]]]. Parlez-vous français?'); + + MT('paragraphLeftAlign', + 'p[attribute <]. Left'); + + MT('paragraphRightAlign', + 'p[attribute >]. Right'); + + MT('paragraphRightAlign', + 'p[attribute =]. Center'); + + MT('paragraphJustified', + 'p[attribute <>]. Justified'); + + MT('paragraphWithLeftIndent1em', + 'p[attribute (]. Left'); + + MT('paragraphWithRightIndent1em', + 'p[attribute )]. Right'); + + MT('paragraphWithLeftIndent2em', + 'p[attribute ((]. Left'); + + MT('paragraphWithRightIndent2em', + 'p[attribute ))]. Right'); + + MT('paragraphWithLeftIndent3emRightIndent2em', + 'p[attribute ((())]. Right'); + + MT('divFormatting', + '[punctuation div. ][punctuation&strong *foo ]' + + '[punctuation&strong&em _bar_][punctuation&strong *]'); + + MT('phraseModifierAttributes', + 'p[attribute (my-class)]. This is a paragraph that has a class and' + + ' this [em _][em&attribute (#special-phrase)][em emphasized phrase_]' + + ' has an id.'); + + MT('linkWithClass', + '[link "(my-class). This is a link with class":http://redcloth.org]'); + + /* + * Layouts + */ + + MT('paragraphLayouts', + 'p. This is one paragraph.', + '', + 'p. This is another.'); + + MT('div', + '[punctuation div. foo bar]'); + + MT('pre', + '[operator pre. Text]'); + + MT('bq.', + '[bracket bq. foo bar]', + '', + 'Normal text.'); + + MT('footnote', + '[variable fn123. foo ][variable&strong *bar*]'); + + /* + * Spanning Layouts + */ + + MT('bq..ThenParagraph', + '[bracket bq.. foo bar]', + '', + '[bracket More quote.]', + 'p. Normal Text'); + + MT('bq..ThenH1', + '[bracket bq.. foo bar]', + '', + '[bracket More quote.]', + '[header&header-1 h1. Header Text]'); + + MT('bc..ThenParagraph', + '[atom bc.. # Some ruby code]', + '[atom obj = {foo: :bar}]', + '[atom puts obj]', + '', + '[atom obj[[:love]] = "*love*"]', + '[atom puts obj.love.upcase]', + '', + 'p. Normal text.'); + + MT('fn1..ThenParagraph', + '[variable fn1.. foo bar]', + '', + '[variable More.]', + 'p. Normal Text'); + + MT('pre..ThenParagraph', + '[operator pre.. foo bar]', + '', + '[operator More.]', + 'p. Normal Text'); + + /* + * Tables + */ + + MT('table', + '[variable-3&operator |_. name |_. age|]', + '[variable-3 |][variable-3&strong *Walter*][variable-3 | 5 |]', + '[variable-3 |Florence| 6 |]', + '', + 'p. Normal text.'); + + MT('tableWithAttributes', + '[variable-3&operator |_. name |_. age|]', + '[variable-3 |][variable-3&attribute /2.][variable-3 Jim |]', + '[variable-3 |][variable-3&attribute \\2{color: red}.][variable-3 Sam |]'); + + /* + * HTML + */ + + MT('html', + '[comment
]', + '[comment
]', + '', + '[header&header-1 h1. Welcome]', + '', + '[variable-2 * Item one]', + '[variable-2 * Item two]', + '', + '[comment Example]', + '', + '[comment
]', + '[comment
]'); + + MT('inlineHtml', + 'I can use HTML directly in my [comment Textile].'); + + /* + * No-Textile + */ + + MT('notextile', + '[string-2 notextile. *No* formatting]'); + + MT('notextileInline', + 'Use [string-2 ==*asterisks*==] for [strong *strong*] text.'); + + MT('notextileWithPre', + '[operator pre. *No* formatting]'); + + MT('notextileWithSpanningPre', + '[operator pre.. *No* formatting]', + '', + '[operator *No* formatting]'); + + /* Only toggling phrases between non-word chars. */ + + MT('phrase-in-word', + 'foo_bar_baz'); + + MT('phrase-non-word', + '[negative -x-] aaa-bbb ccc-ddd [negative -eee-] fff [negative -ggg-]'); + + MT('phrase-lone-dash', + 'foo - bar - baz'); +})(); diff --git a/static/js/mdeditor/lib/codemirror/mode/textile/textile.js b/static/js/mdeditor/lib/codemirror/mode/textile/textile.js new file mode 100644 index 00000000..a6f75765 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/textile/textile.js @@ -0,0 +1,469 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") { // CommonJS + mod(require("../../lib/codemirror")); + } else if (typeof define == "function" && define.amd) { // AMD + define(["../../lib/codemirror"], mod); + } else { // Plain browser env + mod(CodeMirror); + } +})(function(CodeMirror) { + "use strict"; + + var TOKEN_STYLES = { + addition: "positive", + attributes: "attribute", + bold: "strong", + cite: "keyword", + code: "atom", + definitionList: "number", + deletion: "negative", + div: "punctuation", + em: "em", + footnote: "variable", + footCite: "qualifier", + header: "header", + html: "comment", + image: "string", + italic: "em", + link: "link", + linkDefinition: "link", + list1: "variable-2", + list2: "variable-3", + list3: "keyword", + notextile: "string-2", + pre: "operator", + p: "property", + quote: "bracket", + span: "quote", + specialChar: "tag", + strong: "strong", + sub: "builtin", + sup: "builtin", + table: "variable-3", + tableHeading: "operator" + }; + + function startNewLine(stream, state) { + state.mode = Modes.newLayout; + state.tableHeading = false; + + if (state.layoutType === "definitionList" && state.spanningLayout && + stream.match(RE("definitionListEnd"), false)) + state.spanningLayout = false; + } + + function handlePhraseModifier(stream, state, ch) { + if (ch === "_") { + if (stream.eat("_")) + return togglePhraseModifier(stream, state, "italic", /__/, 2); + else + return togglePhraseModifier(stream, state, "em", /_/, 1); + } + + if (ch === "*") { + if (stream.eat("*")) { + return togglePhraseModifier(stream, state, "bold", /\*\*/, 2); + } + return togglePhraseModifier(stream, state, "strong", /\*/, 1); + } + + if (ch === "[") { + if (stream.match(/\d+\]/)) state.footCite = true; + return tokenStyles(state); + } + + if (ch === "(") { + var spec = stream.match(/^(r|tm|c)\)/); + if (spec) + return tokenStylesWith(state, TOKEN_STYLES.specialChar); + } + + if (ch === "<" && stream.match(/(\w+)[^>]+>[^<]+<\/\1>/)) + return tokenStylesWith(state, TOKEN_STYLES.html); + + if (ch === "?" && stream.eat("?")) + return togglePhraseModifier(stream, state, "cite", /\?\?/, 2); + + if (ch === "=" && stream.eat("=")) + return togglePhraseModifier(stream, state, "notextile", /==/, 2); + + if (ch === "-" && !stream.eat("-")) + return togglePhraseModifier(stream, state, "deletion", /-/, 1); + + if (ch === "+") + return togglePhraseModifier(stream, state, "addition", /\+/, 1); + + if (ch === "~") + return togglePhraseModifier(stream, state, "sub", /~/, 1); + + if (ch === "^") + return togglePhraseModifier(stream, state, "sup", /\^/, 1); + + if (ch === "%") + return togglePhraseModifier(stream, state, "span", /%/, 1); + + if (ch === "@") + return togglePhraseModifier(stream, state, "code", /@/, 1); + + if (ch === "!") { + var type = togglePhraseModifier(stream, state, "image", /(?:\([^\)]+\))?!/, 1); + stream.match(/^:\S+/); // optional Url portion + return type; + } + return tokenStyles(state); + } + + function togglePhraseModifier(stream, state, phraseModifier, closeRE, openSize) { + var charBefore = stream.pos > openSize ? stream.string.charAt(stream.pos - openSize - 1) : null; + var charAfter = stream.peek(); + if (state[phraseModifier]) { + if ((!charAfter || /\W/.test(charAfter)) && charBefore && /\S/.test(charBefore)) { + var type = tokenStyles(state); + state[phraseModifier] = false; + return type; + } + } else if ((!charBefore || /\W/.test(charBefore)) && charAfter && /\S/.test(charAfter) && + stream.match(new RegExp("^.*\\S" + closeRE.source + "(?:\\W|$)"), false)) { + state[phraseModifier] = true; + state.mode = Modes.attributes; + } + return tokenStyles(state); + }; + + function tokenStyles(state) { + var disabled = textileDisabled(state); + if (disabled) return disabled; + + var styles = []; + if (state.layoutType) styles.push(TOKEN_STYLES[state.layoutType]); + + styles = styles.concat(activeStyles( + state, "addition", "bold", "cite", "code", "deletion", "em", "footCite", + "image", "italic", "link", "span", "strong", "sub", "sup", "table", "tableHeading")); + + if (state.layoutType === "header") + styles.push(TOKEN_STYLES.header + "-" + state.header); + + return styles.length ? styles.join(" ") : null; + } + + function textileDisabled(state) { + var type = state.layoutType; + + switch(type) { + case "notextile": + case "code": + case "pre": + return TOKEN_STYLES[type]; + default: + if (state.notextile) + return TOKEN_STYLES.notextile + (type ? (" " + TOKEN_STYLES[type]) : ""); + return null; + } + } + + function tokenStylesWith(state, extraStyles) { + var disabled = textileDisabled(state); + if (disabled) return disabled; + + var type = tokenStyles(state); + if (extraStyles) + return type ? (type + " " + extraStyles) : extraStyles; + else + return type; + } + + function activeStyles(state) { + var styles = []; + for (var i = 1; i < arguments.length; ++i) { + if (state[arguments[i]]) + styles.push(TOKEN_STYLES[arguments[i]]); + } + return styles; + } + + function blankLine(state) { + var spanningLayout = state.spanningLayout, type = state.layoutType; + + for (var key in state) if (state.hasOwnProperty(key)) + delete state[key]; + + state.mode = Modes.newLayout; + if (spanningLayout) { + state.layoutType = type; + state.spanningLayout = true; + } + } + + var REs = { + cache: {}, + single: { + bc: "bc", + bq: "bq", + definitionList: /- [^(?::=)]+:=+/, + definitionListEnd: /.*=:\s*$/, + div: "div", + drawTable: /\|.*\|/, + foot: /fn\d+/, + header: /h[1-6]/, + html: /\s*<(?:\/)?(\w+)(?:[^>]+)?>(?:[^<]+<\/\1>)?/, + link: /[^"]+":\S/, + linkDefinition: /\[[^\s\]]+\]\S+/, + list: /(?:#+|\*+)/, + notextile: "notextile", + para: "p", + pre: "pre", + table: "table", + tableCellAttributes: /[\/\\]\d+/, + tableHeading: /\|_\./, + tableText: /[^"_\*\[\(\?\+~\^%@|-]+/, + text: /[^!"_=\*\[\(<\?\+~\^%@-]+/ + }, + attributes: { + align: /(?:<>|<|>|=)/, + selector: /\([^\(][^\)]+\)/, + lang: /\[[^\[\]]+\]/, + pad: /(?:\(+|\)+){1,2}/, + css: /\{[^\}]+\}/ + }, + createRe: function(name) { + switch (name) { + case "drawTable": + return REs.makeRe("^", REs.single.drawTable, "$"); + case "html": + return REs.makeRe("^", REs.single.html, "(?:", REs.single.html, ")*", "$"); + case "linkDefinition": + return REs.makeRe("^", REs.single.linkDefinition, "$"); + case "listLayout": + return REs.makeRe("^", REs.single.list, RE("allAttributes"), "*\\s+"); + case "tableCellAttributes": + return REs.makeRe("^", REs.choiceRe(REs.single.tableCellAttributes, + RE("allAttributes")), "+\\."); + case "type": + return REs.makeRe("^", RE("allTypes")); + case "typeLayout": + return REs.makeRe("^", RE("allTypes"), RE("allAttributes"), + "*\\.\\.?", "(\\s+|$)"); + case "attributes": + return REs.makeRe("^", RE("allAttributes"), "+"); + + case "allTypes": + return REs.choiceRe(REs.single.div, REs.single.foot, + REs.single.header, REs.single.bc, REs.single.bq, + REs.single.notextile, REs.single.pre, REs.single.table, + REs.single.para); + + case "allAttributes": + return REs.choiceRe(REs.attributes.selector, REs.attributes.css, + REs.attributes.lang, REs.attributes.align, REs.attributes.pad); + + default: + return REs.makeRe("^", REs.single[name]); + } + }, + makeRe: function() { + var pattern = ""; + for (var i = 0; i < arguments.length; ++i) { + var arg = arguments[i]; + pattern += (typeof arg === "string") ? arg : arg.source; + } + return new RegExp(pattern); + }, + choiceRe: function() { + var parts = [arguments[0]]; + for (var i = 1; i < arguments.length; ++i) { + parts[i * 2 - 1] = "|"; + parts[i * 2] = arguments[i]; + } + + parts.unshift("(?:"); + parts.push(")"); + return REs.makeRe.apply(null, parts); + } + }; + + function RE(name) { + return (REs.cache[name] || (REs.cache[name] = REs.createRe(name))); + } + + var Modes = { + newLayout: function(stream, state) { + if (stream.match(RE("typeLayout"), false)) { + state.spanningLayout = false; + return (state.mode = Modes.blockType)(stream, state); + } + var newMode; + if (!textileDisabled(state)) { + if (stream.match(RE("listLayout"), false)) + newMode = Modes.list; + else if (stream.match(RE("drawTable"), false)) + newMode = Modes.table; + else if (stream.match(RE("linkDefinition"), false)) + newMode = Modes.linkDefinition; + else if (stream.match(RE("definitionList"))) + newMode = Modes.definitionList; + else if (stream.match(RE("html"), false)) + newMode = Modes.html; + } + return (state.mode = (newMode || Modes.text))(stream, state); + }, + + blockType: function(stream, state) { + var match, type; + state.layoutType = null; + + if (match = stream.match(RE("type"))) + type = match[0]; + else + return (state.mode = Modes.text)(stream, state); + + if (match = type.match(RE("header"))) { + state.layoutType = "header"; + state.header = parseInt(match[0][1]); + } else if (type.match(RE("bq"))) { + state.layoutType = "quote"; + } else if (type.match(RE("bc"))) { + state.layoutType = "code"; + } else if (type.match(RE("foot"))) { + state.layoutType = "footnote"; + } else if (type.match(RE("notextile"))) { + state.layoutType = "notextile"; + } else if (type.match(RE("pre"))) { + state.layoutType = "pre"; + } else if (type.match(RE("div"))) { + state.layoutType = "div"; + } else if (type.match(RE("table"))) { + state.layoutType = "table"; + } + + state.mode = Modes.attributes; + return tokenStyles(state); + }, + + text: function(stream, state) { + if (stream.match(RE("text"))) return tokenStyles(state); + + var ch = stream.next(); + if (ch === '"') + return (state.mode = Modes.link)(stream, state); + return handlePhraseModifier(stream, state, ch); + }, + + attributes: function(stream, state) { + state.mode = Modes.layoutLength; + + if (stream.match(RE("attributes"))) + return tokenStylesWith(state, TOKEN_STYLES.attributes); + else + return tokenStyles(state); + }, + + layoutLength: function(stream, state) { + if (stream.eat(".") && stream.eat(".")) + state.spanningLayout = true; + + state.mode = Modes.text; + return tokenStyles(state); + }, + + list: function(stream, state) { + var match = stream.match(RE("list")); + state.listDepth = match[0].length; + var listMod = (state.listDepth - 1) % 3; + if (!listMod) + state.layoutType = "list1"; + else if (listMod === 1) + state.layoutType = "list2"; + else + state.layoutType = "list3"; + + state.mode = Modes.attributes; + return tokenStyles(state); + }, + + link: function(stream, state) { + state.mode = Modes.text; + if (stream.match(RE("link"))) { + stream.match(/\S+/); + return tokenStylesWith(state, TOKEN_STYLES.link); + } + return tokenStyles(state); + }, + + linkDefinition: function(stream, state) { + stream.skipToEnd(); + return tokenStylesWith(state, TOKEN_STYLES.linkDefinition); + }, + + definitionList: function(stream, state) { + stream.match(RE("definitionList")); + + state.layoutType = "definitionList"; + + if (stream.match(/\s*$/)) + state.spanningLayout = true; + else + state.mode = Modes.attributes; + + return tokenStyles(state); + }, + + html: function(stream, state) { + stream.skipToEnd(); + return tokenStylesWith(state, TOKEN_STYLES.html); + }, + + table: function(stream, state) { + state.layoutType = "table"; + return (state.mode = Modes.tableCell)(stream, state); + }, + + tableCell: function(stream, state) { + if (stream.match(RE("tableHeading"))) + state.tableHeading = true; + else + stream.eat("|"); + + state.mode = Modes.tableCellAttributes; + return tokenStyles(state); + }, + + tableCellAttributes: function(stream, state) { + state.mode = Modes.tableText; + + if (stream.match(RE("tableCellAttributes"))) + return tokenStylesWith(state, TOKEN_STYLES.attributes); + else + return tokenStyles(state); + }, + + tableText: function(stream, state) { + if (stream.match(RE("tableText"))) + return tokenStyles(state); + + if (stream.peek() === "|") { // end of cell + state.mode = Modes.tableCell; + return tokenStyles(state); + } + return handlePhraseModifier(stream, state, stream.next()); + } + }; + + CodeMirror.defineMode("textile", function() { + return { + startState: function() { + return { mode: Modes.newLayout }; + }, + token: function(stream, state) { + if (stream.sol()) startNewLine(stream, state); + return state.mode(stream, state); + }, + blankLine: blankLine + }; + }); + + CodeMirror.defineMIME("text/x-textile", "textile"); +}); diff --git a/static/js/mdeditor/lib/codemirror/mode/tiddlywiki/index.html b/static/js/mdeditor/lib/codemirror/mode/tiddlywiki/index.html new file mode 100644 index 00000000..77dd0457 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/tiddlywiki/index.html @@ -0,0 +1,154 @@ + + +CodeMirror: TiddlyWiki mode + + + + + + + + + + + +
+

TiddlyWiki mode

+ + +
+ + + +

TiddlyWiki mode supports a single configuration.

+ +

MIME types defined: text/x-tiddlywiki.

+
diff --git a/static/js/mdeditor/lib/codemirror/mode/tiddlywiki/tiddlywiki.css b/static/js/mdeditor/lib/codemirror/mode/tiddlywiki/tiddlywiki.css new file mode 100644 index 00000000..9a69b639 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/tiddlywiki/tiddlywiki.css @@ -0,0 +1,14 @@ +span.cm-underlined { + text-decoration: underline; +} +span.cm-strikethrough { + text-decoration: line-through; +} +span.cm-brace { + color: #170; + font-weight: bold; +} +span.cm-table { + color: blue; + font-weight: bold; +} diff --git a/static/js/mdeditor/lib/codemirror/mode/tiddlywiki/tiddlywiki.js b/static/js/mdeditor/lib/codemirror/mode/tiddlywiki/tiddlywiki.js new file mode 100644 index 00000000..88c9768a --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/tiddlywiki/tiddlywiki.js @@ -0,0 +1,369 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +/*** + |''Name''|tiddlywiki.js| + |''Description''|Enables TiddlyWikiy syntax highlighting using CodeMirror| + |''Author''|PMario| + |''Version''|0.1.7| + |''Status''|''stable''| + |''Source''|[[GitHub|https://github.com/pmario/CodeMirror2/blob/tw-syntax/mode/tiddlywiki]]| + |''Documentation''|http://codemirror.tiddlyspace.com/| + |''License''|[[MIT License|http://www.opensource.org/licenses/mit-license.php]]| + |''CoreVersion''|2.5.0| + |''Requires''|codemirror.js| + |''Keywords''|syntax highlighting color code mirror codemirror| + ! Info + CoreVersion parameter is needed for TiddlyWiki only! +***/ +//{{{ + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("tiddlywiki", function () { + // Tokenizer + var textwords = {}; + + var keywords = function () { + function kw(type) { + return { type: type, style: "macro"}; + } + return { + "allTags": kw('allTags'), "closeAll": kw('closeAll'), "list": kw('list'), + "newJournal": kw('newJournal'), "newTiddler": kw('newTiddler'), + "permaview": kw('permaview'), "saveChanges": kw('saveChanges'), + "search": kw('search'), "slider": kw('slider'), "tabs": kw('tabs'), + "tag": kw('tag'), "tagging": kw('tagging'), "tags": kw('tags'), + "tiddler": kw('tiddler'), "timeline": kw('timeline'), + "today": kw('today'), "version": kw('version'), "option": kw('option'), + + "with": kw('with'), + "filter": kw('filter') + }; + }(); + + var isSpaceName = /[\w_\-]/i, + reHR = /^\-\-\-\-+$/, //
+ reWikiCommentStart = /^\/\*\*\*$/, // /*** + reWikiCommentStop = /^\*\*\*\/$/, // ***/ + reBlockQuote = /^<<<$/, + + reJsCodeStart = /^\/\/\{\{\{$/, // //{{{ js block start + reJsCodeStop = /^\/\/\}\}\}$/, // //}}} js stop + reXmlCodeStart = /^$/, // xml block start + reXmlCodeStop = /^$/, // xml stop + + reCodeBlockStart = /^\{\{\{$/, // {{{ TW text div block start + reCodeBlockStop = /^\}\}\}$/, // }}} TW text stop + + reUntilCodeStop = /.*?\}\}\}/; + + function chain(stream, state, f) { + state.tokenize = f; + return f(stream, state); + } + + // Used as scratch variables to communicate multiple values without + // consing up tons of objects. + var type, content; + + function ret(tp, style, cont) { + type = tp; + content = cont; + return style; + } + + function jsTokenBase(stream, state) { + var sol = stream.sol(), ch; + + state.block = false; // indicates the start of a code block. + + ch = stream.peek(); // don't eat, to make matching simpler + + // check start of blocks + if (sol && /[<\/\*{}\-]/.test(ch)) { + if (stream.match(reCodeBlockStart)) { + state.block = true; + return chain(stream, state, twTokenCode); + } + if (stream.match(reBlockQuote)) { + return ret('quote', 'quote'); + } + if (stream.match(reWikiCommentStart) || stream.match(reWikiCommentStop)) { + return ret('code', 'comment'); + } + if (stream.match(reJsCodeStart) || stream.match(reJsCodeStop) || stream.match(reXmlCodeStart) || stream.match(reXmlCodeStop)) { + return ret('code', 'comment'); + } + if (stream.match(reHR)) { + return ret('hr', 'hr'); + } + } // sol + ch = stream.next(); + + if (sol && /[\/\*!#;:>|]/.test(ch)) { + if (ch == "!") { // tw header + stream.skipToEnd(); + return ret("header", "header"); + } + if (ch == "*") { // tw list + stream.eatWhile('*'); + return ret("list", "comment"); + } + if (ch == "#") { // tw numbered list + stream.eatWhile('#'); + return ret("list", "comment"); + } + if (ch == ";") { // definition list, term + stream.eatWhile(';'); + return ret("list", "comment"); + } + if (ch == ":") { // definition list, description + stream.eatWhile(':'); + return ret("list", "comment"); + } + if (ch == ">") { // single line quote + stream.eatWhile(">"); + return ret("quote", "quote"); + } + if (ch == '|') { + return ret('table', 'header'); + } + } + + if (ch == '{' && stream.match(/\{\{/)) { + return chain(stream, state, twTokenCode); + } + + // rudimentary html:// file:// link matching. TW knows much more ... + if (/[hf]/i.test(ch)) { + if (/[ti]/i.test(stream.peek()) && stream.match(/\b(ttps?|tp|ile):\/\/[\-A-Z0-9+&@#\/%?=~_|$!:,.;]*[A-Z0-9+&@#\/%=~_|$]/i)) { + return ret("link", "link"); + } + } + // just a little string indicator, don't want to have the whole string covered + if (ch == '"') { + return ret('string', 'string'); + } + if (ch == '~') { // _no_ CamelCase indicator should be bold + return ret('text', 'brace'); + } + if (/[\[\]]/.test(ch)) { // check for [[..]] + if (stream.peek() == ch) { + stream.next(); + return ret('brace', 'brace'); + } + } + if (ch == "@") { // check for space link. TODO fix @@...@@ highlighting + stream.eatWhile(isSpaceName); + return ret("link", "link"); + } + if (/\d/.test(ch)) { // numbers + stream.eatWhile(/\d/); + return ret("number", "number"); + } + if (ch == "/") { // tw invisible comment + if (stream.eat("%")) { + return chain(stream, state, twTokenComment); + } + else if (stream.eat("/")) { // + return chain(stream, state, twTokenEm); + } + } + if (ch == "_") { // tw underline + if (stream.eat("_")) { + return chain(stream, state, twTokenUnderline); + } + } + // strikethrough and mdash handling + if (ch == "-") { + if (stream.eat("-")) { + // if strikethrough looks ugly, change CSS. + if (stream.peek() != ' ') + return chain(stream, state, twTokenStrike); + // mdash + if (stream.peek() == ' ') + return ret('text', 'brace'); + } + } + if (ch == "'") { // tw bold + if (stream.eat("'")) { + return chain(stream, state, twTokenStrong); + } + } + if (ch == "<") { // tw macro + if (stream.eat("<")) { + return chain(stream, state, twTokenMacro); + } + } + else { + return ret(ch); + } + + // core macro handling + stream.eatWhile(/[\w\$_]/); + var word = stream.current(), + known = textwords.propertyIsEnumerable(word) && textwords[word]; + + return known ? ret(known.type, known.style, word) : ret("text", null, word); + + } // jsTokenBase() + + // tw invisible comment + function twTokenComment(stream, state) { + var maybeEnd = false, + ch; + while (ch = stream.next()) { + if (ch == "/" && maybeEnd) { + state.tokenize = jsTokenBase; + break; + } + maybeEnd = (ch == "%"); + } + return ret("comment", "comment"); + } + + // tw strong / bold + function twTokenStrong(stream, state) { + var maybeEnd = false, + ch; + while (ch = stream.next()) { + if (ch == "'" && maybeEnd) { + state.tokenize = jsTokenBase; + break; + } + maybeEnd = (ch == "'"); + } + return ret("text", "strong"); + } + + // tw code + function twTokenCode(stream, state) { + var ch, sb = state.block; + + if (sb && stream.current()) { + return ret("code", "comment"); + } + + if (!sb && stream.match(reUntilCodeStop)) { + state.tokenize = jsTokenBase; + return ret("code", "comment"); + } + + if (sb && stream.sol() && stream.match(reCodeBlockStop)) { + state.tokenize = jsTokenBase; + return ret("code", "comment"); + } + + ch = stream.next(); + return (sb) ? ret("code", "comment") : ret("code", "comment"); + } + + // tw em / italic + function twTokenEm(stream, state) { + var maybeEnd = false, + ch; + while (ch = stream.next()) { + if (ch == "/" && maybeEnd) { + state.tokenize = jsTokenBase; + break; + } + maybeEnd = (ch == "/"); + } + return ret("text", "em"); + } + + // tw underlined text + function twTokenUnderline(stream, state) { + var maybeEnd = false, + ch; + while (ch = stream.next()) { + if (ch == "_" && maybeEnd) { + state.tokenize = jsTokenBase; + break; + } + maybeEnd = (ch == "_"); + } + return ret("text", "underlined"); + } + + // tw strike through text looks ugly + // change CSS if needed + function twTokenStrike(stream, state) { + var maybeEnd = false, ch; + + while (ch = stream.next()) { + if (ch == "-" && maybeEnd) { + state.tokenize = jsTokenBase; + break; + } + maybeEnd = (ch == "-"); + } + return ret("text", "strikethrough"); + } + + // macro + function twTokenMacro(stream, state) { + var ch, word, known; + + if (stream.current() == '<<') { + return ret('brace', 'macro'); + } + + ch = stream.next(); + if (!ch) { + state.tokenize = jsTokenBase; + return ret(ch); + } + if (ch == ">") { + if (stream.peek() == '>') { + stream.next(); + state.tokenize = jsTokenBase; + return ret("brace", "macro"); + } + } + + stream.eatWhile(/[\w\$_]/); + word = stream.current(); + known = keywords.propertyIsEnumerable(word) && keywords[word]; + + if (known) { + return ret(known.type, known.style, word); + } + else { + return ret("macro", null, word); + } + } + + // Interface + return { + startState: function () { + return { + tokenize: jsTokenBase, + indented: 0, + level: 0 + }; + }, + + token: function (stream, state) { + if (stream.eatSpace()) return null; + var style = state.tokenize(stream, state); + return style; + }, + + electricChars: "" + }; +}); + +CodeMirror.defineMIME("text/x-tiddlywiki", "tiddlywiki"); +}); + +//}}} diff --git a/static/js/mdeditor/lib/codemirror/mode/tiki/index.html b/static/js/mdeditor/lib/codemirror/mode/tiki/index.html new file mode 100644 index 00000000..091c5fb2 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/tiki/index.html @@ -0,0 +1,95 @@ + + +CodeMirror: Tiki wiki mode + + + + + + + + + + +
+

Tiki wiki mode

+ + +
+ + + +
diff --git a/static/js/mdeditor/lib/codemirror/mode/tiki/tiki.css b/static/js/mdeditor/lib/codemirror/mode/tiki/tiki.css new file mode 100644 index 00000000..0dbc3ea0 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/tiki/tiki.css @@ -0,0 +1,26 @@ +.cm-tw-syntaxerror { + color: #FFF; + background-color: #900; +} + +.cm-tw-deleted { + text-decoration: line-through; +} + +.cm-tw-header5 { + font-weight: bold; +} +.cm-tw-listitem:first-child { /*Added first child to fix duplicate padding when highlighting*/ + padding-left: 10px; +} + +.cm-tw-box { + border-top-width: 0px ! important; + border-style: solid; + border-width: 1px; + border-color: inherit; +} + +.cm-tw-underline { + text-decoration: underline; +} \ No newline at end of file diff --git a/static/js/mdeditor/lib/codemirror/mode/tiki/tiki.js b/static/js/mdeditor/lib/codemirror/mode/tiki/tiki.js new file mode 100644 index 00000000..c90aac9e --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/tiki/tiki.js @@ -0,0 +1,323 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode('tiki', function(config) { + function inBlock(style, terminator, returnTokenizer) { + return function(stream, state) { + while (!stream.eol()) { + if (stream.match(terminator)) { + state.tokenize = inText; + break; + } + stream.next(); + } + + if (returnTokenizer) state.tokenize = returnTokenizer; + + return style; + }; + } + + function inLine(style) { + return function(stream, state) { + while(!stream.eol()) { + stream.next(); + } + state.tokenize = inText; + return style; + }; + } + + function inText(stream, state) { + function chain(parser) { + state.tokenize = parser; + return parser(stream, state); + } + + var sol = stream.sol(); + var ch = stream.next(); + + //non start of line + switch (ch) { //switch is generally much faster than if, so it is used here + case "{": //plugin + stream.eat("/"); + stream.eatSpace(); + var tagName = ""; + var c; + while ((c = stream.eat(/[^\s\u00a0=\"\'\/?(}]/))) tagName += c; + state.tokenize = inPlugin; + return "tag"; + break; + case "_": //bold + if (stream.eat("_")) { + return chain(inBlock("strong", "__", inText)); + } + break; + case "'": //italics + if (stream.eat("'")) { + // Italic text + return chain(inBlock("em", "''", inText)); + } + break; + case "(":// Wiki Link + if (stream.eat("(")) { + return chain(inBlock("variable-2", "))", inText)); + } + break; + case "[":// Weblink + return chain(inBlock("variable-3", "]", inText)); + break; + case "|": //table + if (stream.eat("|")) { + return chain(inBlock("comment", "||")); + } + break; + case "-": + if (stream.eat("=")) {//titleBar + return chain(inBlock("header string", "=-", inText)); + } else if (stream.eat("-")) {//deleted + return chain(inBlock("error tw-deleted", "--", inText)); + } + break; + case "=": //underline + if (stream.match("==")) { + return chain(inBlock("tw-underline", "===", inText)); + } + break; + case ":": + if (stream.eat(":")) { + return chain(inBlock("comment", "::")); + } + break; + case "^": //box + return chain(inBlock("tw-box", "^")); + break; + case "~": //np + if (stream.match("np~")) { + return chain(inBlock("meta", "~/np~")); + } + break; + } + + //start of line types + if (sol) { + switch (ch) { + case "!": //header at start of line + if (stream.match('!!!!!')) { + return chain(inLine("header string")); + } else if (stream.match('!!!!')) { + return chain(inLine("header string")); + } else if (stream.match('!!!')) { + return chain(inLine("header string")); + } else if (stream.match('!!')) { + return chain(inLine("header string")); + } else { + return chain(inLine("header string")); + } + break; + case "*": //unordered list line item, or
  • at start of line + case "#": //ordered list line item, or
  • at start of line + case "+": //ordered list line item, or
  • at start of line + return chain(inLine("tw-listitem bracket")); + break; + } + } + + //stream.eatWhile(/[&{]/); was eating up plugins, turned off to act less like html and more like tiki + return null; + } + + var indentUnit = config.indentUnit; + + // Return variables for tokenizers + var pluginName, type; + function inPlugin(stream, state) { + var ch = stream.next(); + var peek = stream.peek(); + + if (ch == "}") { + state.tokenize = inText; + //type = ch == ")" ? "endPlugin" : "selfclosePlugin"; inPlugin + return "tag"; + } else if (ch == "(" || ch == ")") { + return "bracket"; + } else if (ch == "=") { + type = "equals"; + + if (peek == ">") { + ch = stream.next(); + peek = stream.peek(); + } + + //here we detect values directly after equal character with no quotes + if (!/[\'\"]/.test(peek)) { + state.tokenize = inAttributeNoQuote(); + } + //end detect values + + return "operator"; + } else if (/[\'\"]/.test(ch)) { + state.tokenize = inAttribute(ch); + return state.tokenize(stream, state); + } else { + stream.eatWhile(/[^\s\u00a0=\"\'\/?]/); + return "keyword"; + } + } + + function inAttribute(quote) { + return function(stream, state) { + while (!stream.eol()) { + if (stream.next() == quote) { + state.tokenize = inPlugin; + break; + } + } + return "string"; + }; + } + + function inAttributeNoQuote() { + return function(stream, state) { + while (!stream.eol()) { + var ch = stream.next(); + var peek = stream.peek(); + if (ch == " " || ch == "," || /[ )}]/.test(peek)) { + state.tokenize = inPlugin; + break; + } + } + return "string"; +}; + } + +var curState, setStyle; +function pass() { + for (var i = arguments.length - 1; i >= 0; i--) curState.cc.push(arguments[i]); +} + +function cont() { + pass.apply(null, arguments); + return true; +} + +function pushContext(pluginName, startOfLine) { + var noIndent = curState.context && curState.context.noIndent; + curState.context = { + prev: curState.context, + pluginName: pluginName, + indent: curState.indented, + startOfLine: startOfLine, + noIndent: noIndent + }; +} + +function popContext() { + if (curState.context) curState.context = curState.context.prev; +} + +function element(type) { + if (type == "openPlugin") {curState.pluginName = pluginName; return cont(attributes, endplugin(curState.startOfLine));} + else if (type == "closePlugin") { + var err = false; + if (curState.context) { + err = curState.context.pluginName != pluginName; + popContext(); + } else { + err = true; + } + if (err) setStyle = "error"; + return cont(endcloseplugin(err)); + } + else if (type == "string") { + if (!curState.context || curState.context.name != "!cdata") pushContext("!cdata"); + if (curState.tokenize == inText) popContext(); + return cont(); + } + else return cont(); +} + +function endplugin(startOfLine) { + return function(type) { + if ( + type == "selfclosePlugin" || + type == "endPlugin" + ) + return cont(); + if (type == "endPlugin") {pushContext(curState.pluginName, startOfLine); return cont();} + return cont(); + }; +} + +function endcloseplugin(err) { + return function(type) { + if (err) setStyle = "error"; + if (type == "endPlugin") return cont(); + return pass(); + }; +} + +function attributes(type) { + if (type == "keyword") {setStyle = "attribute"; return cont(attributes);} + if (type == "equals") return cont(attvalue, attributes); + return pass(); +} +function attvalue(type) { + if (type == "keyword") {setStyle = "string"; return cont();} + if (type == "string") return cont(attvaluemaybe); + return pass(); +} +function attvaluemaybe(type) { + if (type == "string") return cont(attvaluemaybe); + else return pass(); +} +return { + startState: function() { + return {tokenize: inText, cc: [], indented: 0, startOfLine: true, pluginName: null, context: null}; + }, + token: function(stream, state) { + if (stream.sol()) { + state.startOfLine = true; + state.indented = stream.indentation(); + } + if (stream.eatSpace()) return null; + + setStyle = type = pluginName = null; + var style = state.tokenize(stream, state); + if ((style || type) && style != "comment") { + curState = state; + while (true) { + var comb = state.cc.pop() || element; + if (comb(type || style)) break; + } + } + state.startOfLine = false; + return setStyle || style; + }, + indent: function(state, textAfter) { + var context = state.context; + if (context && context.noIndent) return 0; + if (context && /^{\//.test(textAfter)) + context = context.prev; + while (context && !context.startOfLine) + context = context.prev; + if (context) return context.indent + indentUnit; + else return 0; + }, + electricChars: "/" + }; +}); + +CodeMirror.defineMIME("text/tiki", "tiki"); + +}); diff --git a/static/js/mdeditor/lib/codemirror/mode/toml/index.html b/static/js/mdeditor/lib/codemirror/mode/toml/index.html new file mode 100644 index 00000000..90a2a021 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/toml/index.html @@ -0,0 +1,73 @@ + + +CodeMirror: TOML Mode + + + + + + + + + +
    +

    TOML Mode

    +
    + +

    The TOML Mode

    +

    Created by Forbes Lindesay.

    +

    MIME type defined: text/x-toml.

    +
    diff --git a/static/js/mdeditor/lib/codemirror/mode/toml/toml.js b/static/js/mdeditor/lib/codemirror/mode/toml/toml.js new file mode 100644 index 00000000..baeca155 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/toml/toml.js @@ -0,0 +1,88 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("toml", function () { + return { + startState: function () { + return { + inString: false, + stringType: "", + lhs: true, + inArray: 0 + }; + }, + token: function (stream, state) { + //check for state changes + if (!state.inString && ((stream.peek() == '"') || (stream.peek() == "'"))) { + state.stringType = stream.peek(); + stream.next(); // Skip quote + state.inString = true; // Update state + } + if (stream.sol() && state.inArray === 0) { + state.lhs = true; + } + //return state + if (state.inString) { + while (state.inString && !stream.eol()) { + if (stream.peek() === state.stringType) { + stream.next(); // Skip quote + state.inString = false; // Clear flag + } else if (stream.peek() === '\\') { + stream.next(); + stream.next(); + } else { + stream.match(/^.[^\\\"\']*/); + } + } + return state.lhs ? "property string" : "string"; // Token style + } else if (state.inArray && stream.peek() === ']') { + stream.next(); + state.inArray--; + return 'bracket'; + } else if (state.lhs && stream.peek() === '[' && stream.skipTo(']')) { + stream.next();//skip closing ] + // array of objects has an extra open & close [] + if (stream.peek() === ']') stream.next(); + return "atom"; + } else if (stream.peek() === "#") { + stream.skipToEnd(); + return "comment"; + } else if (stream.eatSpace()) { + return null; + } else if (state.lhs && stream.eatWhile(function (c) { return c != '=' && c != ' '; })) { + return "property"; + } else if (state.lhs && stream.peek() === "=") { + stream.next(); + state.lhs = false; + return null; + } else if (!state.lhs && stream.match(/^\d\d\d\d[\d\-\:\.T]*Z/)) { + return 'atom'; //date + } else if (!state.lhs && (stream.match('true') || stream.match('false'))) { + return 'atom'; + } else if (!state.lhs && stream.peek() === '[') { + state.inArray++; + stream.next(); + return 'bracket'; + } else if (!state.lhs && stream.match(/^\-?\d+(?:\.\d+)?/)) { + return 'number'; + } else if (!stream.eatSpace()) { + stream.next(); + } + return null; + } + }; +}); + +CodeMirror.defineMIME('text/x-toml', 'toml'); + +}); diff --git a/static/js/mdeditor/lib/codemirror/mode/tornado/index.html b/static/js/mdeditor/lib/codemirror/mode/tornado/index.html new file mode 100644 index 00000000..8ee7ef56 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/tornado/index.html @@ -0,0 +1,63 @@ + + +CodeMirror: Tornado template mode + + + + + + + + + + + + +
    +

    Tornado template mode

    +
    + + + +

    Mode for HTML with embedded Tornado template markup.

    + +

    MIME types defined: text/x-tornado

    +
    diff --git a/static/js/mdeditor/lib/codemirror/mode/tornado/tornado.js b/static/js/mdeditor/lib/codemirror/mode/tornado/tornado.js new file mode 100644 index 00000000..dbfbc348 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/tornado/tornado.js @@ -0,0 +1,68 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../htmlmixed/htmlmixed"), + require("../../addon/mode/overlay")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../htmlmixed/htmlmixed", + "../../addon/mode/overlay"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineMode("tornado:inner", function() { + var keywords = ["and","as","assert","autoescape","block","break","class","comment","context", + "continue","datetime","def","del","elif","else","end","escape","except", + "exec","extends","false","finally","for","from","global","if","import","in", + "include","is","json_encode","lambda","length","linkify","load","module", + "none","not","or","pass","print","put","raise","raw","return","self","set", + "squeeze","super","true","try","url_escape","while","with","without","xhtml_escape","yield"]; + keywords = new RegExp("^((" + keywords.join(")|(") + "))\\b"); + + function tokenBase (stream, state) { + stream.eatWhile(/[^\{]/); + var ch = stream.next(); + if (ch == "{") { + if (ch = stream.eat(/\{|%|#/)) { + state.tokenize = inTag(ch); + return "tag"; + } + } + } + function inTag (close) { + if (close == "{") { + close = "}"; + } + return function (stream, state) { + var ch = stream.next(); + if ((ch == close) && stream.eat("}")) { + state.tokenize = tokenBase; + return "tag"; + } + if (stream.match(keywords)) { + return "keyword"; + } + return close == "#" ? "comment" : "string"; + }; + } + return { + startState: function () { + return {tokenize: tokenBase}; + }, + token: function (stream, state) { + return state.tokenize(stream, state); + } + }; + }); + + CodeMirror.defineMode("tornado", function(config) { + var htmlBase = CodeMirror.getMode(config, "text/html"); + var tornadoInner = CodeMirror.getMode(config, "tornado:inner"); + return CodeMirror.overlayMode(htmlBase, tornadoInner); + }); + + CodeMirror.defineMIME("text/x-tornado", "tornado"); +}); diff --git a/static/js/mdeditor/lib/codemirror/mode/turtle/index.html b/static/js/mdeditor/lib/codemirror/mode/turtle/index.html new file mode 100644 index 00000000..a4962b61 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/turtle/index.html @@ -0,0 +1,50 @@ + + +CodeMirror: Turtle mode + + + + + + + + + +
    +

    Turtle mode

    +
    + + +

    MIME types defined: text/turtle.

    + +
    diff --git a/static/js/mdeditor/lib/codemirror/mode/turtle/turtle.js b/static/js/mdeditor/lib/codemirror/mode/turtle/turtle.js new file mode 100644 index 00000000..0988f0a4 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/turtle/turtle.js @@ -0,0 +1,162 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("turtle", function(config) { + var indentUnit = config.indentUnit; + var curPunc; + + function wordRegexp(words) { + return new RegExp("^(?:" + words.join("|") + ")$", "i"); + } + var ops = wordRegexp([]); + var keywords = wordRegexp(["@prefix", "@base", "a"]); + var operatorChars = /[*+\-<>=&|]/; + + function tokenBase(stream, state) { + var ch = stream.next(); + curPunc = null; + if (ch == "<" && !stream.match(/^[\s\u00a0=]/, false)) { + stream.match(/^[^\s\u00a0>]*>?/); + return "atom"; + } + else if (ch == "\"" || ch == "'") { + state.tokenize = tokenLiteral(ch); + return state.tokenize(stream, state); + } + else if (/[{}\(\),\.;\[\]]/.test(ch)) { + curPunc = ch; + return null; + } + else if (ch == "#") { + stream.skipToEnd(); + return "comment"; + } + else if (operatorChars.test(ch)) { + stream.eatWhile(operatorChars); + return null; + } + else if (ch == ":") { + return "operator"; + } else { + stream.eatWhile(/[_\w\d]/); + if(stream.peek() == ":") { + return "variable-3"; + } else { + var word = stream.current(); + + if(keywords.test(word)) { + return "meta"; + } + + if(ch >= "A" && ch <= "Z") { + return "comment"; + } else { + return "keyword"; + } + } + var word = stream.current(); + if (ops.test(word)) + return null; + else if (keywords.test(word)) + return "meta"; + else + return "variable"; + } + } + + function tokenLiteral(quote) { + return function(stream, state) { + var escaped = false, ch; + while ((ch = stream.next()) != null) { + if (ch == quote && !escaped) { + state.tokenize = tokenBase; + break; + } + escaped = !escaped && ch == "\\"; + } + return "string"; + }; + } + + function pushContext(state, type, col) { + state.context = {prev: state.context, indent: state.indent, col: col, type: type}; + } + function popContext(state) { + state.indent = state.context.indent; + state.context = state.context.prev; + } + + return { + startState: function() { + return {tokenize: tokenBase, + context: null, + indent: 0, + col: 0}; + }, + + token: function(stream, state) { + if (stream.sol()) { + if (state.context && state.context.align == null) state.context.align = false; + state.indent = stream.indentation(); + } + if (stream.eatSpace()) return null; + var style = state.tokenize(stream, state); + + if (style != "comment" && state.context && state.context.align == null && state.context.type != "pattern") { + state.context.align = true; + } + + if (curPunc == "(") pushContext(state, ")", stream.column()); + else if (curPunc == "[") pushContext(state, "]", stream.column()); + else if (curPunc == "{") pushContext(state, "}", stream.column()); + else if (/[\]\}\)]/.test(curPunc)) { + while (state.context && state.context.type == "pattern") popContext(state); + if (state.context && curPunc == state.context.type) popContext(state); + } + else if (curPunc == "." && state.context && state.context.type == "pattern") popContext(state); + else if (/atom|string|variable/.test(style) && state.context) { + if (/[\}\]]/.test(state.context.type)) + pushContext(state, "pattern", stream.column()); + else if (state.context.type == "pattern" && !state.context.align) { + state.context.align = true; + state.context.col = stream.column(); + } + } + + return style; + }, + + indent: function(state, textAfter) { + var firstChar = textAfter && textAfter.charAt(0); + var context = state.context; + if (/[\]\}]/.test(firstChar)) + while (context && context.type == "pattern") context = context.prev; + + var closing = context && firstChar == context.type; + if (!context) + return 0; + else if (context.type == "pattern") + return context.col; + else if (context.align) + return context.col + (closing ? 0 : 1); + else + return context.indent + (closing ? 0 : indentUnit); + }, + + lineComment: "#" + }; +}); + +CodeMirror.defineMIME("text/turtle", "turtle"); + +}); diff --git a/static/js/mdeditor/lib/codemirror/mode/vb/index.html b/static/js/mdeditor/lib/codemirror/mode/vb/index.html new file mode 100644 index 00000000..adcc44fd --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/vb/index.html @@ -0,0 +1,102 @@ + + +CodeMirror: VB.NET mode + + + + + + + + + + + +
    +

    VB.NET mode

    + + + +
    + +
    +
    
    +  

    MIME type defined: text/x-vb.

    + +
    diff --git a/static/js/mdeditor/lib/codemirror/mode/vb/vb.js b/static/js/mdeditor/lib/codemirror/mode/vb/vb.js new file mode 100644 index 00000000..902203e0 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/vb/vb.js @@ -0,0 +1,274 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("vb", function(conf, parserConf) { + var ERRORCLASS = 'error'; + + function wordRegexp(words) { + return new RegExp("^((" + words.join(")|(") + "))\\b", "i"); + } + + var singleOperators = new RegExp("^[\\+\\-\\*/%&\\\\|\\^~<>!]"); + var singleDelimiters = new RegExp('^[\\(\\)\\[\\]\\{\\}@,:`=;\\.]'); + var doubleOperators = new RegExp("^((==)|(<>)|(<=)|(>=)|(<>)|(<<)|(>>)|(//)|(\\*\\*))"); + var doubleDelimiters = new RegExp("^((\\+=)|(\\-=)|(\\*=)|(%=)|(/=)|(&=)|(\\|=)|(\\^=))"); + var tripleDelimiters = new RegExp("^((//=)|(>>=)|(<<=)|(\\*\\*=))"); + var identifiers = new RegExp("^[_A-Za-z][_A-Za-z0-9]*"); + + var openingKeywords = ['class','module', 'sub','enum','select','while','if','function', 'get','set','property', 'try']; + var middleKeywords = ['else','elseif','case', 'catch']; + var endKeywords = ['next','loop']; + + var wordOperators = wordRegexp(['and', 'or', 'not', 'xor', 'in']); + var commonkeywords = ['as', 'dim', 'break', 'continue','optional', 'then', 'until', + 'goto', 'byval','byref','new','handles','property', 'return', + 'const','private', 'protected', 'friend', 'public', 'shared', 'static', 'true','false']; + var commontypes = ['integer','string','double','decimal','boolean','short','char', 'float','single']; + + var keywords = wordRegexp(commonkeywords); + var types = wordRegexp(commontypes); + var stringPrefixes = '"'; + + var opening = wordRegexp(openingKeywords); + var middle = wordRegexp(middleKeywords); + var closing = wordRegexp(endKeywords); + var doubleClosing = wordRegexp(['end']); + var doOpening = wordRegexp(['do']); + + var indentInfo = null; + + + + + function indent(_stream, state) { + state.currentIndent++; + } + + function dedent(_stream, state) { + state.currentIndent--; + } + // tokenizers + function tokenBase(stream, state) { + if (stream.eatSpace()) { + return null; + } + + var ch = stream.peek(); + + // Handle Comments + if (ch === "'") { + stream.skipToEnd(); + return 'comment'; + } + + + // Handle Number Literals + if (stream.match(/^((&H)|(&O))?[0-9\.a-f]/i, false)) { + var floatLiteral = false; + // Floats + if (stream.match(/^\d*\.\d+F?/i)) { floatLiteral = true; } + else if (stream.match(/^\d+\.\d*F?/)) { floatLiteral = true; } + else if (stream.match(/^\.\d+F?/)) { floatLiteral = true; } + + if (floatLiteral) { + // Float literals may be "imaginary" + stream.eat(/J/i); + return 'number'; + } + // Integers + var intLiteral = false; + // Hex + if (stream.match(/^&H[0-9a-f]+/i)) { intLiteral = true; } + // Octal + else if (stream.match(/^&O[0-7]+/i)) { intLiteral = true; } + // Decimal + else if (stream.match(/^[1-9]\d*F?/)) { + // Decimal literals may be "imaginary" + stream.eat(/J/i); + // TODO - Can you have imaginary longs? + intLiteral = true; + } + // Zero by itself with no other piece of number. + else if (stream.match(/^0(?![\dx])/i)) { intLiteral = true; } + if (intLiteral) { + // Integer literals may be "long" + stream.eat(/L/i); + return 'number'; + } + } + + // Handle Strings + if (stream.match(stringPrefixes)) { + state.tokenize = tokenStringFactory(stream.current()); + return state.tokenize(stream, state); + } + + // Handle operators and Delimiters + if (stream.match(tripleDelimiters) || stream.match(doubleDelimiters)) { + return null; + } + if (stream.match(doubleOperators) + || stream.match(singleOperators) + || stream.match(wordOperators)) { + return 'operator'; + } + if (stream.match(singleDelimiters)) { + return null; + } + if (stream.match(doOpening)) { + indent(stream,state); + state.doInCurrentLine = true; + return 'keyword'; + } + if (stream.match(opening)) { + if (! state.doInCurrentLine) + indent(stream,state); + else + state.doInCurrentLine = false; + return 'keyword'; + } + if (stream.match(middle)) { + return 'keyword'; + } + + if (stream.match(doubleClosing)) { + dedent(stream,state); + dedent(stream,state); + return 'keyword'; + } + if (stream.match(closing)) { + dedent(stream,state); + return 'keyword'; + } + + if (stream.match(types)) { + return 'keyword'; + } + + if (stream.match(keywords)) { + return 'keyword'; + } + + if (stream.match(identifiers)) { + return 'variable'; + } + + // Handle non-detected items + stream.next(); + return ERRORCLASS; + } + + function tokenStringFactory(delimiter) { + var singleline = delimiter.length == 1; + var OUTCLASS = 'string'; + + return function(stream, state) { + while (!stream.eol()) { + stream.eatWhile(/[^'"]/); + if (stream.match(delimiter)) { + state.tokenize = tokenBase; + return OUTCLASS; + } else { + stream.eat(/['"]/); + } + } + if (singleline) { + if (parserConf.singleLineStringErrors) { + return ERRORCLASS; + } else { + state.tokenize = tokenBase; + } + } + return OUTCLASS; + }; + } + + + function tokenLexer(stream, state) { + var style = state.tokenize(stream, state); + var current = stream.current(); + + // Handle '.' connected identifiers + if (current === '.') { + style = state.tokenize(stream, state); + current = stream.current(); + if (style === 'variable') { + return 'variable'; + } else { + return ERRORCLASS; + } + } + + + var delimiter_index = '[({'.indexOf(current); + if (delimiter_index !== -1) { + indent(stream, state ); + } + if (indentInfo === 'dedent') { + if (dedent(stream, state)) { + return ERRORCLASS; + } + } + delimiter_index = '])}'.indexOf(current); + if (delimiter_index !== -1) { + if (dedent(stream, state)) { + return ERRORCLASS; + } + } + + return style; + } + + var external = { + electricChars:"dDpPtTfFeE ", + startState: function() { + return { + tokenize: tokenBase, + lastToken: null, + currentIndent: 0, + nextLineIndent: 0, + doInCurrentLine: false + + + }; + }, + + token: function(stream, state) { + if (stream.sol()) { + state.currentIndent += state.nextLineIndent; + state.nextLineIndent = 0; + state.doInCurrentLine = 0; + } + var style = tokenLexer(stream, state); + + state.lastToken = {style:style, content: stream.current()}; + + + + return style; + }, + + indent: function(state, textAfter) { + var trueText = textAfter.replace(/^\s+|\s+$/g, '') ; + if (trueText.match(closing) || trueText.match(doubleClosing) || trueText.match(middle)) return conf.indentUnit*(state.currentIndent-1); + if(state.currentIndent < 0) return 0; + return state.currentIndent * conf.indentUnit; + } + + }; + return external; +}); + +CodeMirror.defineMIME("text/x-vb", "vb"); + +}); diff --git a/static/js/mdeditor/lib/codemirror/mode/vbscript/index.html b/static/js/mdeditor/lib/codemirror/mode/vbscript/index.html new file mode 100644 index 00000000..ad7532d7 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/vbscript/index.html @@ -0,0 +1,55 @@ + + +CodeMirror: VBScript mode + + + + + + + + + +
    +

    VBScript mode

    + + +
    + + + +

    MIME types defined: text/vbscript.

    +
    diff --git a/static/js/mdeditor/lib/codemirror/mode/vbscript/vbscript.js b/static/js/mdeditor/lib/codemirror/mode/vbscript/vbscript.js new file mode 100644 index 00000000..b66df223 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/vbscript/vbscript.js @@ -0,0 +1,350 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +/* +For extra ASP classic objects, initialize CodeMirror instance with this option: + isASP: true + +E.G.: + var editor = CodeMirror.fromTextArea(document.getElementById("code"), { + lineNumbers: true, + isASP: true + }); +*/ + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("vbscript", function(conf, parserConf) { + var ERRORCLASS = 'error'; + + function wordRegexp(words) { + return new RegExp("^((" + words.join(")|(") + "))\\b", "i"); + } + + var singleOperators = new RegExp("^[\\+\\-\\*/&\\\\\\^<>=]"); + var doubleOperators = new RegExp("^((<>)|(<=)|(>=))"); + var singleDelimiters = new RegExp('^[\\.,]'); + var brakets = new RegExp('^[\\(\\)]'); + var identifiers = new RegExp("^[A-Za-z][_A-Za-z0-9]*"); + + var openingKeywords = ['class','sub','select','while','if','function', 'property', 'with', 'for']; + var middleKeywords = ['else','elseif','case']; + var endKeywords = ['next','loop','wend']; + + var wordOperators = wordRegexp(['and', 'or', 'not', 'xor', 'is', 'mod', 'eqv', 'imp']); + var commonkeywords = ['dim', 'redim', 'then', 'until', 'randomize', + 'byval','byref','new','property', 'exit', 'in', + 'const','private', 'public', + 'get','set','let', 'stop', 'on error resume next', 'on error goto 0', 'option explicit', 'call', 'me']; + + //This list was from: http://msdn.microsoft.com/en-us/library/f8tbc79x(v=vs.84).aspx + var atomWords = ['true', 'false', 'nothing', 'empty', 'null']; + //This list was from: http://msdn.microsoft.com/en-us/library/3ca8tfek(v=vs.84).aspx + var builtinFuncsWords = ['abs', 'array', 'asc', 'atn', 'cbool', 'cbyte', 'ccur', 'cdate', 'cdbl', 'chr', 'cint', 'clng', 'cos', 'csng', 'cstr', 'date', 'dateadd', 'datediff', 'datepart', + 'dateserial', 'datevalue', 'day', 'escape', 'eval', 'execute', 'exp', 'filter', 'formatcurrency', 'formatdatetime', 'formatnumber', 'formatpercent', 'getlocale', 'getobject', + 'getref', 'hex', 'hour', 'inputbox', 'instr', 'instrrev', 'int', 'fix', 'isarray', 'isdate', 'isempty', 'isnull', 'isnumeric', 'isobject', 'join', 'lbound', 'lcase', 'left', + 'len', 'loadpicture', 'log', 'ltrim', 'rtrim', 'trim', 'maths', 'mid', 'minute', 'month', 'monthname', 'msgbox', 'now', 'oct', 'replace', 'rgb', 'right', 'rnd', 'round', + 'scriptengine', 'scriptenginebuildversion', 'scriptenginemajorversion', 'scriptengineminorversion', 'second', 'setlocale', 'sgn', 'sin', 'space', 'split', 'sqr', 'strcomp', + 'string', 'strreverse', 'tan', 'time', 'timer', 'timeserial', 'timevalue', 'typename', 'ubound', 'ucase', 'unescape', 'vartype', 'weekday', 'weekdayname', 'year']; + + //This list was from: http://msdn.microsoft.com/en-us/library/ydz4cfk3(v=vs.84).aspx + var builtinConsts = ['vbBlack', 'vbRed', 'vbGreen', 'vbYellow', 'vbBlue', 'vbMagenta', 'vbCyan', 'vbWhite', 'vbBinaryCompare', 'vbTextCompare', + 'vbSunday', 'vbMonday', 'vbTuesday', 'vbWednesday', 'vbThursday', 'vbFriday', 'vbSaturday', 'vbUseSystemDayOfWeek', 'vbFirstJan1', 'vbFirstFourDays', 'vbFirstFullWeek', + 'vbGeneralDate', 'vbLongDate', 'vbShortDate', 'vbLongTime', 'vbShortTime', 'vbObjectError', + 'vbOKOnly', 'vbOKCancel', 'vbAbortRetryIgnore', 'vbYesNoCancel', 'vbYesNo', 'vbRetryCancel', 'vbCritical', 'vbQuestion', 'vbExclamation', 'vbInformation', 'vbDefaultButton1', 'vbDefaultButton2', + 'vbDefaultButton3', 'vbDefaultButton4', 'vbApplicationModal', 'vbSystemModal', 'vbOK', 'vbCancel', 'vbAbort', 'vbRetry', 'vbIgnore', 'vbYes', 'vbNo', + 'vbCr', 'VbCrLf', 'vbFormFeed', 'vbLf', 'vbNewLine', 'vbNullChar', 'vbNullString', 'vbTab', 'vbVerticalTab', 'vbUseDefault', 'vbTrue', 'vbFalse', + 'vbEmpty', 'vbNull', 'vbInteger', 'vbLong', 'vbSingle', 'vbDouble', 'vbCurrency', 'vbDate', 'vbString', 'vbObject', 'vbError', 'vbBoolean', 'vbVariant', 'vbDataObject', 'vbDecimal', 'vbByte', 'vbArray']; + //This list was from: http://msdn.microsoft.com/en-us/library/hkc375ea(v=vs.84).aspx + var builtinObjsWords = ['WScript', 'err', 'debug', 'RegExp']; + var knownProperties = ['description', 'firstindex', 'global', 'helpcontext', 'helpfile', 'ignorecase', 'length', 'number', 'pattern', 'source', 'value', 'count']; + var knownMethods = ['clear', 'execute', 'raise', 'replace', 'test', 'write', 'writeline', 'close', 'open', 'state', 'eof', 'update', 'addnew', 'end', 'createobject', 'quit']; + + var aspBuiltinObjsWords = ['server', 'response', 'request', 'session', 'application']; + var aspKnownProperties = ['buffer', 'cachecontrol', 'charset', 'contenttype', 'expires', 'expiresabsolute', 'isclientconnected', 'pics', 'status', //response + 'clientcertificate', 'cookies', 'form', 'querystring', 'servervariables', 'totalbytes', //request + 'contents', 'staticobjects', //application + 'codepage', 'lcid', 'sessionid', 'timeout', //session + 'scripttimeout']; //server + var aspKnownMethods = ['addheader', 'appendtolog', 'binarywrite', 'end', 'flush', 'redirect', //response + 'binaryread', //request + 'remove', 'removeall', 'lock', 'unlock', //application + 'abandon', //session + 'getlasterror', 'htmlencode', 'mappath', 'transfer', 'urlencode']; //server + + var knownWords = knownMethods.concat(knownProperties); + + builtinObjsWords = builtinObjsWords.concat(builtinConsts); + + if (conf.isASP){ + builtinObjsWords = builtinObjsWords.concat(aspBuiltinObjsWords); + knownWords = knownWords.concat(aspKnownMethods, aspKnownProperties); + }; + + var keywords = wordRegexp(commonkeywords); + var atoms = wordRegexp(atomWords); + var builtinFuncs = wordRegexp(builtinFuncsWords); + var builtinObjs = wordRegexp(builtinObjsWords); + var known = wordRegexp(knownWords); + var stringPrefixes = '"'; + + var opening = wordRegexp(openingKeywords); + var middle = wordRegexp(middleKeywords); + var closing = wordRegexp(endKeywords); + var doubleClosing = wordRegexp(['end']); + var doOpening = wordRegexp(['do']); + var noIndentWords = wordRegexp(['on error resume next', 'exit']); + var comment = wordRegexp(['rem']); + + + function indent(_stream, state) { + state.currentIndent++; + } + + function dedent(_stream, state) { + state.currentIndent--; + } + // tokenizers + function tokenBase(stream, state) { + if (stream.eatSpace()) { + return 'space'; + //return null; + } + + var ch = stream.peek(); + + // Handle Comments + if (ch === "'") { + stream.skipToEnd(); + return 'comment'; + } + if (stream.match(comment)){ + stream.skipToEnd(); + return 'comment'; + } + + + // Handle Number Literals + if (stream.match(/^((&H)|(&O))?[0-9\.]/i, false) && !stream.match(/^((&H)|(&O))?[0-9\.]+[a-z_]/i, false)) { + var floatLiteral = false; + // Floats + if (stream.match(/^\d*\.\d+/i)) { floatLiteral = true; } + else if (stream.match(/^\d+\.\d*/)) { floatLiteral = true; } + else if (stream.match(/^\.\d+/)) { floatLiteral = true; } + + if (floatLiteral) { + // Float literals may be "imaginary" + stream.eat(/J/i); + return 'number'; + } + // Integers + var intLiteral = false; + // Hex + if (stream.match(/^&H[0-9a-f]+/i)) { intLiteral = true; } + // Octal + else if (stream.match(/^&O[0-7]+/i)) { intLiteral = true; } + // Decimal + else if (stream.match(/^[1-9]\d*F?/)) { + // Decimal literals may be "imaginary" + stream.eat(/J/i); + // TODO - Can you have imaginary longs? + intLiteral = true; + } + // Zero by itself with no other piece of number. + else if (stream.match(/^0(?![\dx])/i)) { intLiteral = true; } + if (intLiteral) { + // Integer literals may be "long" + stream.eat(/L/i); + return 'number'; + } + } + + // Handle Strings + if (stream.match(stringPrefixes)) { + state.tokenize = tokenStringFactory(stream.current()); + return state.tokenize(stream, state); + } + + // Handle operators and Delimiters + if (stream.match(doubleOperators) + || stream.match(singleOperators) + || stream.match(wordOperators)) { + return 'operator'; + } + if (stream.match(singleDelimiters)) { + return null; + } + + if (stream.match(brakets)) { + return "bracket"; + } + + if (stream.match(noIndentWords)) { + state.doInCurrentLine = true; + + return 'keyword'; + } + + if (stream.match(doOpening)) { + indent(stream,state); + state.doInCurrentLine = true; + + return 'keyword'; + } + if (stream.match(opening)) { + if (! state.doInCurrentLine) + indent(stream,state); + else + state.doInCurrentLine = false; + + return 'keyword'; + } + if (stream.match(middle)) { + return 'keyword'; + } + + + if (stream.match(doubleClosing)) { + dedent(stream,state); + dedent(stream,state); + + return 'keyword'; + } + if (stream.match(closing)) { + if (! state.doInCurrentLine) + dedent(stream,state); + else + state.doInCurrentLine = false; + + return 'keyword'; + } + + if (stream.match(keywords)) { + return 'keyword'; + } + + if (stream.match(atoms)) { + return 'atom'; + } + + if (stream.match(known)) { + return 'variable-2'; + } + + if (stream.match(builtinFuncs)) { + return 'builtin'; + } + + if (stream.match(builtinObjs)){ + return 'variable-2'; + } + + if (stream.match(identifiers)) { + return 'variable'; + } + + // Handle non-detected items + stream.next(); + return ERRORCLASS; + } + + function tokenStringFactory(delimiter) { + var singleline = delimiter.length == 1; + var OUTCLASS = 'string'; + + return function(stream, state) { + while (!stream.eol()) { + stream.eatWhile(/[^'"]/); + if (stream.match(delimiter)) { + state.tokenize = tokenBase; + return OUTCLASS; + } else { + stream.eat(/['"]/); + } + } + if (singleline) { + if (parserConf.singleLineStringErrors) { + return ERRORCLASS; + } else { + state.tokenize = tokenBase; + } + } + return OUTCLASS; + }; + } + + + function tokenLexer(stream, state) { + var style = state.tokenize(stream, state); + var current = stream.current(); + + // Handle '.' connected identifiers + if (current === '.') { + style = state.tokenize(stream, state); + + current = stream.current(); + if (style && (style.substr(0, 8) === 'variable' || style==='builtin' || style==='keyword')){//|| knownWords.indexOf(current.substring(1)) > -1) { + if (style === 'builtin' || style === 'keyword') style='variable'; + if (knownWords.indexOf(current.substr(1)) > -1) style='variable-2'; + + return style; + } else { + return ERRORCLASS; + } + } + + return style; + } + + var external = { + electricChars:"dDpPtTfFeE ", + startState: function() { + return { + tokenize: tokenBase, + lastToken: null, + currentIndent: 0, + nextLineIndent: 0, + doInCurrentLine: false, + ignoreKeyword: false + + + }; + }, + + token: function(stream, state) { + if (stream.sol()) { + state.currentIndent += state.nextLineIndent; + state.nextLineIndent = 0; + state.doInCurrentLine = 0; + } + var style = tokenLexer(stream, state); + + state.lastToken = {style:style, content: stream.current()}; + + if (style==='space') style=null; + + return style; + }, + + indent: function(state, textAfter) { + var trueText = textAfter.replace(/^\s+|\s+$/g, '') ; + if (trueText.match(closing) || trueText.match(doubleClosing) || trueText.match(middle)) return conf.indentUnit*(state.currentIndent-1); + if(state.currentIndent < 0) return 0; + return state.currentIndent * conf.indentUnit; + } + + }; + return external; +}); + +CodeMirror.defineMIME("text/vbscript", "vbscript"); + +}); diff --git a/static/js/mdeditor/lib/codemirror/mode/velocity/index.html b/static/js/mdeditor/lib/codemirror/mode/velocity/index.html new file mode 100644 index 00000000..27478786 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/velocity/index.html @@ -0,0 +1,118 @@ + + +CodeMirror: Velocity mode + + + + + + + + + + +
    +

    Velocity mode

    +
    + + +

    MIME types defined: text/velocity.

    + +
    diff --git a/static/js/mdeditor/lib/codemirror/mode/velocity/velocity.js b/static/js/mdeditor/lib/codemirror/mode/velocity/velocity.js new file mode 100644 index 00000000..8fc4f95d --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/velocity/velocity.js @@ -0,0 +1,201 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("velocity", function() { + function parseWords(str) { + var obj = {}, words = str.split(" "); + for (var i = 0; i < words.length; ++i) obj[words[i]] = true; + return obj; + } + + var keywords = parseWords("#end #else #break #stop #[[ #]] " + + "#{end} #{else} #{break} #{stop}"); + var functions = parseWords("#if #elseif #foreach #set #include #parse #macro #define #evaluate " + + "#{if} #{elseif} #{foreach} #{set} #{include} #{parse} #{macro} #{define} #{evaluate}"); + var specials = parseWords("$foreach.count $foreach.hasNext $foreach.first $foreach.last $foreach.topmost $foreach.parent.count $foreach.parent.hasNext $foreach.parent.first $foreach.parent.last $foreach.parent $velocityCount $!bodyContent $bodyContent"); + var isOperatorChar = /[+\-*&%=<>!?:\/|]/; + + function chain(stream, state, f) { + state.tokenize = f; + return f(stream, state); + } + function tokenBase(stream, state) { + var beforeParams = state.beforeParams; + state.beforeParams = false; + var ch = stream.next(); + // start of unparsed string? + if ((ch == "'") && state.inParams) { + state.lastTokenWasBuiltin = false; + return chain(stream, state, tokenString(ch)); + } + // start of parsed string? + else if ((ch == '"')) { + state.lastTokenWasBuiltin = false; + if (state.inString) { + state.inString = false; + return "string"; + } + else if (state.inParams) + return chain(stream, state, tokenString(ch)); + } + // is it one of the special signs []{}().,;? Seperator? + else if (/[\[\]{}\(\),;\.]/.test(ch)) { + if (ch == "(" && beforeParams) + state.inParams = true; + else if (ch == ")") { + state.inParams = false; + state.lastTokenWasBuiltin = true; + } + return null; + } + // start of a number value? + else if (/\d/.test(ch)) { + state.lastTokenWasBuiltin = false; + stream.eatWhile(/[\w\.]/); + return "number"; + } + // multi line comment? + else if (ch == "#" && stream.eat("*")) { + state.lastTokenWasBuiltin = false; + return chain(stream, state, tokenComment); + } + // unparsed content? + else if (ch == "#" && stream.match(/ *\[ *\[/)) { + state.lastTokenWasBuiltin = false; + return chain(stream, state, tokenUnparsed); + } + // single line comment? + else if (ch == "#" && stream.eat("#")) { + state.lastTokenWasBuiltin = false; + stream.skipToEnd(); + return "comment"; + } + // variable? + else if (ch == "$") { + stream.eatWhile(/[\w\d\$_\.{}]/); + // is it one of the specials? + if (specials && specials.propertyIsEnumerable(stream.current())) { + return "keyword"; + } + else { + state.lastTokenWasBuiltin = true; + state.beforeParams = true; + return "builtin"; + } + } + // is it a operator? + else if (isOperatorChar.test(ch)) { + state.lastTokenWasBuiltin = false; + stream.eatWhile(isOperatorChar); + return "operator"; + } + else { + // get the whole word + stream.eatWhile(/[\w\$_{}@]/); + var word = stream.current(); + // is it one of the listed keywords? + if (keywords && keywords.propertyIsEnumerable(word)) + return "keyword"; + // is it one of the listed functions? + if (functions && functions.propertyIsEnumerable(word) || + (stream.current().match(/^#@?[a-z0-9_]+ *$/i) && stream.peek()=="(") && + !(functions && functions.propertyIsEnumerable(word.toLowerCase()))) { + state.beforeParams = true; + state.lastTokenWasBuiltin = false; + return "keyword"; + } + if (state.inString) { + state.lastTokenWasBuiltin = false; + return "string"; + } + if (stream.pos > word.length && stream.string.charAt(stream.pos-word.length-1)=="." && state.lastTokenWasBuiltin) + return "builtin"; + // default: just a "word" + state.lastTokenWasBuiltin = false; + return null; + } + } + + function tokenString(quote) { + return function(stream, state) { + var escaped = false, next, end = false; + while ((next = stream.next()) != null) { + if ((next == quote) && !escaped) { + end = true; + break; + } + if (quote=='"' && stream.peek() == '$' && !escaped) { + state.inString = true; + end = true; + break; + } + escaped = !escaped && next == "\\"; + } + if (end) state.tokenize = tokenBase; + return "string"; + }; + } + + function tokenComment(stream, state) { + var maybeEnd = false, ch; + while (ch = stream.next()) { + if (ch == "#" && maybeEnd) { + state.tokenize = tokenBase; + break; + } + maybeEnd = (ch == "*"); + } + return "comment"; + } + + function tokenUnparsed(stream, state) { + var maybeEnd = 0, ch; + while (ch = stream.next()) { + if (ch == "#" && maybeEnd == 2) { + state.tokenize = tokenBase; + break; + } + if (ch == "]") + maybeEnd++; + else if (ch != " ") + maybeEnd = 0; + } + return "meta"; + } + // Interface + + return { + startState: function() { + return { + tokenize: tokenBase, + beforeParams: false, + inParams: false, + inString: false, + lastTokenWasBuiltin: false + }; + }, + + token: function(stream, state) { + if (stream.eatSpace()) return null; + return state.tokenize(stream, state); + }, + blockCommentStart: "#*", + blockCommentEnd: "*#", + lineComment: "##", + fold: "velocity" + }; +}); + +CodeMirror.defineMIME("text/velocity", "velocity"); + +}); diff --git a/static/js/mdeditor/lib/codemirror/mode/verilog/index.html b/static/js/mdeditor/lib/codemirror/mode/verilog/index.html new file mode 100644 index 00000000..96b3d647 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/verilog/index.html @@ -0,0 +1,120 @@ + + +CodeMirror: Verilog/SystemVerilog mode + + + + + + + + + + +
    +

    SystemVerilog mode

    + +
    + + + +

    +Syntax highlighting and indentation for the Verilog and SystemVerilog languages (IEEE 1800). +

    Configuration options:

    +
      +
    • noIndentKeywords - List of keywords which should not cause identation to increase. E.g. ["package", "module"]. Default: None
    • +
    +

    + +

    MIME types defined: text/x-verilog and text/x-systemverilog.

    +
    diff --git a/static/js/mdeditor/lib/codemirror/mode/verilog/test.js b/static/js/mdeditor/lib/codemirror/mode/verilog/test.js new file mode 100644 index 00000000..9c8c0949 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/verilog/test.js @@ -0,0 +1,273 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function() { + var mode = CodeMirror.getMode({indentUnit: 4}, "verilog"); + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); } + + MT("binary_literals", + "[number 1'b0]", + "[number 1'b1]", + "[number 1'bx]", + "[number 1'bz]", + "[number 1'bX]", + "[number 1'bZ]", + "[number 1'B0]", + "[number 1'B1]", + "[number 1'Bx]", + "[number 1'Bz]", + "[number 1'BX]", + "[number 1'BZ]", + "[number 1'b0]", + "[number 1'b1]", + "[number 2'b01]", + "[number 2'bxz]", + "[number 2'b11]", + "[number 2'b10]", + "[number 2'b1Z]", + "[number 12'b0101_0101_0101]", + "[number 1'b 0]", + "[number 'b0101]" + ); + + MT("octal_literals", + "[number 3'o7]", + "[number 3'O7]", + "[number 3'so7]", + "[number 3'SO7]" + ); + + MT("decimal_literals", + "[number 0]", + "[number 1]", + "[number 7]", + "[number 123_456]", + "[number 'd33]", + "[number 8'd255]", + "[number 8'D255]", + "[number 8'sd255]", + "[number 8'SD255]", + "[number 32'd123]", + "[number 32 'd123]", + "[number 32 'd 123]" + ); + + MT("hex_literals", + "[number 4'h0]", + "[number 4'ha]", + "[number 4'hF]", + "[number 4'hx]", + "[number 4'hz]", + "[number 4'hX]", + "[number 4'hZ]", + "[number 32'hdc78]", + "[number 32'hDC78]", + "[number 32 'hDC78]", + "[number 32'h DC78]", + "[number 32 'h DC78]", + "[number 32'h44x7]", + "[number 32'hFFF?]" + ); + + MT("real_number_literals", + "[number 1.2]", + "[number 0.1]", + "[number 2394.26331]", + "[number 1.2E12]", + "[number 1.2e12]", + "[number 1.30e-2]", + "[number 0.1e-0]", + "[number 23E10]", + "[number 29E-2]", + "[number 236.123_763_e-12]" + ); + + MT("operators", + "[meta ^]" + ); + + MT("keywords", + "[keyword logic]", + "[keyword logic] [variable foo]", + "[keyword reg] [variable abc]" + ); + + MT("variables", + "[variable _leading_underscore]", + "[variable _if]", + "[number 12] [variable foo]", + "[variable foo] [number 14]" + ); + + MT("tick_defines", + "[def `FOO]", + "[def `foo]", + "[def `FOO_bar]" + ); + + MT("system_calls", + "[meta $display]", + "[meta $vpi_printf]" + ); + + MT("line_comment", "[comment // Hello world]"); + + // Alignment tests + MT("align_port_map_style1", + /** + * mod mod(.a(a), + * .b(b) + * ); + */ + "[variable mod] [variable mod][bracket (].[variable a][bracket (][variable a][bracket )],", + " .[variable b][bracket (][variable b][bracket )]", + " [bracket )];", + "" + ); + + MT("align_port_map_style2", + /** + * mod mod( + * .a(a), + * .b(b) + * ); + */ + "[variable mod] [variable mod][bracket (]", + " .[variable a][bracket (][variable a][bracket )],", + " .[variable b][bracket (][variable b][bracket )]", + "[bracket )];", + "" + ); + + // Indentation tests + MT("indent_single_statement_if", + "[keyword if] [bracket (][variable foo][bracket )]", + " [keyword break];", + "" + ); + + MT("no_indent_after_single_line_if", + "[keyword if] [bracket (][variable foo][bracket )] [keyword break];", + "" + ); + + MT("indent_after_if_begin_same_line", + "[keyword if] [bracket (][variable foo][bracket )] [keyword begin]", + " [keyword break];", + " [keyword break];", + "[keyword end]", + "" + ); + + MT("indent_after_if_begin_next_line", + "[keyword if] [bracket (][variable foo][bracket )]", + " [keyword begin]", + " [keyword break];", + " [keyword break];", + " [keyword end]", + "" + ); + + MT("indent_single_statement_if_else", + "[keyword if] [bracket (][variable foo][bracket )]", + " [keyword break];", + "[keyword else]", + " [keyword break];", + "" + ); + + MT("indent_if_else_begin_same_line", + "[keyword if] [bracket (][variable foo][bracket )] [keyword begin]", + " [keyword break];", + " [keyword break];", + "[keyword end] [keyword else] [keyword begin]", + " [keyword break];", + " [keyword break];", + "[keyword end]", + "" + ); + + MT("indent_if_else_begin_next_line", + "[keyword if] [bracket (][variable foo][bracket )]", + " [keyword begin]", + " [keyword break];", + " [keyword break];", + " [keyword end]", + "[keyword else]", + " [keyword begin]", + " [keyword break];", + " [keyword break];", + " [keyword end]", + "" + ); + + MT("indent_if_nested_without_begin", + "[keyword if] [bracket (][variable foo][bracket )]", + " [keyword if] [bracket (][variable foo][bracket )]", + " [keyword if] [bracket (][variable foo][bracket )]", + " [keyword break];", + "" + ); + + MT("indent_case", + "[keyword case] [bracket (][variable state][bracket )]", + " [variable FOO]:", + " [keyword break];", + " [variable BAR]:", + " [keyword break];", + "[keyword endcase]", + "" + ); + + MT("unindent_after_end_with_preceding_text", + "[keyword begin]", + " [keyword break]; [keyword end]", + "" + ); + + MT("export_function_one_line_does_not_indent", + "[keyword export] [string \"DPI-C\"] [keyword function] [variable helloFromSV];", + "" + ); + + MT("export_task_one_line_does_not_indent", + "[keyword export] [string \"DPI-C\"] [keyword task] [variable helloFromSV];", + "" + ); + + MT("export_function_two_lines_indents_properly", + "[keyword export]", + " [string \"DPI-C\"] [keyword function] [variable helloFromSV];", + "" + ); + + MT("export_task_two_lines_indents_properly", + "[keyword export]", + " [string \"DPI-C\"] [keyword task] [variable helloFromSV];", + "" + ); + + MT("import_function_one_line_does_not_indent", + "[keyword import] [string \"DPI-C\"] [keyword function] [variable helloFromC];", + "" + ); + + MT("import_task_one_line_does_not_indent", + "[keyword import] [string \"DPI-C\"] [keyword task] [variable helloFromC];", + "" + ); + + MT("import_package_single_line_does_not_indent", + "[keyword import] [variable p]::[variable x];", + "[keyword import] [variable p]::[variable y];", + "" + ); + + MT("covergoup_with_function_indents_properly", + "[keyword covergroup] [variable cg] [keyword with] [keyword function] [variable sample][bracket (][keyword bit] [variable b][bracket )];", + " [variable c] : [keyword coverpoint] [variable c];", + "[keyword endgroup]: [variable cg]", + "" + ); + +})(); diff --git a/static/js/mdeditor/lib/codemirror/mode/verilog/verilog.js b/static/js/mdeditor/lib/codemirror/mode/verilog/verilog.js new file mode 100644 index 00000000..96b9f245 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/verilog/verilog.js @@ -0,0 +1,537 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("verilog", function(config, parserConfig) { + + var indentUnit = config.indentUnit, + statementIndentUnit = parserConfig.statementIndentUnit || indentUnit, + dontAlignCalls = parserConfig.dontAlignCalls, + noIndentKeywords = parserConfig.noIndentKeywords || [], + multiLineStrings = parserConfig.multiLineStrings, + hooks = parserConfig.hooks || {}; + + function words(str) { + var obj = {}, words = str.split(" "); + for (var i = 0; i < words.length; ++i) obj[words[i]] = true; + return obj; + } + + /** + * Keywords from IEEE 1800-2012 + */ + var keywords = words( + "accept_on alias always always_comb always_ff always_latch and assert assign assume automatic before begin bind " + + "bins binsof bit break buf bufif0 bufif1 byte case casex casez cell chandle checker class clocking cmos config " + + "const constraint context continue cover covergroup coverpoint cross deassign default defparam design disable " + + "dist do edge else end endcase endchecker endclass endclocking endconfig endfunction endgenerate endgroup " + + "endinterface endmodule endpackage endprimitive endprogram endproperty endspecify endsequence endtable endtask " + + "enum event eventually expect export extends extern final first_match for force foreach forever fork forkjoin " + + "function generate genvar global highz0 highz1 if iff ifnone ignore_bins illegal_bins implements implies import " + + "incdir include initial inout input inside instance int integer interconnect interface intersect join join_any " + + "join_none large let liblist library local localparam logic longint macromodule matches medium modport module " + + "nand negedge nettype new nexttime nmos nor noshowcancelled not notif0 notif1 null or output package packed " + + "parameter pmos posedge primitive priority program property protected pull0 pull1 pulldown pullup " + + "pulsestyle_ondetect pulsestyle_onevent pure rand randc randcase randsequence rcmos real realtime ref reg " + + "reject_on release repeat restrict return rnmos rpmos rtran rtranif0 rtranif1 s_always s_eventually s_nexttime " + + "s_until s_until_with scalared sequence shortint shortreal showcancelled signed small soft solve specify " + + "specparam static string strong strong0 strong1 struct super supply0 supply1 sync_accept_on sync_reject_on " + + "table tagged task this throughout time timeprecision timeunit tran tranif0 tranif1 tri tri0 tri1 triand trior " + + "trireg type typedef union unique unique0 unsigned until until_with untyped use uwire var vectored virtual void " + + "wait wait_order wand weak weak0 weak1 while wildcard wire with within wor xnor xor"); + + /** Operators from IEEE 1800-2012 + unary_operator ::= + + | - | ! | ~ | & | ~& | | | ~| | ^ | ~^ | ^~ + binary_operator ::= + + | - | * | / | % | == | != | === | !== | ==? | !=? | && | || | ** + | < | <= | > | >= | & | | | ^ | ^~ | ~^ | >> | << | >>> | <<< + | -> | <-> + inc_or_dec_operator ::= ++ | -- + unary_module_path_operator ::= + ! | ~ | & | ~& | | | ~| | ^ | ~^ | ^~ + binary_module_path_operator ::= + == | != | && | || | & | | | ^ | ^~ | ~^ + */ + var isOperatorChar = /[\+\-\*\/!~&|^%=?:]/; + var isBracketChar = /[\[\]{}()]/; + + var unsignedNumber = /\d[0-9_]*/; + var decimalLiteral = /\d*\s*'s?d\s*\d[0-9_]*/i; + var binaryLiteral = /\d*\s*'s?b\s*[xz01][xz01_]*/i; + var octLiteral = /\d*\s*'s?o\s*[xz0-7][xz0-7_]*/i; + var hexLiteral = /\d*\s*'s?h\s*[0-9a-fxz?][0-9a-fxz?_]*/i; + var realLiteral = /(\d[\d_]*(\.\d[\d_]*)?E-?[\d_]+)|(\d[\d_]*\.\d[\d_]*)/i; + + var closingBracketOrWord = /^((\w+)|[)}\]])/; + var closingBracket = /[)}\]]/; + + var curPunc; + var curKeyword; + + // Block openings which are closed by a matching keyword in the form of ("end" + keyword) + // E.g. "task" => "endtask" + var blockKeywords = words( + "case checker class clocking config function generate interface module package" + + "primitive program property specify sequence table task" + ); + + // Opening/closing pairs + var openClose = {}; + for (var keyword in blockKeywords) { + openClose[keyword] = "end" + keyword; + } + openClose["begin"] = "end"; + openClose["casex"] = "endcase"; + openClose["casez"] = "endcase"; + openClose["do" ] = "while"; + openClose["fork" ] = "join;join_any;join_none"; + openClose["covergroup"] = "endgroup"; + + for (var i in noIndentKeywords) { + var keyword = noIndentKeywords[i]; + if (openClose[keyword]) { + openClose[keyword] = undefined; + } + } + + // Keywords which open statements that are ended with a semi-colon + var statementKeywords = words("always always_comb always_ff always_latch assert assign assume else export for foreach forever if import initial repeat while"); + + function tokenBase(stream, state) { + var ch = stream.peek(), style; + if (hooks[ch] && (style = hooks[ch](stream, state)) != false) return style; + if (hooks.tokenBase && (style = hooks.tokenBase(stream, state)) != false) + return style; + + if (/[,;:\.]/.test(ch)) { + curPunc = stream.next(); + return null; + } + if (isBracketChar.test(ch)) { + curPunc = stream.next(); + return "bracket"; + } + // Macros (tick-defines) + if (ch == '`') { + stream.next(); + if (stream.eatWhile(/[\w\$_]/)) { + return "def"; + } else { + return null; + } + } + // System calls + if (ch == '$') { + stream.next(); + if (stream.eatWhile(/[\w\$_]/)) { + return "meta"; + } else { + return null; + } + } + // Time literals + if (ch == '#') { + stream.next(); + stream.eatWhile(/[\d_.]/); + return "def"; + } + // Strings + if (ch == '"') { + stream.next(); + state.tokenize = tokenString(ch); + return state.tokenize(stream, state); + } + // Comments + if (ch == "/") { + stream.next(); + if (stream.eat("*")) { + state.tokenize = tokenComment; + return tokenComment(stream, state); + } + if (stream.eat("/")) { + stream.skipToEnd(); + return "comment"; + } + stream.backUp(1); + } + + // Numeric literals + if (stream.match(realLiteral) || + stream.match(decimalLiteral) || + stream.match(binaryLiteral) || + stream.match(octLiteral) || + stream.match(hexLiteral) || + stream.match(unsignedNumber) || + stream.match(realLiteral)) { + return "number"; + } + + // Operators + if (stream.eatWhile(isOperatorChar)) { + return "meta"; + } + + // Keywords / plain variables + if (stream.eatWhile(/[\w\$_]/)) { + var cur = stream.current(); + if (keywords[cur]) { + if (openClose[cur]) { + curPunc = "newblock"; + } + if (statementKeywords[cur]) { + curPunc = "newstatement"; + } + curKeyword = cur; + return "keyword"; + } + return "variable"; + } + + stream.next(); + return null; + } + + function tokenString(quote) { + return function(stream, state) { + var escaped = false, next, end = false; + while ((next = stream.next()) != null) { + if (next == quote && !escaped) {end = true; break;} + escaped = !escaped && next == "\\"; + } + if (end || !(escaped || multiLineStrings)) + state.tokenize = tokenBase; + return "string"; + }; + } + + function tokenComment(stream, state) { + var maybeEnd = false, ch; + while (ch = stream.next()) { + if (ch == "/" && maybeEnd) { + state.tokenize = tokenBase; + break; + } + maybeEnd = (ch == "*"); + } + return "comment"; + } + + function Context(indented, column, type, align, prev) { + this.indented = indented; + this.column = column; + this.type = type; + this.align = align; + this.prev = prev; + } + function pushContext(state, col, type) { + var indent = state.indented; + var c = new Context(indent, col, type, null, state.context); + return state.context = c; + } + function popContext(state) { + var t = state.context.type; + if (t == ")" || t == "]" || t == "}") { + state.indented = state.context.indented; + } + return state.context = state.context.prev; + } + + function isClosing(text, contextClosing) { + if (text == contextClosing) { + return true; + } else { + // contextClosing may be mulitple keywords separated by ; + var closingKeywords = contextClosing.split(";"); + for (var i in closingKeywords) { + if (text == closingKeywords[i]) { + return true; + } + } + return false; + } + } + + function buildElectricInputRegEx() { + // Reindentation should occur on any bracket char: {}()[] + // or on a match of any of the block closing keywords, at + // the end of a line + var allClosings = []; + for (var i in openClose) { + if (openClose[i]) { + var closings = openClose[i].split(";"); + for (var j in closings) { + allClosings.push(closings[j]); + } + } + } + var re = new RegExp("[{}()\\[\\]]|(" + allClosings.join("|") + ")$"); + return re; + } + + // Interface + return { + + // Regex to force current line to reindent + electricInput: buildElectricInputRegEx(), + + startState: function(basecolumn) { + var state = { + tokenize: null, + context: new Context((basecolumn || 0) - indentUnit, 0, "top", false), + indented: 0, + startOfLine: true + }; + if (hooks.startState) hooks.startState(state); + return state; + }, + + token: function(stream, state) { + var ctx = state.context; + if (stream.sol()) { + if (ctx.align == null) ctx.align = false; + state.indented = stream.indentation(); + state.startOfLine = true; + } + if (hooks.token) hooks.token(stream, state); + if (stream.eatSpace()) return null; + curPunc = null; + curKeyword = null; + var style = (state.tokenize || tokenBase)(stream, state); + if (style == "comment" || style == "meta" || style == "variable") return style; + if (ctx.align == null) ctx.align = true; + + if (curPunc == ctx.type) { + popContext(state); + } else if ((curPunc == ";" && ctx.type == "statement") || + (ctx.type && isClosing(curKeyword, ctx.type))) { + ctx = popContext(state); + while (ctx && ctx.type == "statement") ctx = popContext(state); + } else if (curPunc == "{") { + pushContext(state, stream.column(), "}"); + } else if (curPunc == "[") { + pushContext(state, stream.column(), "]"); + } else if (curPunc == "(") { + pushContext(state, stream.column(), ")"); + } else if (ctx && ctx.type == "endcase" && curPunc == ":") { + pushContext(state, stream.column(), "statement"); + } else if (curPunc == "newstatement") { + pushContext(state, stream.column(), "statement"); + } else if (curPunc == "newblock") { + if (curKeyword == "function" && ctx && (ctx.type == "statement" || ctx.type == "endgroup")) { + // The 'function' keyword can appear in some other contexts where it actually does not + // indicate a function (import/export DPI and covergroup definitions). + // Do nothing in this case + } else if (curKeyword == "task" && ctx && ctx.type == "statement") { + // Same thing for task + } else { + var close = openClose[curKeyword]; + pushContext(state, stream.column(), close); + } + } + + state.startOfLine = false; + return style; + }, + + indent: function(state, textAfter) { + if (state.tokenize != tokenBase && state.tokenize != null) return CodeMirror.Pass; + if (hooks.indent) { + var fromHook = hooks.indent(state); + if (fromHook >= 0) return fromHook; + } + var ctx = state.context, firstChar = textAfter && textAfter.charAt(0); + if (ctx.type == "statement" && firstChar == "}") ctx = ctx.prev; + var closing = false; + var possibleClosing = textAfter.match(closingBracketOrWord); + if (possibleClosing) + closing = isClosing(possibleClosing[0], ctx.type); + if (ctx.type == "statement") return ctx.indented + (firstChar == "{" ? 0 : statementIndentUnit); + else if (closingBracket.test(ctx.type) && ctx.align && !dontAlignCalls) return ctx.column + (closing ? 0 : 1); + else if (ctx.type == ")" && !closing) return ctx.indented + statementIndentUnit; + else return ctx.indented + (closing ? 0 : indentUnit); + }, + + blockCommentStart: "/*", + blockCommentEnd: "*/", + lineComment: "//" + }; +}); + + CodeMirror.defineMIME("text/x-verilog", { + name: "verilog" + }); + + CodeMirror.defineMIME("text/x-systemverilog", { + name: "verilog" + }); + + // SVXVerilog mode + + var svxchScopePrefixes = { + ">": "property", "->": "property", "-": "hr", "|": "link", "?$": "qualifier", "?*": "qualifier", + "@-": "variable-3", "@": "variable-3", "?": "qualifier" + }; + + function svxGenIndent(stream, state) { + var svxindentUnit = 2; + var rtnIndent = -1, indentUnitRq = 0, curIndent = stream.indentation(); + switch (state.svxCurCtlFlowChar) { + case "\\": + curIndent = 0; + break; + case "|": + if (state.svxPrevPrevCtlFlowChar == "@") { + indentUnitRq = -2; //-2 new pipe rq after cur pipe + break; + } + if (svxchScopePrefixes[state.svxPrevCtlFlowChar]) + indentUnitRq = 1; // +1 new scope + break; + case "M": // m4 + if (state.svxPrevPrevCtlFlowChar == "@") { + indentUnitRq = -2; //-2 new inst rq after pipe + break; + } + if (svxchScopePrefixes[state.svxPrevCtlFlowChar]) + indentUnitRq = 1; // +1 new scope + break; + case "@": + if (state.svxPrevCtlFlowChar == "S") + indentUnitRq = -1; // new pipe stage after stmts + if (state.svxPrevCtlFlowChar == "|") + indentUnitRq = 1; // 1st pipe stage + break; + case "S": + if (state.svxPrevCtlFlowChar == "@") + indentUnitRq = 1; // flow in pipe stage + if (svxchScopePrefixes[state.svxPrevCtlFlowChar]) + indentUnitRq = 1; // +1 new scope + break; + } + var statementIndentUnit = svxindentUnit; + rtnIndent = curIndent + (indentUnitRq*statementIndentUnit); + return rtnIndent >= 0 ? rtnIndent : curIndent; + } + + CodeMirror.defineMIME("text/x-svx", { + name: "verilog", + hooks: { + "\\": function(stream, state) { + var vxIndent = 0, style = false; + var curPunc = stream.string; + if ((stream.sol()) && (/\\SV/.test(stream.string))) { + curPunc = (/\\SVX_version/.test(stream.string)) + ? "\\SVX_version" : stream.string; + stream.skipToEnd(); + if (curPunc == "\\SV" && state.vxCodeActive) {state.vxCodeActive = false;}; + if ((/\\SVX/.test(curPunc) && !state.vxCodeActive) + || (curPunc=="\\SVX_version" && state.vxCodeActive)) {state.vxCodeActive = true;}; + style = "keyword"; + state.svxCurCtlFlowChar = state.svxPrevPrevCtlFlowChar + = state.svxPrevCtlFlowChar = ""; + if (state.vxCodeActive == true) { + state.svxCurCtlFlowChar = "\\"; + vxIndent = svxGenIndent(stream, state); + } + state.vxIndentRq = vxIndent; + } + return style; + }, + tokenBase: function(stream, state) { + var vxIndent = 0, style = false; + var svxisOperatorChar = /[\[\]=:]/; + var svxkpScopePrefixs = { + "**":"variable-2", "*":"variable-2", "$$":"variable", "$":"variable", + "^^":"attribute", "^":"attribute"}; + var ch = stream.peek(); + var vxCurCtlFlowCharValueAtStart = state.svxCurCtlFlowChar; + if (state.vxCodeActive == true) { + if (/[\[\]{}\(\);\:]/.test(ch)) { + // bypass nesting and 1 char punc + style = "meta"; + stream.next(); + } else if (ch == "/") { + stream.next(); + if (stream.eat("/")) { + stream.skipToEnd(); + style = "comment"; + state.svxCurCtlFlowChar = "S"; + } else { + stream.backUp(1); + } + } else if (ch == "@") { + // pipeline stage + style = svxchScopePrefixes[ch]; + state.svxCurCtlFlowChar = "@"; + stream.next(); + stream.eatWhile(/[\w\$_]/); + } else if (stream.match(/\b[mM]4+/, true)) { // match: function(pattern, consume, caseInsensitive) + // m4 pre proc + stream.skipTo("("); + style = "def"; + state.svxCurCtlFlowChar = "M"; + } else if (ch == "!" && stream.sol()) { + // v stmt in svx region + // state.svxCurCtlFlowChar = "S"; + style = "comment"; + stream.next(); + } else if (svxisOperatorChar.test(ch)) { + // operators + stream.eatWhile(svxisOperatorChar); + style = "operator"; + } else if (ch == "#") { + // phy hier + state.svxCurCtlFlowChar = (state.svxCurCtlFlowChar == "") + ? ch : state.svxCurCtlFlowChar; + stream.next(); + stream.eatWhile(/[+-]\d/); + style = "tag"; + } else if (svxkpScopePrefixs.propertyIsEnumerable(ch)) { + // special SVX operators + style = svxkpScopePrefixs[ch]; + state.svxCurCtlFlowChar = state.svxCurCtlFlowChar == "" ? "S" : state.svxCurCtlFlowChar; // stmt + stream.next(); + stream.match(/[a-zA-Z_0-9]+/); + } else if (style = svxchScopePrefixes[ch] || false) { + // special SVX operators + state.svxCurCtlFlowChar = state.svxCurCtlFlowChar == "" ? ch : state.svxCurCtlFlowChar; + stream.next(); + stream.match(/[a-zA-Z_0-9]+/); + } + if (state.svxCurCtlFlowChar != vxCurCtlFlowCharValueAtStart) { // flow change + vxIndent = svxGenIndent(stream, state); + state.vxIndentRq = vxIndent; + } + } + return style; + }, + token: function(stream, state) { + if (state.vxCodeActive == true && stream.sol() && state.svxCurCtlFlowChar != "") { + state.svxPrevPrevCtlFlowChar = state.svxPrevCtlFlowChar; + state.svxPrevCtlFlowChar = state.svxCurCtlFlowChar; + state.svxCurCtlFlowChar = ""; + } + }, + indent: function(state) { + return (state.vxCodeActive == true) ? state.vxIndentRq : -1; + }, + startState: function(state) { + state.svxCurCtlFlowChar = ""; + state.svxPrevCtlFlowChar = ""; + state.svxPrevPrevCtlFlowChar = ""; + state.vxCodeActive = true; + state.vxIndentRq = 0; + } + } + }); +}); diff --git a/static/js/mdeditor/lib/codemirror/mode/xml/index.html b/static/js/mdeditor/lib/codemirror/mode/xml/index.html new file mode 100644 index 00000000..7149f06b --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/xml/index.html @@ -0,0 +1,57 @@ + + +CodeMirror: XML mode + + + + + + + + + +
    +

    XML mode

    +
    + +

    The XML mode supports two configuration parameters:

    +
    +
    htmlMode (boolean)
    +
    This switches the mode to parse HTML instead of XML. This + means attributes do not have to be quoted, and some elements + (such as br) do not require a closing tag.
    +
    alignCDATA (boolean)
    +
    Setting this to true will force the opening tag of CDATA + blocks to not be indented.
    +
    + +

    MIME types defined: application/xml, text/html.

    +
    diff --git a/static/js/mdeditor/lib/codemirror/mode/xml/test.js b/static/js/mdeditor/lib/codemirror/mode/xml/test.js new file mode 100644 index 00000000..f48156b5 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/xml/test.js @@ -0,0 +1,51 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function() { + var mode = CodeMirror.getMode({indentUnit: 2}, "xml"), mname = "xml"; + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1), mname); } + + MT("matching", + "[tag&bracket <][tag top][tag&bracket >]", + " text", + " [tag&bracket <][tag inner][tag&bracket />]", + "[tag&bracket ]"); + + MT("nonmatching", + "[tag&bracket <][tag top][tag&bracket >]", + " [tag&bracket <][tag inner][tag&bracket />]", + " [tag&bracket ]"); + + MT("doctype", + "[meta ]", + "[tag&bracket <][tag top][tag&bracket />]"); + + MT("cdata", + "[tag&bracket <][tag top][tag&bracket >]", + " [atom ]", + "[tag&bracket ]"); + + // HTML tests + mode = CodeMirror.getMode({indentUnit: 2}, "text/html"); + + MT("selfclose", + "[tag&bracket <][tag html][tag&bracket >]", + " [tag&bracket <][tag link] [attribute rel]=[string stylesheet] [attribute href]=[string \"/foobar\"][tag&bracket >]", + "[tag&bracket ]"); + + MT("list", + "[tag&bracket <][tag ol][tag&bracket >]", + " [tag&bracket <][tag li][tag&bracket >]one", + " [tag&bracket <][tag li][tag&bracket >]two", + "[tag&bracket ]"); + + MT("valueless", + "[tag&bracket <][tag input] [attribute type]=[string checkbox] [attribute checked][tag&bracket />]"); + + MT("pThenArticle", + "[tag&bracket <][tag p][tag&bracket >]", + " foo", + "[tag&bracket <][tag article][tag&bracket >]bar"); + +})(); diff --git a/static/js/mdeditor/lib/codemirror/mode/xml/xml.js b/static/js/mdeditor/lib/codemirror/mode/xml/xml.js new file mode 100644 index 00000000..2f3b8f87 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/xml/xml.js @@ -0,0 +1,384 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("xml", function(config, parserConfig) { + var indentUnit = config.indentUnit; + var multilineTagIndentFactor = parserConfig.multilineTagIndentFactor || 1; + var multilineTagIndentPastTag = parserConfig.multilineTagIndentPastTag; + if (multilineTagIndentPastTag == null) multilineTagIndentPastTag = true; + + var Kludges = parserConfig.htmlMode ? { + autoSelfClosers: {'area': true, 'base': true, 'br': true, 'col': true, 'command': true, + 'embed': true, 'frame': true, 'hr': true, 'img': true, 'input': true, + 'keygen': true, 'link': true, 'meta': true, 'param': true, 'source': true, + 'track': true, 'wbr': true, 'menuitem': true}, + implicitlyClosed: {'dd': true, 'li': true, 'optgroup': true, 'option': true, 'p': true, + 'rp': true, 'rt': true, 'tbody': true, 'td': true, 'tfoot': true, + 'th': true, 'tr': true}, + contextGrabbers: { + 'dd': {'dd': true, 'dt': true}, + 'dt': {'dd': true, 'dt': true}, + 'li': {'li': true}, + 'option': {'option': true, 'optgroup': true}, + 'optgroup': {'optgroup': true}, + 'p': {'address': true, 'article': true, 'aside': true, 'blockquote': true, 'dir': true, + 'div': true, 'dl': true, 'fieldset': true, 'footer': true, 'form': true, + 'h1': true, 'h2': true, 'h3': true, 'h4': true, 'h5': true, 'h6': true, + 'header': true, 'hgroup': true, 'hr': true, 'menu': true, 'nav': true, 'ol': true, + 'p': true, 'pre': true, 'section': true, 'table': true, 'ul': true}, + 'rp': {'rp': true, 'rt': true}, + 'rt': {'rp': true, 'rt': true}, + 'tbody': {'tbody': true, 'tfoot': true}, + 'td': {'td': true, 'th': true}, + 'tfoot': {'tbody': true}, + 'th': {'td': true, 'th': true}, + 'thead': {'tbody': true, 'tfoot': true}, + 'tr': {'tr': true} + }, + doNotIndent: {"pre": true}, + allowUnquoted: true, + allowMissing: true, + caseFold: true + } : { + autoSelfClosers: {}, + implicitlyClosed: {}, + contextGrabbers: {}, + doNotIndent: {}, + allowUnquoted: false, + allowMissing: false, + caseFold: false + }; + var alignCDATA = parserConfig.alignCDATA; + + // Return variables for tokenizers + var type, setStyle; + + function inText(stream, state) { + function chain(parser) { + state.tokenize = parser; + return parser(stream, state); + } + + var ch = stream.next(); + if (ch == "<") { + if (stream.eat("!")) { + if (stream.eat("[")) { + if (stream.match("CDATA[")) return chain(inBlock("atom", "]]>")); + else return null; + } else if (stream.match("--")) { + return chain(inBlock("comment", "-->")); + } else if (stream.match("DOCTYPE", true, true)) { + stream.eatWhile(/[\w\._\-]/); + return chain(doctype(1)); + } else { + return null; + } + } else if (stream.eat("?")) { + stream.eatWhile(/[\w\._\-]/); + state.tokenize = inBlock("meta", "?>"); + return "meta"; + } else { + type = stream.eat("/") ? "closeTag" : "openTag"; + state.tokenize = inTag; + return "tag bracket"; + } + } else if (ch == "&") { + var ok; + if (stream.eat("#")) { + if (stream.eat("x")) { + ok = stream.eatWhile(/[a-fA-F\d]/) && stream.eat(";"); + } else { + ok = stream.eatWhile(/[\d]/) && stream.eat(";"); + } + } else { + ok = stream.eatWhile(/[\w\.\-:]/) && stream.eat(";"); + } + return ok ? "atom" : "error"; + } else { + stream.eatWhile(/[^&<]/); + return null; + } + } + + function inTag(stream, state) { + var ch = stream.next(); + if (ch == ">" || (ch == "/" && stream.eat(">"))) { + state.tokenize = inText; + type = ch == ">" ? "endTag" : "selfcloseTag"; + return "tag bracket"; + } else if (ch == "=") { + type = "equals"; + return null; + } else if (ch == "<") { + state.tokenize = inText; + state.state = baseState; + state.tagName = state.tagStart = null; + var next = state.tokenize(stream, state); + return next ? next + " tag error" : "tag error"; + } else if (/[\'\"]/.test(ch)) { + state.tokenize = inAttribute(ch); + state.stringStartCol = stream.column(); + return state.tokenize(stream, state); + } else { + stream.match(/^[^\s\u00a0=<>\"\']*[^\s\u00a0=<>\"\'\/]/); + return "word"; + } + } + + function inAttribute(quote) { + var closure = function(stream, state) { + while (!stream.eol()) { + if (stream.next() == quote) { + state.tokenize = inTag; + break; + } + } + return "string"; + }; + closure.isInAttribute = true; + return closure; + } + + function inBlock(style, terminator) { + return function(stream, state) { + while (!stream.eol()) { + if (stream.match(terminator)) { + state.tokenize = inText; + break; + } + stream.next(); + } + return style; + }; + } + function doctype(depth) { + return function(stream, state) { + var ch; + while ((ch = stream.next()) != null) { + if (ch == "<") { + state.tokenize = doctype(depth + 1); + return state.tokenize(stream, state); + } else if (ch == ">") { + if (depth == 1) { + state.tokenize = inText; + break; + } else { + state.tokenize = doctype(depth - 1); + return state.tokenize(stream, state); + } + } + } + return "meta"; + }; + } + + function Context(state, tagName, startOfLine) { + this.prev = state.context; + this.tagName = tagName; + this.indent = state.indented; + this.startOfLine = startOfLine; + if (Kludges.doNotIndent.hasOwnProperty(tagName) || (state.context && state.context.noIndent)) + this.noIndent = true; + } + function popContext(state) { + if (state.context) state.context = state.context.prev; + } + function maybePopContext(state, nextTagName) { + var parentTagName; + while (true) { + if (!state.context) { + return; + } + parentTagName = state.context.tagName; + if (!Kludges.contextGrabbers.hasOwnProperty(parentTagName) || + !Kludges.contextGrabbers[parentTagName].hasOwnProperty(nextTagName)) { + return; + } + popContext(state); + } + } + + function baseState(type, stream, state) { + if (type == "openTag") { + state.tagStart = stream.column(); + return tagNameState; + } else if (type == "closeTag") { + return closeTagNameState; + } else { + return baseState; + } + } + function tagNameState(type, stream, state) { + if (type == "word") { + state.tagName = stream.current(); + setStyle = "tag"; + return attrState; + } else { + setStyle = "error"; + return tagNameState; + } + } + function closeTagNameState(type, stream, state) { + if (type == "word") { + var tagName = stream.current(); + if (state.context && state.context.tagName != tagName && + Kludges.implicitlyClosed.hasOwnProperty(state.context.tagName)) + popContext(state); + if (state.context && state.context.tagName == tagName) { + setStyle = "tag"; + return closeState; + } else { + setStyle = "tag error"; + return closeStateErr; + } + } else { + setStyle = "error"; + return closeStateErr; + } + } + + function closeState(type, _stream, state) { + if (type != "endTag") { + setStyle = "error"; + return closeState; + } + popContext(state); + return baseState; + } + function closeStateErr(type, stream, state) { + setStyle = "error"; + return closeState(type, stream, state); + } + + function attrState(type, _stream, state) { + if (type == "word") { + setStyle = "attribute"; + return attrEqState; + } else if (type == "endTag" || type == "selfcloseTag") { + var tagName = state.tagName, tagStart = state.tagStart; + state.tagName = state.tagStart = null; + if (type == "selfcloseTag" || + Kludges.autoSelfClosers.hasOwnProperty(tagName)) { + maybePopContext(state, tagName); + } else { + maybePopContext(state, tagName); + state.context = new Context(state, tagName, tagStart == state.indented); + } + return baseState; + } + setStyle = "error"; + return attrState; + } + function attrEqState(type, stream, state) { + if (type == "equals") return attrValueState; + if (!Kludges.allowMissing) setStyle = "error"; + return attrState(type, stream, state); + } + function attrValueState(type, stream, state) { + if (type == "string") return attrContinuedState; + if (type == "word" && Kludges.allowUnquoted) {setStyle = "string"; return attrState;} + setStyle = "error"; + return attrState(type, stream, state); + } + function attrContinuedState(type, stream, state) { + if (type == "string") return attrContinuedState; + return attrState(type, stream, state); + } + + return { + startState: function() { + return {tokenize: inText, + state: baseState, + indented: 0, + tagName: null, tagStart: null, + context: null}; + }, + + token: function(stream, state) { + if (!state.tagName && stream.sol()) + state.indented = stream.indentation(); + + if (stream.eatSpace()) return null; + type = null; + var style = state.tokenize(stream, state); + if ((style || type) && style != "comment") { + setStyle = null; + state.state = state.state(type || style, stream, state); + if (setStyle) + style = setStyle == "error" ? style + " error" : setStyle; + } + return style; + }, + + indent: function(state, textAfter, fullLine) { + var context = state.context; + // Indent multi-line strings (e.g. css). + if (state.tokenize.isInAttribute) { + if (state.tagStart == state.indented) + return state.stringStartCol + 1; + else + return state.indented + indentUnit; + } + if (context && context.noIndent) return CodeMirror.Pass; + if (state.tokenize != inTag && state.tokenize != inText) + return fullLine ? fullLine.match(/^(\s*)/)[0].length : 0; + // Indent the starts of attribute names. + if (state.tagName) { + if (multilineTagIndentPastTag) + return state.tagStart + state.tagName.length + 2; + else + return state.tagStart + indentUnit * multilineTagIndentFactor; + } + if (alignCDATA && /$/, + blockCommentStart: "", + + configuration: parserConfig.htmlMode ? "html" : "xml", + helperType: parserConfig.htmlMode ? "html" : "xml" + }; +}); + +CodeMirror.defineMIME("text/xml", "xml"); +CodeMirror.defineMIME("application/xml", "xml"); +if (!CodeMirror.mimeModes.hasOwnProperty("text/html")) + CodeMirror.defineMIME("text/html", {name: "xml", htmlMode: true}); + +}); diff --git a/static/js/mdeditor/lib/codemirror/mode/xquery/index.html b/static/js/mdeditor/lib/codemirror/mode/xquery/index.html new file mode 100644 index 00000000..7ac5aaef --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/xquery/index.html @@ -0,0 +1,210 @@ + + +CodeMirror: XQuery mode + + + + + + + + + + +
    +

    XQuery mode

    + + +
    + +
    + + + +

    MIME types defined: application/xquery.

    + +

    Development of the CodeMirror XQuery mode was sponsored by + MarkLogic and developed by + Mike Brevoort. +

    + +
    diff --git a/static/js/mdeditor/lib/codemirror/mode/xquery/test.js b/static/js/mdeditor/lib/codemirror/mode/xquery/test.js new file mode 100644 index 00000000..1f148cdb --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/xquery/test.js @@ -0,0 +1,67 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// Don't take these too seriously -- the expected results appear to be +// based on the results of actual runs without any serious manual +// verification. If a change you made causes them to fail, the test is +// as likely to wrong as the code. + +(function() { + var mode = CodeMirror.getMode({tabSize: 4}, "xquery"); + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); } + + MT("eviltest", + "[keyword xquery] [keyword version] [variable "1][keyword .][atom 0][keyword -][variable ml"][def&variable ;] [comment (: this is : a \"comment\" :)]", + " [keyword let] [variable $let] [keyword :=] [variable <x] [variable attr][keyword =][variable "value">"test"<func>][def&variable ;function]() [variable $var] {[keyword function]()} {[variable $var]}[variable <][keyword /][variable func><][keyword /][variable x>]", + " [keyword let] [variable $joe][keyword :=][atom 1]", + " [keyword return] [keyword element] [variable element] {", + " [keyword attribute] [variable attribute] { [atom 1] },", + " [keyword element] [variable test] { [variable 'a'] }, [keyword attribute] [variable foo] { [variable "bar"] },", + " [def&variable fn:doc]()[[ [variable foo][keyword /][variable @bar] [keyword eq] [variable $let] ]],", + " [keyword //][variable x] } [comment (: a more 'evil' test :)]", + " [comment (: Modified Blakeley example (: with nested comment :) ... :)]", + " [keyword declare] [keyword private] [keyword function] [def&variable local:declare]() {()}[variable ;]", + " [keyword declare] [keyword private] [keyword function] [def&variable local:private]() {()}[variable ;]", + " [keyword declare] [keyword private] [keyword function] [def&variable local:function]() {()}[variable ;]", + " [keyword declare] [keyword private] [keyword function] [def&variable local:local]() {()}[variable ;]", + " [keyword let] [variable $let] [keyword :=] [variable <let>let] [variable $let] [keyword :=] [variable "let"<][keyword /let][variable >]", + " [keyword return] [keyword element] [variable element] {", + " [keyword attribute] [variable attribute] { [keyword try] { [def&variable xdmp:version]() } [keyword catch]([variable $e]) { [def&variable xdmp:log]([variable $e]) } },", + " [keyword attribute] [variable fn:doc] { [variable "bar"] [variable castable] [keyword as] [atom xs:string] },", + " [keyword element] [variable text] { [keyword text] { [variable "text"] } },", + " [def&variable fn:doc]()[[ [qualifier child::][variable eq][keyword /]([variable @bar] [keyword |] [qualifier attribute::][variable attribute]) [keyword eq] [variable $let] ]],", + " [keyword //][variable fn:doc]", + " }"); + + MT("testEmptySequenceKeyword", + "[string \"foo\"] [keyword instance] [keyword of] [keyword empty-sequence]()"); + + MT("testMultiAttr", + "[tag

    ][variable hello] [variable world][tag

    ]"); + + MT("test namespaced variable", + "[keyword declare] [keyword namespace] [variable e] [keyword =] [string \"http://example.com/ANamespace\"][variable ;declare] [keyword variable] [variable $e:exampleComThisVarIsNotRecognized] [keyword as] [keyword element]([keyword *]) [variable external;]"); + + MT("test EQName variable", + "[keyword declare] [keyword variable] [variable $\"http://www.example.com/ns/my\":var] [keyword :=] [atom 12][variable ;]", + "[tag ]{[variable $\"http://www.example.com/ns/my\":var]}[tag ]"); + + MT("test EQName function", + "[keyword declare] [keyword function] [def&variable \"http://www.example.com/ns/my\":fn] ([variable $a] [keyword as] [atom xs:integer]) [keyword as] [atom xs:integer] {", + " [variable $a] [keyword +] [atom 2]", + "}[variable ;]", + "[tag ]{[def&variable \"http://www.example.com/ns/my\":fn]([atom 12])}[tag ]"); + + MT("test EQName function with single quotes", + "[keyword declare] [keyword function] [def&variable 'http://www.example.com/ns/my':fn] ([variable $a] [keyword as] [atom xs:integer]) [keyword as] [atom xs:integer] {", + " [variable $a] [keyword +] [atom 2]", + "}[variable ;]", + "[tag ]{[def&variable 'http://www.example.com/ns/my':fn]([atom 12])}[tag ]"); + + MT("testProcessingInstructions", + "[def&variable data]([comment&meta ]) [keyword instance] [keyword of] [atom xs:string]"); + + MT("testQuoteEscapeDouble", + "[keyword let] [variable $rootfolder] [keyword :=] [string \"c:\\builds\\winnt\\HEAD\\qa\\scripts\\\"]", + "[keyword let] [variable $keysfolder] [keyword :=] [def&variable concat]([variable $rootfolder], [string \"keys\\\"])"); +})(); diff --git a/static/js/mdeditor/lib/codemirror/mode/xquery/xquery.js b/static/js/mdeditor/lib/codemirror/mode/xquery/xquery.js new file mode 100644 index 00000000..c8f3d90a --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/xquery/xquery.js @@ -0,0 +1,447 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("xquery", function() { + + // The keywords object is set to the result of this self executing + // function. Each keyword is a property of the keywords object whose + // value is {type: atype, style: astyle} + var keywords = function(){ + // conveinence functions used to build keywords object + function kw(type) {return {type: type, style: "keyword"};} + var A = kw("keyword a") + , B = kw("keyword b") + , C = kw("keyword c") + , operator = kw("operator") + , atom = {type: "atom", style: "atom"} + , punctuation = {type: "punctuation", style: null} + , qualifier = {type: "axis_specifier", style: "qualifier"}; + + // kwObj is what is return from this function at the end + var kwObj = { + 'if': A, 'switch': A, 'while': A, 'for': A, + 'else': B, 'then': B, 'try': B, 'finally': B, 'catch': B, + 'element': C, 'attribute': C, 'let': C, 'implements': C, 'import': C, 'module': C, 'namespace': C, + 'return': C, 'super': C, 'this': C, 'throws': C, 'where': C, 'private': C, + ',': punctuation, + 'null': atom, 'fn:false()': atom, 'fn:true()': atom + }; + + // a list of 'basic' keywords. For each add a property to kwObj with the value of + // {type: basic[i], style: "keyword"} e.g. 'after' --> {type: "after", style: "keyword"} + var basic = ['after','ancestor','ancestor-or-self','and','as','ascending','assert','attribute','before', + 'by','case','cast','child','comment','declare','default','define','descendant','descendant-or-self', + 'descending','document','document-node','element','else','eq','every','except','external','following', + 'following-sibling','follows','for','function','if','import','in','instance','intersect','item', + 'let','module','namespace','node','node','of','only','or','order','parent','precedes','preceding', + 'preceding-sibling','processing-instruction','ref','return','returns','satisfies','schema','schema-element', + 'self','some','sortby','stable','text','then','to','treat','typeswitch','union','variable','version','where', + 'xquery', 'empty-sequence']; + for(var i=0, l=basic.length; i < l; i++) { kwObj[basic[i]] = kw(basic[i]);}; + + // a list of types. For each add a property to kwObj with the value of + // {type: "atom", style: "atom"} + var types = ['xs:string', 'xs:float', 'xs:decimal', 'xs:double', 'xs:integer', 'xs:boolean', 'xs:date', 'xs:dateTime', + 'xs:time', 'xs:duration', 'xs:dayTimeDuration', 'xs:time', 'xs:yearMonthDuration', 'numeric', 'xs:hexBinary', + 'xs:base64Binary', 'xs:anyURI', 'xs:QName', 'xs:byte','xs:boolean','xs:anyURI','xf:yearMonthDuration']; + for(var i=0, l=types.length; i < l; i++) { kwObj[types[i]] = atom;}; + + // each operator will add a property to kwObj with value of {type: "operator", style: "keyword"} + var operators = ['eq', 'ne', 'lt', 'le', 'gt', 'ge', ':=', '=', '>', '>=', '<', '<=', '.', '|', '?', 'and', 'or', 'div', 'idiv', 'mod', '*', '/', '+', '-']; + for(var i=0, l=operators.length; i < l; i++) { kwObj[operators[i]] = operator;}; + + // each axis_specifiers will add a property to kwObj with value of {type: "axis_specifier", style: "qualifier"} + var axis_specifiers = ["self::", "attribute::", "child::", "descendant::", "descendant-or-self::", "parent::", + "ancestor::", "ancestor-or-self::", "following::", "preceding::", "following-sibling::", "preceding-sibling::"]; + for(var i=0, l=axis_specifiers.length; i < l; i++) { kwObj[axis_specifiers[i]] = qualifier; }; + + return kwObj; + }(); + + // Used as scratch variables to communicate multiple values without + // consing up tons of objects. + var type, content; + + function ret(tp, style, cont) { + type = tp; content = cont; + return style; + } + + function chain(stream, state, f) { + state.tokenize = f; + return f(stream, state); + } + + // the primary mode tokenizer + function tokenBase(stream, state) { + var ch = stream.next(), + mightBeFunction = false, + isEQName = isEQNameAhead(stream); + + // an XML tag (if not in some sub, chained tokenizer) + if (ch == "<") { + if(stream.match("!--", true)) + return chain(stream, state, tokenXMLComment); + + if(stream.match("![CDATA", false)) { + state.tokenize = tokenCDATA; + return ret("tag", "tag"); + } + + if(stream.match("?", false)) { + return chain(stream, state, tokenPreProcessing); + } + + var isclose = stream.eat("/"); + stream.eatSpace(); + var tagName = "", c; + while ((c = stream.eat(/[^\s\u00a0=<>\"\'\/?]/))) tagName += c; + + return chain(stream, state, tokenTag(tagName, isclose)); + } + // start code block + else if(ch == "{") { + pushStateStack(state,{ type: "codeblock"}); + return ret("", null); + } + // end code block + else if(ch == "}") { + popStateStack(state); + return ret("", null); + } + // if we're in an XML block + else if(isInXmlBlock(state)) { + if(ch == ">") + return ret("tag", "tag"); + else if(ch == "/" && stream.eat(">")) { + popStateStack(state); + return ret("tag", "tag"); + } + else + return ret("word", "variable"); + } + // if a number + else if (/\d/.test(ch)) { + stream.match(/^\d*(?:\.\d*)?(?:E[+\-]?\d+)?/); + return ret("number", "atom"); + } + // comment start + else if (ch === "(" && stream.eat(":")) { + pushStateStack(state, { type: "comment"}); + return chain(stream, state, tokenComment); + } + // quoted string + else if ( !isEQName && (ch === '"' || ch === "'")) + return chain(stream, state, tokenString(ch)); + // variable + else if(ch === "$") { + return chain(stream, state, tokenVariable); + } + // assignment + else if(ch ===":" && stream.eat("=")) { + return ret("operator", "keyword"); + } + // open paren + else if(ch === "(") { + pushStateStack(state, { type: "paren"}); + return ret("", null); + } + // close paren + else if(ch === ")") { + popStateStack(state); + return ret("", null); + } + // open paren + else if(ch === "[") { + pushStateStack(state, { type: "bracket"}); + return ret("", null); + } + // close paren + else if(ch === "]") { + popStateStack(state); + return ret("", null); + } + else { + var known = keywords.propertyIsEnumerable(ch) && keywords[ch]; + + // if there's a EQName ahead, consume the rest of the string portion, it's likely a function + if(isEQName && ch === '\"') while(stream.next() !== '"'){} + if(isEQName && ch === '\'') while(stream.next() !== '\''){} + + // gobble up a word if the character is not known + if(!known) stream.eatWhile(/[\w\$_-]/); + + // gobble a colon in the case that is a lib func type call fn:doc + var foundColon = stream.eat(":"); + + // if there's not a second colon, gobble another word. Otherwise, it's probably an axis specifier + // which should get matched as a keyword + if(!stream.eat(":") && foundColon) { + stream.eatWhile(/[\w\$_-]/); + } + // if the next non whitespace character is an open paren, this is probably a function (if not a keyword of other sort) + if(stream.match(/^[ \t]*\(/, false)) { + mightBeFunction = true; + } + // is the word a keyword? + var word = stream.current(); + known = keywords.propertyIsEnumerable(word) && keywords[word]; + + // if we think it's a function call but not yet known, + // set style to variable for now for lack of something better + if(mightBeFunction && !known) known = {type: "function_call", style: "variable def"}; + + // if the previous word was element, attribute, axis specifier, this word should be the name of that + if(isInXmlConstructor(state)) { + popStateStack(state); + return ret("word", "variable", word); + } + // as previously checked, if the word is element,attribute, axis specifier, call it an "xmlconstructor" and + // push the stack so we know to look for it on the next word + if(word == "element" || word == "attribute" || known.type == "axis_specifier") pushStateStack(state, {type: "xmlconstructor"}); + + // if the word is known, return the details of that else just call this a generic 'word' + return known ? ret(known.type, known.style, word) : + ret("word", "variable", word); + } + } + + // handle comments, including nested + function tokenComment(stream, state) { + var maybeEnd = false, maybeNested = false, nestedCount = 0, ch; + while (ch = stream.next()) { + if (ch == ")" && maybeEnd) { + if(nestedCount > 0) + nestedCount--; + else { + popStateStack(state); + break; + } + } + else if(ch == ":" && maybeNested) { + nestedCount++; + } + maybeEnd = (ch == ":"); + maybeNested = (ch == "("); + } + + return ret("comment", "comment"); + } + + // tokenizer for string literals + // optionally pass a tokenizer function to set state.tokenize back to when finished + function tokenString(quote, f) { + return function(stream, state) { + var ch; + + if(isInString(state) && stream.current() == quote) { + popStateStack(state); + if(f) state.tokenize = f; + return ret("string", "string"); + } + + pushStateStack(state, { type: "string", name: quote, tokenize: tokenString(quote, f) }); + + // if we're in a string and in an XML block, allow an embedded code block + if(stream.match("{", false) && isInXmlAttributeBlock(state)) { + state.tokenize = tokenBase; + return ret("string", "string"); + } + + + while (ch = stream.next()) { + if (ch == quote) { + popStateStack(state); + if(f) state.tokenize = f; + break; + } + else { + // if we're in a string and in an XML block, allow an embedded code block in an attribute + if(stream.match("{", false) && isInXmlAttributeBlock(state)) { + state.tokenize = tokenBase; + return ret("string", "string"); + } + + } + } + + return ret("string", "string"); + }; + } + + // tokenizer for variables + function tokenVariable(stream, state) { + var isVariableChar = /[\w\$_-]/; + + // a variable may start with a quoted EQName so if the next character is quote, consume to the next quote + if(stream.eat("\"")) { + while(stream.next() !== '\"'){}; + stream.eat(":"); + } else { + stream.eatWhile(isVariableChar); + if(!stream.match(":=", false)) stream.eat(":"); + } + stream.eatWhile(isVariableChar); + state.tokenize = tokenBase; + return ret("variable", "variable"); + } + + // tokenizer for XML tags + function tokenTag(name, isclose) { + return function(stream, state) { + stream.eatSpace(); + if(isclose && stream.eat(">")) { + popStateStack(state); + state.tokenize = tokenBase; + return ret("tag", "tag"); + } + // self closing tag without attributes? + if(!stream.eat("/")) + pushStateStack(state, { type: "tag", name: name, tokenize: tokenBase}); + if(!stream.eat(">")) { + state.tokenize = tokenAttribute; + return ret("tag", "tag"); + } + else { + state.tokenize = tokenBase; + } + return ret("tag", "tag"); + }; + } + + // tokenizer for XML attributes + function tokenAttribute(stream, state) { + var ch = stream.next(); + + if(ch == "/" && stream.eat(">")) { + if(isInXmlAttributeBlock(state)) popStateStack(state); + if(isInXmlBlock(state)) popStateStack(state); + return ret("tag", "tag"); + } + if(ch == ">") { + if(isInXmlAttributeBlock(state)) popStateStack(state); + return ret("tag", "tag"); + } + if(ch == "=") + return ret("", null); + // quoted string + if (ch == '"' || ch == "'") + return chain(stream, state, tokenString(ch, tokenAttribute)); + + if(!isInXmlAttributeBlock(state)) + pushStateStack(state, { type: "attribute", tokenize: tokenAttribute}); + + stream.eat(/[a-zA-Z_:]/); + stream.eatWhile(/[-a-zA-Z0-9_:.]/); + stream.eatSpace(); + + // the case where the attribute has not value and the tag was closed + if(stream.match(">", false) || stream.match("/", false)) { + popStateStack(state); + state.tokenize = tokenBase; + } + + return ret("attribute", "attribute"); + } + + // handle comments, including nested + function tokenXMLComment(stream, state) { + var ch; + while (ch = stream.next()) { + if (ch == "-" && stream.match("->", true)) { + state.tokenize = tokenBase; + return ret("comment", "comment"); + } + } + } + + + // handle CDATA + function tokenCDATA(stream, state) { + var ch; + while (ch = stream.next()) { + if (ch == "]" && stream.match("]", true)) { + state.tokenize = tokenBase; + return ret("comment", "comment"); + } + } + } + + // handle preprocessing instructions + function tokenPreProcessing(stream, state) { + var ch; + while (ch = stream.next()) { + if (ch == "?" && stream.match(">", true)) { + state.tokenize = tokenBase; + return ret("comment", "comment meta"); + } + } + } + + + // functions to test the current context of the state + function isInXmlBlock(state) { return isIn(state, "tag"); } + function isInXmlAttributeBlock(state) { return isIn(state, "attribute"); } + function isInXmlConstructor(state) { return isIn(state, "xmlconstructor"); } + function isInString(state) { return isIn(state, "string"); } + + function isEQNameAhead(stream) { + // assume we've already eaten a quote (") + if(stream.current() === '"') + return stream.match(/^[^\"]+\"\:/, false); + else if(stream.current() === '\'') + return stream.match(/^[^\"]+\'\:/, false); + else + return false; + } + + function isIn(state, type) { + return (state.stack.length && state.stack[state.stack.length - 1].type == type); + } + + function pushStateStack(state, newState) { + state.stack.push(newState); + } + + function popStateStack(state) { + state.stack.pop(); + var reinstateTokenize = state.stack.length && state.stack[state.stack.length-1].tokenize; + state.tokenize = reinstateTokenize || tokenBase; + } + + // the interface for the mode API + return { + startState: function() { + return { + tokenize: tokenBase, + cc: [], + stack: [] + }; + }, + + token: function(stream, state) { + if (stream.eatSpace()) return null; + var style = state.tokenize(stream, state); + return style; + }, + + blockCommentStart: "(:", + blockCommentEnd: ":)" + + }; + +}); + +CodeMirror.defineMIME("application/xquery", "xquery"); + +}); diff --git a/static/js/mdeditor/lib/codemirror/mode/yaml/index.html b/static/js/mdeditor/lib/codemirror/mode/yaml/index.html new file mode 100644 index 00000000..be9b6323 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/yaml/index.html @@ -0,0 +1,80 @@ + + +CodeMirror: YAML mode + + + + + + + + + +
    +

    YAML mode

    +
    + + +

    MIME types defined: text/x-yaml.

    + +
    diff --git a/static/js/mdeditor/lib/codemirror/mode/yaml/yaml.js b/static/js/mdeditor/lib/codemirror/mode/yaml/yaml.js new file mode 100644 index 00000000..b7015e59 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/yaml/yaml.js @@ -0,0 +1,117 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("yaml", function() { + + var cons = ['true', 'false', 'on', 'off', 'yes', 'no']; + var keywordRegex = new RegExp("\\b(("+cons.join(")|(")+"))$", 'i'); + + return { + token: function(stream, state) { + var ch = stream.peek(); + var esc = state.escaped; + state.escaped = false; + /* comments */ + if (ch == "#" && (stream.pos == 0 || /\s/.test(stream.string.charAt(stream.pos - 1)))) { + stream.skipToEnd(); + return "comment"; + } + + if (stream.match(/^('([^']|\\.)*'?|"([^"]|\\.)*"?)/)) + return "string"; + + if (state.literal && stream.indentation() > state.keyCol) { + stream.skipToEnd(); return "string"; + } else if (state.literal) { state.literal = false; } + if (stream.sol()) { + state.keyCol = 0; + state.pair = false; + state.pairStart = false; + /* document start */ + if(stream.match(/---/)) { return "def"; } + /* document end */ + if (stream.match(/\.\.\./)) { return "def"; } + /* array list item */ + if (stream.match(/\s*-\s+/)) { return 'meta'; } + } + /* inline pairs/lists */ + if (stream.match(/^(\{|\}|\[|\])/)) { + if (ch == '{') + state.inlinePairs++; + else if (ch == '}') + state.inlinePairs--; + else if (ch == '[') + state.inlineList++; + else + state.inlineList--; + return 'meta'; + } + + /* list seperator */ + if (state.inlineList > 0 && !esc && ch == ',') { + stream.next(); + return 'meta'; + } + /* pairs seperator */ + if (state.inlinePairs > 0 && !esc && ch == ',') { + state.keyCol = 0; + state.pair = false; + state.pairStart = false; + stream.next(); + return 'meta'; + } + + /* start of value of a pair */ + if (state.pairStart) { + /* block literals */ + if (stream.match(/^\s*(\||\>)\s*/)) { state.literal = true; return 'meta'; }; + /* references */ + if (stream.match(/^\s*(\&|\*)[a-z0-9\._-]+\b/i)) { return 'variable-2'; } + /* numbers */ + if (state.inlinePairs == 0 && stream.match(/^\s*-?[0-9\.\,]+\s?$/)) { return 'number'; } + if (state.inlinePairs > 0 && stream.match(/^\s*-?[0-9\.\,]+\s?(?=(,|}))/)) { return 'number'; } + /* keywords */ + if (stream.match(keywordRegex)) { return 'keyword'; } + } + + /* pairs (associative arrays) -> key */ + if (!state.pair && stream.match(/^\s*(?:[,\[\]{}&*!|>'"%@`][^\s'":]|[^,\[\]{}#&*!|>'"%@`])[^#]*?(?=\s*:($|\s))/)) { + state.pair = true; + state.keyCol = stream.indentation(); + return "atom"; + } + if (state.pair && stream.match(/^:\s*/)) { state.pairStart = true; return 'meta'; } + + /* nothing found, continue */ + state.pairStart = false; + state.escaped = (ch == '\\'); + stream.next(); + return null; + }, + startState: function() { + return { + pair: false, + pairStart: false, + keyCol: 0, + inlinePairs: 0, + inlineList: 0, + literal: false, + escaped: false + }; + } + }; +}); + +CodeMirror.defineMIME("text/x-yaml", "yaml"); + +}); diff --git a/static/js/mdeditor/lib/codemirror/mode/z80/index.html b/static/js/mdeditor/lib/codemirror/mode/z80/index.html new file mode 100644 index 00000000..1ad3ace0 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/z80/index.html @@ -0,0 +1,52 @@ + + +CodeMirror: Z80 assembly mode + + + + + + + + + +
    +

    Z80 assembly mode

    + + +
    + + + +

    MIME type defined: text/x-z80.

    +
    diff --git a/static/js/mdeditor/lib/codemirror/mode/z80/z80.js b/static/js/mdeditor/lib/codemirror/mode/z80/z80.js new file mode 100644 index 00000000..ec41d050 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/mode/z80/z80.js @@ -0,0 +1,100 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode('z80', function() { + var keywords1 = /^(exx?|(ld|cp|in)([di]r?)?|pop|push|ad[cd]|cpl|daa|dec|inc|neg|sbc|sub|and|bit|[cs]cf|x?or|res|set|r[lr]c?a?|r[lr]d|s[lr]a|srl|djnz|nop|rst|[de]i|halt|im|ot[di]r|out[di]?)\b/i; + var keywords2 = /^(call|j[pr]|ret[in]?)\b/i; + var keywords3 = /^b_?(call|jump)\b/i; + var variables1 = /^(af?|bc?|c|de?|e|hl?|l|i[xy]?|r|sp)\b/i; + var variables2 = /^(n?[zc]|p[oe]?|m)\b/i; + var errors = /^([hl][xy]|i[xy][hl]|slia|sll)\b/i; + var numbers = /^([\da-f]+h|[0-7]+o|[01]+b|\d+)\b/i; + + return { + startState: function() { + return {context: 0}; + }, + token: function(stream, state) { + if (!stream.column()) + state.context = 0; + + if (stream.eatSpace()) + return null; + + var w; + + if (stream.eatWhile(/\w/)) { + w = stream.current(); + + if (stream.indentation()) { + if (state.context == 1 && variables1.test(w)) + return 'variable-2'; + + if (state.context == 2 && variables2.test(w)) + return 'variable-3'; + + if (keywords1.test(w)) { + state.context = 1; + return 'keyword'; + } else if (keywords2.test(w)) { + state.context = 2; + return 'keyword'; + } else if (keywords3.test(w)) { + state.context = 3; + return 'keyword'; + } + + if (errors.test(w)) + return 'error'; + } else if (numbers.test(w)) { + return 'number'; + } else { + return null; + } + } else if (stream.eat(';')) { + stream.skipToEnd(); + return 'comment'; + } else if (stream.eat('"')) { + while (w = stream.next()) { + if (w == '"') + break; + + if (w == '\\') + stream.next(); + } + return 'string'; + } else if (stream.eat('\'')) { + if (stream.match(/\\?.'/)) + return 'number'; + } else if (stream.eat('.') || stream.sol() && stream.eat('#')) { + state.context = 4; + + if (stream.eatWhile(/\w/)) + return 'def'; + } else if (stream.eat('$')) { + if (stream.eatWhile(/[\da-f]/i)) + return 'number'; + } else if (stream.eat('%')) { + if (stream.eatWhile(/[01]/)) + return 'number'; + } else { + stream.next(); + } + return null; + } + }; +}); + +CodeMirror.defineMIME("text/x-z80", "z80"); + +}); diff --git a/static/js/mdeditor/lib/codemirror/modes.min.js b/static/js/mdeditor/lib/codemirror/modes.min.js new file mode 100644 index 00000000..49faebea --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/modes.min.js @@ -0,0 +1,10 @@ +/*! Editor.md v1.5.0 | modes.min.js | Open source online markdown editor. | MIT License | By: Pandao | https://github.com/pandao/editor.md | 2015-06-09 */ +!function(e){"object"==typeof exports&&"object"==typeof module?e(require("../lib/codemirror")):"function"==typeof define&&define.amd?define(["../lib/codemirror"],e):e(CodeMirror)}(function(e){"use strict";e.modeInfo=[{name:"APL",mime:"text/apl",mode:"apl",ext:["dyalog","apl"]},{name:"Asterisk",mime:"text/x-asterisk",mode:"asterisk",file:/^extensions\.conf$/i},{name:"C",mime:"text/x-csrc",mode:"clike",ext:["c","h"]},{name:"C++",mime:"text/x-c++src",mode:"clike",ext:["cpp","c++","cc","cxx","hpp","h++","hh","hxx"],alias:["cpp"]},{name:"Cobol",mime:"text/x-cobol",mode:"cobol",ext:["cob","cpy"]},{name:"C#",mime:"text/x-csharp",mode:"clike",ext:["cs"],alias:["csharp"]},{name:"Clojure",mime:"text/x-clojure",mode:"clojure",ext:["clj"]},{name:"CoffeeScript",mime:"text/x-coffeescript",mode:"coffeescript",ext:["coffee"],alias:["coffee","coffee-script"]},{name:"Common Lisp",mime:"text/x-common-lisp",mode:"commonlisp",ext:["cl","lisp","el"],alias:["lisp"]},{name:"Cypher",mime:"application/x-cypher-query",mode:"cypher",ext:["cyp","cypher"]},{name:"Cython",mime:"text/x-cython",mode:"python",ext:["pyx","pxd","pxi"]},{name:"CSS",mime:"text/css",mode:"css",ext:["css"]},{name:"CQL",mime:"text/x-cassandra",mode:"sql",ext:["cql"]},{name:"D",mime:"text/x-d",mode:"d",ext:["d"]},{name:"Dart",mimes:["application/dart","text/x-dart"],mode:"dart",ext:["dart"]},{name:"diff",mime:"text/x-diff",mode:"diff",ext:["diff","patch"]},{name:"Django",mime:"text/x-django",mode:"django"},{name:"Dockerfile",mime:"text/x-dockerfile",mode:"dockerfile",file:/^Dockerfile$/},{name:"DTD",mime:"application/xml-dtd",mode:"dtd",ext:["dtd"]},{name:"Dylan",mime:"text/x-dylan",mode:"dylan",ext:["dylan","dyl","intr"]},{name:"EBNF",mime:"text/x-ebnf",mode:"ebnf"},{name:"ECL",mime:"text/x-ecl",mode:"ecl",ext:["ecl"]},{name:"Eiffel",mime:"text/x-eiffel",mode:"eiffel",ext:["e"]},{name:"Embedded Javascript",mime:"application/x-ejs",mode:"htmlembedded",ext:["ejs"]},{name:"Embedded Ruby",mime:"application/x-erb",mode:"htmlembedded",ext:["erb"]},{name:"Erlang",mime:"text/x-erlang",mode:"erlang",ext:["erl"]},{name:"Forth",mime:"text/x-forth",mode:"forth",ext:["forth","fth","4th"]},{name:"Fortran",mime:"text/x-fortran",mode:"fortran",ext:["f","for","f77","f90"]},{name:"F#",mime:"text/x-fsharp",mode:"mllike",ext:["fs"],alias:["fsharp"]},{name:"Gas",mime:"text/x-gas",mode:"gas",ext:["s"]},{name:"Gherkin",mime:"text/x-feature",mode:"gherkin",ext:["feature"]},{name:"GitHub Flavored Markdown",mime:"text/x-gfm",mode:"gfm",file:/^(readme|contributing|history).md$/i},{name:"Go",mime:"text/x-go",mode:"go",ext:["go"]},{name:"Groovy",mime:"text/x-groovy",mode:"groovy",ext:["groovy"]},{name:"HAML",mime:"text/x-haml",mode:"haml",ext:["haml"]},{name:"Haskell",mime:"text/x-haskell",mode:"haskell",ext:["hs"]},{name:"Haxe",mime:"text/x-haxe",mode:"haxe",ext:["hx"]},{name:"HXML",mime:"text/x-hxml",mode:"haxe",ext:["hxml"]},{name:"ASP.NET",mime:"application/x-aspx",mode:"htmlembedded",ext:["aspx"],alias:["asp","aspx"]},{name:"HTML",mime:"text/html",mode:"htmlmixed",ext:["html","htm"],alias:["xhtml"]},{name:"HTTP",mime:"message/http",mode:"http"},{name:"IDL",mime:"text/x-idl",mode:"idl",ext:["pro"]},{name:"Jade",mime:"text/x-jade",mode:"jade",ext:["jade"]},{name:"Java",mime:"text/x-java",mode:"clike",ext:["java"]},{name:"Java Server Pages",mime:"application/x-jsp",mode:"htmlembedded",ext:["jsp"],alias:["jsp"]},{name:"JavaScript",mimes:["text/javascript","text/ecmascript","application/javascript","application/x-javascript","application/ecmascript"],mode:"javascript",ext:["js"],alias:["ecmascript","js","node"]},{name:"JSON",mimes:["application/json","application/x-json"],mode:"javascript",ext:["json","map"],alias:["json5"]},{name:"JSON-LD",mime:"application/ld+json",mode:"javascript",ext:["jsonld"],alias:["jsonld"]},{name:"Jinja2",mime:"null",mode:"jinja2"},{name:"Julia",mime:"text/x-julia",mode:"julia",ext:["jl"]},{name:"Kotlin",mime:"text/x-kotlin",mode:"kotlin",ext:["kt"]},{name:"LESS",mime:"text/x-less",mode:"css",ext:["less"]},{name:"LiveScript",mime:"text/x-livescript",mode:"livescript",ext:["ls"],alias:["ls"]},{name:"Lua",mime:"text/x-lua",mode:"lua",ext:["lua"]},{name:"Markdown",mime:"text/x-markdown",mode:"markdown",ext:["markdown","md","mkd"]},{name:"mIRC",mime:"text/mirc",mode:"mirc"},{name:"MariaDB SQL",mime:"text/x-mariadb",mode:"sql"},{name:"Modelica",mime:"text/x-modelica",mode:"modelica",ext:["mo"]},{name:"MS SQL",mime:"text/x-mssql",mode:"sql"},{name:"MySQL",mime:"text/x-mysql",mode:"sql"},{name:"Nginx",mime:"text/x-nginx-conf",mode:"nginx",file:/nginx.*\.conf$/i},{name:"NTriples",mime:"text/n-triples",mode:"ntriples",ext:["nt"]},{name:"Objective C",mime:"text/x-objectivec",mode:"clike",ext:["m","mm"]},{name:"OCaml",mime:"text/x-ocaml",mode:"mllike",ext:["ml","mli","mll","mly"]},{name:"Octave",mime:"text/x-octave",mode:"octave",ext:["m"]},{name:"Pascal",mime:"text/x-pascal",mode:"pascal",ext:["p","pas"]},{name:"PEG.js",mime:"null",mode:"pegjs",ext:["jsonld"]},{name:"Perl",mime:"text/x-perl",mode:"perl",ext:["pl","pm"]},{name:"PHP",mime:"application/x-httpd-php",mode:"php",ext:["php","php3","php4","php5","phtml"]},{name:"Pig",mime:"text/x-pig",mode:"pig",ext:["pig"]},{name:"Plain Text",mime:"text/plain",mode:"null",ext:["txt","text","conf","def","list","log"]},{name:"PLSQL",mime:"text/x-plsql",mode:"sql",ext:["pls"]},{name:"Properties files",mime:"text/x-properties",mode:"properties",ext:["properties","ini","in"],alias:["ini","properties"]},{name:"Python",mime:"text/x-python",mode:"python",ext:["py","pyw"]},{name:"Puppet",mime:"text/x-puppet",mode:"puppet",ext:["pp"]},{name:"Q",mime:"text/x-q",mode:"q",ext:["q"]},{name:"R",mime:"text/x-rsrc",mode:"r",ext:["r"],alias:["rscript"]},{name:"reStructuredText",mime:"text/x-rst",mode:"rst",ext:["rst"],alias:["rst"]},{name:"RPM Changes",mime:"text/x-rpm-changes",mode:"rpm"},{name:"RPM Spec",mime:"text/x-rpm-spec",mode:"rpm",ext:["spec"]},{name:"Ruby",mime:"text/x-ruby",mode:"ruby",ext:["rb"],alias:["jruby","macruby","rake","rb","rbx"]},{name:"Rust",mime:"text/x-rustsrc",mode:"rust",ext:["rs"]},{name:"Sass",mime:"text/x-sass",mode:"sass",ext:["sass"]},{name:"Scala",mime:"text/x-scala",mode:"clike",ext:["scala"]},{name:"Scheme",mime:"text/x-scheme",mode:"scheme",ext:["scm","ss"]},{name:"SCSS",mime:"text/x-scss",mode:"css",ext:["scss"]},{name:"Shell",mime:"text/x-sh",mode:"shell",ext:["sh","ksh","bash"],alias:["bash","sh","zsh"]},{name:"Sieve",mime:"application/sieve",mode:"sieve",ext:["siv","sieve"]},{name:"Slim",mimes:["text/x-slim","application/x-slim"],mode:"slim",ext:["slim"]},{name:"Smalltalk",mime:"text/x-stsrc",mode:"smalltalk",ext:["st"]},{name:"Smarty",mime:"text/x-smarty",mode:"smarty",ext:["tpl"]},{name:"SmartyMixed",mime:"text/x-smarty",mode:"smartymixed"},{name:"Solr",mime:"text/x-solr",mode:"solr"},{name:"Soy",mime:"text/x-soy",mode:"soy",ext:["soy"],alias:["closure template"]},{name:"SPARQL",mime:"application/sparql-query",mode:"sparql",ext:["rq","sparql"],alias:["sparul"]},{name:"Spreadsheet",mime:"text/x-spreadsheet",mode:"spreadsheet",alias:["excel","formula"]},{name:"SQL",mime:"text/x-sql",mode:"sql",ext:["sql"]},{name:"MariaDB",mime:"text/x-mariadb",mode:"sql"},{name:"sTeX",mime:"text/x-stex",mode:"stex"},{name:"LaTeX",mime:"text/x-latex",mode:"stex",ext:["text","ltx"],alias:["tex"]},{name:"SystemVerilog",mime:"text/x-systemverilog",mode:"verilog",ext:["v"]},{name:"Tcl",mime:"text/x-tcl",mode:"tcl",ext:["tcl"]},{name:"Textile",mime:"text/x-textile",mode:"textile",ext:["textile"]},{name:"TiddlyWiki ",mime:"text/x-tiddlywiki",mode:"tiddlywiki"},{name:"Tiki wiki",mime:"text/tiki",mode:"tiki"},{name:"TOML",mime:"text/x-toml",mode:"toml",ext:["toml"]},{name:"Tornado",mime:"text/x-tornado",mode:"tornado"},{name:"Turtle",mime:"text/turtle",mode:"turtle",ext:["ttl"]},{name:"TypeScript",mime:"application/typescript",mode:"javascript",ext:["ts"],alias:["ts"]},{name:"VB.NET",mime:"text/x-vb",mode:"vb",ext:["vb"]},{name:"VBScript",mime:"text/vbscript",mode:"vbscript",ext:["vbs"]},{name:"Velocity",mime:"text/velocity",mode:"velocity",ext:["vtl"]},{name:"Verilog",mime:"text/x-verilog",mode:"verilog",ext:["v"]},{name:"XML",mimes:["application/xml","text/xml"],mode:"xml",ext:["xml","xsl","xsd"],alias:["rss","wsdl","xsd"]},{name:"XQuery",mime:"application/xquery",mode:"xquery",ext:["xy","xquery"]},{name:"YAML",mime:"text/x-yaml",mode:"yaml",ext:["yaml"],alias:["yml"]},{name:"Z80",mime:"text/x-z80",mode:"z80",ext:["z80"]}];for(var t=0;t-1&&t.substring(i+1,t.length);return o?e.findModeByExtension(o):void 0},e.findModeByName=function(t){t=t.toLowerCase();for(var r=0;r")?(e.match("-->"),t.tokenize=null):e.skipToEnd(),["comment","comment"]}e.defineMode("css",function(t,r){function n(e,t){return m=t,e}function i(e,t){var r=e.next();if(g[r]){var i=g[r](e,t);if(i!==!1)return i}return"@"==r?(e.eatWhile(/[\w\\\-]/),n("def",e.current())):"="==r||("~"==r||"|"==r)&&e.eat("=")?n(null,"compare"):'"'==r||"'"==r?(t.tokenize=o(r),t.tokenize(e,t)):"#"==r?(e.eatWhile(/[\w\\\-]/),n("atom","hash")):"!"==r?(e.match(/^\s*\w*/),n("keyword","important")):/\d/.test(r)||"."==r&&e.eat(/\d/)?(e.eatWhile(/[\w.%]/),n("number","unit")):"-"!==r?/[,+>*\/]/.test(r)?n(null,"select-op"):"."==r&&e.match(/^-?[_a-z][_a-z0-9-]*/i)?n("qualifier","qualifier"):/[:;{}\[\]\(\)]/.test(r)?n(null,r):"u"==r&&e.match(/rl(-prefix)?\(/)||"d"==r&&e.match("omain(")||"r"==r&&e.match("egexp(")?(e.backUp(1),t.tokenize=a,n("property","word")):/[\w\\\-]/.test(r)?(e.eatWhile(/[\w\\\-]/),n("property","word")):n(null,null):/[\d.]/.test(e.peek())?(e.eatWhile(/[\w.%]/),n("number","unit")):e.match(/^-[\w\\\-]+/)?(e.eatWhile(/[\w\\\-]/),e.match(/^\s*:/,!1)?n("variable-2","variable-definition"):n("variable-2","variable")):e.match(/^\w+-/)?n("meta","meta"):void 0}function o(e){return function(t,r){for(var i,o=!1;null!=(i=t.next());){if(i==e&&!o){")"==e&&t.backUp(1);break}o=!o&&"\\"==i}return(i==e||!o&&")"!=e)&&(r.tokenize=null),n("string","string")}}function a(e,t){return e.next(),e.match(/\s*[\"\')]/,!1)?t.tokenize=null:t.tokenize=o(")"),n(null,"(")}function s(e,t,r){this.type=e,this.indent=t,this.prev=r}function l(e,t,r){return e.context=new s(r,t.indentation()+p,e.context),r}function c(e){return e.context=e.context.prev,e.context.type}function u(e,t,r){return M[r.context.type](e,t,r)}function d(e,t,r,n){for(var i=n||1;i>0;i--)r.context=r.context.prev;return u(e,t,r)}function f(e){var t=e.current().toLowerCase();h=S.hasOwnProperty(t)?"atom":C.hasOwnProperty(t)?"keyword":"variable"}r.propertyKeywords||(r=e.resolveMode("text/css"));var m,h,p=t.indentUnit,g=r.tokenHooks,v=r.documentTypes||{},b=r.mediaTypes||{},y=r.mediaFeatures||{},x=r.propertyKeywords||{},k=r.nonStandardPropertyKeywords||{},w=r.fontProperties||{},_=r.counterDescriptors||{},C=r.colorKeywords||{},S=r.valueKeywords||{},T=r.allowNested,M={};return M.top=function(e,t,r){if("{"==e)return l(r,t,"block");if("}"==e&&r.context.prev)return c(r);if(/@(media|supports|(-moz-)?document)/.test(e))return l(r,t,"atBlock");if(/@(font-face|counter-style)/.test(e))return r.stateArg=e,"restricted_atBlock_before";if(/^@(-(moz|ms|o|webkit)-)?keyframes$/.test(e))return"keyframes";if(e&&"@"==e.charAt(0))return l(r,t,"at");if("hash"==e)h="builtin";else if("word"==e)h="tag";else{if("variable-definition"==e)return"maybeprop";if("interpolation"==e)return l(r,t,"interpolation");if(":"==e)return"pseudo";if(T&&"("==e)return l(r,t,"parens")}return r.context.type},M.block=function(e,t,r){if("word"==e){var n=t.current().toLowerCase();return x.hasOwnProperty(n)?(h="property","maybeprop"):k.hasOwnProperty(n)?(h="string-2","maybeprop"):T?(h=t.match(/^\s*:(?:\s|$)/,!1)?"property":"tag","block"):(h+=" error","maybeprop")}return"meta"==e?"block":T||"hash"!=e&&"qualifier"!=e?M.top(e,t,r):(h="error","block")},M.maybeprop=function(e,t,r){return":"==e?l(r,t,"prop"):u(e,t,r)},M.prop=function(e,t,r){if(";"==e)return c(r);if("{"==e&&T)return l(r,t,"propBlock");if("}"==e||"{"==e)return d(e,t,r);if("("==e)return l(r,t,"parens");if("hash"!=e||/^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/.test(t.current())){if("word"==e)f(t);else if("interpolation"==e)return l(r,t,"interpolation")}else h+=" error";return"prop"},M.propBlock=function(e,t,r){return"}"==e?c(r):"word"==e?(h="property","maybeprop"):r.context.type},M.parens=function(e,t,r){return"{"==e||"}"==e?d(e,t,r):")"==e?c(r):"("==e?l(r,t,"parens"):("word"==e&&f(t),"parens")},M.pseudo=function(e,t,r){return"word"==e?(h="variable-3",r.context.type):u(e,t,r)},M.atBlock=function(e,t,r){if("("==e)return l(r,t,"atBlock_parens");if("}"==e)return d(e,t,r);if("{"==e)return c(r)&&l(r,t,T?"block":"top");if("word"==e){var n=t.current().toLowerCase();h="only"==n||"not"==n||"and"==n||"or"==n?"keyword":v.hasOwnProperty(n)?"tag":b.hasOwnProperty(n)?"attribute":y.hasOwnProperty(n)?"property":x.hasOwnProperty(n)?"property":k.hasOwnProperty(n)?"string-2":S.hasOwnProperty(n)?"atom":"error"}return r.context.type},M.atBlock_parens=function(e,t,r){return")"==e?c(r):"{"==e||"}"==e?d(e,t,r,2):M.atBlock(e,t,r)},M.restricted_atBlock_before=function(e,t,r){return"{"==e?l(r,t,"restricted_atBlock"):"word"==e&&"@counter-style"==r.stateArg?(h="variable","restricted_atBlock_before"):u(e,t,r)},M.restricted_atBlock=function(e,t,r){return"}"==e?(r.stateArg=null,c(r)):"word"==e?(h="@font-face"==r.stateArg&&!w.hasOwnProperty(t.current().toLowerCase())||"@counter-style"==r.stateArg&&!_.hasOwnProperty(t.current().toLowerCase())?"error":"property","maybeprop"):"restricted_atBlock"},M.keyframes=function(e,t,r){return"word"==e?(h="variable","keyframes"):"{"==e?l(r,t,"top"):u(e,t,r)},M.at=function(e,t,r){return";"==e?c(r):"{"==e||"}"==e?d(e,t,r):("word"==e?h="tag":"hash"==e&&(h="builtin"),"at")},M.interpolation=function(e,t,r){return"}"==e?c(r):"{"==e||";"==e?d(e,t,r):("variable"!=e&&(h="error"),"interpolation")},{startState:function(e){return{tokenize:null,state:"top",stateArg:null,context:new s("top",e||0,null)}},token:function(e,t){if(!t.tokenize&&e.eatSpace())return null;var r=(t.tokenize||i)(e,t);return r&&"object"==typeof r&&(m=r[1],r=r[0]),h=r,t.state=M[t.state](m,e,t),h},indent:function(e,t){var r=e.context,n=t&&t.charAt(0),i=r.indent;return"prop"!=r.type||"}"!=n&&")"!=n||(r=r.prev),!r.prev||("}"!=n||"block"!=r.type&&"top"!=r.type&&"interpolation"!=r.type&&"restricted_atBlock"!=r.type)&&(")"!=n||"parens"!=r.type&&"atBlock_parens"!=r.type)&&("{"!=n||"at"!=r.type&&"atBlock"!=r.type)||(i=r.indent-p,r=r.prev),i},electricChars:"}",blockCommentStart:"/*",blockCommentEnd:"*/",fold:"brace"}});var i=["domain","regexp","url","url-prefix"],o=t(i),a=["all","aural","braille","handheld","print","projection","screen","tty","tv","embossed"],s=t(a),l=["width","min-width","max-width","height","min-height","max-height","device-width","min-device-width","max-device-width","device-height","min-device-height","max-device-height","aspect-ratio","min-aspect-ratio","max-aspect-ratio","device-aspect-ratio","min-device-aspect-ratio","max-device-aspect-ratio","color","min-color","max-color","color-index","min-color-index","max-color-index","monochrome","min-monochrome","max-monochrome","resolution","min-resolution","max-resolution","scan","grid"],c=t(l),u=["align-content","align-items","align-self","alignment-adjust","alignment-baseline","anchor-point","animation","animation-delay","animation-direction","animation-duration","animation-fill-mode","animation-iteration-count","animation-name","animation-play-state","animation-timing-function","appearance","azimuth","backface-visibility","background","background-attachment","background-clip","background-color","background-image","background-origin","background-position","background-repeat","background-size","baseline-shift","binding","bleed","bookmark-label","bookmark-level","bookmark-state","bookmark-target","border","border-bottom","border-bottom-color","border-bottom-left-radius","border-bottom-right-radius","border-bottom-style","border-bottom-width","border-collapse","border-color","border-image","border-image-outset","border-image-repeat","border-image-slice","border-image-source","border-image-width","border-left","border-left-color","border-left-style","border-left-width","border-radius","border-right","border-right-color","border-right-style","border-right-width","border-spacing","border-style","border-top","border-top-color","border-top-left-radius","border-top-right-radius","border-top-style","border-top-width","border-width","bottom","box-decoration-break","box-shadow","box-sizing","break-after","break-before","break-inside","caption-side","clear","clip","color","color-profile","column-count","column-fill","column-gap","column-rule","column-rule-color","column-rule-style","column-rule-width","column-span","column-width","columns","content","counter-increment","counter-reset","crop","cue","cue-after","cue-before","cursor","direction","display","dominant-baseline","drop-initial-after-adjust","drop-initial-after-align","drop-initial-before-adjust","drop-initial-before-align","drop-initial-size","drop-initial-value","elevation","empty-cells","fit","fit-position","flex","flex-basis","flex-direction","flex-flow","flex-grow","flex-shrink","flex-wrap","float","float-offset","flow-from","flow-into","font","font-feature-settings","font-family","font-kerning","font-language-override","font-size","font-size-adjust","font-stretch","font-style","font-synthesis","font-variant","font-variant-alternates","font-variant-caps","font-variant-east-asian","font-variant-ligatures","font-variant-numeric","font-variant-position","font-weight","grid","grid-area","grid-auto-columns","grid-auto-flow","grid-auto-position","grid-auto-rows","grid-column","grid-column-end","grid-column-start","grid-row","grid-row-end","grid-row-start","grid-template","grid-template-areas","grid-template-columns","grid-template-rows","hanging-punctuation","height","hyphens","icon","image-orientation","image-rendering","image-resolution","inline-box-align","justify-content","left","letter-spacing","line-break","line-height","line-stacking","line-stacking-ruby","line-stacking-shift","line-stacking-strategy","list-style","list-style-image","list-style-position","list-style-type","margin","margin-bottom","margin-left","margin-right","margin-top","marker-offset","marks","marquee-direction","marquee-loop","marquee-play-count","marquee-speed","marquee-style","max-height","max-width","min-height","min-width","move-to","nav-down","nav-index","nav-left","nav-right","nav-up","object-fit","object-position","opacity","order","orphans","outline","outline-color","outline-offset","outline-style","outline-width","overflow","overflow-style","overflow-wrap","overflow-x","overflow-y","padding","padding-bottom","padding-left","padding-right","padding-top","page","page-break-after","page-break-before","page-break-inside","page-policy","pause","pause-after","pause-before","perspective","perspective-origin","pitch","pitch-range","play-during","position","presentation-level","punctuation-trim","quotes","region-break-after","region-break-before","region-break-inside","region-fragment","rendering-intent","resize","rest","rest-after","rest-before","richness","right","rotation","rotation-point","ruby-align","ruby-overhang","ruby-position","ruby-span","shape-image-threshold","shape-inside","shape-margin","shape-outside","size","speak","speak-as","speak-header","speak-numeral","speak-punctuation","speech-rate","stress","string-set","tab-size","table-layout","target","target-name","target-new","target-position","text-align","text-align-last","text-decoration","text-decoration-color","text-decoration-line","text-decoration-skip","text-decoration-style","text-emphasis","text-emphasis-color","text-emphasis-position","text-emphasis-style","text-height","text-indent","text-justify","text-outline","text-overflow","text-shadow","text-size-adjust","text-space-collapse","text-transform","text-underline-position","text-wrap","top","transform","transform-origin","transform-style","transition","transition-delay","transition-duration","transition-property","transition-timing-function","unicode-bidi","vertical-align","visibility","voice-balance","voice-duration","voice-family","voice-pitch","voice-range","voice-rate","voice-stress","voice-volume","volume","white-space","widows","width","word-break","word-spacing","word-wrap","z-index","clip-path","clip-rule","mask","enable-background","filter","flood-color","flood-opacity","lighting-color","stop-color","stop-opacity","pointer-events","color-interpolation","color-interpolation-filters","color-rendering","fill","fill-opacity","fill-rule","image-rendering","marker","marker-end","marker-mid","marker-start","shape-rendering","stroke","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","text-rendering","baseline-shift","dominant-baseline","glyph-orientation-horizontal","glyph-orientation-vertical","text-anchor","writing-mode"],d=t(u),f=["scrollbar-arrow-color","scrollbar-base-color","scrollbar-dark-shadow-color","scrollbar-face-color","scrollbar-highlight-color","scrollbar-shadow-color","scrollbar-3d-light-color","scrollbar-track-color","shape-inside","searchfield-cancel-button","searchfield-decoration","searchfield-results-button","searchfield-results-decoration","zoom"],m=t(f),h=["font-family","src","unicode-range","font-variant","font-feature-settings","font-stretch","font-weight","font-style"],p=t(h),g=["additive-symbols","fallback","negative","pad","prefix","range","speak-as","suffix","symbols","system"],v=t(g),b=["aliceblue","antiquewhite","aqua","aquamarine","azure","beige","bisque","black","blanchedalmond","blue","blueviolet","brown","burlywood","cadetblue","chartreuse","chocolate","coral","cornflowerblue","cornsilk","crimson","cyan","darkblue","darkcyan","darkgoldenrod","darkgray","darkgreen","darkkhaki","darkmagenta","darkolivegreen","darkorange","darkorchid","darkred","darksalmon","darkseagreen","darkslateblue","darkslategray","darkturquoise","darkviolet","deeppink","deepskyblue","dimgray","dodgerblue","firebrick","floralwhite","forestgreen","fuchsia","gainsboro","ghostwhite","gold","goldenrod","gray","grey","green","greenyellow","honeydew","hotpink","indianred","indigo","ivory","khaki","lavender","lavenderblush","lawngreen","lemonchiffon","lightblue","lightcoral","lightcyan","lightgoldenrodyellow","lightgray","lightgreen","lightpink","lightsalmon","lightseagreen","lightskyblue","lightslategray","lightsteelblue","lightyellow","lime","limegreen","linen","magenta","maroon","mediumaquamarine","mediumblue","mediumorchid","mediumpurple","mediumseagreen","mediumslateblue","mediumspringgreen","mediumturquoise","mediumvioletred","midnightblue","mintcream","mistyrose","moccasin","navajowhite","navy","oldlace","olive","olivedrab","orange","orangered","orchid","palegoldenrod","palegreen","paleturquoise","palevioletred","papayawhip","peachpuff","peru","pink","plum","powderblue","purple","rebeccapurple","red","rosybrown","royalblue","saddlebrown","salmon","sandybrown","seagreen","seashell","sienna","silver","skyblue","slateblue","slategray","snow","springgreen","steelblue","tan","teal","thistle","tomato","turquoise","violet","wheat","white","whitesmoke","yellow","yellowgreen"],y=t(b),x=["above","absolute","activeborder","additive","activecaption","afar","after-white-space","ahead","alias","all","all-scroll","alphabetic","alternate","always","amharic","amharic-abegede","antialiased","appworkspace","arabic-indic","armenian","asterisks","attr","auto","avoid","avoid-column","avoid-page","avoid-region","background","backwards","baseline","below","bidi-override","binary","bengali","blink","block","block-axis","bold","bolder","border","border-box","both","bottom","break","break-all","break-word","bullets","button","button-bevel","buttonface","buttonhighlight","buttonshadow","buttontext","calc","cambodian","capitalize","caps-lock-indicator","caption","captiontext","caret","cell","center","checkbox","circle","cjk-decimal","cjk-earthly-branch","cjk-heavenly-stem","cjk-ideographic","clear","clip","close-quote","col-resize","collapse","column","compact","condensed","contain","content","content-box","context-menu","continuous","copy","counter","counters","cover","crop","cross","crosshair","currentcolor","cursive","cyclic","dashed","decimal","decimal-leading-zero","default","default-button","destination-atop","destination-in","destination-out","destination-over","devanagari","disc","discard","disclosure-closed","disclosure-open","document","dot-dash","dot-dot-dash","dotted","double","down","e-resize","ease","ease-in","ease-in-out","ease-out","element","ellipse","ellipsis","embed","end","ethiopic","ethiopic-abegede","ethiopic-abegede-am-et","ethiopic-abegede-gez","ethiopic-abegede-ti-er","ethiopic-abegede-ti-et","ethiopic-halehame-aa-er","ethiopic-halehame-aa-et","ethiopic-halehame-am-et","ethiopic-halehame-gez","ethiopic-halehame-om-et","ethiopic-halehame-sid-et","ethiopic-halehame-so-et","ethiopic-halehame-ti-er","ethiopic-halehame-ti-et","ethiopic-halehame-tig","ethiopic-numeric","ew-resize","expanded","extends","extra-condensed","extra-expanded","fantasy","fast","fill","fixed","flat","flex","footnotes","forwards","from","geometricPrecision","georgian","graytext","groove","gujarati","gurmukhi","hand","hangul","hangul-consonant","hebrew","help","hidden","hide","higher","highlight","highlighttext","hiragana","hiragana-iroha","horizontal","hsl","hsla","icon","ignore","inactiveborder","inactivecaption","inactivecaptiontext","infinite","infobackground","infotext","inherit","initial","inline","inline-axis","inline-block","inline-flex","inline-table","inset","inside","intrinsic","invert","italic","japanese-formal","japanese-informal","justify","kannada","katakana","katakana-iroha","keep-all","khmer","korean-hangul-formal","korean-hanja-formal","korean-hanja-informal","landscape","lao","large","larger","left","level","lighter","line-through","linear","linear-gradient","lines","list-item","listbox","listitem","local","logical","loud","lower","lower-alpha","lower-armenian","lower-greek","lower-hexadecimal","lower-latin","lower-norwegian","lower-roman","lowercase","ltr","malayalam","match","matrix","matrix3d","media-controls-background","media-current-time-display","media-fullscreen-button","media-mute-button","media-play-button","media-return-to-realtime-button","media-rewind-button","media-seek-back-button","media-seek-forward-button","media-slider","media-sliderthumb","media-time-remaining-display","media-volume-slider","media-volume-slider-container","media-volume-sliderthumb","medium","menu","menulist","menulist-button","menulist-text","menulist-textfield","menutext","message-box","middle","min-intrinsic","mix","mongolian","monospace","move","multiple","myanmar","n-resize","narrower","ne-resize","nesw-resize","no-close-quote","no-drop","no-open-quote","no-repeat","none","normal","not-allowed","nowrap","ns-resize","numbers","numeric","nw-resize","nwse-resize","oblique","octal","open-quote","optimizeLegibility","optimizeSpeed","oriya","oromo","outset","outside","outside-shape","overlay","overline","padding","padding-box","painted","page","paused","persian","perspective","plus-darker","plus-lighter","pointer","polygon","portrait","pre","pre-line","pre-wrap","preserve-3d","progress","push-button","radial-gradient","radio","read-only","read-write","read-write-plaintext-only","rectangle","region","relative","repeat","repeating-linear-gradient","repeating-radial-gradient","repeat-x","repeat-y","reset","reverse","rgb","rgba","ridge","right","rotate","rotate3d","rotateX","rotateY","rotateZ","round","row-resize","rtl","run-in","running","s-resize","sans-serif","scale","scale3d","scaleX","scaleY","scaleZ","scroll","scrollbar","se-resize","searchfield","searchfield-cancel-button","searchfield-decoration","searchfield-results-button","searchfield-results-decoration","semi-condensed","semi-expanded","separate","serif","show","sidama","simp-chinese-formal","simp-chinese-informal","single","skew","skewX","skewY","skip-white-space","slide","slider-horizontal","slider-vertical","sliderthumb-horizontal","sliderthumb-vertical","slow","small","small-caps","small-caption","smaller","solid","somali","source-atop","source-in","source-out","source-over","space","spell-out","square","square-button","start","static","status-bar","stretch","stroke","sub","subpixel-antialiased","super","sw-resize","symbolic","symbols","table","table-caption","table-cell","table-column","table-column-group","table-footer-group","table-header-group","table-row","table-row-group","tamil","telugu","text","text-bottom","text-top","textarea","textfield","thai","thick","thin","threeddarkshadow","threedface","threedhighlight","threedlightshadow","threedshadow","tibetan","tigre","tigrinya-er","tigrinya-er-abegede","tigrinya-et","tigrinya-et-abegede","to","top","trad-chinese-formal","trad-chinese-informal","translate","translate3d","translateX","translateY","translateZ","transparent","ultra-condensed","ultra-expanded","underline","up","upper-alpha","upper-armenian","upper-greek","upper-hexadecimal","upper-latin","upper-norwegian","upper-roman","uppercase","urdu","url","var","vertical","vertical-text","visible","visibleFill","visiblePainted","visibleStroke","visual","w-resize","wait","wave","wider","window","windowframe","windowtext","words","x-large","x-small","xor","xx-large","xx-small"],k=t(x),w=i.concat(a).concat(l).concat(u).concat(f).concat(b).concat(x);e.registerHelper("hintWords","css",w),e.defineMIME("text/css",{documentTypes:o,mediaTypes:s,mediaFeatures:c,propertyKeywords:d,nonStandardPropertyKeywords:m,fontProperties:p,counterDescriptors:v,colorKeywords:y,valueKeywords:k,tokenHooks:{"<":function(e,t){return e.match("!--")?(t.tokenize=n,n(e,t)):!1},"/":function(e,t){return e.eat("*")?(t.tokenize=r,r(e,t)):!1}},name:"css"}),e.defineMIME("text/x-scss",{mediaTypes:s,mediaFeatures:c,propertyKeywords:d,nonStandardPropertyKeywords:m,colorKeywords:y,valueKeywords:k,fontProperties:p,allowNested:!0,tokenHooks:{"/":function(e,t){return e.eat("/")?(e.skipToEnd(),["comment","comment"]):e.eat("*")?(t.tokenize=r,r(e,t)):["operator","operator"]},":":function(e){return e.match(/\s*\{/)?[null,"{"]:!1},$:function(e){return e.match(/^[\w-]+/),e.match(/^\s*:/,!1)?["variable-2","variable-definition"]:["variable-2","variable"]},"#":function(e){return e.eat("{")?[null,"interpolation"]:!1}},name:"css",helperType:"scss"}),e.defineMIME("text/x-less",{mediaTypes:s,mediaFeatures:c,propertyKeywords:d,nonStandardPropertyKeywords:m,colorKeywords:y,valueKeywords:k,fontProperties:p,allowNested:!0,tokenHooks:{"/":function(e,t){return e.eat("/")?(e.skipToEnd(),["comment","comment"]):e.eat("*")?(t.tokenize=r,r(e,t)):["operator","operator"]},"@":function(e){return e.match(/^(charset|document|font-face|import|(-(moz|ms|o|webkit)-)?keyframes|media|namespace|page|supports)\b/,!1)?!1:(e.eatWhile(/[\w\\\-]/), +e.match(/^\s*:/,!1)?["variable-2","variable-definition"]:["variable-2","variable"])},"&":function(){return["atom","atom"]}},name:"css",helperType:"less"})}),function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],e):e(CodeMirror)}(function(e){"use strict";e.defineMode("sass",function(e){function t(e){return new RegExp("^"+e.join("|"))}function r(e,t){var r=e.peek();return")"===r?(e.next(),t.tokenizer=l,"operator"):"("===r?(e.next(),e.eatSpace(),"operator"):"'"===r||'"'===r?(t.tokenizer=i(e.next()),"string"):(t.tokenizer=i(")",!1),"string")}function n(e,t){return function(r,n){return r.sol()&&r.indentation()<=e?(n.tokenizer=l,l(r,n)):(t&&r.skipTo("*/")?(r.next(),r.next(),n.tokenizer=l):r.skipToEnd(),"comment")}}function i(e,t){function r(n,i){var a=n.next(),s=n.peek(),c=n.string.charAt(n.pos-2),u="\\"!==a&&s===e||a===e&&"\\"!==c;return u?(a!==e&&t&&n.next(),i.tokenizer=l,"string"):"#"===a&&"{"===s?(i.tokenizer=o(r),n.next(),"operator"):"string"}return null==t&&(t=!0),r}function o(e){return function(t,r){return"}"===t.peek()?(t.next(),r.tokenizer=e,"operator"):l(t,r)}}function a(t){if(0==t.indentCount){t.indentCount++;var r=t.scopes[0].offset,n=r+e.indentUnit;t.scopes.unshift({offset:n})}}function s(e){1!=e.scopes.length&&e.scopes.shift()}function l(e,t){var c=e.peek();if(e.match("/*"))return t.tokenizer=n(e.indentation(),!0),t.tokenizer(e,t);if(e.match("//"))return t.tokenizer=n(e.indentation(),!1),t.tokenizer(e,t);if(e.match("#{"))return t.tokenizer=o(l),"operator";if('"'===c||"'"===c)return e.next(),t.tokenizer=i(c),"string";if(t.cursorHalf){if("#"===c&&(e.next(),e.match(/[0-9a-fA-F]{6}|[0-9a-fA-F]{3}/)))return e.peek()||(t.cursorHalf=0),"number";if(e.match(/^-?[0-9\.]+/))return e.peek()||(t.cursorHalf=0),"number";if(e.match(/^(px|em|in)\b/))return e.peek()||(t.cursorHalf=0),"unit";if(e.match(d))return e.peek()||(t.cursorHalf=0),"keyword";if(e.match(/^url/)&&"("===e.peek())return t.tokenizer=r,e.peek()||(t.cursorHalf=0),"atom";if("$"===c)return e.next(),e.eatWhile(/[\w-]/),e.peek()||(t.cursorHalf=0),"variable-3";if("!"===c)return e.next(),e.peek()||(t.cursorHalf=0),e.match(/^[\w]+/)?"keyword":"operator";if(e.match(m))return e.peek()||(t.cursorHalf=0),"operator";if(e.eatWhile(/[\w-]/))return e.peek()||(t.cursorHalf=0),"attribute";if(!e.peek())return t.cursorHalf=0,null}else{if("."===c){if(e.next(),e.match(/^[\w-]+/))return a(t),"atom";if("#"===e.peek())return a(t),"atom"}if("#"===c){if(e.next(),e.match(/^[\w-]+/))return a(t),"atom";if("#"===e.peek())return a(t),"atom"}if("$"===c)return e.next(),e.eatWhile(/[\w-]/),"variable-2";if(e.match(/^-?[0-9\.]+/))return"number";if(e.match(/^(px|em|in)\b/))return"unit";if(e.match(d))return"keyword";if(e.match(/^url/)&&"("===e.peek())return t.tokenizer=r,"atom";if("="===c&&e.match(/^=[\w-]+/))return a(t),"meta";if("+"===c&&e.match(/^\+[\w-]+/))return"variable-3";if("@"===c&&e.match(/@extend/)&&(e.match(/\s*[\w]/)||s(t)),e.match(/^@(else if|if|media|else|for|each|while|mixin|function)/))return a(t),"meta";if("@"===c)return e.next(),e.eatWhile(/[\w-]/),"meta";if(e.eatWhile(/[\w-]/))return e.match(/ *: *[\w-\+\$#!\("']/,!1)?"propery":e.match(/ *:/,!1)?(a(t),t.cursorHalf=1,"atom"):e.match(/ *,/,!1)?"atom":(a(t),"atom");if(":"===c)return e.match(h)?"keyword":(e.next(),t.cursorHalf=1,"operator")}return e.match(m)?"operator":(e.next(),null)}function c(t,r){t.sol()&&(r.indentCount=0);var n=r.tokenizer(t,r),i=t.current();if(("@return"===i||"}"===i)&&s(r),null!==n){for(var o=t.pos-i.length,a=o+e.indentUnit*r.indentCount,l=[],c=0;c","<","==",">=","<=","\\+","-","\\!=","/","\\*","%","and","or","not",";","\\{","\\}",":"],m=t(f),h=/^::?[a-zA-Z_][\w\-]*/;return{startState:function(){return{tokenizer:l,scopes:[{offset:0,type:"sass"}],indentCount:0,cursorHalf:0,definedVars:[],definedMixins:[]}},token:function(e,t){var r=c(e,t);return t.lastToken={style:r,content:e.current()},r},indent:function(e){return e.scopes[0].offset}}}),e.defineMIME("text/x-sass","sass")}),function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],e):e(CodeMirror)}(function(e){"use strict";e.defineMode("shell",function(){function e(e,t){for(var r=t.split(" "),n=0;n1&&e.eat("$");var i=e.next(),o=/\w/;return"{"===i&&(o=/[^}]/),"("===i?(t.tokens[0]=r(")"),n(e,t)):(/\d/.test(i)||(e.eatWhile(o),e.eat("}")),t.tokens.shift(),"def")};return{startState:function(){return{tokens:[]}},token:function(e,t){return n(e,t)},lineComment:"#",fold:"brace"}}),e.defineMIME("text/x-sh","shell")}),function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],e):e(CodeMirror)}(function(e){"use strict";e.defineMode("sql",function(t,r){function n(e,t){var r=e.next();if(h[r]){var n=h[r](e,t);if(n!==!1)return n}if(1==m.hexNumber&&("0"==r&&e.match(/^[xX][0-9a-fA-F]+/)||("x"==r||"X"==r)&&e.match(/^'[0-9a-fA-F]+'/)))return"number";if(1==m.binaryNumber&&(("b"==r||"B"==r)&&e.match(/^'[01]+'/)||"0"==r&&e.match(/^b[01]+/)))return"number";if(r.charCodeAt(0)>47&&r.charCodeAt(0)<58)return e.match(/^[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?/),1==m.decimallessFloat&&e.eat("."),"number";if("?"==r&&(e.eatSpace()||e.eol()||e.eat(";")))return"variable-3";if("'"==r||'"'==r&&m.doubleQuote)return t.tokenize=i(r),t.tokenize(e,t);if((1==m.nCharCast&&("n"==r||"N"==r)||1==m.charsetCast&&"_"==r&&e.match(/[a-z][a-z0-9]*/i))&&("'"==e.peek()||'"'==e.peek()))return"keyword";if(/^[\(\),\;\[\]]/.test(r))return null;if(m.commentSlashSlash&&"/"==r&&e.eat("/"))return e.skipToEnd(),"comment";if(m.commentHash&&"#"==r||"-"==r&&e.eat("-")&&(!m.commentSpaceRequired||e.eat(" ")))return e.skipToEnd(),"comment";if("/"==r&&e.eat("*"))return t.tokenize=o,t.tokenize(e,t);if("."!=r){if(f.test(r))return e.eatWhile(f),null;if("{"==r&&(e.match(/^( )*(d|D|t|T|ts|TS)( )*'[^']*'( )*}/)||e.match(/^( )*(d|D|t|T|ts|TS)( )*"[^"]*"( )*}/)))return"number";e.eatWhile(/^[_\w\d]/);var a=e.current().toLowerCase();return p.hasOwnProperty(a)&&(e.match(/^( )+'[^']*'/)||e.match(/^( )+"[^"]*"/))?"number":c.hasOwnProperty(a)?"atom":u.hasOwnProperty(a)?"builtin":d.hasOwnProperty(a)?"keyword":l.hasOwnProperty(a)?"string-2":null}return 1==m.zerolessFloat&&e.match(/^(?:\d+(?:e[+-]?\d+)?)/i)?"number":1==m.ODBCdotTable&&e.match(/^[a-zA-Z_]+/)?"variable-2":void 0}function i(e){return function(t,r){for(var i,o=!1;null!=(i=t.next());){if(i==e&&!o){r.tokenize=n;break}o=!o&&"\\"==i}return"string"}}function o(e,t){for(;;){if(!e.skipTo("*")){e.skipToEnd();break}if(e.next(),e.eat("/")){t.tokenize=n;break}}return"comment"}function a(e,t,r){t.context={prev:t.context,indent:e.indentation(),col:e.column(),type:r}}function s(e){e.indent=e.context.indent,e.context=e.context.prev}var l=r.client||{},c=r.atoms||{"false":!0,"true":!0,"null":!0},u=r.builtin||{},d=r.keywords||{},f=r.operatorChars||/^[*+\-%<>!=&|~^]/,m=r.support||{},h=r.hooks||{},p=r.dateSQL||{date:!0,time:!0,timestamp:!0};return{startState:function(){return{tokenize:n,context:null}},token:function(e,t){if(e.sol()&&t.context&&null==t.context.align&&(t.context.align=!1),e.eatSpace())return null;var r=t.tokenize(e,t);if("comment"==r)return r;t.context&&null==t.context.align&&(t.context.align=!0);var n=e.current();return"("==n?a(e,t,")"):"["==n?a(e,t,"]"):t.context&&t.context.type==n&&s(t),r},indent:function(r,n){var i=r.context;if(!i)return e.Pass;var o=n.charAt(0)==i.type;return i.align?i.col+(o?0:1):i.indent+(o?0:t.indentUnit)},blockCommentStart:"/*",blockCommentEnd:"*/",lineComment:m.commentSlashSlash?"//":m.commentHash?"#":null}}),function(){function t(e){for(var t;null!=(t=e.next());)if("`"==t&&!e.eat("`"))return"variable-2";return e.backUp(e.current().length-1),e.eatWhile(/\w/)?"variable-2":null}function r(e){return e.eat("@")&&(e.match(/^session\./),e.match(/^local\./),e.match(/^global\./)),e.eat("'")?(e.match(/^.*'/),"variable-2"):e.eat('"')?(e.match(/^.*"/),"variable-2"):e.eat("`")?(e.match(/^.*`/),"variable-2"):e.match(/^[0-9a-zA-Z$\.\_]+/)?"variable-2":null}function n(e){return e.eat("N")?"atom":e.match(/^[a-zA-Z.#!?]/)?"variable-2":null}function i(e){for(var t={},r=e.split(" "),n=0;n!=]/,dateSQL:i("date time timestamp"),support:i("ODBCdotTable doubleQuote binaryNumber hexNumber")}),e.defineMIME("text/x-mssql",{name:"sql",client:i("charset clear connect edit ego exit go help nopager notee nowarning pager print prompt quit rehash source status system tee"),keywords:i(o+"begin trigger proc view index for add constraint key primary foreign collate clustered nonclustered"),builtin:i("bigint numeric bit smallint decimal smallmoney int tinyint money float real char varchar text nchar nvarchar ntext binary varbinary image cursor timestamp hierarchyid uniqueidentifier sql_variant xml table "),atoms:i("false true null unknown"),operatorChars:/^[*+\-%<>!=]/,dateSQL:i("date datetimeoffset datetime2 smalldatetime datetime time"),hooks:{"@":r}}),e.defineMIME("text/x-mysql",{name:"sql",client:i("charset clear connect edit ego exit go help nopager notee nowarning pager print prompt quit rehash source status system tee"),keywords:i(o+"accessible action add after algorithm all analyze asensitive at authors auto_increment autocommit avg avg_row_length before binary binlog both btree cache call cascade cascaded case catalog_name chain change changed character check checkpoint checksum class_origin client_statistics close coalesce code collate collation collations column columns comment commit committed completion concurrent condition connection consistent constraint contains continue contributors convert cross current current_date current_time current_timestamp current_user cursor data database databases day_hour day_microsecond day_minute day_second deallocate dec declare default delay_key_write delayed delimiter des_key_file describe deterministic dev_pop dev_samp deviance diagnostics directory disable discard distinctrow div dual dumpfile each elseif enable enclosed end ends engine engines enum errors escape escaped even event events every execute exists exit explain extended fast fetch field fields first flush for force foreign found_rows full fulltext function general get global grant grants group groupby_concat handler hash help high_priority hosts hour_microsecond hour_minute hour_second if ignore ignore_server_ids import index index_statistics infile inner innodb inout insensitive insert_method install interval invoker isolation iterate key keys kill language last leading leave left level limit linear lines list load local localtime localtimestamp lock logs low_priority master master_heartbeat_period master_ssl_verify_server_cert masters match max max_rows maxvalue message_text middleint migrate min min_rows minute_microsecond minute_second mod mode modifies modify mutex mysql_errno natural next no no_write_to_binlog offline offset one online open optimize option optionally out outer outfile pack_keys parser partition partitions password phase plugin plugins prepare preserve prev primary privileges procedure processlist profile profiles purge query quick range read read_write reads real rebuild recover references regexp relaylog release remove rename reorganize repair repeatable replace require resignal restrict resume return returns revoke right rlike rollback rollup row row_format rtree savepoint schedule schema schema_name schemas second_microsecond security sensitive separator serializable server session share show signal slave slow smallint snapshot soname spatial specific sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_no_cache sql_small_result sqlexception sqlstate sqlwarning ssl start starting starts status std stddev stddev_pop stddev_samp storage straight_join subclass_origin sum suspend table_name table_statistics tables tablespace temporary terminated to trailing transaction trigger triggers truncate uncommitted undo uninstall unique unlock upgrade usage use use_frm user user_resources user_statistics using utc_date utc_time utc_timestamp value variables varying view views warnings when while with work write xa xor year_month zerofill begin do then else loop repeat"),builtin:i("bool boolean bit blob decimal double float long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision date datetime year unsigned signed numeric"),atoms:i("false true null unknown"),operatorChars:/^[*+\-%<>!=&|^]/,dateSQL:i("date time timestamp"),support:i("ODBCdotTable decimallessFloat zerolessFloat binaryNumber hexNumber doubleQuote nCharCast charsetCast commentHash commentSpaceRequired"),hooks:{"@":r,"`":t,"\\":n}}),e.defineMIME("text/x-mariadb",{name:"sql",client:i("charset clear connect edit ego exit go help nopager notee nowarning pager print prompt quit rehash source status system tee"),keywords:i(o+"accessible action add after algorithm all always analyze asensitive at authors auto_increment autocommit avg avg_row_length before binary binlog both btree cache call cascade cascaded case catalog_name chain change changed character check checkpoint checksum class_origin client_statistics close coalesce code collate collation collations column columns comment commit committed completion concurrent condition connection consistent constraint contains continue contributors convert cross current current_date current_time current_timestamp current_user cursor data database databases day_hour day_microsecond day_minute day_second deallocate dec declare default delay_key_write delayed delimiter des_key_file describe deterministic dev_pop dev_samp deviance diagnostics directory disable discard distinctrow div dual dumpfile each elseif enable enclosed end ends engine engines enum errors escape escaped even event events every execute exists exit explain extended fast fetch field fields first flush for force foreign found_rows full fulltext function general generated get global grant grants group groupby_concat handler hard hash help high_priority hosts hour_microsecond hour_minute hour_second if ignore ignore_server_ids import index index_statistics infile inner innodb inout insensitive insert_method install interval invoker isolation iterate key keys kill language last leading leave left level limit linear lines list load local localtime localtimestamp lock logs low_priority master master_heartbeat_period master_ssl_verify_server_cert masters match max max_rows maxvalue message_text middleint migrate min min_rows minute_microsecond minute_second mod mode modifies modify mutex mysql_errno natural next no no_write_to_binlog offline offset one online open optimize option optionally out outer outfile pack_keys parser partition partitions password persistent phase plugin plugins prepare preserve prev primary privileges procedure processlist profile profiles purge query quick range read read_write reads real rebuild recover references regexp relaylog release remove rename reorganize repair repeatable replace require resignal restrict resume return returns revoke right rlike rollback rollup row row_format rtree savepoint schedule schema schema_name schemas second_microsecond security sensitive separator serializable server session share show shutdown signal slave slow smallint snapshot soft soname spatial specific sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_no_cache sql_small_result sqlexception sqlstate sqlwarning ssl start starting starts status std stddev stddev_pop stddev_samp storage straight_join subclass_origin sum suspend table_name table_statistics tables tablespace temporary terminated to trailing transaction trigger triggers truncate uncommitted undo uninstall unique unlock upgrade usage use use_frm user user_resources user_statistics using utc_date utc_time utc_timestamp value variables varying view views virtual warnings when while with work write xa xor year_month zerofill begin do then else loop repeat"),builtin:i("bool boolean bit blob decimal double float long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision date datetime year unsigned signed numeric"),atoms:i("false true null unknown"),operatorChars:/^[*+\-%<>!=&|^]/,dateSQL:i("date time timestamp"),support:i("ODBCdotTable decimallessFloat zerolessFloat binaryNumber hexNumber doubleQuote nCharCast charsetCast commentHash commentSpaceRequired"),hooks:{"@":r,"`":t,"\\":n}}),e.defineMIME("text/x-cassandra",{name:"sql",client:{},keywords:i("use select from using consistency where limit first reversed first and in insert into values using consistency ttl update set delete truncate begin batch apply create keyspace with columnfamily primary key index on drop alter type add any one quorum all local_quorum each_quorum"),builtin:i("ascii bigint blob boolean counter decimal double float int text timestamp uuid varchar varint"),atoms:i("false true"),operatorChars:/^[<>=]/,dateSQL:{},support:i("commentSlashSlash decimallessFloat"),hooks:{}}),e.defineMIME("text/x-plsql",{name:"sql",client:i("appinfo arraysize autocommit autoprint autorecovery autotrace blockterminator break btitle cmdsep colsep compatibility compute concat copycommit copytypecheck define describe echo editfile embedded escape exec execute feedback flagger flush heading headsep instance linesize lno loboffset logsource long longchunksize markup native newpage numformat numwidth pagesize pause pno recsep recsepchar release repfooter repheader serveroutput shiftinout show showmode size spool sqlblanklines sqlcase sqlcode sqlcontinue sqlnumber sqlpluscompatibility sqlprefix sqlprompt sqlterminator suffix tab term termout time timing trimout trimspool ttitle underline verify version wrap"),keywords:i("abort accept access add all alter and any array arraylen as asc assert assign at attributes audit authorization avg base_table begin between binary_integer body boolean by case cast char char_base check close cluster clusters colauth column comment commit compress connect connected constant constraint crash create current currval cursor data_base database date dba deallocate debugoff debugon decimal declare default definition delay delete desc digits dispose distinct do drop else elseif elsif enable end entry escape exception exception_init exchange exclusive exists exit external fast fetch file for force form from function generic goto grant group having identified if immediate in increment index indexes indicator initial initrans insert interface intersect into is key level library like limited local lock log logging long loop master maxextents maxtrans member minextents minus mislabel mode modify multiset new next no noaudit nocompress nologging noparallel not nowait number_base object of off offline on online only open option or order out package parallel partition pctfree pctincrease pctused pls_integer positive positiven pragma primary prior private privileges procedure public raise range raw read rebuild record ref references refresh release rename replace resource restrict return returning returns reverse revoke rollback row rowid rowlabel rownum rows run savepoint schema segment select separate session set share snapshot some space split sql start statement storage subtype successful synonym tabauth table tables tablespace task terminate then to trigger truncate type union unique unlimited unrecoverable unusable update use using validate value values variable view views when whenever where while with work"),builtin:i("abs acos add_months ascii asin atan atan2 average bfile bfilename bigserial bit blob ceil character chartorowid chr clob concat convert cos cosh count dec decode deref dual dump dup_val_on_index empty error exp false float floor found glb greatest hextoraw initcap instr instrb int integer isopen last_day least lenght lenghtb ln lower lpad ltrim lub make_ref max min mlslabel mod months_between natural naturaln nchar nclob new_time next_day nextval nls_charset_decl_len nls_charset_id nls_charset_name nls_initcap nls_lower nls_sort nls_upper nlssort no_data_found notfound null number numeric nvarchar2 nvl others power rawtohex real reftohex round rowcount rowidtochar rowtype rpad rtrim serial sign signtype sin sinh smallint soundex sqlcode sqlerrm sqrt stddev string substr substrb sum sysdate tan tanh to_char text to_date to_label to_multi_byte to_number to_single_byte translate true trunc uid unlogged upper user userenv varchar varchar2 variance varying vsize xml"),operatorChars:/^[*+\-%<>!=~]/,dateSQL:i("date time timestamp"),support:i("doubleQuote nCharCast zerolessFloat binaryNumber hexNumber")}),e.defineMIME("text/x-hive",{name:"sql",keywords:i("select alter $elem$ $key$ $value$ add after all analyze and archive as asc before between binary both bucket buckets by cascade case cast change cluster clustered clusterstatus collection column columns comment compute concatenate continue create cross cursor data database databases dbproperties deferred delete delimited desc describe directory disable distinct distribute drop else enable end escaped exclusive exists explain export extended external false fetch fields fileformat first format formatted from full function functions grant group having hold_ddltime idxproperties if import in index indexes inpath inputdriver inputformat insert intersect into is items join keys lateral left like limit lines load local location lock locks mapjoin materialized minus msck no_drop nocompress not of offline on option or order out outer outputdriver outputformat overwrite partition partitioned partitions percent plus preserve procedure purge range rcfile read readonly reads rebuild recordreader recordwriter recover reduce regexp rename repair replace restrict revoke right rlike row schema schemas semi sequencefile serde serdeproperties set shared show show_database sort sorted ssl statistics stored streamtable table tables tablesample tblproperties temporary terminated textfile then tmp to touch transform trigger true unarchive undo union uniquejoin unlock update use using utc utc_tmestamp view when where while with"),builtin:i("bool boolean long timestamp tinyint smallint bigint int float double date datetime unsigned string array struct map uniontype"),atoms:i("false true null unknown"),operatorChars:/^[*+\-%<>!=]/,dateSQL:i("date timestamp"),support:i("ODBCdotTable doubleQuote binaryNumber hexNumber")})}()}),function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],e):e(CodeMirror)}(function(e){"use strict";function t(e){for(var t={},r=e.split(" "),n=0;n!?|\/]/;return{startState:function(e){return{tokenize:null,context:new a((e||0)-u,0,"top",!1),indented:0,startOfLine:!0}},token:function(e,t){var r=t.context;if(e.sol()&&(null==r.align&&(r.align=!1),t.indented=e.indentation(),t.startOfLine=!0),e.eatSpace())return null;c=null;var i=(t.tokenize||n)(e,t);if("comment"==i||"meta"==i)return i;if(null==r.align&&(r.align=!0),";"!=c&&":"!=c&&","!=c||"statement"!=r.type)if("{"==c)s(t,e.column(),"}");else if("["==c)s(t,e.column(),"]");else if("("==c)s(t,e.column(),")");else if("}"==c){for(;"statement"==r.type;)r=l(t);for("}"==r.type&&(r=l(t));"statement"==r.type;)r=l(t)}else c==r.type?l(t):y&&(("}"==r.type||"top"==r.type)&&";"!=c||"statement"==r.type&&"newstatement"==c)&&s(t,e.column(),"statement");else l(t);return t.startOfLine=!1,i},indent:function(t,r){if(t.tokenize!=n&&null!=t.tokenize)return e.Pass;var i=t.context,o=r&&r.charAt(0);"statement"==i.type&&"}"==o&&(i=i.prev);var a=o==i.type;return"statement"==i.type?i.indented+("{"==o?0:d):!i.align||f&&")"==i.type?")"!=i.type||a?i.indented+(a?0:u):i.indented+d:i.column+(a?0:1)},electricChars:"{}",blockCommentStart:"/*",blockCommentEnd:"*/",lineComment:"//",fold:"brace"}});var l="auto if break int case long char register continue return default short do sizeof double static else struct entry switch extern typedef float union for unsigned goto while enum void const signed volatile";a(["text/x-csrc","text/x-c","text/x-chdr"],{name:"clike",keywords:t(l),blockKeywords:t("case do else for if switch while struct"),atoms:t("null"),hooks:{"#":r},modeProps:{fold:["brace","include"]}}),a(["text/x-c++src","text/x-c++hdr"],{name:"clike",keywords:t(l+" asm dynamic_cast namespace reinterpret_cast try bool explicit new static_cast typeid catch operator template typename class friend private this using const_cast inline public throw virtual delete mutable protected wchar_t alignas alignof constexpr decltype nullptr noexcept thread_local final static_assert override"),blockKeywords:t("catch class do else finally for if struct switch try while"),atoms:t("true false null"),hooks:{"#":r,u:n,U:n,L:n,R:n},modeProps:{fold:["brace","include"]}}),a("text/x-java",{name:"clike",keywords:t("abstract assert boolean break byte case catch char class const continue default do double else enum extends final finally float for goto if implements import instanceof int interface long native new package private protected public return short static strictfp super switch synchronized this throw throws transient try void volatile while"),blockKeywords:t("catch class do else finally for if switch try while"),atoms:t("true false null"),hooks:{"@":function(e){return e.eatWhile(/[\w\$_]/),"meta"}},modeProps:{fold:["brace","import"]}}),a("text/x-csharp",{name:"clike",keywords:t("abstract as base break case catch checked class const continue default delegate do else enum event explicit extern finally fixed for foreach goto if implicit in interface internal is lock namespace new operator out override params private protected public readonly ref return sealed sizeof stackalloc static struct switch this throw try typeof unchecked unsafe using virtual void volatile while add alias ascending descending dynamic from get global group into join let orderby partial remove select set value var yield"),blockKeywords:t("catch class do else finally for foreach if struct switch try while"),builtin:t("Boolean Byte Char DateTime DateTimeOffset Decimal Double Guid Int16 Int32 Int64 Object SByte Single String TimeSpan UInt16 UInt32 UInt64 bool byte char decimal double short int long object sbyte float string ushort uint ulong"),atoms:t("true false null"),hooks:{"@":function(e,t){return e.eat('"')?(t.tokenize=i,i(e,t)):(e.eatWhile(/[\w\$_]/),"meta")}}}),a("text/x-scala",{name:"clike",keywords:t("abstract case catch class def do else extends false final finally for forSome if implicit import lazy match new null object override package private protected return sealed super this throw trait try trye type val var while with yield _ : = => <- <: <% >: # @ assert assume require print println printf readLine readBoolean readByte readShort readChar readInt readLong readFloat readDouble AnyVal App Application Array BufferedIterator BigDecimal BigInt Char Console Either Enumeration Equiv Error Exception Fractional Function IndexedSeq Integral Iterable Iterator List Map Numeric Nil NotNull Option Ordered Ordering PartialFunction PartialOrdering Product Proxy Range Responder Seq Serializable Set Specializable Stream StringBuilder StringContext Symbol Throwable Traversable TraversableOnce Tuple Unit Vector :: #:: Boolean Byte Character CharSequence Class ClassLoader Cloneable Comparable Compiler Double Exception Float Integer Long Math Number Object Package Pair Process Runtime Runnable SecurityManager Short StackTraceElement StrictMath String StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void"), +multiLineStrings:!0,blockKeywords:t("catch class do else finally for forSome if match switch try while"),atoms:t("true false null"),indentStatements:!1,hooks:{"@":function(e){return e.eatWhile(/[\w\$_]/),"meta"},'"':function(e,t){return e.match('""')?(t.tokenize=s,t.tokenize(e,t)):!1},"'":function(e){return e.eatWhile(/[\w\$_\xa1-\uffff]/),"atom"}}}),a(["x-shader/x-vertex","x-shader/x-fragment"],{name:"clike",keywords:t("float int bool void vec2 vec3 vec4 ivec2 ivec3 ivec4 bvec2 bvec3 bvec4 mat2 mat3 mat4 sampler1D sampler2D sampler3D samplerCube sampler1DShadow sampler2DShadow const attribute uniform varying break continue discard return for while do if else struct in out inout"),blockKeywords:t("for while do if else struct"),builtin:t("radians degrees sin cos tan asin acos atan pow exp log exp2 sqrt inversesqrt abs sign floor ceil fract mod min max clamp mix step smoothstep length distance dot cross normalize ftransform faceforward reflect refract matrixCompMult lessThan lessThanEqual greaterThan greaterThanEqual equal notEqual any all not texture1D texture1DProj texture1DLod texture1DProjLod texture2D texture2DProj texture2DLod texture2DProjLod texture3D texture3DProj texture3DLod texture3DProjLod textureCube textureCubeLod shadow1D shadow2D shadow1DProj shadow2DProj shadow1DLod shadow2DLod shadow1DProjLod shadow2DProjLod dFdx dFdy fwidth noise1 noise2 noise3 noise4"),atoms:t("true false gl_FragColor gl_SecondaryColor gl_Normal gl_Vertex gl_MultiTexCoord0 gl_MultiTexCoord1 gl_MultiTexCoord2 gl_MultiTexCoord3 gl_MultiTexCoord4 gl_MultiTexCoord5 gl_MultiTexCoord6 gl_MultiTexCoord7 gl_FogCoord gl_PointCoord gl_Position gl_PointSize gl_ClipVertex gl_FrontColor gl_BackColor gl_FrontSecondaryColor gl_BackSecondaryColor gl_TexCoord gl_FogFragCoord gl_FragCoord gl_FrontFacing gl_FragData gl_FragDepth gl_ModelViewMatrix gl_ProjectionMatrix gl_ModelViewProjectionMatrix gl_TextureMatrix gl_NormalMatrix gl_ModelViewMatrixInverse gl_ProjectionMatrixInverse gl_ModelViewProjectionMatrixInverse gl_TexureMatrixTranspose gl_ModelViewMatrixInverseTranspose gl_ProjectionMatrixInverseTranspose gl_ModelViewProjectionMatrixInverseTranspose gl_TextureMatrixInverseTranspose gl_NormalScale gl_DepthRange gl_ClipPlane gl_Point gl_FrontMaterial gl_BackMaterial gl_LightSource gl_LightModel gl_FrontLightModelProduct gl_BackLightModelProduct gl_TextureColor gl_EyePlaneS gl_EyePlaneT gl_EyePlaneR gl_EyePlaneQ gl_FogParameters gl_MaxLights gl_MaxClipPlanes gl_MaxTextureUnits gl_MaxTextureCoords gl_MaxVertexAttribs gl_MaxVertexUniformComponents gl_MaxVaryingFloats gl_MaxVertexTextureImageUnits gl_MaxTextureImageUnits gl_MaxFragmentUniformComponents gl_MaxCombineTextureImageUnits gl_MaxDrawBuffers"),hooks:{"#":r},modeProps:{fold:["brace","include"]}}),a("text/x-nesc",{name:"clike",keywords:t(l+"as atomic async call command component components configuration event generic implementation includes interface module new norace nx_struct nx_union post provides signal task uses abstract extends"),blockKeywords:t("case do else for if switch while struct"),atoms:t("null"),hooks:{"#":r},modeProps:{fold:["brace","include"]}}),a("text/x-objectivec",{name:"clike",keywords:t(l+"inline restrict _Bool _Complex _Imaginery BOOL Class bycopy byref id IMP in inout nil oneway out Protocol SEL self super atomic nonatomic retain copy readwrite readonly"),atoms:t("YES NO NULL NILL ON OFF"),hooks:{"@":function(e){return e.eatWhile(/[\w\$]/),"keyword"},"#":r},modeProps:{fold:"brace"}})}),function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror"),require("../htmlmixed/htmlmixed"),require("../clike/clike")):"function"==typeof define&&define.amd?define(["../../lib/codemirror","../htmlmixed/htmlmixed","../clike/clike"],e):e(CodeMirror)}(function(e){"use strict";function t(e){for(var t={},r=e.split(" "),n=0;n\w/,!1)&&(t.tokenize=r([[["->",null]],[[/[\w]+/,"variable"]]],n)),"variable-2";for(var i=!1;!e.eol()&&(i||!e.match("{$",!1)&&!e.match(/^(\$[a-zA-Z_][a-zA-Z0-9_]*|\$\{)/,!1));){if(!i&&e.match(n)){t.tokenize=null,t.tokStack.pop(),t.tokStack.pop();break}i="\\"==e.next()&&!i}return"string"}var o="abstract and array as break case catch class clone const continue declare default do else elseif enddeclare endfor endforeach endif endswitch endwhile extends final for foreach function global goto if implements interface instanceof namespace new or private protected public static switch throw trait try use var while xor die echo empty exit eval include include_once isset list require require_once return print unset __halt_compiler self static parent yield insteadof finally",a="true false null TRUE FALSE NULL __CLASS__ __DIR__ __FILE__ __LINE__ __METHOD__ __FUNCTION__ __NAMESPACE__ __TRAIT__",s="func_num_args func_get_arg func_get_args strlen strcmp strncmp strcasecmp strncasecmp each error_reporting define defined trigger_error user_error set_error_handler restore_error_handler get_declared_classes get_loaded_extensions extension_loaded get_extension_funcs debug_backtrace constant bin2hex hex2bin sleep usleep time mktime gmmktime strftime gmstrftime strtotime date gmdate getdate localtime checkdate flush wordwrap htmlspecialchars htmlentities html_entity_decode md5 md5_file crc32 getimagesize image_type_to_mime_type phpinfo phpversion phpcredits strnatcmp strnatcasecmp substr_count strspn strcspn strtok strtoupper strtolower strpos strrpos strrev hebrev hebrevc nl2br basename dirname pathinfo stripslashes stripcslashes strstr stristr strrchr str_shuffle str_word_count strcoll substr substr_replace quotemeta ucfirst ucwords strtr addslashes addcslashes rtrim str_replace str_repeat count_chars chunk_split trim ltrim strip_tags similar_text explode implode setlocale localeconv parse_str str_pad chop strchr sprintf printf vprintf vsprintf sscanf fscanf parse_url urlencode urldecode rawurlencode rawurldecode readlink linkinfo link unlink exec system escapeshellcmd escapeshellarg passthru shell_exec proc_open proc_close rand srand getrandmax mt_rand mt_srand mt_getrandmax base64_decode base64_encode abs ceil floor round is_finite is_nan is_infinite bindec hexdec octdec decbin decoct dechex base_convert number_format fmod ip2long long2ip getenv putenv getopt microtime gettimeofday getrusage uniqid quoted_printable_decode set_time_limit get_cfg_var magic_quotes_runtime set_magic_quotes_runtime get_magic_quotes_gpc get_magic_quotes_runtime import_request_variables error_log serialize unserialize memory_get_usage var_dump var_export debug_zval_dump print_r highlight_file show_source highlight_string ini_get ini_get_all ini_set ini_alter ini_restore get_include_path set_include_path restore_include_path setcookie header headers_sent connection_aborted connection_status ignore_user_abort parse_ini_file is_uploaded_file move_uploaded_file intval floatval doubleval strval gettype settype is_null is_resource is_bool is_long is_float is_int is_integer is_double is_real is_numeric is_string is_array is_object is_scalar ereg ereg_replace eregi eregi_replace split spliti join sql_regcase dl pclose popen readfile rewind rmdir umask fclose feof fgetc fgets fgetss fread fopen fpassthru ftruncate fstat fseek ftell fflush fwrite fputs mkdir rename copy tempnam tmpfile file file_get_contents stream_select stream_context_create stream_context_set_params stream_context_set_option stream_context_get_options stream_filter_prepend stream_filter_append fgetcsv flock get_meta_tags stream_set_write_buffer set_file_buffer set_socket_blocking stream_set_blocking socket_set_blocking stream_get_meta_data stream_register_wrapper stream_wrapper_register stream_set_timeout socket_set_timeout socket_get_status realpath fnmatch fsockopen pfsockopen pack unpack get_browser crypt opendir closedir chdir getcwd rewinddir readdir dir glob fileatime filectime filegroup fileinode filemtime fileowner fileperms filesize filetype file_exists is_writable is_writeable is_readable is_executable is_file is_dir is_link stat lstat chown touch clearstatcache mail ob_start ob_flush ob_clean ob_end_flush ob_end_clean ob_get_flush ob_get_clean ob_get_length ob_get_level ob_get_status ob_get_contents ob_implicit_flush ob_list_handlers ksort krsort natsort natcasesort asort arsort sort rsort usort uasort uksort shuffle array_walk count end prev next reset current key min max in_array array_search extract compact array_fill range array_multisort array_push array_pop array_shift array_unshift array_splice array_slice array_merge array_merge_recursive array_keys array_values array_count_values array_reverse array_reduce array_pad array_flip array_change_key_case array_rand array_unique array_intersect array_intersect_assoc array_diff array_diff_assoc array_sum array_filter array_map array_chunk array_key_exists pos sizeof key_exists assert assert_options version_compare ftok str_rot13 aggregate session_name session_module_name session_save_path session_id session_regenerate_id session_decode session_register session_unregister session_is_registered session_encode session_start session_destroy session_unset session_set_save_handler session_cache_limiter session_cache_expire session_set_cookie_params session_get_cookie_params session_write_close preg_match preg_match_all preg_replace preg_replace_callback preg_split preg_quote preg_grep overload ctype_alnum ctype_alpha ctype_cntrl ctype_digit ctype_lower ctype_graph ctype_print ctype_punct ctype_space ctype_upper ctype_xdigit virtual apache_request_headers apache_note apache_lookup_uri apache_child_terminate apache_setenv apache_response_headers apache_get_version getallheaders mysql_connect mysql_pconnect mysql_close mysql_select_db mysql_create_db mysql_drop_db mysql_query mysql_unbuffered_query mysql_db_query mysql_list_dbs mysql_list_tables mysql_list_fields mysql_list_processes mysql_error mysql_errno mysql_affected_rows mysql_insert_id mysql_result mysql_num_rows mysql_num_fields mysql_fetch_row mysql_fetch_array mysql_fetch_assoc mysql_fetch_object mysql_data_seek mysql_fetch_lengths mysql_fetch_field mysql_field_seek mysql_free_result mysql_field_name mysql_field_table mysql_field_len mysql_field_type mysql_field_flags mysql_escape_string mysql_real_escape_string mysql_stat mysql_thread_id mysql_client_encoding mysql_get_client_info mysql_get_host_info mysql_get_proto_info mysql_get_server_info mysql_info mysql mysql_fieldname mysql_fieldtable mysql_fieldlen mysql_fieldtype mysql_fieldflags mysql_selectdb mysql_createdb mysql_dropdb mysql_freeresult mysql_numfields mysql_numrows mysql_listdbs mysql_listtables mysql_listfields mysql_db_name mysql_dbname mysql_tablename mysql_table_name pg_connect pg_pconnect pg_close pg_connection_status pg_connection_busy pg_connection_reset pg_host pg_dbname pg_port pg_tty pg_options pg_ping pg_query pg_send_query pg_cancel_query pg_fetch_result pg_fetch_row pg_fetch_assoc pg_fetch_array pg_fetch_object pg_fetch_all pg_affected_rows pg_get_result pg_result_seek pg_result_status pg_free_result pg_last_oid pg_num_rows pg_num_fields pg_field_name pg_field_num pg_field_size pg_field_type pg_field_prtlen pg_field_is_null pg_get_notify pg_get_pid pg_result_error pg_last_error pg_last_notice pg_put_line pg_end_copy pg_copy_to pg_copy_from pg_trace pg_untrace pg_lo_create pg_lo_unlink pg_lo_open pg_lo_close pg_lo_read pg_lo_write pg_lo_read_all pg_lo_import pg_lo_export pg_lo_seek pg_lo_tell pg_escape_string pg_escape_bytea pg_unescape_bytea pg_client_encoding pg_set_client_encoding pg_meta_data pg_convert pg_insert pg_update pg_delete pg_select pg_exec pg_getlastoid pg_cmdtuples pg_errormessage pg_numrows pg_numfields pg_fieldname pg_fieldsize pg_fieldtype pg_fieldnum pg_fieldprtlen pg_fieldisnull pg_freeresult pg_result pg_loreadall pg_locreate pg_lounlink pg_loopen pg_loclose pg_loread pg_lowrite pg_loimport pg_loexport http_response_code get_declared_traits getimagesizefromstring socket_import_stream stream_set_chunk_size trait_exists header_register_callback class_uses session_status session_register_shutdown echo print global static exit array empty eval isset unset die include require include_once require_once json_decode json_encode json_last_error json_last_error_msg curl_close curl_copy_handle curl_errno curl_error curl_escape curl_exec curl_file_create curl_getinfo curl_init curl_multi_add_handle curl_multi_close curl_multi_exec curl_multi_getcontent curl_multi_info_read curl_multi_init curl_multi_remove_handle curl_multi_select curl_multi_setopt curl_multi_strerror curl_pause curl_reset curl_setopt_array curl_setopt curl_share_close curl_share_init curl_share_setopt curl_strerror curl_unescape curl_version mysqli_affected_rows mysqli_autocommit mysqli_change_user mysqli_character_set_name mysqli_close mysqli_commit mysqli_connect_errno mysqli_connect_error mysqli_connect mysqli_data_seek mysqli_debug mysqli_dump_debug_info mysqli_errno mysqli_error_list mysqli_error mysqli_fetch_all mysqli_fetch_array mysqli_fetch_assoc mysqli_fetch_field_direct mysqli_fetch_field mysqli_fetch_fields mysqli_fetch_lengths mysqli_fetch_object mysqli_fetch_row mysqli_field_count mysqli_field_seek mysqli_field_tell mysqli_free_result mysqli_get_charset mysqli_get_client_info mysqli_get_client_stats mysqli_get_client_version mysqli_get_connection_stats mysqli_get_host_info mysqli_get_proto_info mysqli_get_server_info mysqli_get_server_version mysqli_info mysqli_init mysqli_insert_id mysqli_kill mysqli_more_results mysqli_multi_query mysqli_next_result mysqli_num_fields mysqli_num_rows mysqli_options mysqli_ping mysqli_prepare mysqli_query mysqli_real_connect mysqli_real_escape_string mysqli_real_query mysqli_reap_async_query mysqli_refresh mysqli_rollback mysqli_select_db mysqli_set_charset mysqli_set_local_infile_default mysqli_set_local_infile_handler mysqli_sqlstate mysqli_ssl_set mysqli_stat mysqli_stmt_init mysqli_store_result mysqli_thread_id mysqli_thread_safe mysqli_use_result mysqli_warning_count";e.registerHelper("hintWords","php",[o,a,s].join(" ").split(" ")),e.registerHelper("wordChars","php",/[\w$]/);var l={name:"clike",helperType:"php",keywords:t(o),blockKeywords:t("catch do else elseif for foreach if switch try while finally"),atoms:t(a),builtin:t(s),multiLineStrings:!0,hooks:{$:function(e){return e.eatWhile(/[\w\$_]/),"variable-2"},"<":function(e,t){if(e.match(/<",!1);)e.next();return"comment"},"/":function(e){if(e.eat("/")){for(;!e.eol()&&!e.match("?>",!1);)e.next();return"comment"}return!1},'"':function(e,t){return(t.tokStack||(t.tokStack=[])).push('"',0),t.tokenize=n('"'),"string"},"{":function(e,t){return t.tokStack&&t.tokStack.length&&t.tokStack[t.tokStack.length-1]++,!1},"}":function(e,t){return t.tokStack&&t.tokStack.length>0&&!--t.tokStack[t.tokStack.length-1]&&(t.tokenize=n(t.tokStack[t.tokStack.length-2])),!1}}};e.defineMode("php",function(t,r){function n(e,t){var r=t.curMode==o;if(e.sol()&&t.pending&&'"'!=t.pending&&"'"!=t.pending&&(t.pending=null),r)return r&&null==t.php.tokenize&&e.match("?>")?(t.curMode=i,t.curState=t.html,"meta"):o.token(e,t.curState);if(e.match(/^<\?\w*/))return t.curMode=o,t.curState=t.php,"meta";if('"'==t.pending||"'"==t.pending){for(;!e.eol()&&e.next()!=t.pending;);var n="string"}else if(t.pending&&e.pos/.test(s)?t.pending=a[0]:t.pending={end:e.pos,style:n},e.backUp(s.length-l)),n}var i=e.getMode(t,"text/html"),o=e.getMode(t,l);return{startState:function(){var t=e.startState(i),n=e.startState(o);return{html:t,php:n,curMode:r.startOpen?o:i,curState:r.startOpen?n:t,pending:null}},copyState:function(t){var r,n=t.html,a=e.copyState(i,n),s=t.php,l=e.copyState(o,s);return r=t.curMode==i?a:l,{html:a,php:l,curMode:t.curMode,curState:r,pending:t.pending}},token:n,indent:function(e,t){return e.curMode!=o&&/^\s*<\//.test(t)||e.curMode==o&&/^\?>/.test(t)?i.indent(e.html,t):e.curMode.indent(e.curState,t)},blockCommentStart:"/*",blockCommentEnd:"*/",lineComment:"//",innerMode:function(e){return{state:e.curState,mode:e.curMode}}}},"htmlmixed","clike"),e.defineMIME("application/x-httpd-php","php"),e.defineMIME("application/x-httpd-php-open",{name:"php",startOpen:!0}),e.defineMIME("text/x-php",l)}),function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],e):e(CodeMirror)}(function(e){"use strict";e.defineMode("xml",function(t,r){function n(e,t){function r(r){return t.tokenize=r,r(e,t)}var n=e.next();if("<"==n)return e.eat("!")?e.eat("[")?e.match("CDATA[")?r(a("atom","]]>")):null:e.match("--")?r(a("comment","-->")):e.match("DOCTYPE",!0,!0)?(e.eatWhile(/[\w\._\-]/),r(s(1))):null:e.eat("?")?(e.eatWhile(/[\w\._\-]/),t.tokenize=a("meta","?>"),"meta"):(_=e.eat("/")?"closeTag":"openTag",t.tokenize=i,"tag bracket");if("&"==n){var o;return o=e.eat("#")?e.eat("x")?e.eatWhile(/[a-fA-F\d]/)&&e.eat(";"):e.eatWhile(/[\d]/)&&e.eat(";"):e.eatWhile(/[\w\.\-:]/)&&e.eat(";"),o?"atom":"error"}return e.eatWhile(/[^&<]/),null}function i(e,t){var r=e.next();if(">"==r||"/"==r&&e.eat(">"))return t.tokenize=n,_=">"==r?"endTag":"selfcloseTag","tag bracket";if("="==r)return _="equals",null;if("<"==r){t.tokenize=n,t.state=d,t.tagName=t.tagStart=null;var i=t.tokenize(e,t);return i?i+" tag error":"tag error"}return/[\'\"]/.test(r)?(t.tokenize=o(r),t.stringStartCol=e.column(),t.tokenize(e,t)):(e.match(/^[^\s\u00a0=<>\"\']*[^\s\u00a0=<>\"\'\/]/),"word")}function o(e){var t=function(t,r){for(;!t.eol();)if(t.next()==e){r.tokenize=i;break}return"string"};return t.isInAttribute=!0,t}function a(e,t){return function(r,i){for(;!r.eol();){if(r.match(t)){i.tokenize=n;break}r.next()}return e}}function s(e){return function(t,r){for(var i;null!=(i=t.next());){if("<"==i)return r.tokenize=s(e+1),r.tokenize(t,r);if(">"==i){if(1==e){r.tokenize=n;break}return r.tokenize=s(e-1),r.tokenize(t,r)}}return"meta"}}function l(e,t,r){this.prev=e.context,this.tagName=t,this.indent=e.indented,this.startOfLine=r,(S.doNotIndent.hasOwnProperty(t)||e.context&&e.context.noIndent)&&(this.noIndent=!0)}function c(e){e.context&&(e.context=e.context.prev)}function u(e,t){for(var r;;){if(!e.context)return;if(r=e.context.tagName,!S.contextGrabbers.hasOwnProperty(r)||!S.contextGrabbers[r].hasOwnProperty(t))return;c(e)}}function d(e,t,r){return"openTag"==e?(r.tagStart=t.column(),f):"closeTag"==e?m:d}function f(e,t,r){return"word"==e?(r.tagName=t.current(),C="tag",g):(C="error",f)}function m(e,t,r){if("word"==e){var n=t.current();return r.context&&r.context.tagName!=n&&S.implicitlyClosed.hasOwnProperty(r.context.tagName)&&c(r),r.context&&r.context.tagName==n?(C="tag",h):(C="tag error",p)}return C="error",p}function h(e,t,r){return"endTag"!=e?(C="error",h):(c(r),d)}function p(e,t,r){return C="error",h(e,t,r)}function g(e,t,r){if("word"==e)return C="attribute",v;if("endTag"==e||"selfcloseTag"==e){var n=r.tagName,i=r.tagStart;return r.tagName=r.tagStart=null,"selfcloseTag"==e||S.autoSelfClosers.hasOwnProperty(n)?u(r,n):(u(r,n),r.context=new l(r,n,i==r.indented)),d}return C="error",g}function v(e,t,r){return"equals"==e?b:(S.allowMissing||(C="error"),g(e,t,r))}function b(e,t,r){return"string"==e?y:"word"==e&&S.allowUnquoted?(C="string",g):(C="error",g(e,t,r))}function y(e,t,r){return"string"==e?y:g(e,t,r)}var x=t.indentUnit,k=r.multilineTagIndentFactor||1,w=r.multilineTagIndentPastTag;null==w&&(w=!0);var _,C,S=r.htmlMode?{autoSelfClosers:{area:!0,base:!0,br:!0,col:!0,command:!0,embed:!0,frame:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0,menuitem:!0},implicitlyClosed:{dd:!0,li:!0,optgroup:!0,option:!0,p:!0,rp:!0,rt:!0,tbody:!0,td:!0,tfoot:!0,th:!0,tr:!0},contextGrabbers:{dd:{dd:!0,dt:!0},dt:{dd:!0,dt:!0},li:{li:!0},option:{option:!0,optgroup:!0},optgroup:{optgroup:!0},p:{address:!0,article:!0,aside:!0,blockquote:!0,dir:!0,div:!0,dl:!0,fieldset:!0,footer:!0,form:!0,h1:!0,h2:!0,h3:!0,h4:!0,h5:!0,h6:!0,header:!0,hgroup:!0,hr:!0,menu:!0,nav:!0,ol:!0,p:!0,pre:!0,section:!0,table:!0,ul:!0},rp:{rp:!0,rt:!0},rt:{rp:!0,rt:!0},tbody:{tbody:!0,tfoot:!0},td:{td:!0,th:!0},tfoot:{tbody:!0},th:{td:!0,th:!0},thead:{tbody:!0,tfoot:!0},tr:{tr:!0}},doNotIndent:{pre:!0},allowUnquoted:!0,allowMissing:!0,caseFold:!0}:{autoSelfClosers:{},implicitlyClosed:{},contextGrabbers:{},doNotIndent:{},allowUnquoted:!1,allowMissing:!1,caseFold:!1},T=r.alignCDATA;return{startState:function(){return{tokenize:n,state:d,indented:0,tagName:null,tagStart:null,context:null}},token:function(e,t){if(!t.tagName&&e.sol()&&(t.indented=e.indentation()),e.eatSpace())return null;_=null;var r=t.tokenize(e,t);return(r||_)&&"comment"!=r&&(C=null,t.state=t.state(_||r,e,t),C&&(r="error"==C?r+" error":C)),r},indent:function(t,r,o){var a=t.context;if(t.tokenize.isInAttribute)return t.tagStart==t.indented?t.stringStartCol+1:t.indented+x;if(a&&a.noIndent)return e.Pass;if(t.tokenize!=i&&t.tokenize!=n)return o?o.match(/^(\s*)/)[0].length:0;if(t.tagName)return w?t.tagStart+t.tagName.length+2:t.tagStart+x*k;if(T&&/$/,blockCommentStart:"",configuration:r.htmlMode?"html":"xml",helperType:r.htmlMode?"html":"xml"}}),e.defineMIME("text/xml","xml"),e.defineMIME("application/xml","xml"),e.mimeModes.hasOwnProperty("text/html")||e.defineMIME("text/html",{name:"xml",htmlMode:!0})}),function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror"),require("../xml/xml"),require("../meta")):"function"==typeof define&&define.amd?define(["../../lib/codemirror","../xml/xml","../meta"],e):e(CodeMirror)}(function(e){"use strict";e.defineMode("markdown",function(t,r){function n(r){if(e.findModeByName){var n=e.findModeByName(r);n&&(r=n.mime||n.mimes[0])}var i=e.getMode(t,r);return"null"==i.name?null:i}function i(e,t,r){return t.f=t.inline=r,r(e,t)}function o(e,t,r){return t.f=t.block=r,r(e,t)}function a(e){return e.linkTitle=!1,e.em=!1,e.strong=!1,e.strikethrough=!1,e.quote=0,k||e.f!=l||(e.f=m,e.block=s),e.trailingSpace=0,e.trailingSpaceNewLine=!1,e.thisLineHasContent=!1,null}function s(e,t){var o=e.sol(),a=t.list!==!1;t.list!==!1&&t.indentationDiff>=0?(t.indentationDiff<4&&(t.indentation-=t.indentationDiff),t.list=null):t.list!==!1&&t.indentation>0?(t.list=null,t.listDepth=Math.floor(t.indentation/4)):t.list!==!1&&(t.list=!1,t.listDepth=0);var s=null;if(t.indentationDiff>=4)return t.indentation-=4,e.skipToEnd(),S;if(e.eatSpace())return null;if(s=e.match(U))return t.header=s[0].length<=6?s[0].length:6,r.highlightFormatting&&(t.formatting="header"),t.f=t.inline,d(t);if(t.prevLineHasContent&&(s=e.match(W)))return t.header="="==s[0].charAt(0)?1:2,r.highlightFormatting&&(t.formatting="header"),t.f=t.inline,d(t);if(e.eat(">"))return t.indentation++,t.quote=o?1:t.quote+1,r.highlightFormatting&&(t.formatting="quote"),e.eatSpace(),d(t);if("["===e.peek())return i(e,t,v);if(e.match(F,!0))return q;if((!t.prevLineHasContent||a)&&(e.match(H,!1)||e.match(N,!1))){var l=null;return e.match(H,!0)?l="ul":(e.match(N,!0),l="ol"),t.indentation+=4,t.list=!0,t.listDepth++,r.taskLists&&e.match(B,!1)&&(t.taskList=!0),t.f=t.inline,r.highlightFormatting&&(t.formatting=["list","list-"+l]),d(t)}return r.fencedCodeBlocks&&e.match(/^```[ \t]*([\w+#]*)/,!0)?(t.localMode=n(RegExp.$1),t.localMode&&(t.localState=t.localMode.startState()),t.f=t.block=c,r.highlightFormatting&&(t.formatting="code-block"),t.code=!0,d(t)):i(e,t,t.inline)}function l(e,t){var r=w.token(e,t.htmlState);return(k&&null===t.htmlState.tagStart&&!t.htmlState.context||t.md_inside&&e.current().indexOf(">")>-1)&&(t.f=m,t.block=s,t.htmlState=null),r}function c(e,t){return e.sol()&&e.match("```",!1)?(t.localMode=t.localState=null,t.f=t.block=u,null):t.localMode?t.localMode.token(e,t.localState):(e.skipToEnd(),S)}function u(e,t){e.match("```"),t.block=s,t.f=m,r.highlightFormatting&&(t.formatting="code-block"),t.code=!0;var n=d(t);return t.code=!1,n}function d(e){var t=[];if(e.formatting){t.push(z),"string"==typeof e.formatting&&(e.formatting=[e.formatting]);for(var n=0;n=e.quote?z+"-"+e.formatting[n]+"-"+e.quote:"error")}if(e.taskOpen)return t.push("meta"),t.length?t.join(" "):null;if(e.taskClosed)return t.push("property"),t.length?t.join(" "):null;if(e.linkHref)return t.push(A),t.length?t.join(" "):null;if(e.strong&&t.push(O),e.em&&t.push($),e.strikethrough&&t.push(R),e.linkText&&t.push(D),e.code&&t.push(S),e.header&&(t.push(C),t.push(C+"-"+e.header)),e.quote&&(t.push(T),t.push(!r.maxBlockquoteDepth||r.maxBlockquoteDepth>=e.quote?T+"-"+e.quote:T+"-"+r.maxBlockquoteDepth)),e.list!==!1){var i=(e.listDepth-1)%3;t.push(i?1===i?L:E:M)}return e.trailingSpaceNewLine?t.push("trailing-space-new-line"):e.trailingSpace&&t.push("trailing-space-"+(e.trailingSpace%2?"a":"b")),t.length?t.join(" "):null}function f(e,t){return e.match(V,!0)?d(t):void 0}function m(t,n){var i=n.text(t,n);if("undefined"!=typeof i)return i;if(n.list)return n.list=null,d(n);if(n.taskList){var a="x"!==t.match(B,!0)[1];return a?n.taskOpen=!0:n.taskClosed=!0,r.highlightFormatting&&(n.formatting="task"),n.taskList=!1,d(n)}if(n.taskOpen=!1,n.taskClosed=!1,n.header&&t.match(/^#+$/,!0))return r.highlightFormatting&&(n.formatting="header"),d(n);var s=t.sol(),c=t.next();if("\\"===c&&(t.next(),r.highlightFormatting)){var u=d(n);return u?u+" formatting-escape":"formatting-escape"}if(n.linkTitle){n.linkTitle=!1;var f=c;"("===c&&(f=")"),f=(f+"").replace(/([.?*+^$[\]\\(){}|-])/g,"\\$1");var m="^\\s*(?:[^"+f+"\\\\]+|\\\\\\\\|\\\\.)"+f;if(t.match(new RegExp(m),!0))return A}if("`"===c){var g=n.formatting;r.highlightFormatting&&(n.formatting="code");var v=d(n),b=t.pos;t.eatWhile("`");var y=1+t.pos-b;return n.code?y===_?(n.code=!1,v):(n.formatting=g,d(n)):(_=y,n.code=!0,d(n))}if(n.code)return d(n);if("!"===c&&t.match(/\[[^\]]*\] ?(?:\(|\[)/,!1))return t.match(/\[[^\]]*\]/),n.inline=n.f=p,j;if("["===c&&t.match(/.*\](\(.*\)| ?\[.*\])/,!1))return n.linkText=!0,r.highlightFormatting&&(n.formatting="link"),d(n);if("]"===c&&n.linkText&&t.match(/\(.*\)| ?\[.*\]/,!1)){r.highlightFormatting&&(n.formatting="link");var u=d(n);return n.linkText=!1,n.inline=n.f=p,u}if("<"===c&&t.match(/^(https?|ftps?):\/\/(?:[^\\>]|\\.)+>/,!1)){n.f=n.inline=h,r.highlightFormatting&&(n.formatting="link");var u=d(n);return u?u+=" ":u="",u+I}if("<"===c&&t.match(/^[^> \\]+@(?:[^\\>]|\\.)+>/,!1)){n.f=n.inline=h,r.highlightFormatting&&(n.formatting="link");var u=d(n);return u?u+=" ":u="",u+P}if("<"===c&&t.match(/^\w/,!1)){if(-1!=t.string.indexOf(">")){var x=t.string.substring(1,t.string.indexOf(">"));/markdown\s*=\s*('|"){0,1}1('|"){0,1}/.test(x)&&(n.md_inside=!0)}return t.backUp(1),n.htmlState=e.startState(w),o(t,n,l)}if("<"===c&&t.match(/^\/\w*?>/))return n.md_inside=!1,"tag";var k=!1;if(!r.underscoresBreakWords&&"_"===c&&"_"!==t.peek()&&t.match(/(\w)/,!1)){var C=t.pos-2;if(C>=0){var S=t.string.charAt(C);"_"!==S&&S.match(/(\w)/,!1)&&(k=!0)}}if("*"===c||"_"===c&&!k)if(s&&" "===t.peek());else{if(n.strong===c&&t.eat(c)){r.highlightFormatting&&(n.formatting="strong");var v=d(n);return n.strong=!1,v}if(!n.strong&&t.eat(c))return n.strong=c,r.highlightFormatting&&(n.formatting="strong"),d(n);if(n.em===c){r.highlightFormatting&&(n.formatting="em");var v=d(n);return n.em=!1,v}if(!n.em)return n.em=c,r.highlightFormatting&&(n.formatting="em"),d(n)}else if(" "===c&&(t.eat("*")||t.eat("_"))){if(" "===t.peek())return d(n);t.backUp(1)}if(r.strikethrough)if("~"===c&&t.eatWhile(c)){if(n.strikethrough){r.highlightFormatting&&(n.formatting="strikethrough");var v=d(n);return n.strikethrough=!1,v}if(t.match(/^[^\s]/,!1))return n.strikethrough=!0,r.highlightFormatting&&(n.formatting="strikethrough"),d(n)}else if(" "===c&&t.match(/^~~/,!0)){if(" "===t.peek())return d(n);t.backUp(2)}return" "===c&&(t.match(/ +$/,!1)?n.trailingSpace++:n.trailingSpace&&(n.trailingSpaceNewLine=!0)),d(n)}function h(e,t){var n=e.next();if(">"===n){t.f=t.inline=m,r.highlightFormatting&&(t.formatting="link");var i=d(t);return i?i+=" ":i="",i+I}return e.match(/^[^>]+/,!0),I}function p(e,t){if(e.eatSpace())return null;var n=e.next();return"("===n||"["===n?(t.f=t.inline=g("("===n?")":"]"),r.highlightFormatting&&(t.formatting="link-string"),t.linkHref=!0,d(t)):"error"}function g(e){return function(t,n){var i=t.next();if(i===e){n.f=n.inline=m,r.highlightFormatting&&(n.formatting="link-string");var o=d(n);return n.linkHref=!1,o}return t.match(x(e),!0)&&t.backUp(1),n.linkHref=!0,d(n)}}function v(e,t){return e.match(/^[^\]]*\]:/,!1)?(t.f=b,e.next(),r.highlightFormatting&&(t.formatting="link"),t.linkText=!0,d(t)):i(e,t,m)}function b(e,t){if(e.match(/^\]:/,!0)){t.f=t.inline=y,r.highlightFormatting&&(t.formatting="link");var n=d(t);return t.linkText=!1,n}return e.match(/^[^\]]+/,!0),D}function y(e,t){return e.eatSpace()?null:(e.match(/^[^\s]+/,!0),void 0===e.peek()?t.linkTitle=!0:e.match(/^(?:\s+(?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\)))?/,!0),t.f=t.inline=m,A)}function x(e){return K[e]||(e=(e+"").replace(/([.?*+^$[\]\\(){}|-])/g,"\\$1"),K[e]=new RegExp("^(?:[^\\\\]|\\\\.)*?("+e+")")),K[e]}var k=e.modes.hasOwnProperty("xml"),w=e.getMode(t,k?{name:"xml",htmlMode:!0}:"text/plain");void 0===r.highlightFormatting&&(r.highlightFormatting=!1),void 0===r.maxBlockquoteDepth&&(r.maxBlockquoteDepth=0),void 0===r.underscoresBreakWords&&(r.underscoresBreakWords=!0),void 0===r.fencedCodeBlocks&&(r.fencedCodeBlocks=!1),void 0===r.taskLists&&(r.taskLists=!1),void 0===r.strikethrough&&(r.strikethrough=!1);var _=0,C="header",S="comment",T="quote",M="variable-2",L="variable-3",E="keyword",q="hr",j="tag",z="formatting",I="link",P="link",D="link",A="string",$="em",O="strong",R="strikethrough",F=/^([*\-=_])(?:\s*\1){2,}\s*$/,H=/^[*\-+]\s+/,N=/^[0-9]+\.\s+/,B=/^\[(x| )\](?=\s)/,U=/^#+/,W=/^(?:\={1,}|-{1,})$/,V=/^[^#!\[\]*_\\<>` "'(~]+/,K=[],Z={startState:function(){return{f:s,prevLineHasContent:!1,thisLineHasContent:!1,block:s,htmlState:null,indentation:0,inline:m,text:f,formatting:!1,linkText:!1,linkHref:!1,linkTitle:!1,em:!1,strong:!1,header:0,taskList:!1,list:!1,listDepth:0,quote:0,trailingSpace:0,trailingSpaceNewLine:!1,strikethrough:!1}},copyState:function(t){return{f:t.f,prevLineHasContent:t.prevLineHasContent,thisLineHasContent:t.thisLineHasContent,block:t.block,htmlState:t.htmlState&&e.copyState(w,t.htmlState),indentation:t.indentation,localMode:t.localMode,localState:t.localMode?e.copyState(t.localMode,t.localState):null,inline:t.inline,text:t.text,formatting:!1,linkTitle:t.linkTitle,em:t.em,strong:t.strong,strikethrough:t.strikethrough,header:t.header,taskList:t.taskList,list:t.list,listDepth:t.listDepth,quote:t.quote, +trailingSpace:t.trailingSpace,trailingSpaceNewLine:t.trailingSpaceNewLine,md_inside:t.md_inside}},token:function(e,t){if(t.formatting=!1,e.sol()){var r=!!t.header;if(t.header=0,e.match(/^\s*$/,!0)||r)return t.prevLineHasContent=!1,a(t),r?this.token(e,t):null;t.prevLineHasContent=t.thisLineHasContent,t.thisLineHasContent=!0,t.taskList=!1,t.code=!1,t.trailingSpace=0,t.trailingSpaceNewLine=!1,t.f=t.block;var n=e.match(/^\s*/,!0)[0].replace(/\t/g," ").length,i=4*Math.floor((n-t.indentation)/4);i>4&&(i=4);var o=t.indentation+i;if(t.indentationDiff=o-t.indentation,t.indentation=o,n>0)return null}return t.f(e,t)},innerMode:function(e){return e.block==l?{state:e.htmlState,mode:w}:e.localState?{state:e.localState,mode:e.localMode}:{state:e,mode:Z}},blankLine:a,getType:d,fold:"markdown"};return Z},"xml"),e.defineMIME("text/x-markdown","markdown")}),function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],e):e(CodeMirror)}(function(e){"use strict";e.defineMode("javascript",function(t,r){function n(e){for(var t,r=!1,n=!1;null!=(t=e.next());){if(!r){if("/"==t&&!n)return;"["==t?n=!0:n&&"]"==t&&(n=!1)}r=!r&&"\\"==t}}function i(e,t,r){return pe=e,ge=r,t}function o(e,t){var r=e.next();if('"'==r||"'"==r)return t.tokenize=a(r),t.tokenize(e,t);if("."==r&&e.match(/^\d+(?:[eE][+\-]?\d+)?/))return i("number","number");if("."==r&&e.match(".."))return i("spread","meta");if(/[\[\]{}\(\),;\:\.]/.test(r))return i(r);if("="==r&&e.eat(">"))return i("=>","operator");if("0"==r&&e.eat(/x/i))return e.eatWhile(/[\da-f]/i),i("number","number");if(/\d/.test(r))return e.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/),i("number","number");if("/"==r)return e.eat("*")?(t.tokenize=s,s(e,t)):e.eat("/")?(e.skipToEnd(),i("comment","comment")):"operator"==t.lastType||"keyword c"==t.lastType||"sof"==t.lastType||/^[\[{}\(,;:]$/.test(t.lastType)?(n(e),e.match(/^\b(([gimyu])(?![gimyu]*\2))+\b/),i("regexp","string-2")):(e.eatWhile(Ce),i("operator","operator",e.current()));if("`"==r)return t.tokenize=l,l(e,t);if("#"==r)return e.skipToEnd(),i("error","error");if(Ce.test(r))return e.eatWhile(Ce),i("operator","operator",e.current());if(we.test(r)){e.eatWhile(we);var o=e.current(),c=_e.propertyIsEnumerable(o)&&_e[o];return c&&"."!=t.lastType?i(c.type,c.style,o):i("variable","variable",o)}}function a(e){return function(t,r){var n,a=!1;if(ye&&"@"==t.peek()&&t.match(Se))return r.tokenize=o,i("jsonld-keyword","meta");for(;null!=(n=t.next())&&(n!=e||a);)a=!a&&"\\"==n;return a||(r.tokenize=o),i("string","string")}}function s(e,t){for(var r,n=!1;r=e.next();){if("/"==r&&n){t.tokenize=o;break}n="*"==r}return i("comment","comment")}function l(e,t){for(var r,n=!1;null!=(r=e.next());){if(!n&&("`"==r||"$"==r&&e.eat("{"))){t.tokenize=o;break}n=!n&&"\\"==r}return i("quasi","string-2",e.current())}function c(e,t){t.fatArrowAt&&(t.fatArrowAt=null);var r=e.string.indexOf("=>",e.start);if(!(0>r)){for(var n=0,i=!1,o=r-1;o>=0;--o){var a=e.string.charAt(o),s=Te.indexOf(a);if(s>=0&&3>s){if(!n){++o;break}if(0==--n)break}else if(s>=3&&6>s)++n;else if(we.test(a))i=!0;else{if(/["'\/]/.test(a))return;if(i&&!n){++o;break}}}i&&!n&&(t.fatArrowAt=o)}}function u(e,t,r,n,i,o){this.indented=e,this.column=t,this.type=r,this.prev=i,this.info=o,null!=n&&(this.align=n)}function d(e,t){for(var r=e.localVars;r;r=r.next)if(r.name==t)return!0;for(var n=e.context;n;n=n.prev)for(var r=n.vars;r;r=r.next)if(r.name==t)return!0}function f(e,t,r,n,i){var o=e.cc;for(Le.state=e,Le.stream=i,Le.marked=null,Le.cc=o,Le.style=t,e.lexical.hasOwnProperty("align")||(e.lexical.align=!0);;){var a=o.length?o.pop():xe?w:k;if(a(r,n)){for(;o.length&&o[o.length-1].lex;)o.pop()();return Le.marked?Le.marked:"variable"==r&&d(e,n)?"variable-2":t}}}function m(){for(var e=arguments.length-1;e>=0;e--)Le.cc.push(arguments[e])}function h(){return m.apply(null,arguments),!0}function p(e){function t(t){for(var r=t;r;r=r.next)if(r.name==e)return!0;return!1}var n=Le.state;if(n.context){if(Le.marked="def",t(n.localVars))return;n.localVars={name:e,next:n.localVars}}else{if(t(n.globalVars))return;r.globalVars&&(n.globalVars={name:e,next:n.globalVars})}}function g(){Le.state.context={prev:Le.state.context,vars:Le.state.localVars},Le.state.localVars=Ee}function v(){Le.state.localVars=Le.state.context.vars,Le.state.context=Le.state.context.prev}function b(e,t){var r=function(){var r=Le.state,n=r.indented;if("stat"==r.lexical.type)n=r.lexical.indented;else for(var i=r.lexical;i&&")"==i.type&&i.align;i=i.prev)n=i.indented;r.lexical=new u(n,Le.stream.column(),e,null,r.lexical,t)};return r.lex=!0,r}function y(){var e=Le.state;e.lexical.prev&&(")"==e.lexical.type&&(e.indented=e.lexical.indented),e.lexical=e.lexical.prev)}function x(e){function t(r){return r==e?h():";"==e?m():h(t)}return t}function k(e,t){return"var"==e?h(b("vardef",t.length),B,x(";"),y):"keyword a"==e?h(b("form"),w,k,y):"keyword b"==e?h(b("form"),k,y):"{"==e?h(b("}"),F,y):";"==e?h():"if"==e?("else"==Le.state.lexical.info&&Le.state.cc[Le.state.cc.length-1]==y&&Le.state.cc.pop()(),h(b("form"),w,k,y,Z)):"function"==e?h(ee):"for"==e?h(b("form"),G,k,y):"variable"==e?h(b("stat"),I):"switch"==e?h(b("form"),w,b("}","switch"),x("{"),F,y,y):"case"==e?h(w,x(":")):"default"==e?h(x(":")):"catch"==e?h(b("form"),g,x("("),te,x(")"),k,y,v):"module"==e?h(b("form"),g,ae,v,y):"class"==e?h(b("form"),re,y):"export"==e?h(b("form"),se,y):"import"==e?h(b("form"),le,y):m(b("stat"),w,x(";"),y)}function w(e){return C(e,!1)}function _(e){return C(e,!0)}function C(e,t){if(Le.state.fatArrowAt==Le.stream.start){var r=t?z:j;if("("==e)return h(g,b(")"),O(U,")"),y,x("=>"),r,v);if("variable"==e)return m(g,U,x("=>"),r,v)}var n=t?L:M;return Me.hasOwnProperty(e)?h(n):"function"==e?h(ee,n):"keyword c"==e?h(t?T:S):"("==e?h(b(")"),S,me,x(")"),y,n):"operator"==e||"spread"==e?h(t?_:w):"["==e?h(b("]"),de,y,n):"{"==e?R(D,"}",null,n):"quasi"==e?m(E,n):h()}function S(e){return e.match(/[;\}\)\],]/)?m():m(w)}function T(e){return e.match(/[;\}\)\],]/)?m():m(_)}function M(e,t){return","==e?h(w):L(e,t,!1)}function L(e,t,r){var n=0==r?M:L,i=0==r?w:_;return"=>"==e?h(g,r?z:j,v):"operator"==e?/\+\+|--/.test(t)?h(n):"?"==t?h(w,x(":"),i):h(i):"quasi"==e?m(E,n):";"!=e?"("==e?R(_,")","call",n):"."==e?h(P,n):"["==e?h(b("]"),S,x("]"),y,n):void 0:void 0}function E(e,t){return"quasi"!=e?m():"${"!=t.slice(t.length-2)?h(E):h(w,q)}function q(e){return"}"==e?(Le.marked="string-2",Le.state.tokenize=l,h(E)):void 0}function j(e){return c(Le.stream,Le.state),m("{"==e?k:w)}function z(e){return c(Le.stream,Le.state),m("{"==e?k:_)}function I(e){return":"==e?h(y,k):m(M,x(";"),y)}function P(e){return"variable"==e?(Le.marked="property",h()):void 0}function D(e,t){return"variable"==e||"keyword"==Le.style?(Le.marked="property",h("get"==t||"set"==t?A:$)):"number"==e||"string"==e?(Le.marked=ye?"property":Le.style+" property",h($)):"jsonld-keyword"==e?h($):"["==e?h(w,x("]"),$):void 0}function A(e){return"variable"!=e?m($):(Le.marked="property",h(ee))}function $(e){return":"==e?h(_):"("==e?m(ee):void 0}function O(e,t){function r(n){if(","==n){var i=Le.state.lexical;return"call"==i.info&&(i.pos=(i.pos||0)+1),h(e,r)}return n==t?h():h(x(t))}return function(n){return n==t?h():m(e,r)}}function R(e,t,r){for(var n=3;n!?|~^]/,Se=/^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/,Te="([{}])",Me={atom:!0,number:!0,variable:!0,string:!0,regexp:!0,"this":!0,"jsonld-keyword":!0},Le={state:null,column:null,marked:null,cc:null},Ee={name:"this",next:{name:"arguments"}};return y.lex=!0,{startState:function(e){var t={tokenize:o,lastType:"sof",cc:[],lexical:new u((e||0)-ve,0,"block",!1),localVars:r.localVars,context:r.localVars&&{vars:r.localVars},indented:0};return r.globalVars&&"object"==typeof r.globalVars&&(t.globalVars=r.globalVars),t},token:function(e,t){if(e.sol()&&(t.lexical.hasOwnProperty("align")||(t.lexical.align=!1),t.indented=e.indentation(),c(e,t)),t.tokenize!=s&&e.eatSpace())return null;var r=t.tokenize(e,t);return"comment"==pe?r:(t.lastType="operator"!=pe||"++"!=ge&&"--"!=ge?pe:"incdec",f(t,r,pe,ge,e))},indent:function(t,n){if(t.tokenize==s)return e.Pass;if(t.tokenize!=o)return 0;var i=n&&n.charAt(0),a=t.lexical;if(!/^\s*else\b/.test(n))for(var l=t.cc.length-1;l>=0;--l){var c=t.cc[l];if(c==y)a=a.prev;else if(c!=Z)break}"stat"==a.type&&"}"==i&&(a=a.prev),be&&")"==a.type&&"stat"==a.prev.type&&(a=a.prev);var u=a.type,d=i==u;return"vardef"==u?a.indented+("operator"==t.lastType||","==t.lastType?a.info+1:0):"form"==u&&"{"==i?a.indented:"form"==u?a.indented+ve:"stat"==u?a.indented+(he(t,n)?be||ve:0):"switch"!=a.info||d||0==r.doubleIndentSwitch?a.align?a.column+(d?0:1):a.indented+(d?0:ve):a.indented+(/^(?:case|default)\b/.test(n)?ve:2*ve)},electricInput:/^\s*(?:case .*?:|default:|\{|\})$/,blockCommentStart:xe?null:"/*",blockCommentEnd:xe?null:"*/",lineComment:xe?null:"//",fold:"brace",helperType:xe?"json":"javascript",jsonldMode:ye,jsonMode:xe}}),e.registerHelper("wordChars","javascript",/[\w$]/),e.defineMIME("text/javascript","javascript"),e.defineMIME("text/ecmascript","javascript"),e.defineMIME("application/javascript","javascript"),e.defineMIME("application/x-javascript","javascript"),e.defineMIME("application/ecmascript","javascript"),e.defineMIME("application/json",{name:"javascript",json:!0}),e.defineMIME("application/x-json",{name:"javascript",json:!0}),e.defineMIME("application/ld+json",{name:"javascript",jsonld:!0}),e.defineMIME("text/typescript",{name:"javascript",typescript:!0}),e.defineMIME("application/typescript",{name:"javascript",typescript:!0})}),function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror"),require("../xml/xml"),require("../javascript/javascript"),require("../css/css")):"function"==typeof define&&define.amd?define(["../../lib/codemirror","../xml/xml","../javascript/javascript","../css/css"],e):e(CodeMirror)}(function(e){"use strict";e.defineMode("htmlmixed",function(t,r){function n(e,t){var r=t.htmlState.tagName;r&&(r=r.toLowerCase());var n=s.token(e,t.htmlState);if("script"==r&&/\btag\b/.test(n)&&">"==e.current()){var i=e.string.slice(Math.max(0,e.pos-100),e.pos).match(/\btype\s*=\s*("[^"]+"|'[^']+'|\S+)[^<]*$/i);i=i?i[1]:"",i&&/[\"\']/.test(i.charAt(0))&&(i=i.slice(1,i.length-1));for(var u=0;u"==e.current()&&(t.token=a,t.localMode=l,t.localState=l.startState(s.indent(t.htmlState,"")));return n}function i(e,t,r){var n,i=e.current(),o=i.search(t);return o>-1?e.backUp(i.length-o):(n=i.match(/<\/?$/))&&(e.backUp(i.length),e.match(t,!1)||e.match(i)),r}function o(e,t){return e.match(/^<\/\s*script\s*>/i,!1)?(t.token=n,t.localState=t.localMode=null,null):i(e,/<\/\s*script\s*>/,t.localMode.token(e,t.localState))}function a(e,t){return e.match(/^<\/\s*style\s*>/i,!1)?(t.token=n,t.localState=t.localMode=null,null):i(e,/<\/\s*style\s*>/,l.token(e,t.localState))}var s=e.getMode(t,{name:"xml",htmlMode:!0,multilineTagIndentFactor:r.multilineTagIndentFactor,multilineTagIndentPastTag:r.multilineTagIndentPastTag}),l=e.getMode(t,"css"),c=[],u=r&&r.scriptTypes;if(c.push({matches:/^(?:text|application)\/(?:x-)?(?:java|ecma)script$|^$/i,mode:e.getMode(t,"javascript")}),u)for(var d=0;d]|\([^\s()<>]*\))+(?:\([^\s()<>]*\)|[^\s`*!()\[\]{};:'".,<>?«»“”‘’]))/i)&&"]("!=e.string.slice(e.start-2,e.start)?(t.combineTokens=!0,"link"):(e.next(),null)},blankLine:n},a={underscoresBreakWords:!1,taskLists:!0,fencedCodeBlocks:!0,strikethrough:!0};for(var s in r)a[s]=r[s];return a.name="markdown",e.defineMIME("gfmBase",a),e.overlayMode(e.getMode(t,"gfmBase"),o)},"markdown")}),function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],e):e(CodeMirror)}(function(e){"use strict";e.defineMode("http",function(){function e(e,t){return e.skipToEnd(),t.cur=a,"error"}function t(t,n){return t.match(/^HTTP\/\d\.\d/)?(n.cur=r,"keyword"):t.match(/^[A-Z]+/)&&/[ \t]/.test(t.peek())?(n.cur=i,"keyword"):e(t,n)}function r(t,r){var i=t.match(/^\d+/);if(!i)return e(t,r);r.cur=n;var o=Number(i[0]);return o>=100&&200>o?"positive informational":o>=200&&300>o?"positive success":o>=300&&400>o?"positive redirect":o>=400&&500>o?"negative client-error":o>=500&&600>o?"negative server-error":"error"}function n(e,t){return e.skipToEnd(),t.cur=a,null}function i(e,t){return e.eatWhile(/\S/),t.cur=o,"string-2"}function o(t,r){return t.match(/^HTTP\/\d\.\d$/)?(r.cur=a,"keyword"):e(t,r)}function a(e){return e.sol()&&!e.eat(/[ \t]/)?e.match(/^.*?:/)?"atom":(e.skipToEnd(),"error"):(e.skipToEnd(),"string")}function s(e){return e.skipToEnd(),null}return{token:function(e,t){var r=t.cur;return r!=a&&r!=s&&e.eatSpace()?null:r(e,t)},blankLine:function(e){e.cur=s},startState:function(){return{cur:t}}}}),e.defineMIME("message/http","http")}),function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],e):e(CodeMirror)}(function(e){"use strict";e.defineMode("go",function(e){function t(e,t){var i=e.next();if('"'==i||"'"==i||"`"==i)return t.tokenize=r(i),t.tokenize(e,t);if(/[\d\.]/.test(i))return"."==i?e.match(/^[0-9]+([eE][\-+]?[0-9]+)?/):"0"==i?e.match(/^[xX][0-9a-fA-F]+/)||e.match(/^0[0-7]+/):e.match(/^[0-9]*\.?[0-9]*([eE][\-+]?[0-9]+)?/),"number";if(/[\[\]{}\(\),;\:\.]/.test(i))return s=i,null;if("/"==i){if(e.eat("*"))return t.tokenize=n,n(e,t);if(e.eat("/"))return e.skipToEnd(),"comment"}if(d.test(i))return e.eatWhile(d),"operator";e.eatWhile(/[\w\$_\xa1-\uffff]/);var o=e.current();return c.propertyIsEnumerable(o)?(("case"==o||"default"==o)&&(s="case"),"keyword"):u.propertyIsEnumerable(o)?"atom":"variable"}function r(e){return function(r,n){for(var i,o=!1,a=!1;null!=(i=r.next());){if(i==e&&!o){a=!0;break}o=!o&&"\\"==i}return(a||!o&&"`"!=e)&&(n.tokenize=t),"string"}}function n(e,r){for(var n,i=!1;n=e.next();){if("/"==n&&i){r.tokenize=t;break}i="*"==n}return"comment"}function i(e,t,r,n,i){this.indented=e,this.column=t,this.type=r,this.align=n,this.prev=i}function o(e,t,r){return e.context=new i(e.indented,t,r,null,e.context)}function a(e){if(e.context.prev){var t=e.context.type;return(")"==t||"]"==t||"}"==t)&&(e.indented=e.context.indented),e.context=e.context.prev}}var s,l=e.indentUnit,c={"break":!0,"case":!0,chan:!0,"const":!0,"continue":!0,"default":!0,defer:!0,"else":!0,fallthrough:!0,"for":!0,func:!0,go:!0,"goto":!0,"if":!0,"import":!0,"interface":!0,map:!0,"package":!0,range:!0,"return":!0,select:!0,struct:!0,"switch":!0,type:!0,"var":!0,bool:!0,"byte":!0,complex64:!0,complex128:!0,float32:!0,float64:!0,int8:!0,int16:!0,int32:!0,int64:!0,string:!0,uint8:!0,uint16:!0,uint32:!0,uint64:!0,"int":!0,uint:!0,uintptr:!0},u={"true":!0,"false":!0,iota:!0,nil:!0,append:!0,cap:!0,close:!0,complex:!0,copy:!0,imag:!0,len:!0,make:!0,"new":!0,panic:!0,print:!0,println:!0,real:!0,recover:!0},d=/[+\-*&^%:=<>!|\/]/;return{startState:function(e){return{tokenize:null,context:new i((e||0)-l,0,"top",!1),indented:0,startOfLine:!0}},token:function(e,r){var n=r.context;if(e.sol()&&(null==n.align&&(n.align=!1),r.indented=e.indentation(),r.startOfLine=!0,"case"==n.type&&(n.type="}")),e.eatSpace())return null;s=null;var i=(r.tokenize||t)(e,r);return"comment"==i?i:(null==n.align&&(n.align=!0),"{"==s?o(r,e.column(),"}"):"["==s?o(r,e.column(),"]"):"("==s?o(r,e.column(),")"):"case"==s?n.type="case":"}"==s&&"}"==n.type?n=a(r):s==n.type&&a(r),r.startOfLine=!1,i)},indent:function(e,r){if(e.tokenize!=t&&null!=e.tokenize)return 0;var n=e.context,i=r&&r.charAt(0);if("case"==n.type&&/^(?:case|default)\b/.test(r))return e.context.type="}",n.indented;var o=i==n.type;return n.align?n.column+(o?0:1):n.indented+(o?0:l)},electricChars:"{}):",fold:"brace",blockCommentStart:"/*",blockCommentEnd:"*/",lineComment:"//"}}),e.defineMIME("text/x-go","go")}),function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror"),require("../clike/clike")):"function"==typeof define&&define.amd?define(["../../lib/codemirror","../clike/clike"],e):e(CodeMirror)}(function(e){"use strict";function t(e){for(var t={},r=0;rr&&"coffee"==t.scope.type?"indent":r>n?"dedent":null}r>0&&s(e,t)}if(e.eatSpace())return null;var a=e.peek();if(e.match("####"))return e.skipToEnd(),"comment";if(e.match("###"))return t.tokenize=o,t.tokenize(e,t);if("#"===a)return e.skipToEnd(),"comment";if(e.match(/^-?[0-9\.]/,!1)){var l=!1;if(e.match(/^-?\d*\.\d+(e[\+\-]?\d+)?/i)&&(l=!0),e.match(/^-?\d+\.\d*/)&&(l=!0),e.match(/^-?\.\d+/)&&(l=!0),l)return"."==e.peek()&&e.backUp(1),"number";var p=!1;if(e.match(/^-?0x[0-9a-f]+/i)&&(p=!0),e.match(/^-?[1-9]\d*(e[\+\-]?\d+)?/)&&(p=!0),e.match(/^-?0(?![\dx])/i)&&(p=!0),p)return"number"}if(e.match(b))return t.tokenize=i(e.current(),!1,"string"),t.tokenize(e,t);if(e.match(y)){if("/"!=e.current()||e.match(/^.*\//,!1))return t.tokenize=i(e.current(),!0,"string-2"),t.tokenize(e,t);e.backUp(1)}return e.match(u)||e.match(h)?"operator":e.match(d)?"punctuation":e.match(k)?"atom":e.match(v)?"keyword":e.match(f)?"variable":e.match(m)?"property":(e.next(),c)}function i(e,r,i){return function(o,a){for(;!o.eol();)if(o.eatWhile(/[^'"\/\\]/),o.eat("\\")){if(o.next(),r&&o.eol())return i}else{if(o.match(e))return a.tokenize=n,i;o.eat(/['"\/]/)}return r&&(t.singleLineStringErrors?i=c:a.tokenize=n),i}}function o(e,t){for(;!e.eol();){if(e.eatWhile(/[^#]/),e.match("###")){t.tokenize=n;break}e.eatWhile("#")}return"comment"}function a(t,r,n){n=n||"coffee";for(var i=0,o=!1,a=null,s=r.scope;s;s=s.prev)if("coffee"===s.type||"}"==s.type){i=s.offset+e.indentUnit;break}"coffee"!==n?(o=null,a=t.column()+t.current().length):r.scope.align&&(r.scope.align=!1),r.scope={offset:i,type:n,prev:r.scope,align:o,alignOffset:a}}function s(e,t){if(t.scope.prev){if("coffee"===t.scope.type){for(var r=e.indentation(),n=!1,i=t.scope;i;i=i.prev)if(r===i.offset){n=!0;break}if(!n)return!0;for(;t.scope.prev&&t.scope.offset!==r;)t.scope=t.scope.prev;return!1}return t.scope=t.scope.prev,!1}}function l(e,t){var r=t.tokenize(e,t),n=e.current();if("."===n)return r=t.tokenize(e,t),n=e.current(),/^\.[\w$]+$/.test(n)?"variable":c;"return"===n&&(t.dedent=!0),("->"!==n&&"=>"!==n||t.lambda||e.peek())&&"indent"!==r||a(e,t);var i="[({".indexOf(n);if(-1!==i&&a(e,t,"])}".slice(i,i+1)),p.exec(n)&&a(e,t),"then"==n&&s(e,t),"dedent"===r&&s(e,t))return c;if(i="])}".indexOf(n),-1!==i){for(;"coffee"==t.scope.type&&t.scope.prev;)t.scope=t.scope.prev;t.scope.type==n&&(t.scope=t.scope.prev)}return t.dedent&&e.eol()&&("coffee"==t.scope.type&&t.scope.prev&&(t.scope=t.scope.prev),t.dedent=!1),r}var c="error",u=/^(?:->|=>|\+[+=]?|-[\-=]?|\*[\*=]?|\/[\/=]?|[=!]=|<[><]?=?|>>?=?|%=?|&=?|\|=?|\^=?|\~|!|\?|(or|and|\|\||&&|\?)=)/,d=/^(?:[()\[\]{},:`=;]|\.\.?\.?)/,f=/^[_A-Za-z$][_A-Za-z$0-9]*/,m=/^(@|this\.)[_A-Za-z$][_A-Za-z$0-9]*/,h=r(["and","or","not","is","isnt","in","instanceof","typeof"]),p=["for","while","loop","if","unless","else","switch","try","catch","finally","class"],g=["break","by","continue","debugger","delete","do","in","of","new","return","then","this","@","throw","when","until","extends"],v=r(p.concat(g));p=r(p);var b=/^('{3}|\"{3}|['\"])/,y=/^(\/{3}|\/)/,x=["Infinity","NaN","undefined","null","true","false","on","off","yes","no"],k=r(x),w={startState:function(e){return{tokenize:n,scope:{offset:e||0,type:"coffee",prev:null,align:!1},lastToken:null,lambda:!1,dedent:0}},token:function(e,t){var r=null===t.scope.align&&t.scope;r&&e.sol()&&(r.align=!1);var n=l(e,t);return r&&n&&"comment"!=n&&(r.align=!0),t.lastToken={style:n,content:e.current()},e.eol()&&e.lambda&&(t.lambda=!1),n},indent:function(e,t){if(e.tokenize!=n)return 0;var r=e.scope,i=t&&"])}".indexOf(t.charAt(0))>-1;if(i)for(;"coffee"==r.type&&r.prev;)r=r.prev;var o=i&&r.type===t.charAt(0);return r.align?r.alignOffset-(o?1:0):(o?r.prev:r).offset},lineComment:"#",fold:"indent"};return w}),e.defineMIME("text/x-coffeescript","coffeescript")}),function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],e):e(CodeMirror)}(function(e){"use strict";e.defineMode("nginx",function(e){function t(e){for(var t={},r=e.split(" "),n=0;n*\/]/.test(s)?r(null,"select-op"):/[;{}:\[\]]/.test(s)?r(null,s):(e.eatWhile(/[\w\\\-]/),r("variable","variable")):r(null,"compare"):void r(null,"compare")}function i(e,t){for(var i,o=!1;null!=(i=e.next());){if(o&&"/"==i){t.tokenize=n;break}o="*"==i}return r("comment","comment")}function o(e,t){for(var i,o=0;null!=(i=e.next());){if(o>=2&&">"==i){t.tokenize=n;break}o="-"==i?o+1:0}return r("comment","comment")}function a(e){return function(t,i){for(var o,a=!1;null!=(o=t.next())&&(o!=e||a);)a=!a&&"\\"==o;return a||(i.tokenize=n),r("string","string")}}var s,l=t("break return rewrite set accept_mutex accept_mutex_delay access_log add_after_body add_before_body add_header addition_types aio alias allow ancient_browser ancient_browser_value auth_basic auth_basic_user_file auth_http auth_http_header auth_http_timeout autoindex autoindex_exact_size autoindex_localtime charset charset_types client_body_buffer_size client_body_in_file_only client_body_in_single_buffer client_body_temp_path client_body_timeout client_header_buffer_size client_header_timeout client_max_body_size connection_pool_size create_full_put_path daemon dav_access dav_methods debug_connection debug_points default_type degradation degrade deny devpoll_changes devpoll_events directio directio_alignment empty_gif env epoll_events error_log eventport_events expires fastcgi_bind fastcgi_buffer_size fastcgi_buffers fastcgi_busy_buffers_size fastcgi_cache fastcgi_cache_key fastcgi_cache_methods fastcgi_cache_min_uses fastcgi_cache_path fastcgi_cache_use_stale fastcgi_cache_valid fastcgi_catch_stderr fastcgi_connect_timeout fastcgi_hide_header fastcgi_ignore_client_abort fastcgi_ignore_headers fastcgi_index fastcgi_intercept_errors fastcgi_max_temp_file_size fastcgi_next_upstream fastcgi_param fastcgi_pass_header fastcgi_pass_request_body fastcgi_pass_request_headers fastcgi_read_timeout fastcgi_send_lowat fastcgi_send_timeout fastcgi_split_path_info fastcgi_store fastcgi_store_access fastcgi_temp_file_write_size fastcgi_temp_path fastcgi_upstream_fail_timeout fastcgi_upstream_max_fails flv geoip_city geoip_country google_perftools_profiles gzip gzip_buffers gzip_comp_level gzip_disable gzip_hash gzip_http_version gzip_min_length gzip_no_buffer gzip_proxied gzip_static gzip_types gzip_vary gzip_window if_modified_since ignore_invalid_headers image_filter image_filter_buffer image_filter_jpeg_quality image_filter_transparency imap_auth imap_capabilities imap_client_buffer index ip_hash keepalive_requests keepalive_timeout kqueue_changes kqueue_events large_client_header_buffers limit_conn limit_conn_log_level limit_rate limit_rate_after limit_req limit_req_log_level limit_req_zone limit_zone lingering_time lingering_timeout lock_file log_format log_not_found log_subrequest map_hash_bucket_size map_hash_max_size master_process memcached_bind memcached_buffer_size memcached_connect_timeout memcached_next_upstream memcached_read_timeout memcached_send_timeout memcached_upstream_fail_timeout memcached_upstream_max_fails merge_slashes min_delete_depth modern_browser modern_browser_value msie_padding msie_refresh multi_accept open_file_cache open_file_cache_errors open_file_cache_events open_file_cache_min_uses open_file_cache_valid open_log_file_cache output_buffers override_charset perl perl_modules perl_require perl_set pid pop3_auth pop3_capabilities port_in_redirect postpone_gzipping postpone_output protocol proxy proxy_bind proxy_buffer proxy_buffer_size proxy_buffering proxy_buffers proxy_busy_buffers_size proxy_cache proxy_cache_key proxy_cache_methods proxy_cache_min_uses proxy_cache_path proxy_cache_use_stale proxy_cache_valid proxy_connect_timeout proxy_headers_hash_bucket_size proxy_headers_hash_max_size proxy_hide_header proxy_ignore_client_abort proxy_ignore_headers proxy_intercept_errors proxy_max_temp_file_size proxy_method proxy_next_upstream proxy_pass_error_message proxy_pass_header proxy_pass_request_body proxy_pass_request_headers proxy_read_timeout proxy_redirect proxy_send_lowat proxy_send_timeout proxy_set_body proxy_set_header proxy_ssl_session_reuse proxy_store proxy_store_access proxy_temp_file_write_size proxy_temp_path proxy_timeout proxy_upstream_fail_timeout proxy_upstream_max_fails random_index read_ahead real_ip_header recursive_error_pages request_pool_size reset_timedout_connection resolver resolver_timeout rewrite_log rtsig_overflow_events rtsig_overflow_test rtsig_overflow_threshold rtsig_signo satisfy secure_link_secret send_lowat send_timeout sendfile sendfile_max_chunk server_name_in_redirect server_names_hash_bucket_size server_names_hash_max_size server_tokens set_real_ip_from smtp_auth smtp_capabilities smtp_client_buffer smtp_greeting_delay so_keepalive source_charset ssi ssi_ignore_recycled_buffers ssi_min_file_chunk ssi_silent_errors ssi_types ssi_value_length ssl ssl_certificate ssl_certificate_key ssl_ciphers ssl_client_certificate ssl_crl ssl_dhparam ssl_engine ssl_prefer_server_ciphers ssl_protocols ssl_session_cache ssl_session_timeout ssl_verify_client ssl_verify_depth starttls stub_status sub_filter sub_filter_once sub_filter_types tcp_nodelay tcp_nopush thread_stack_size timeout timer_resolution types_hash_bucket_size types_hash_max_size underscores_in_headers uninitialized_variable_warn use user userid userid_domain userid_expires userid_mark userid_name userid_p3p userid_path userid_service valid_referers variables_hash_bucket_size variables_hash_max_size worker_connections worker_cpu_affinity worker_priority worker_processes worker_rlimit_core worker_rlimit_nofile worker_rlimit_sigpending worker_threads working_directory xclient xml_entities xslt_stylesheet xslt_typesdrew@li229-23"),c=t("http mail events server types location upstream charset_map limit_except if geo map"),u=t("include root server server_name listen internal proxy_pass memcached_pass fastcgi_pass try_files"),d=e.indentUnit; + +return{startState:function(e){return{tokenize:n,baseIndent:e||0,stack:[]}},token:function(e,t){if(e.eatSpace())return null;s=null;var r=t.tokenize(e,t),n=t.stack[t.stack.length-1];return"hash"==s&&"rule"==n?r="atom":"variable"==r&&("rule"==n?r="number":n&&"@media{"!=n||(r="tag")),"rule"==n&&/^[\{\};]$/.test(s)&&t.stack.pop(),"{"==s?"@media"==n?t.stack[t.stack.length-1]="@media{":t.stack.push("{"):"}"==s?t.stack.pop():"@media"==s?t.stack.push("@media"):"{"==n&&"comment"!=s&&t.stack.push("rule"),r},indent:function(e,t){var r=e.stack.length;return/^\}/.test(t)&&(r-="rule"==e.stack[e.stack.length-1]?2:1),e.baseIndent+r*d},electricChars:"}"}}),e.defineMIME("text/nginx","text/x-nginx-conf")}),function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],e):e(CodeMirror)}(function(e){"use strict";function t(e){return new RegExp("^(("+e.join(")|(")+"))\\b")}function r(e){return e.scopes[e.scopes.length-1]}var n=t(["and","or","not","is"]),i=["as","assert","break","class","continue","def","del","elif","else","except","finally","for","from","global","if","import","lambda","pass","raise","return","try","while","with","yield","in"],o=["abs","all","any","bin","bool","bytearray","callable","chr","classmethod","compile","complex","delattr","dict","dir","divmod","enumerate","eval","filter","float","format","frozenset","getattr","globals","hasattr","hash","help","hex","id","input","int","isinstance","issubclass","iter","len","list","locals","map","max","memoryview","min","next","object","oct","open","ord","pow","property","range","repr","reversed","round","set","setattr","slice","sorted","staticmethod","str","sum","super","tuple","type","vars","zip","__import__","NotImplemented","Ellipsis","__debug__"],a={builtins:["apply","basestring","buffer","cmp","coerce","execfile","file","intern","long","raw_input","reduce","reload","unichr","unicode","xrange","False","True","None"],keywords:["exec","print"]},s={builtins:["ascii","bytes","exec","print"],keywords:["nonlocal","False","True","None"]};e.registerHelper("hintWords","python",i.concat(o)),e.defineMode("python",function(l,c){function u(e,t){if(e.sol()&&"py"==r(t).type){var n=r(t).offset;if(e.eatSpace()){var i=e.indentation();return i>n?m(e,t,"py"):n>i&&h(e,t)&&(t.errorToken=!0),null}var o=d(e,t);return n>0&&h(e,t)&&(o+=" "+g),o}return d(e,t)}function d(e,t){if(e.eatSpace())return null;var r=e.peek();if("#"==r)return e.skipToEnd(),"comment";if(e.match(/^[0-9\.]/,!1)){var i=!1;if(e.match(/^\d*\.\d+(e[\+\-]?\d+)?/i)&&(i=!0),e.match(/^\d+\.\d*/)&&(i=!0),e.match(/^\.\d+/)&&(i=!0),i)return e.eat(/J/i),"number";var o=!1;if(e.match(/^0x[0-9a-f]+/i)&&(o=!0),e.match(/^0b[01]+/i)&&(o=!0),e.match(/^0o[0-7]+/i)&&(o=!0),e.match(/^[1-9]\d*(e[\+\-]?\d+)?/)&&(e.eat(/J/i),o=!0),e.match(/^0(?![\dx])/i)&&(o=!0),o)return e.eat(/L/i),"number"}return e.match(T)?(t.tokenize=f(e.current()),t.tokenize(e,t)):e.match(x)||e.match(y)?null:e.match(b)||e.match(k)||e.match(n)?"operator":e.match(v)?null:e.match(M)?"keyword":e.match(L)?"builtin":e.match(/^(self|cls)\b/)?"variable-2":e.match(w)?"def"==t.lastToken||"class"==t.lastToken?"def":"variable":(e.next(),g)}function f(e){function t(t,i){for(;!t.eol();)if(t.eatWhile(/[^'"\\]/),t.eat("\\")){if(t.next(),r&&t.eol())return n}else{if(t.match(e))return i.tokenize=u,n;t.eat(/['"]/)}if(r){if(c.singleLineStringErrors)return g;i.tokenize=u}return n}for(;"rub".indexOf(e.charAt(0).toLowerCase())>=0;)e=e.substr(1);var r=1==e.length,n="string";return t.isString=!0,t}function m(e,t,n){var i=0,o=null;if("py"==n)for(;"py"!=r(t).type;)t.scopes.pop();i=r(t).offset+("py"==n?l.indentUnit:_),"py"==n||e.match(/^(\s|#.*)*$/,!1)||(o=e.column()+1),t.scopes.push({offset:i,type:n,align:o})}function h(e,t){for(var n=e.indentation();r(t).offset>n;){if("py"!=r(t).type)return!0;t.scopes.pop()}return r(t).offset!=n}function p(e,t){var n=t.tokenize(e,t),i=e.current();if("."==i)return n=e.match(w,!1)?null:g,null==n&&"meta"==t.lastStyle&&(n="meta"),n;if("@"==i)return c.version&&3==parseInt(c.version,10)?e.match(w,!1)?"meta":"operator":e.match(w,!1)?"meta":g;"variable"!=n&&"builtin"!=n||"meta"!=t.lastStyle||(n="meta"),("pass"==i||"return"==i)&&(t.dedent+=1),"lambda"==i&&(t.lambda=!0),":"!=i||t.lambda||"py"!=r(t).type||m(e,t,"py");var o=1==i.length?"[({".indexOf(i):-1;if(-1!=o&&m(e,t,"])}".slice(o,o+1)),o="])}".indexOf(i),-1!=o){if(r(t).type!=i)return g;t.scopes.pop()}return t.dedent>0&&e.eol()&&"py"==r(t).type&&(t.scopes.length>1&&t.scopes.pop(),t.dedent-=1),n}var g="error",v=c.singleDelimiters||new RegExp("^[\\(\\)\\[\\]\\{\\}@,:`=;\\.]"),b=c.doubleOperators||new RegExp("^((==)|(!=)|(<=)|(>=)|(<>)|(<<)|(>>)|(//)|(\\*\\*))"),y=c.doubleDelimiters||new RegExp("^((\\+=)|(\\-=)|(\\*=)|(%=)|(/=)|(&=)|(\\|=)|(\\^=))"),x=c.tripleDelimiters||new RegExp("^((//=)|(>>=)|(<<=)|(\\*\\*=))");if(c.version&&3==parseInt(c.version,10))var k=c.singleOperators||new RegExp("^[\\+\\-\\*/%&|\\^~<>!@]"),w=c.identifiers||new RegExp("^[_A-Za-z¡-￿][_A-Za-z0-9¡-￿]*");else var k=c.singleOperators||new RegExp("^[\\+\\-\\*/%&|\\^~<>!]"),w=c.identifiers||new RegExp("^[_A-Za-z][_A-Za-z0-9]*");var _=c.hangingIndent||l.indentUnit,C=i,S=o;if(void 0!=c.extra_keywords&&(C=C.concat(c.extra_keywords)),void 0!=c.extra_builtins&&(S=S.concat(c.extra_builtins)),c.version&&3==parseInt(c.version,10)){C=C.concat(s.keywords),S=S.concat(s.builtins);var T=new RegExp("^(([rb]|(br))?('{3}|\"{3}|['\"]))","i")}else{C=C.concat(a.keywords),S=S.concat(a.builtins);var T=new RegExp("^(([rub]|(ur)|(br))?('{3}|\"{3}|['\"]))","i")}var M=t(C),L=t(S),E={startState:function(e){return{tokenize:u,scopes:[{offset:e||0,type:"py",align:null}],lastStyle:null,lastToken:null,lambda:!1,dedent:0}},token:function(e,t){var r=t.errorToken;r&&(t.errorToken=!1);var n=p(e,t);t.lastStyle=n;var i=e.current();return i&&n&&(t.lastToken=i),e.eol()&&t.lambda&&(t.lambda=!1),r?n+" "+g:n},indent:function(t,n){if(t.tokenize!=u)return t.tokenize.isString?e.Pass:0;var i=r(t),o=n&&n.charAt(0)==i.type;return null!=i.align?i.align-(o?1:0):o&&t.scopes.length>1?t.scopes[t.scopes.length-2].offset:i.offset},lineComment:"#",fold:"indent"};return E}),e.defineMIME("text/x-python","python");var l=function(e){return e.split(" ")};e.defineMIME("text/x-cython",{name:"python",extra_keywords:l("by cdef cimport cpdef ctypedef enum exceptextern gil include nogil property publicreadonly struct union DEF IF ELIF ELSE")})}),function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],e):e(CodeMirror)}(function(e){"use strict";function t(e,t){return e.string.charAt(e.pos+(t||0))}function r(e,t){if(t){var r=e.pos-t;return e.string.substr(r>=0?r:0,t)}return e.string.substr(0,e.pos-1)}function n(e,t){var r=e.string.length,n=r-e.pos+1;return e.string.substr(e.pos,t&&r>t?t:n)}function i(e,t){var r,n=e.pos+t;0>=n?e.pos=0:n>=(r=e.string.length-1)?e.pos=r:e.pos=n}e.defineMode("perl",function(){function e(e,t,r,n,i){return t.chain=null,t.style=null,t.tail=null,t.tokenize=function(e,t){for(var o,s=!1,l=0;o=e.next();){if(o===r[l]&&!s)return void 0!==r[++l]?(t.chain=r[l],t.style=n,t.tail=i):i&&e.eatWhile(i),t.tokenize=a,n;s=!s&&"\\"==o}return n},t.tokenize(e,t)}function o(e,t,r){return t.tokenize=function(e,t){return e.string==r&&(t.tokenize=a),e.skipToEnd(),"string"},t.tokenize(e,t)}function a(a,u){if(a.eatSpace())return null;if(u.chain)return e(a,u,u.chain,u.style,u.tail);if(a.match(/^\-?[\d\.]/,!1)&&a.match(/^(\-?(\d*\.\d+(e[+-]?\d+)?|\d+\.\d*)|0x[\da-fA-F]+|0b[01]+|\d+(e[+-]?\d+)?)/))return"number";if(a.match(/^<<(?=\w)/))return a.eatWhile(/\w/),o(a,u,a.current().substr(2));if(a.sol()&&a.match(/^\=item(?!\w)/))return o(a,u,"=cut");var d=a.next();if('"'==d||"'"==d){if(r(a,3)=="<<"+d){var f=a.pos;a.eatWhile(/\w/);var m=a.current().substr(1);if(m&&a.eat(d))return o(a,u,m);a.pos=f}return e(a,u,[d],"string")}if("q"==d){var h=t(a,-2);if(!h||!/\w/.test(h))if(h=t(a,0),"x"==h){if(h=t(a,1),"("==h)return i(a,2),e(a,u,[")"],l,c);if("["==h)return i(a,2),e(a,u,["]"],l,c);if("{"==h)return i(a,2),e(a,u,["}"],l,c);if("<"==h)return i(a,2),e(a,u,[">"],l,c);if(/[\^'"!~\/]/.test(h))return i(a,1),e(a,u,[a.eat(h)],l,c)}else if("q"==h){if(h=t(a,1),"("==h)return i(a,2),e(a,u,[")"],"string");if("["==h)return i(a,2),e(a,u,["]"],"string");if("{"==h)return i(a,2),e(a,u,["}"],"string");if("<"==h)return i(a,2),e(a,u,[">"],"string");if(/[\^'"!~\/]/.test(h))return i(a,1),e(a,u,[a.eat(h)],"string")}else if("w"==h){if(h=t(a,1),"("==h)return i(a,2),e(a,u,[")"],"bracket");if("["==h)return i(a,2),e(a,u,["]"],"bracket");if("{"==h)return i(a,2),e(a,u,["}"],"bracket");if("<"==h)return i(a,2),e(a,u,[">"],"bracket");if(/[\^'"!~\/]/.test(h))return i(a,1),e(a,u,[a.eat(h)],"bracket")}else if("r"==h){if(h=t(a,1),"("==h)return i(a,2),e(a,u,[")"],l,c);if("["==h)return i(a,2),e(a,u,["]"],l,c);if("{"==h)return i(a,2),e(a,u,["}"],l,c);if("<"==h)return i(a,2),e(a,u,[">"],l,c);if(/[\^'"!~\/]/.test(h))return i(a,1),e(a,u,[a.eat(h)],l,c)}else if(/[\^'"!~\/(\[{<]/.test(h)){if("("==h)return i(a,1),e(a,u,[")"],"string");if("["==h)return i(a,1),e(a,u,["]"],"string");if("{"==h)return i(a,1),e(a,u,["}"],"string");if("<"==h)return i(a,1),e(a,u,[">"],"string");if(/[\^'"!~\/]/.test(h))return e(a,u,[a.eat(h)],"string")}}if("m"==d){var h=t(a,-2);if((!h||!/\w/.test(h))&&(h=a.eat(/[(\[{<\^'"!~\/]/))){if(/[\^'"!~\/]/.test(h))return e(a,u,[h],l,c);if("("==h)return e(a,u,[")"],l,c);if("["==h)return e(a,u,["]"],l,c);if("{"==h)return e(a,u,["}"],l,c);if("<"==h)return e(a,u,[">"],l,c)}}if("s"==d){var h=/[\/>\]})\w]/.test(t(a,-2));if(!h&&(h=a.eat(/[(\[{<\^'"!~\/]/)))return"["==h?e(a,u,["]","]"],l,c):"{"==h?e(a,u,["}","}"],l,c):"<"==h?e(a,u,[">",">"],l,c):"("==h?e(a,u,[")",")"],l,c):e(a,u,[h,h],l,c)}if("y"==d){var h=/[\/>\]})\w]/.test(t(a,-2));if(!h&&(h=a.eat(/[(\[{<\^'"!~\/]/)))return"["==h?e(a,u,["]","]"],l,c):"{"==h?e(a,u,["}","}"],l,c):"<"==h?e(a,u,[">",">"],l,c):"("==h?e(a,u,[")",")"],l,c):e(a,u,[h,h],l,c)}if("t"==d){var h=/[\/>\]})\w]/.test(t(a,-2));if(!h&&(h=a.eat("r"),h&&(h=a.eat(/[(\[{<\^'"!~\/]/))))return"["==h?e(a,u,["]","]"],l,c):"{"==h?e(a,u,["}","}"],l,c):"<"==h?e(a,u,[">",">"],l,c):"("==h?e(a,u,[")",")"],l,c):e(a,u,[h,h],l,c)}if("`"==d)return e(a,u,[d],"variable-2");if("/"==d)return/~\s*$/.test(r(a))?e(a,u,[d],l,c):"operator";if("$"==d){var f=a.pos;if(a.eatWhile(/\d/)||a.eat("{")&&a.eatWhile(/\d/)&&a.eat("}"))return"variable-2";a.pos=f}if(/[$@%]/.test(d)){var f=a.pos;if(a.eat("^")&&a.eat(/[A-Z]/)||!/[@$%&]/.test(t(a,-2))&&a.eat(/[=|\\\-#?@;:&`~\^!\[\]*'"$+.,\/<>()]/)){var h=a.current();if(s[h])return"variable-2"}a.pos=f}if(/[$@%&]/.test(d)&&(a.eatWhile(/[\w$\[\]]/)||a.eat("{")&&a.eatWhile(/[\w$\[\]]/)&&a.eat("}"))){var h=a.current();return s[h]?"variable-2":"variable"}if("#"==d&&"$"!=t(a,-2))return a.skipToEnd(),"comment";if(/[:+\-\^*$&%@=<>!?|\/~\.]/.test(d)){var f=a.pos;if(a.eatWhile(/[:+\-\^*$&%@=<>!?|\/~\.]/),s[a.current()])return"operator";a.pos=f}if("_"==d&&1==a.pos){if("_END__"==n(a,6))return e(a,u,["\x00"],"comment");if("_DATA__"==n(a,7))return e(a,u,["\x00"],"variable-2");if("_C__"==n(a,7))return e(a,u,["\x00"],"string")}if(/\w/.test(d)){var f=a.pos;if("{"==t(a,-2)&&("}"==t(a,0)||a.eatWhile(/\w/)&&"}"==t(a,0)))return"string";a.pos=f}if(/[A-Z]/.test(d)){var p=t(a,-2),f=a.pos;if(a.eatWhile(/[A-Z_]/),!/[\da-z]/.test(t(a,0))){var h=s[a.current()];return h?(h[1]&&(h=h[0]),":"!=p?1==h?"keyword":2==h?"def":3==h?"atom":4==h?"operator":5==h?"variable-2":"meta":"meta"):"meta"}a.pos=f}if(/[a-zA-Z_]/.test(d)){var p=t(a,-2);a.eatWhile(/\w/);var h=s[a.current()];return h?(h[1]&&(h=h[0]),":"!=p?1==h?"keyword":2==h?"def":3==h?"atom":4==h?"operator":5==h?"variable-2":"meta":"meta"):"meta"}return null}var s={"->":4,"++":4,"--":4,"**":4,"=~":4,"!~":4,"*":4,"/":4,"%":4,x:4,"+":4,"-":4,".":4,"<<":4,">>":4,"<":4,">":4,"<=":4,">=":4,lt:4,gt:4,le:4,ge:4,"==":4,"!=":4,"<=>":4,eq:4,ne:4,cmp:4,"~~":4,"&":4,"|":4,"^":4,"&&":4,"||":4,"//":4,"..":4,"...":4,"?":4,":":4,"=":4,"+=":4,"-=":4,"*=":4,",":4,"=>":4,"::":4,not:4,and:4,or:4,xor:4,BEGIN:[5,1],END:[5,1],PRINT:[5,1],PRINTF:[5,1],GETC:[5,1],READ:[5,1],READLINE:[5,1],DESTROY:[5,1],TIE:[5,1],TIEHANDLE:[5,1],UNTIE:[5,1],STDIN:5,STDIN_TOP:5,STDOUT:5,STDOUT_TOP:5,STDERR:5,STDERR_TOP:5,$ARG:5,$_:5,"@ARG":5,"@_":5,$LIST_SEPARATOR:5,'$"':5,$PROCESS_ID:5,$PID:5,$$:5,$REAL_GROUP_ID:5,$GID:5,"$(":5,$EFFECTIVE_GROUP_ID:5,$EGID:5,"$)":5,$PROGRAM_NAME:5,$0:5,$SUBSCRIPT_SEPARATOR:5,$SUBSEP:5,"$;":5,$REAL_USER_ID:5,$UID:5,"$<":5,$EFFECTIVE_USER_ID:5,$EUID:5,"$>":5,$a:5,$b:5,$COMPILING:5,"$^C":5,$DEBUGGING:5,"$^D":5,"${^ENCODING}":5,$ENV:5,"%ENV":5,$SYSTEM_FD_MAX:5,"$^F":5,"@F":5,"${^GLOBAL_PHASE}":5,"$^H":5,"%^H":5,"@INC":5,"%INC":5,$INPLACE_EDIT:5,"$^I":5,"$^M":5,$OSNAME:5,"$^O":5,"${^OPEN}":5,$PERLDB:5,"$^P":5,$SIG:5,"%SIG":5,$BASETIME:5,"$^T":5,"${^TAINT}":5,"${^UNICODE}":5,"${^UTF8CACHE}":5,"${^UTF8LOCALE}":5,$PERL_VERSION:5,"$^V":5,"${^WIN32_SLOPPY_STAT}":5,$EXECUTABLE_NAME:5,"$^X":5,$1:5,$MATCH:5,"$&":5,"${^MATCH}":5,$PREMATCH:5,"$`":5,"${^PREMATCH}":5,$POSTMATCH:5,"$'":5,"${^POSTMATCH}":5,$LAST_PAREN_MATCH:5,"$+":5,$LAST_SUBMATCH_RESULT:5,"$^N":5,"@LAST_MATCH_END":5,"@+":5,"%LAST_PAREN_MATCH":5,"%+":5,"@LAST_MATCH_START":5,"@-":5,"%LAST_MATCH_START":5,"%-":5,$LAST_REGEXP_CODE_RESULT:5,"$^R":5,"${^RE_DEBUG_FLAGS}":5,"${^RE_TRIE_MAXBUF}":5,$ARGV:5,"@ARGV":5,ARGV:5,ARGVOUT:5,$OUTPUT_FIELD_SEPARATOR:5,$OFS:5,"$,":5,$INPUT_LINE_NUMBER:5,$NR:5,"$.":5,$INPUT_RECORD_SEPARATOR:5,$RS:5,"$/":5,$OUTPUT_RECORD_SEPARATOR:5,$ORS:5,"$\\":5,$OUTPUT_AUTOFLUSH:5,"$|":5,$ACCUMULATOR:5,"$^A":5,$FORMAT_FORMFEED:5,"$^L":5,$FORMAT_PAGE_NUMBER:5,"$%":5,$FORMAT_LINES_LEFT:5,"$-":5,$FORMAT_LINE_BREAK_CHARACTERS:5,"$:":5,$FORMAT_LINES_PER_PAGE:5,"$=":5,$FORMAT_TOP_NAME:5,"$^":5,$FORMAT_NAME:5,"$~":5,"${^CHILD_ERROR_NATIVE}":5,$EXTENDED_OS_ERROR:5,"$^E":5,$EXCEPTIONS_BEING_CAUGHT:5,"$^S":5,$WARNING:5,"$^W":5,"${^WARNING_BITS}":5,$OS_ERROR:5,$ERRNO:5,"$!":5,"%OS_ERROR":5,"%ERRNO":5,"%!":5,$CHILD_ERROR:5,"$?":5,$EVAL_ERROR:5,"$@":5,$OFMT:5,"$#":5,"$*":5,$ARRAY_BASE:5,"$[":5,$OLD_PERL_VERSION:5,"$]":5,"if":[1,1],elsif:[1,1],"else":[1,1],"while":[1,1],unless:[1,1],"for":[1,1],foreach:[1,1],abs:1,accept:1,alarm:1,atan2:1,bind:1,binmode:1,bless:1,bootstrap:1,"break":1,caller:1,chdir:1,chmod:1,chomp:1,chop:1,chown:1,chr:1,chroot:1,close:1,closedir:1,connect:1,"continue":[1,1],cos:1,crypt:1,dbmclose:1,dbmopen:1,"default":1,defined:1,"delete":1,die:1,"do":1,dump:1,each:1,endgrent:1,endhostent:1,endnetent:1,endprotoent:1,endpwent:1,endservent:1,eof:1,eval:1,exec:1,exists:1,exit:1,exp:1,fcntl:1,fileno:1,flock:1,fork:1,format:1,formline:1,getc:1,getgrent:1,getgrgid:1,getgrnam:1,gethostbyaddr:1,gethostbyname:1,gethostent:1,getlogin:1,getnetbyaddr:1,getnetbyname:1,getnetent:1,getpeername:1,getpgrp:1,getppid:1,getpriority:1,getprotobyname:1,getprotobynumber:1,getprotoent:1,getpwent:1,getpwnam:1,getpwuid:1,getservbyname:1,getservbyport:1,getservent:1,getsockname:1,getsockopt:1,given:1,glob:1,gmtime:1,"goto":1,grep:1,hex:1,"import":1,index:1,"int":1,ioctl:1,join:1,keys:1,kill:1,last:1,lc:1,lcfirst:1,length:1,link:1,listen:1,local:2,localtime:1,lock:1,log:1,lstat:1,m:null,map:1,mkdir:1,msgctl:1,msgget:1,msgrcv:1,msgsnd:1,my:2,"new":1,next:1,no:1,oct:1,open:1,opendir:1,ord:1,our:2,pack:1,"package":1,pipe:1,pop:1,pos:1,print:1,printf:1,prototype:1,push:1,q:null,qq:null,qr:null,quotemeta:null,qw:null,qx:null,rand:1,read:1,readdir:1,readline:1,readlink:1,readpipe:1,recv:1,redo:1,ref:1,rename:1,require:1,reset:1,"return":1,reverse:1,rewinddir:1,rindex:1,rmdir:1,s:null,say:1,scalar:1,seek:1,seekdir:1,select:1,semctl:1,semget:1,semop:1,send:1,setgrent:1,sethostent:1,setnetent:1,setpgrp:1,setpriority:1,setprotoent:1,setpwent:1,setservent:1,setsockopt:1,shift:1,shmctl:1,shmget:1,shmread:1,shmwrite:1,shutdown:1,sin:1,sleep:1,socket:1,socketpair:1,sort:1,splice:1,split:1,sprintf:1,sqrt:1,srand:1,stat:1,state:1,study:1,sub:1,substr:1,symlink:1,syscall:1,sysopen:1,sysread:1,sysseek:1,system:1,syswrite:1,tell:1,telldir:1,tie:1,tied:1,time:1,times:1,tr:null,truncate:1,uc:1,ucfirst:1,umask:1,undef:1,unlink:1,unpack:1,unshift:1,untie:1,use:1,utime:1,values:1,vec:1,wait:1,waitpid:1,wantarray:1,warn:1,when:1,write:1,y:null},l="string-2",c=/[goseximacplud]/;return{startState:function(){return{tokenize:a,chain:null,style:null,tail:null}},token:function(e,t){return(t.tokenize||a)(e,t)},lineComment:"#"}}),e.registerHelper("wordChars","perl",/[\w$]/),e.defineMIME("text/x-perl","perl")}),function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],e):e(CodeMirror)}(function(e){"use strict";e.defineMode("lua",function(e,t){function r(e){return new RegExp("^(?:"+e.join("|")+")","i")}function n(e){return new RegExp("^(?:"+e.join("|")+")$","i")}function i(e){for(var t=0;e.eat("=");)++t;return e.eat("["),t}function o(e,t){var r=e.next();return"-"==r&&e.eat("-")?e.eat("[")&&e.eat("[")?(t.cur=a(i(e),"comment"))(e,t):(e.skipToEnd(),"comment"):'"'==r||"'"==r?(t.cur=s(r))(e,t):"["==r&&/[\[=]/.test(e.peek())?(t.cur=a(i(e),"string"))(e,t):/\d/.test(r)?(e.eatWhile(/[\w.%]/),"number"):/[\w_]/.test(r)?(e.eatWhile(/[\w\\\-_.]/),"variable"):null}function a(e,t){return function(r,n){for(var i,a=null;null!=(i=r.next());)if(null==a)"]"==i&&(a=0);else if("="==i)++a;else{if("]"==i&&a==e){n.cur=o;break}a=null}return t}}function s(e){return function(t,r){for(var n,i=!1;null!=(n=t.next())&&(n!=e||i);)i=!i&&"\\"==n;return i||(r.cur=o),"string"}}var l=e.indentUnit,c=n(t.specials||[]),u=n(["_G","_VERSION","assert","collectgarbage","dofile","error","getfenv","getmetatable","ipairs","load","loadfile","loadstring","module","next","pairs","pcall","print","rawequal","rawget","rawset","require","select","setfenv","setmetatable","tonumber","tostring","type","unpack","xpcall","coroutine.create","coroutine.resume","coroutine.running","coroutine.status","coroutine.wrap","coroutine.yield","debug.debug","debug.getfenv","debug.gethook","debug.getinfo","debug.getlocal","debug.getmetatable","debug.getregistry","debug.getupvalue","debug.setfenv","debug.sethook","debug.setlocal","debug.setmetatable","debug.setupvalue","debug.traceback","close","flush","lines","read","seek","setvbuf","write","io.close","io.flush","io.input","io.lines","io.open","io.output","io.popen","io.read","io.stderr","io.stdin","io.stdout","io.tmpfile","io.type","io.write","math.abs","math.acos","math.asin","math.atan","math.atan2","math.ceil","math.cos","math.cosh","math.deg","math.exp","math.floor","math.fmod","math.frexp","math.huge","math.ldexp","math.log","math.log10","math.max","math.min","math.modf","math.pi","math.pow","math.rad","math.random","math.randomseed","math.sin","math.sinh","math.sqrt","math.tan","math.tanh","os.clock","os.date","os.difftime","os.execute","os.exit","os.getenv","os.remove","os.rename","os.setlocale","os.time","os.tmpname","package.cpath","package.loaded","package.loaders","package.loadlib","package.path","package.preload","package.seeall","string.byte","string.char","string.dump","string.find","string.format","string.gmatch","string.gsub","string.len","string.lower","string.match","string.rep","string.reverse","string.sub","string.upper","table.concat","table.insert","table.maxn","table.remove","table.sort"]),d=n(["and","break","elseif","false","nil","not","or","return","true","function","end","if","then","else","do","while","repeat","until","for","in","local"]),f=n(["function","if","repeat","do","\\(","{"]),m=n(["end","until","\\)","}"]),h=r(["end","until","\\)","}","else","elseif"]);return{startState:function(e){return{basecol:e||0,indentDepth:0,cur:o}},token:function(e,t){if(e.eatSpace())return null;var r=t.cur(e,t),n=e.current();return"variable"==r&&(d.test(n)?r="keyword":u.test(n)?r="builtin":c.test(n)&&(r="variable-2")),"comment"!=r&&"string"!=r&&(f.test(n)?++t.indentDepth:m.test(n)&&--t.indentDepth),r},indent:function(e,t){var r=h.test(t);return e.basecol+l*(e.indentDepth-(r?1:0))},lineComment:"--",blockCommentStart:"--[[",blockCommentEnd:"]]"}}),e.defineMIME("text/x-lua","lua")}),function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],e):e(CodeMirror)}(function(e){"use strict";e.defineMode("r",function(e){function t(e){for(var t=e.split(" "),r={},n=0;n=!&|~$:]/;return{startState:function(){return{tokenize:r,ctx:{type:"top",indent:-e.indentUnit,align:!1},indent:0,afterIdent:!1}},token:function(e,t){if(e.sol()&&(null==t.ctx.align&&(t.ctx.align=!1),t.indent=e.indentation()),e.eatSpace())return null;var r=t.tokenize(e,t);"comment"!=r&&null==t.ctx.align&&(t.ctx.align=!0);var n=t.ctx.type;return";"!=a&&"{"!=a&&"}"!=a||"block"!=n||o(t),"{"==a?i(t,"}",e):"("==a?(i(t,")",e),t.afterIdent&&(t.ctx.argList=!0)):"["==a?i(t,"]",e):"block"==a?i(t,"block",e):a==n&&o(t),t.afterIdent="variable"==r||"keyword"==r,r},indent:function(t,n){if(t.tokenize!=r)return 0;var i=n&&n.charAt(0),o=t.ctx,a=i==o.type;return"block"==o.type?o.indent+("{"==i?0:e.indentUnit):o.align?o.column+(a?0:1):o.indent+(a?0:e.indentUnit)},lineComment:"#"}}),e.defineMIME("text/x-rsrc","r")}),function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],e):e(CodeMirror)}(function(e){"use strict";e.defineMode("ruby",function(e){function t(e){for(var t={},r=0,n=e.length;n>r;++r)t[e[r]]=!0;return t}function r(e,t,r){return r.tokenize.push(e),e(t,r)}function n(e,t){if(c=null,e.sol()&&e.match("=begin")&&e.eol())return t.tokenize.push(l),"comment";if(e.eatSpace())return null;var n,i=e.next();if("`"==i||"'"==i||'"'==i)return r(a(i,"string",'"'==i||"`"==i),e,t);if("/"==i){var o=e.current().length;if(e.skipTo("/")){var u=e.current().length;e.backUp(e.current().length-o);for(var d=0;e.current().lengthd)break}if(e.backUp(e.current().length-o),0==d)return r(a(i,"string-2",!0),e,t)}return"operator"}if("%"==i){var h="string",p=!0;e.eat("s")?h="atom":e.eat(/[WQ]/)?h="string":e.eat(/[r]/)?h="string-2":e.eat(/[wxq]/)&&(h="string",p=!1);var g=e.eat(/[^\w\s=]/);return g?(m.propertyIsEnumerable(g)&&(g=m[g]),r(a(g,h,p,!0),e,t)):"operator"}if("#"==i)return e.skipToEnd(),"comment";if("<"==i&&(n=e.match(/^<-?[\`\"\']?([a-zA-Z_?]\w*)[\`\"\']?(?:;|$)/)))return r(s(n[1]),e,t);if("0"==i)return e.eatWhile(e.eat("x")?/[\da-fA-F]/:e.eat("b")?/[01]/:/[0-7]/),"number";if(/\d/.test(i))return e.match(/^[\d_]*(?:\.[\d_]+)?(?:[eE][+\-]?[\d_]+)?/),"number";if("?"==i){for(;e.match(/^\\[CM]-/););return e.eat("\\")?e.eatWhile(/\w/):e.next(),"string"}if(":"==i)return e.eat("'")?r(a("'","atom",!1),e,t):e.eat('"')?r(a('"',"atom",!0),e,t):e.eat(/[\<\>]/)?(e.eat(/[\<\>]/),"atom"):e.eat(/[\+\-\*\/\&\|\:\!]/)?"atom":e.eat(/[a-zA-Z$@_\xa1-\uffff]/)?(e.eatWhile(/[\w$\xa1-\uffff]/),e.eat(/[\?\!\=]/),"atom"):"operator";if("@"==i&&e.match(/^@?[a-zA-Z_\xa1-\uffff]/))return e.eat("@"),e.eatWhile(/[\w\xa1-\uffff]/),"variable-2";if("$"==i)return e.eat(/[a-zA-Z_]/)?e.eatWhile(/[\w]/):e.eat(/\d/)?e.eat(/\d/):e.next(),"variable-3";if(/[a-zA-Z_\xa1-\uffff]/.test(i))return e.eatWhile(/[\w\xa1-\uffff]/),e.eat(/[\?\!]/),e.eat(":")?"atom":"ident";if("|"!=i||!t.varList&&"{"!=t.lastTok&&"do"!=t.lastTok){if(/[\(\)\[\]{}\\;]/.test(i))return c=i,null;if("-"==i&&e.eat(">"))return"arrow";if(/[=+\-\/*:\.^%<>~|]/.test(i)){var v=e.eatWhile(/[=+\-\/*:\.^%<>~|]/);return"."!=i||v||(c="."),"operator"}return null}return c="|",null}function i(e){return e||(e=1),function(t,r){if("}"==t.peek()){if(1==e)return r.tokenize.pop(),r.tokenize[r.tokenize.length-1](t,r);r.tokenize[r.tokenize.length-1]=i(e-1)}else"{"==t.peek()&&(r.tokenize[r.tokenize.length-1]=i(e+1));return n(t,r)}}function o(){var e=!1;return function(t,r){return e?(r.tokenize.pop(),r.tokenize[r.tokenize.length-1](t,r)):(e=!0,n(t,r))}}function a(e,t,r,n){return function(a,s){var l,c=!1;for("read-quoted-paused"===s.context.type&&(s.context=s.context.prev,a.eat("}"));null!=(l=a.next());){if(l==e&&(n||!c)){s.tokenize.pop();break}if(r&&"#"==l&&!c){if(a.eat("{")){"}"==e&&(s.context={prev:s.context,type:"read-quoted-paused"}),s.tokenize.push(i());break}if(/[@\$]/.test(a.peek())){s.tokenize.push(o());break}}c=!c&&"\\"==l}return t}}function s(e){return function(t,r){return t.match(e)?r.tokenize.pop():t.skipToEnd(),"string"}}function l(e,t){return e.sol()&&e.match("=end")&&e.eol()&&t.tokenize.pop(),e.skipToEnd(),"comment"}var c,u=t(["alias","and","BEGIN","begin","break","case","class","def","defined?","do","else","elsif","END","end","ensure","false","for","if","in","module","next","not","or","redo","rescue","retry","return","self","super","then","true","undef","unless","until","when","while","yield","nil","raise","throw","catch","fail","loop","callcc","caller","lambda","proc","public","protected","private","require","load","require_relative","extend","autoload","__END__","__FILE__","__LINE__","__dir__"]),d=t(["def","class","case","for","while","module","then","catch","loop","proc","begin"]),f=t(["end","until"]),m={"[":"]","{":"}","(":")"};return{startState:function(){return{tokenize:[n],indented:0,context:{type:"top",indented:-e.indentUnit},continuedLine:!1,lastTok:null,varList:!1}},token:function(e,t){e.sol()&&(t.indented=e.indentation());var r,n=t.tokenize[t.tokenize.length-1](e,t),i=c;if("ident"==n){var o=e.current();n="."==t.lastTok?"property":u.propertyIsEnumerable(e.current())?"keyword":/^[A-Z]/.test(o)?"tag":"def"==t.lastTok||"class"==t.lastTok||t.varList?"def":"variable","keyword"==n&&(i=o,d.propertyIsEnumerable(o)?r="indent":f.propertyIsEnumerable(o)?r="dedent":"if"!=o&&"unless"!=o||e.column()!=e.indentation()?"do"==o&&t.context.indented\\?]*[^\\W_])?)",y=new RegExp(r("^{0}",b)),x="(?:[^\\W\\d_](?:[\\w\\s!\"#$%&'()\\*\\+,\\-\\./:;<=>\\?]*[^\\W_])?)",k=r("(?:{0}|`{1}`)",b,x),w="(?:[^\\s\\|](?:[^\\|]*[^\\s\\|])?)",_="(?:[^\\`]+)",C=new RegExp(r("^{0}",_)),S=new RegExp("^([!'#$%&\"()*+,-./:;<=>?@\\[\\\\\\]^_`{|}~])\\1{3,}\\s*$"),T=new RegExp(r("^\\.\\.{0}",p)),M=new RegExp(r("^_{0}:{1}|^__:{1}",k,g)),L=new RegExp(r("^{0}::{1}",k,g)),E=new RegExp(r("^\\|{0}\\|{1}{2}::{3}",w,p,k,g)),q=new RegExp(r("^\\[(?:\\d+|#{0}?|\\*)]{1}",k,g)),j=new RegExp(r("^\\[{0}\\]{1}",k,g)),z=new RegExp(r("^\\|{0}\\|",w)),I=new RegExp(r("^\\[(?:\\d+|#{0}?|\\*)]_",k)),P=new RegExp(r("^\\[{0}\\]_",k)),D=new RegExp(r("^{0}__?",k)),A=new RegExp(r("^`{0}`_",_)),$=new RegExp(r("^:{0}:`{1}`{2}",b,_,g)),O=new RegExp(r("^`{1}`:{0}:{2}",b,_,g)),R=new RegExp(r("^:{0}:{1}",b,g)),F=new RegExp(r("^{0}",k)),H=new RegExp(r("^::{0}",g)),N=new RegExp(r("^\\|{0}\\|",w)),B=new RegExp(r("^{0}",p)),U=new RegExp(r("^{0}",k)),W=new RegExp(r("^::{0}",g)),V=new RegExp("^_"),K=new RegExp(r("^{0}|_",k)),Z=new RegExp(r("^:{0}",g)),G=new RegExp("^::\\s*$"),X=new RegExp("^\\s+(?:>>>|In \\[\\d+\\]:)\\s");return{startState:function(){return{tok:n,ctx:c(void 0,0)}},copyState:function(t){var r=t.ctx,n=t.tmp;return r.local&&(r={mode:r.mode,local:e.copyState(r.mode,r.local)}),n&&(n={mode:n.mode,local:e.copyState(n.mode,n.local)}),{tok:t.tok,ctx:r,tmp:n}},innerMode:function(e){return e.tmp?{state:e.tmp.local,mode:e.tmp.mode}:e.ctx.mode?{state:e.ctx.local,mode:e.ctx.mode}:null},token:function(e,t){return t.tok(e,t)}}},"python","stex"),e.defineMIME("text/x-rst","rst")}),function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror"),require("../htmlmixed/htmlmixed"),require("../smarty/smarty")):"function"==typeof define&&define.amd?define(["../../lib/codemirror","../htmlmixed/htmlmixed","../smarty/smarty"],e):e(CodeMirror)}(function(e){"use strict";e.defineMode("smartymixed",function(t){function r(e){return e.replace(/[^\s\w]/g,"\\$&")}var n=e.getMode(t,"htmlmixed"),i=e.getMode(t,"smarty"),o={rightDelimiter:"}",leftDelimiter:"{"};t.hasOwnProperty("leftDelimiter")&&(o.leftDelimiter=t.leftDelimiter),t.hasOwnProperty("rightDelimiter")&&(o.rightDelimiter=t.rightDelimiter);var a=r(o.leftDelimiter),s=r(o.rightDelimiter),l={smartyComment:new RegExp("^"+s+"\\*"),literalOpen:new RegExp(a+"literal"+s),literalClose:new RegExp(a+"/literal"+s),hasLeftDelimeter:new RegExp(".*"+a),htmlHasLeftDelimeter:new RegExp("[^<>]*"+a)},c={chain:function(e,t,r){return t.tokenize=r,r(e,t)},cleanChain:function(e,t,r){return t.tokenize=null,t.localState=null,t.localMode=null,"string"==typeof r?r?r:null:r(e,t)},maybeBackup:function(e,t,r){var n,i=e.current(),o=i.search(t);return o>-1?e.backUp(i.length-o):(n=i.match(/<\/?$/))&&(e.backUp(i.length),e.match(t,!1)||e.match(i[0])),r}},u={html:function(e,t){var r=t.htmlMixedState.htmlState.context&&t.htmlMixedState.htmlState.context.tagName?t.htmlMixedState.htmlState.context.tagName:null;return!t.inLiteral&&e.match(l.htmlHasLeftDelimeter,!1)&&null===r?(t.tokenize=u.smarty,t.localMode=i,t.localState=i.startState(n.indent(t.htmlMixedState,"")),c.maybeBackup(e,o.leftDelimiter,i.token(e,t.localState))):!t.inLiteral&&e.match(o.leftDelimiter,!1)?(t.tokenize=u.smarty,t.localMode=i,t.localState=i.startState(n.indent(t.htmlMixedState,"")),c.maybeBackup(e,o.leftDelimiter,i.token(e,t.localState))):n.token(e,t.htmlMixedState)},smarty:function(e,t){if(e.match(o.leftDelimiter,!1)){if(e.match(l.smartyComment,!1))return c.chain(e,t,u.inBlock("comment","*"+o.rightDelimiter))}else if(e.match(o.rightDelimiter,!1))return e.eat(o.rightDelimiter),t.tokenize=u.html,t.localMode=n,t.localState=t.htmlMixedState,"tag";return c.maybeBackup(e,o.rightDelimiter,i.token(e,t.localState))},inBlock:function(e,t){return function(r,n){for(;!r.eol();){if(r.match(t)){c.cleanChain(r,n,"");break}r.next()}return e}}};return{startState:function(){var e=n.startState();return{token:u.html,localMode:null,localState:null,htmlMixedState:e,tokenize:null,inLiteral:!1}},copyState:function(t){var r=null,o=t.tokenize||t.token;return t.localState&&(r=e.copyState(o!=u.html?i:n,t.localState)),{token:t.token,tokenize:t.tokenize,localMode:t.localMode,localState:r,htmlMixedState:e.copyState(n,t.htmlMixedState),inLiteral:t.inLiteral}},token:function(e,t){if(e.match(o.leftDelimiter,!1)){if(!t.inLiteral&&e.match(l.literalOpen,!0))return t.inLiteral=!0,"keyword";if(t.inLiteral&&e.match(l.literalClose,!0))return t.inLiteral=!1,"keyword"}t.inLiteral&&t.localState!=t.htmlMixedState&&(t.tokenize=u.html,t.localMode=n,t.localState=t.htmlMixedState);var r=(t.tokenize||t.token)(e,t);return r},indent:function(t,r){return t.localMode==i||t.inLiteral&&!t.localMode||l.hasLeftDelimeter.test(r)?e.Pass:n.indent(t.htmlMixedState,r)},innerMode:function(e){return{state:e.localState||e.htmlMixedState,mode:e.localMode||n}}}},"htmlmixed","smarty"),e.defineMIME("text/x-smarty","smartymixed")}),function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],e):e(CodeMirror)}(function(e){"use strict";e.defineMode("vb",function(e,t){function r(e){return new RegExp("^(("+e.join(")|(")+"))\\b","i")}function n(e,t){t.currentIndent++}function i(e,t){t.currentIndent--}function o(e,t){if(e.eatSpace())return null;var r=e.peek();if("'"===r)return e.skipToEnd(),"comment";if(e.match(/^((&H)|(&O))?[0-9\.a-f]/i,!1)){var o=!1;if(e.match(/^\d*\.\d+F?/i)?o=!0:e.match(/^\d+\.\d*F?/)?o=!0:e.match(/^\.\d+F?/)&&(o=!0),o)return e.eat(/J/i),"number";var s=!1;if(e.match(/^&H[0-9a-f]+/i)?s=!0:e.match(/^&O[0-7]+/i)?s=!0:e.match(/^[1-9]\d*F?/)?(e.eat(/J/i),s=!0):e.match(/^0(?![\dx])/i)&&(s=!0),s)return e.eat(/L/i),"number"}return e.match(_)?(t.tokenize=a(e.current()),t.tokenize(e,t)):e.match(m)||e.match(f)?null:e.match(d)||e.match(c)||e.match(b)?"operator":e.match(u)?null:e.match(L)?(n(e,t),t.doInCurrentLine=!0,"keyword"):e.match(C)?(t.doInCurrentLine?t.doInCurrentLine=!1:n(e,t),"keyword"):e.match(S)?"keyword":e.match(M)?(i(e,t),i(e,t),"keyword"):e.match(T)?(i(e,t),"keyword"):e.match(w)?"keyword":e.match(k)?"keyword":e.match(h)?"variable":(e.next(),l)}function a(e){var r=1==e.length,n="string";return function(i,a){for(;!i.eol();){if(i.eatWhile(/[^'"]/),i.match(e))return a.tokenize=o,n;i.eat(/['"]/)}if(r){if(t.singleLineStringErrors)return l;a.tokenize=o}return n}}function s(e,t){var r=t.tokenize(e,t),o=e.current();if("."===o)return r=t.tokenize(e,t),o=e.current(),"variable"===r?"variable":l;var a="[({".indexOf(o);return-1!==a&&n(e,t),"dedent"===E&&i(e,t)?l:(a="])}".indexOf(o),-1!==a&&i(e,t)?l:r)}var l="error",c=new RegExp("^[\\+\\-\\*/%&\\\\|\\^~<>!]"),u=new RegExp("^[\\(\\)\\[\\]\\{\\}@,:`=;\\.]"),d=new RegExp("^((==)|(<>)|(<=)|(>=)|(<>)|(<<)|(>>)|(//)|(\\*\\*))"),f=new RegExp("^((\\+=)|(\\-=)|(\\*=)|(%=)|(/=)|(&=)|(\\|=)|(\\^=))"),m=new RegExp("^((//=)|(>>=)|(<<=)|(\\*\\*=))"),h=new RegExp("^[_A-Za-z][_A-Za-z0-9]*"),p=["class","module","sub","enum","select","while","if","function","get","set","property","try"],g=["else","elseif","case","catch"],v=["next","loop"],b=r(["and","or","not","xor","in"]),y=["as","dim","break","continue","optional","then","until","goto","byval","byref","new","handles","property","return","const","private","protected","friend","public","shared","static","true","false"],x=["integer","string","double","decimal","boolean","short","char","float","single"],k=r(y),w=r(x),_='"',C=r(p),S=r(g),T=r(v),M=r(["end"]),L=r(["do"]),E=null,q={electricChars:"dDpPtTfFeE ",startState:function(){return{tokenize:o,lastToken:null,currentIndent:0,nextLineIndent:0,doInCurrentLine:!1}},token:function(e,t){e.sol()&&(t.currentIndent+=t.nextLineIndent,t.nextLineIndent=0,t.doInCurrentLine=0);var r=s(e,t);return t.lastToken={style:r,content:e.current()},r},indent:function(t,r){var n=r.replace(/^\s+|\s+$/g,"");return n.match(T)||n.match(M)||n.match(S)?e.indentUnit*(t.currentIndent-1):t.currentIndent<0?0:t.currentIndent*e.indentUnit}};return q}),e.defineMIME("text/x-vb","vb")}),function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],e):e(CodeMirror)}(function(e){"use strict";e.defineMode("vbscript",function(e,t){function r(e){return new RegExp("^(("+e.join(")|(")+"))\\b","i")}function n(e,t){t.currentIndent++}function i(e,t){t.currentIndent--}function o(e,t){if(e.eatSpace())return"space";var r=e.peek();if("'"===r)return e.skipToEnd(),"comment";if(e.match(H))return e.skipToEnd(),"comment";if(e.match(/^((&H)|(&O))?[0-9\.]/i,!1)&&!e.match(/^((&H)|(&O))?[0-9\.]+[a-z_]/i,!1)){var o=!1;if(e.match(/^\d*\.\d+/i)?o=!0:e.match(/^\d+\.\d*/)?o=!0:e.match(/^\.\d+/)&&(o=!0),o)return e.eat(/J/i),"number";var s=!1;if(e.match(/^&H[0-9a-f]+/i)?s=!0:e.match(/^&O[0-7]+/i)?s=!0:e.match(/^[1-9]\d*F?/)?(e.eat(/J/i),s=!0):e.match(/^0(?![\dx])/i)&&(s=!0),s)return e.eat(/L/i),"number"}return e.match(P)?(t.tokenize=a(e.current()),t.tokenize(e,t)):e.match(u)||e.match(c)||e.match(v)?"operator":e.match(d)?null:e.match(f)?"bracket":e.match(F)?(t.doInCurrentLine=!0,"keyword"):e.match(R)?(n(e,t),t.doInCurrentLine=!0,"keyword"):e.match(D)?(t.doInCurrentLine?t.doInCurrentLine=!1:n(e,t),"keyword"):e.match(A)?"keyword":e.match(O)?(i(e,t),i(e,t),"keyword"):e.match($)?(t.doInCurrentLine?t.doInCurrentLine=!1:i(e,t),"keyword"):e.match(E)?"keyword":e.match(q)?"atom":e.match(I)?"variable-2":e.match(j)?"builtin":e.match(z)?"variable-2":e.match(m)?"variable":(e.next(),l)}function a(e){var r=1==e.length,n="string";return function(i,a){for(;!i.eol();){if(i.eatWhile(/[^'"]/),i.match(e))return a.tokenize=o,n;i.eat(/['"]/)}if(r){if(t.singleLineStringErrors)return l;a.tokenize=o}return n}}function s(e,t){var r=t.tokenize(e,t),n=e.current();return"."===n?(r=t.tokenize(e,t),n=e.current(),!r||"variable"!==r.substr(0,8)&&"builtin"!==r&&"keyword"!==r?l:(("builtin"===r||"keyword"===r)&&(r="variable"),L.indexOf(n.substr(1))>-1&&(r="variable-2"),r)):r}var l="error",c=new RegExp("^[\\+\\-\\*/&\\\\\\^<>=]"),u=new RegExp("^((<>)|(<=)|(>=))"),d=new RegExp("^[\\.,]"),f=new RegExp("^[\\(\\)]"),m=new RegExp("^[A-Za-z][_A-Za-z0-9]*"),h=["class","sub","select","while","if","function","property","with","for"],p=["else","elseif","case"],g=["next","loop","wend"],v=r(["and","or","not","xor","is","mod","eqv","imp"]),b=["dim","redim","then","until","randomize","byval","byref","new","property","exit","in","const","private","public","get","set","let","stop","on error resume next","on error goto 0","option explicit","call","me"],y=["true","false","nothing","empty","null"],x=["abs","array","asc","atn","cbool","cbyte","ccur","cdate","cdbl","chr","cint","clng","cos","csng","cstr","date","dateadd","datediff","datepart","dateserial","datevalue","day","escape","eval","execute","exp","filter","formatcurrency","formatdatetime","formatnumber","formatpercent","getlocale","getobject","getref","hex","hour","inputbox","instr","instrrev","int","fix","isarray","isdate","isempty","isnull","isnumeric","isobject","join","lbound","lcase","left","len","loadpicture","log","ltrim","rtrim","trim","maths","mid","minute","month","monthname","msgbox","now","oct","replace","rgb","right","rnd","round","scriptengine","scriptenginebuildversion","scriptenginemajorversion","scriptengineminorversion","second","setlocale","sgn","sin","space","split","sqr","strcomp","string","strreverse","tan","time","timer","timeserial","timevalue","typename","ubound","ucase","unescape","vartype","weekday","weekdayname","year"],k=["vbBlack","vbRed","vbGreen","vbYellow","vbBlue","vbMagenta","vbCyan","vbWhite","vbBinaryCompare","vbTextCompare","vbSunday","vbMonday","vbTuesday","vbWednesday","vbThursday","vbFriday","vbSaturday","vbUseSystemDayOfWeek","vbFirstJan1","vbFirstFourDays","vbFirstFullWeek","vbGeneralDate","vbLongDate","vbShortDate","vbLongTime","vbShortTime","vbObjectError","vbOKOnly","vbOKCancel","vbAbortRetryIgnore","vbYesNoCancel","vbYesNo","vbRetryCancel","vbCritical","vbQuestion","vbExclamation","vbInformation","vbDefaultButton1","vbDefaultButton2","vbDefaultButton3","vbDefaultButton4","vbApplicationModal","vbSystemModal","vbOK","vbCancel","vbAbort","vbRetry","vbIgnore","vbYes","vbNo","vbCr","VbCrLf","vbFormFeed","vbLf","vbNewLine","vbNullChar","vbNullString","vbTab","vbVerticalTab","vbUseDefault","vbTrue","vbFalse","vbEmpty","vbNull","vbInteger","vbLong","vbSingle","vbDouble","vbCurrency","vbDate","vbString","vbObject","vbError","vbBoolean","vbVariant","vbDataObject","vbDecimal","vbByte","vbArray"],w=["WScript","err","debug","RegExp"],_=["description","firstindex","global","helpcontext","helpfile","ignorecase","length","number","pattern","source","value","count"],C=["clear","execute","raise","replace","test","write","writeline","close","open","state","eof","update","addnew","end","createobject","quit"],S=["server","response","request","session","application"],T=["buffer","cachecontrol","charset","contenttype","expires","expiresabsolute","isclientconnected","pics","status","clientcertificate","cookies","form","querystring","servervariables","totalbytes","contents","staticobjects","codepage","lcid","sessionid","timeout","scripttimeout"],M=["addheader","appendtolog","binarywrite","end","flush","redirect","binaryread","remove","removeall","lock","unlock","abandon","getlasterror","htmlencode","mappath","transfer","urlencode"],L=C.concat(_);w=w.concat(k),e.isASP&&(w=w.concat(S),L=L.concat(M,T));var E=r(b),q=r(y),j=r(x),z=r(w),I=r(L),P='"',D=r(h),A=r(p),$=r(g),O=r(["end"]),R=r(["do"]),F=r(["on error resume next","exit"]),H=r(["rem"]),N={electricChars:"dDpPtTfFeE ",startState:function(){return{tokenize:o,lastToken:null,currentIndent:0,nextLineIndent:0,doInCurrentLine:!1,ignoreKeyword:!1}},token:function(e,t){e.sol()&&(t.currentIndent+=t.nextLineIndent,t.nextLineIndent=0,t.doInCurrentLine=0);var r=s(e,t);return t.lastToken={style:r,content:e.current()},"space"===r&&(r=null),r},indent:function(t,r){var n=r.replace(/^\s+|\s+$/g,"");return n.match($)||n.match(O)||n.match(A)?e.indentUnit*(t.currentIndent-1):t.currentIndent<0?0:t.currentIndent*e.indentUnit}};return N}),e.defineMIME("text/vbscript","vbscript")}),function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],e):e(CodeMirror)}(function(e){"use strict";e.defineMode("velocity",function(){function e(e){for(var t={},r=e.split(" "),n=0;nf.length&&"."==e.string.charAt(e.pos-f.length-1)&&r.lastTokenWasBuiltin?"builtin":(r.lastTokenWasBuiltin=!1,null)}return r.lastTokenWasBuiltin=!1,r.inString?(r.inString=!1,"string"):r.inParams?t(e,r,n(d)):void 0}function n(e){return function(t,n){for(var i,o=!1,a=!1;null!=(i=t.next());){if(i==e&&!o){a=!0;break}if('"'==e&&"$"==t.peek()&&!o){n.inString=!0,a=!0;break}o=!o&&"\\"==i}return a&&(n.tokenize=r),"string"}}function i(e,t){for(var n,i=!1;n=e.next();){if("#"==n&&i){t.tokenize=r;break}i="*"==n}return"comment"}function o(e,t){for(var n,i=0;n=e.next();){if("#"==n&&2==i){t.tokenize=r;break}"]"==n?i++:" "!=n&&(i=0)}return"meta"}var a=e("#end #else #break #stop #[[ #]] #{end} #{else} #{break} #{stop}"),s=e("#if #elseif #foreach #set #include #parse #macro #define #evaluate #{if} #{elseif} #{foreach} #{set} #{include} #{parse} #{macro} #{define} #{evaluate}"),l=e("$foreach.count $foreach.hasNext $foreach.first $foreach.last $foreach.topmost $foreach.parent.count $foreach.parent.hasNext $foreach.parent.first $foreach.parent.last $foreach.parent $velocityCount $!bodyContent $bodyContent"),c=/[+\-*&%=<>!?:\/|]/;return{startState:function(){return{tokenize:r,beforeParams:!1,inParams:!1,inString:!1,lastTokenWasBuiltin:!1}},token:function(e,t){return e.eatSpace()?null:t.tokenize(e,t)},blockCommentStart:"#*",blockCommentEnd:"*#",lineComment:"##",fold:"velocity"}}),e.defineMIME("text/velocity","velocity")}),function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],e):e(CodeMirror)}(function(e){"use strict";e.defineMode("xquery",function(){function e(e,t,r){return y=e,x=r,t}function t(e,t,r){return t.tokenize=r,r(e,t)}function r(r,s){var f=r.next(),h=!1,g=p(r);if("<"==f){if(r.match("!--",!0))return t(r,s,l);if(r.match("![CDATA",!1))return s.tokenize=c,e("tag","tag");if(r.match("?",!1))return t(r,s,u);var y=r.eat("/");r.eatSpace();for(var x,w="";x=r.eat(/[^\s\u00a0=<>\"\'\/?]/);)w+=x;return t(r,s,a(w,y))}if("{"==f)return v(s,{type:"codeblock"}),e("",null);if("}"==f)return b(s),e("",null);if(d(s))return">"==f?e("tag","tag"):"/"==f&&r.eat(">")?(b(s),e("tag","tag")):e("word","variable");if(/\d/.test(f))return r.match(/^\d*(?:\.\d*)?(?:E[+\-]?\d+)?/),e("number","atom");if("("===f&&r.eat(":"))return v(s,{type:"comment"}),t(r,s,n);if(g||'"'!==f&&"'"!==f){if("$"===f)return t(r,s,o);if(":"===f&&r.eat("="))return e("operator","keyword");if("("===f)return v(s,{type:"paren"}),e("",null);if(")"===f)return b(s),e("",null);if("["===f)return v(s,{type:"bracket"}),e("",null);if("]"===f)return b(s),e("",null);var _=k.propertyIsEnumerable(f)&&k[f];if(g&&'"'===f)for(;'"'!==r.next(););if(g&&"'"===f)for(;"'"!==r.next(););_||r.eatWhile(/[\w\$_-]/);var C=r.eat(":");!r.eat(":")&&C&&r.eatWhile(/[\w\$_-]/),r.match(/^[ \t]*\(/,!1)&&(h=!0);var S=r.current();return _=k.propertyIsEnumerable(S)&&k[S],h&&!_&&(_={type:"function_call",style:"variable def"}),m(s)?(b(s),e("word","variable",S)):(("element"==S||"attribute"==S||"axis_specifier"==_.type)&&v(s,{type:"xmlconstructor"}),_?e(_.type,_.style,S):e("word","variable",S))}return t(r,s,i(f))}function n(t,r){for(var n,i=!1,o=!1,a=0;n=t.next();){if(")"==n&&i){if(!(a>0)){b(r);break}a--}else":"==n&&o&&a++;i=":"==n,o="("==n}return e("comment","comment")}function i(t,n){return function(o,a){var s;if(h(a)&&o.current()==t)return b(a),n&&(a.tokenize=n),e("string","string");if(v(a,{type:"string",name:t,tokenize:i(t,n)}),o.match("{",!1)&&f(a))return a.tokenize=r,e("string","string");for(;s=o.next();){if(s==t){b(a),n&&(a.tokenize=n);break}if(o.match("{",!1)&&f(a))return a.tokenize=r,e("string","string")}return e("string","string")}}function o(t,n){var i=/[\w\$_-]/;if(t.eat('"')){for(;'"'!==t.next(););t.eat(":")}else t.eatWhile(i),t.match(":=",!1)||t.eat(":");return t.eatWhile(i),n.tokenize=r,e("variable","variable")}function a(t,n){return function(i,o){return i.eatSpace(),n&&i.eat(">")?(b(o),o.tokenize=r,e("tag","tag")):(i.eat("/")||v(o,{type:"tag",name:t,tokenize:r}),i.eat(">")?(o.tokenize=r,e("tag","tag")):(o.tokenize=s,e("tag","tag")))}}function s(n,o){var a=n.next();return"/"==a&&n.eat(">")?(f(o)&&b(o),d(o)&&b(o),e("tag","tag")):">"==a?(f(o)&&b(o),e("tag","tag")):"="==a?e("",null):'"'==a||"'"==a?t(n,o,i(a,s)):(f(o)||v(o,{type:"attribute",tokenize:s}),n.eat(/[a-zA-Z_:]/),n.eatWhile(/[-a-zA-Z0-9_:.]/),n.eatSpace(),(n.match(">",!1)||n.match("/",!1))&&(b(o),o.tokenize=r),e("attribute","attribute"))}function l(t,n){for(var i;i=t.next();)if("-"==i&&t.match("->",!0))return n.tokenize=r,e("comment","comment")}function c(t,n){for(var i;i=t.next();)if("]"==i&&t.match("]",!0))return n.tokenize=r,e("comment","comment")}function u(t,n){for(var i;i=t.next();)if("?"==i&&t.match(">",!0))return n.tokenize=r,e("comment","comment meta")}function d(e){return g(e,"tag")}function f(e){return g(e,"attribute")}function m(e){return g(e,"xmlconstructor")}function h(e){return g(e,"string")}function p(e){return'"'===e.current()?e.match(/^[^\"]+\"\:/,!1):"'"===e.current()?e.match(/^[^\"]+\'\:/,!1):!1}function g(e,t){return e.stack.length&&e.stack[e.stack.length-1].type==t}function v(e,t){e.stack.push(t)}function b(e){e.stack.pop();var t=e.stack.length&&e.stack[e.stack.length-1].tokenize;e.tokenize=t||r}var y,x,k=function(){function e(e){return{type:e,style:"keyword"}}for(var t=e("keyword a"),r=e("keyword b"),n=e("keyword c"),i=e("operator"),o={type:"atom",style:"atom"},a={type:"punctuation",style:null},s={type:"axis_specifier",style:"qualifier"},l={"if":t,"switch":t,"while":t,"for":t,"else":r,then:r,"try":r,"finally":r,"catch":r,element:n,attribute:n,let:n,"implements":n,"import":n,module:n,namespace:n,"return":n,"super":n,"this":n,"throws":n,where:n,"private":n,",":a,"null":o,"fn:false()":o,"fn:true()":o},c=["after","ancestor","ancestor-or-self","and","as","ascending","assert","attribute","before","by","case","cast","child","comment","declare","default","define","descendant","descendant-or-self","descending","document","document-node","element","else","eq","every","except","external","following","following-sibling","follows","for","function","if","import","in","instance","intersect","item","let","module","namespace","node","node","of","only","or","order","parent","precedes","preceding","preceding-sibling","processing-instruction","ref","return","returns","satisfies","schema","schema-element","self","some","sortby","stable","text","then","to","treat","typeswitch","union","variable","version","where","xquery","empty-sequence"],u=0,d=c.length;d>u;u++)l[c[u]]=e(c[u]);for(var f=["xs:string","xs:float","xs:decimal","xs:double","xs:integer","xs:boolean","xs:date","xs:dateTime","xs:time","xs:duration","xs:dayTimeDuration","xs:time","xs:yearMonthDuration","numeric","xs:hexBinary","xs:base64Binary","xs:anyURI","xs:QName","xs:byte","xs:boolean","xs:anyURI","xf:yearMonthDuration"],u=0,d=f.length;d>u;u++)l[f[u]]=o;for(var m=["eq","ne","lt","le","gt","ge",":=","=",">",">=","<","<=",".","|","?","and","or","div","idiv","mod","*","/","+","-"],u=0,d=m.length;d>u;u++)l[m[u]]=i;for(var h=["self::","attribute::","child::","descendant::","descendant-or-self::","parent::","ancestor::","ancestor-or-self::","following::","preceding::","following-sibling::","preceding-sibling::"],u=0,d=h.length;d>u;u++)l[h[u]]=s;return l}();return{startState:function(){return{tokenize:r,cc:[],stack:[]}},token:function(e,t){if(e.eatSpace())return null;var r=t.tokenize(e,t);return r},blockCommentStart:"(:",blockCommentEnd:":)"}}),e.defineMIME("application/xquery","xquery")}),function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],e):e(CodeMirror)}(function(e){"use strict";e.defineMode("yaml",function(){var e=["true","false","on","off","yes","no"],t=new RegExp("\\b(("+e.join(")|(")+"))$","i");return{token:function(e,r){var n=e.peek(),i=r.escaped;if(r.escaped=!1,"#"==n&&(0==e.pos||/\s/.test(e.string.charAt(e.pos-1))))return e.skipToEnd(),"comment";if(e.match(/^('([^']|\\.)*'?|"([^"]|\\.)*"?)/))return"string";if(r.literal&&e.indentation()>r.keyCol)return e.skipToEnd(),"string";if(r.literal&&(r.literal=!1),e.sol()){if(r.keyCol=0,r.pair=!1,r.pairStart=!1,e.match(/---/))return"def";if(e.match(/\.\.\./))return"def";if(e.match(/\s*-\s+/))return"meta"}if(e.match(/^(\{|\}|\[|\])/))return"{"==n?r.inlinePairs++:"}"==n?r.inlinePairs--:"["==n?r.inlineList++:r.inlineList--,"meta";if(r.inlineList>0&&!i&&","==n)return e.next(),"meta";if(r.inlinePairs>0&&!i&&","==n)return r.keyCol=0,r.pair=!1,r.pairStart=!1,e.next(),"meta";if(r.pairStart){if(e.match(/^\s*(\||\>)\s*/))return r.literal=!0,"meta";if(e.match(/^\s*(\&|\*)[a-z0-9\._-]+\b/i))return"variable-2";if(0==r.inlinePairs&&e.match(/^\s*-?[0-9\.\,]+\s?$/))return"number";if(r.inlinePairs>0&&e.match(/^\s*-?[0-9\.\,]+\s?(?=(,|}))/))return"number";if(e.match(t))return"keyword"}return!r.pair&&e.match(/^\s*(?:[,\[\]{}&*!|>'"%@`][^\s'":]|[^,\[\]{}#&*!|>'"%@`])[^#]*?(?=\s*:($|\s))/)?(r.pair=!0,r.keyCol=e.indentation(),"atom"):r.pair&&e.match(/^:\s*/)?(r.pairStart=!0,"meta"):(r.pairStart=!1,r.escaped="\\"==n,e.next(),null)},startState:function(){return{pair:!1,pairStart:!1,keyCol:0,inlinePairs:0,inlineList:0,literal:!1,escaped:!1}}}}),e.defineMIME("text/x-yaml","yaml")}),function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],e):e(CodeMirror)}(function(e){"use strict";e.defineMIME("text/x-erlang","erlang"),e.defineMode("erlang",function(t){function r(e,t){if(t.in_string)return t.in_string=!o(e),u(t,e,"string");if(t.in_atom)return t.in_atom=!a(e),u(t,e,"atom");if(e.eatSpace())return u(t,e,"whitespace");if(!h(t)&&e.match(/-\s*[a-zß-öø-ÿ][\wØ-ÞÀ-Öß-öø-ÿ]*/))return c(e.current(),T)?u(t,e,"type"):u(t,e,"attribute");var r=e.next();if("%"==r)return e.skipToEnd(),u(t,e,"comment");if(":"==r)return u(t,e,"colon");if("?"==r)return e.eatSpace(),e.eatWhile(R),u(t,e,"macro");if("#"==r)return e.eatSpace(),e.eatWhile(R),u(t,e,"record");if("$"==r)return"\\"!=e.next()||e.match(F)?u(t,e,"number"):u(t,e,"error");if("."==r)return u(t,e,"dot");if("'"==r){if(!(t.in_atom=!a(e))){if(e.match(/\s*\/\s*[0-9]/,!1))return e.match(/\s*\/\s*[0-9]/,!0),u(t,e,"fun");if(e.match(/\s*\(/,!1)||e.match(/\s*:/,!1))return u(t,e,"function")}return u(t,e,"atom")}if('"'==r)return t.in_string=!o(e),u(t,e,"string");if(/[A-Z_Ø-ÞÀ-Ö]/.test(r))return e.eatWhile(R),u(t,e,"variable");if(/[a-z_ß-öø-ÿ]/.test(r)){if(e.eatWhile(R),e.match(/\s*\/\s*[0-9]/,!1))return e.match(/\s*\/\s*[0-9]/,!0),u(t,e,"fun");var s=e.current();return c(s,M)?u(t,e,"keyword"):c(s,q)?u(t,e,"operator"):e.match(/\s*\(/,!1)?!c(s,O)||":"==h(t).token&&"erlang"!=h(t,2).token?c(s,$)?u(t,e,"guard"):u(t,e,"function"):u(t,e,"builtin"):c(s,q)?u(t,e,"operator"):":"==l(e)?"erlang"==s?u(t,e,"builtin"):u(t,e,"function"):c(s,["true","false"])?u(t,e,"boolean"):c(s,["true","false"])?u(t,e,"boolean"):u(t,e,"atom")}var d=/[0-9]/,f=/[0-9a-zA-Z]/;return d.test(r)?(e.eatWhile(d),e.eat("#")?e.eatWhile(f)||e.backUp(1):e.eat(".")&&(e.eatWhile(d)?e.eat(/[eE]/)&&(e.eat(/[-+]/)?e.eatWhile(d)||e.backUp(2):e.eatWhile(d)||e.backUp(1)):e.backUp(1)),u(t,e,"number")):n(e,I,P)?u(t,e,"open_paren"):n(e,D,A)?u(t,e,"close_paren"):i(e,L,E)?u(t,e,"separator"):i(e,j,z)?u(t,e,"operator"):u(t,e,null)}function n(e,t,r){if(1==e.current().length&&t.test(e.current())){for(e.backUp(1);t.test(e.peek());)if(e.next(),c(e.current(),r))return!0;e.backUp(e.current().length-1)}return!1}function i(e,t,r){if(1==e.current().length&&t.test(e.current())){for(;t.test(e.peek());)e.next();for(;0r?!1:e.tokenStack[r-n]}function p(e,t){"comment"!=t.type&&"whitespace"!=t.type&&(e.tokenStack=g(e.tokenStack,t),e.tokenStack=v(e.tokenStack))}function g(e,t){var r=e.length-1;return r>0&&"record"===e[r].type&&"dot"===t.type?e.pop():r>0&&"group"===e[r].type?(e.pop(),e.push(t)):e.push(t),e}function v(e){var t=e.length-1;if("dot"===e[t].type)return[];if("fun"===e[t].type&&"fun"===e[t-1].token)return e.slice(0,t-1);switch(e[e.length-1].token){case"}":return b(e,{g:["{"]});case"]":return b(e,{i:["["]});case")":return b(e,{i:["("]});case">>":return b(e,{i:["<<"]});case"end":return b(e,{i:["begin","case","fun","if","receive","try"]});case",":return b(e,{e:["begin","try","when","->",",","(","[","{","<<"]});case"->":return b(e,{r:["when"],m:["try","if","case","receive"]});case";":return b(e,{E:["case","fun","if","receive","try","when"]});case"catch":return b(e,{e:["try"]});case"of":return b(e,{e:["case"]});case"after":return b(e,{e:["receive","try"]});default:return e}}function b(e,t){for(var r in t)for(var n=e.length-1,i=t[r],o=n-1;o>-1;o--)if(c(e[o].token,i)){var a=e.slice(0,o);switch(r){case"m":return a.concat(e[o]).concat(e[n]);case"r":return a.concat(e[n]);case"i":return a;case"g":return a.concat(m("group"));case"E":return a.concat(e[o]);case"e":return a.concat(e[o])}}return"E"==r?[]:e}function y(r,n){var i,o=t.indentUnit,a=x(n),s=h(r,1),l=h(r,2);return r.in_string||r.in_atom?e.Pass:l?"when"==s.token?s.column+o:"when"===a&&"function"===l.type?l.indent+o:"("===a&&"fun"===s.token?s.column+3:"catch"===a&&(i=_(r,["try"]))?i.column:c(a,["end","after","of"])?(i=_(r,["begin","case","fun","if","receive","try"]),i?i.column:e.Pass):c(a,A)?(i=_(r,P),i?i.column:e.Pass):c(s.token,[",","|","||"])||c(a,[",","|","||"])?(i=k(r),i?i.column+i.token.length:o):"->"==s.token?c(l.token,["receive","case","if","try"])?l.column+o+o:l.column+o:c(s.token,P)?s.column+s.token.length:(i=w(r),S(i)?i.column+o:0):0}function x(e){var t=e.match(/,|[a-z]+|\}|\]|\)|>>|\|+|\(/);return S(t)&&0===t.index?t[0]:""}function k(e){var t=e.tokenStack.slice(0,-1),r=C(t,"type",["open_paren"]);return S(t[r])?t[r]:!1}function w(e){var t=e.tokenStack,r=C(t,"type",["open_paren","separator","keyword"]),n=C(t,"type",["operator"]);return S(r)&&S(n)&&n>r?t[r+1]:S(r)?t[r]:!1}function _(e,t){var r=e.tokenStack,n=C(r,"token",t); + +return S(r[n])?r[n]:!1}function C(e,t,r){for(var n=e.length-1;n>-1;n--)if(c(e[n][t],r))return n;return!1}function S(e){return e!==!1&&null!=e}var T=["-type","-spec","-export_type","-opaque"],M=["after","begin","catch","case","cond","end","fun","if","let","of","query","receive","try","when"],L=/[\->,;]/,E=["->",";",","],q=["and","andalso","band","bnot","bor","bsl","bsr","bxor","div","not","or","orelse","rem","xor"],j=/[\+\-\*\/<>=\|:!]/,z=["=","+","-","*","/",">",">=","<","=<","=:=","==","=/=","/=","||","<-","!"],I=/[<\(\[\{]/,P=["<<","(","[","{"],D=/[>\)\]\}]/,A=["}","]",")",">>"],$=["is_atom","is_binary","is_bitstring","is_boolean","is_float","is_function","is_integer","is_list","is_number","is_pid","is_port","is_record","is_reference","is_tuple","atom","binary","bitstring","boolean","function","integer","list","number","pid","port","record","reference","tuple"],O=["abs","adler32","adler32_combine","alive","apply","atom_to_binary","atom_to_list","binary_to_atom","binary_to_existing_atom","binary_to_list","binary_to_term","bit_size","bitstring_to_list","byte_size","check_process_code","contact_binary","crc32","crc32_combine","date","decode_packet","delete_module","disconnect_node","element","erase","exit","float","float_to_list","garbage_collect","get","get_keys","group_leader","halt","hd","integer_to_list","internal_bif","iolist_size","iolist_to_binary","is_alive","is_atom","is_binary","is_bitstring","is_boolean","is_float","is_function","is_integer","is_list","is_number","is_pid","is_port","is_process_alive","is_record","is_reference","is_tuple","length","link","list_to_atom","list_to_binary","list_to_bitstring","list_to_existing_atom","list_to_float","list_to_integer","list_to_pid","list_to_tuple","load_module","make_ref","module_loaded","monitor_node","node","node_link","node_unlink","nodes","notalive","now","open_port","pid_to_list","port_close","port_command","port_connect","port_control","pre_loaded","process_flag","process_info","processes","purge_module","put","register","registered","round","self","setelement","size","spawn","spawn_link","spawn_monitor","spawn_opt","split_binary","statistics","term_to_binary","time","throw","tl","trunc","tuple_size","tuple_to_list","unlink","unregister","whereis"],R=/[\w@Ø-ÞÀ-Öß-öø-ÿ]/,F=/[0-7]{1,3}|[bdefnrstv\\"']|\^[a-zA-Z]|x[0-9a-zA-Z]{2}|x{[0-9a-zA-Z]+}/;return{startState:function(){return{tokenStack:[],in_string:!1,in_atom:!1}},token:function(e,t){return r(e,t)},indent:function(e,t){return y(e,t)},lineComment:"%"}})}),function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror"),require("../javascript/javascript"),require("../css/css"),require("../htmlmixed/htmlmixed")):"function"==typeof define&&define.amd?define(["../../lib/codemirror","../javascript/javascript","../css/css","../htmlmixed/htmlmixed"],e):e(CodeMirror)}(function(e){"use strict";e.defineMode("jade",function(t){function r(){this.javaScriptLine=!1,this.javaScriptLineExcludesColon=!1,this.javaScriptArguments=!1,this.javaScriptArgumentsDepth=0,this.isInterpolating=!1,this.interpolationNesting=0,this.jsState=Q.startState(),this.restOfLine="",this.isIncludeFiltered=!1,this.isEach=!1,this.lastTag="",this.scriptType="",this.isAttrs=!1,this.attrsNest=[],this.inAttributeName=!0,this.attributeIsType=!1,this.attrValue="",this.indentOf=1/0,this.indentToken="",this.innerMode=null,this.innerState=null,this.innerModeForLine=!1}function n(e,t){if(e.sol()&&(t.javaScriptLine=!1,t.javaScriptLineExcludesColon=!1),t.javaScriptLine){if(t.javaScriptLineExcludesColon&&":"===e.peek())return t.javaScriptLine=!1,void(t.javaScriptLineExcludesColon=!1);var r=Q.token(e,t.jsState);return e.eol()&&(t.javaScriptLine=!1),r||!0}}function i(e,t){if(t.javaScriptArguments){if(0===t.javaScriptArgumentsDepth&&"("!==e.peek())return void(t.javaScriptArguments=!1);if("("===e.peek()?t.javaScriptArgumentsDepth++:")"===e.peek()&&t.javaScriptArgumentsDepth--,0===t.javaScriptArgumentsDepth)return void(t.javaScriptArguments=!1);var r=Q.token(e,t.jsState);return r||!0}}function o(e){return e.match(/^yield\b/)?"keyword":void 0}function a(e){return e.match(/^(?:doctype) *([^\n]+)?/)?K:void 0}function s(e,t){return e.match("#{")?(t.isInterpolating=!0,t.interpolationNesting=0,"punctuation"):void 0}function l(e,t){if(t.isInterpolating){if("}"===e.peek()){if(t.interpolationNesting--,t.interpolationNesting<0)return e.next(),t.isInterpolating=!1,"puncutation"}else"{"===e.peek()&&t.interpolationNesting++;return Q.token(e,t.jsState)||!0}}function c(e,t){return e.match(/^case\b/)?(t.javaScriptLine=!0,V):void 0}function u(e,t){return e.match(/^when\b/)?(t.javaScriptLine=!0,t.javaScriptLineExcludesColon=!0,V):void 0}function d(e){return e.match(/^default\b/)?V:void 0}function f(e,t){return e.match(/^extends?\b/)?(t.restOfLine="string",V):void 0}function m(e,t){return e.match(/^append\b/)?(t.restOfLine="variable",V):void 0}function h(e,t){return e.match(/^prepend\b/)?(t.restOfLine="variable",V):void 0}function p(e,t){return e.match(/^block\b *(?:(prepend|append)\b)?/)?(t.restOfLine="variable",V):void 0}function g(e,t){return e.match(/^include\b/)?(t.restOfLine="string",V):void 0}function v(e,t){return e.match(/^include:([a-zA-Z0-9\-]+)/,!1)&&e.match("include")?(t.isIncludeFiltered=!0,V):void 0}function b(e,t){if(t.isIncludeFiltered){var r=M(e,t);return t.isIncludeFiltered=!1,t.restOfLine="string",r}}function y(e,t){return e.match(/^mixin\b/)?(t.javaScriptLine=!0,V):void 0}function x(e,t){return e.match(/^\+([-\w]+)/)?(e.match(/^\( *[-\w]+ *=/,!1)||(t.javaScriptArguments=!0,t.javaScriptArgumentsDepth=0),"variable"):e.match(/^\+#{/,!1)?(e.next(),t.mixinCallAfter=!0,s(e,t)):void 0}function k(e,t){return t.mixinCallAfter?(t.mixinCallAfter=!1,e.match(/^\( *[-\w]+ *=/,!1)||(t.javaScriptArguments=!0,t.javaScriptArgumentsDepth=0),!0):void 0}function w(e,t){return e.match(/^(if|unless|else if|else)\b/)?(t.javaScriptLine=!0,V):void 0}function _(e,t){return e.match(/^(- *)?(each|for)\b/)?(t.isEach=!0,V):void 0}function C(e,t){if(t.isEach){if(e.match(/^ in\b/))return t.javaScriptLine=!0,t.isEach=!1,V;if(e.sol()||e.eol())t.isEach=!1;else if(e.next()){for(;!e.match(/^ in\b/,!1)&&e.next(););return"variable"}}}function S(e,t){return e.match(/^while\b/)?(t.javaScriptLine=!0,V):void 0}function T(e,t){var r;return(r=e.match(/^(\w(?:[-:\w]*\w)?)\/?/))?(t.lastTag=r[1].toLowerCase(),"script"===t.lastTag&&(t.scriptType="application/javascript"),"tag"):void 0}function M(r,n){if(r.match(/^:([\w\-]+)/)){var i;return t&&t.innerModes&&(i=t.innerModes(r.current().substring(1))),i||(i=r.current().substring(1)),"string"==typeof i&&(i=e.getMode(t,i)),F(r,n,i),"atom"}}function L(e,t){return e.match(/^(!?=|-)/)?(t.javaScriptLine=!0,"punctuation"):void 0}function E(e){return e.match(/^#([\w-]+)/)?Z:void 0}function q(e){return e.match(/^\.([\w-]+)/)?G:void 0}function j(e,t){return"("==e.peek()?(e.next(),t.isAttrs=!0,t.attrsNest=[],t.inAttributeName=!0,t.attrValue="",t.attributeIsType=!1,"punctuation"):void 0}function z(e,t){if(t.isAttrs){if(X[e.peek()]&&t.attrsNest.push(X[e.peek()]),t.attrsNest[t.attrsNest.length-1]===e.peek())t.attrsNest.pop();else if(e.eat(")"))return t.isAttrs=!1,"punctuation";if(t.inAttributeName&&e.match(/^[^=,\)!]+/))return("="===e.peek()||"!"===e.peek())&&(t.inAttributeName=!1,t.jsState=Q.startState(),"script"===t.lastTag&&"type"===e.current().trim().toLowerCase()?t.attributeIsType=!0:t.attributeIsType=!1),"attribute";var r=Q.token(e,t.jsState);if(t.attributeIsType&&"string"===r&&(t.scriptType=e.current().toString()),0===t.attrsNest.length&&("string"===r||"variable"===r||"keyword"===r))try{return Function("","var x "+t.attrValue.replace(/,\s*$/,"").replace(/^!/,"")),t.inAttributeName=!0,t.attrValue="",e.backUp(e.current().length),z(e,t)}catch(n){}return t.attrValue+=e.current(),r||!0}}function I(e,t){return e.match(/^&attributes\b/)?(t.javaScriptArguments=!0,t.javaScriptArgumentsDepth=0,"keyword"):void 0}function P(e){return e.sol()&&e.eatSpace()?"indent":void 0}function D(e,t){return e.match(/^ *\/\/(-)?([^\n]*)/)?(t.indentOf=e.indentation(),t.indentToken="comment","comment"):void 0}function A(e){return e.match(/^: */)?"colon":void 0}function $(e,t){return e.match(/^(?:\| ?| )([^\n]+)/)?"string":e.match(/^(<[^\n]*)/,!1)?(F(e,t,"htmlmixed"),t.innerModeForLine=!0,H(e,t,!0)):void 0}function O(e,t){if(e.eat(".")){var r=null;return"script"===t.lastTag&&-1!=t.scriptType.toLowerCase().indexOf("javascript")?r=t.scriptType.toLowerCase().replace(/"|'/g,""):"style"===t.lastTag&&(r="css"),F(e,t,r),"dot"}}function R(e){return e.next(),null}function F(r,n,i){i=e.mimeModes[i]||i,i=t.innerModes?t.innerModes(i)||i:i,i=e.mimeModes[i]||i,i=e.getMode(t,i),n.indentOf=r.indentation(),i&&"null"!==i.name?n.innerMode=i:n.indentToken="string"}function H(e,t,r){return e.indentation()>t.indentOf||t.innerModeForLine&&!e.sol()||r?t.innerMode?(t.innerState||(t.innerState=t.innerMode.startState?t.innerMode.startState(e.indentation()):{}),e.hideFirstChars(t.indentOf+2,function(){return t.innerMode.token(e,t.innerState)||!0})):(e.skipToEnd(),t.indentToken):void(e.sol()&&(t.indentOf=1/0,t.indentToken=null,t.innerMode=null,t.innerState=null))}function N(e,t){if(e.sol()&&(t.restOfLine=""),t.restOfLine){e.skipToEnd();var r=t.restOfLine;return t.restOfLine="",r}}function B(){return new r}function U(e){return e.copy()}function W(e,t){var r=H(e,t)||N(e,t)||l(e,t)||b(e,t)||C(e,t)||z(e,t)||n(e,t)||i(e,t)||k(e,t)||o(e,t)||a(e,t)||s(e,t)||c(e,t)||u(e,t)||d(e,t)||f(e,t)||m(e,t)||h(e,t)||p(e,t)||g(e,t)||v(e,t)||y(e,t)||x(e,t)||w(e,t)||_(e,t)||S(e,t)||T(e,t)||M(e,t)||L(e,t)||E(e,t)||q(e,t)||j(e,t)||I(e,t)||P(e,t)||$(e,t)||D(e,t)||A(e,t)||O(e,t)||R(e,t);return r===!0?null:r}var V="keyword",K="meta",Z="builtin",G="qualifier",X={"{":"}","(":")","[":"]"},Q=e.getMode(t,"javascript");return r.prototype.copy=function(){var t=new r;return t.javaScriptLine=this.javaScriptLine,t.javaScriptLineExcludesColon=this.javaScriptLineExcludesColon,t.javaScriptArguments=this.javaScriptArguments,t.javaScriptArgumentsDepth=this.javaScriptArgumentsDepth,t.isInterpolating=this.isInterpolating,t.interpolationNesting=this.intpolationNesting,t.jsState=e.copyState(Q,this.jsState),t.innerMode=this.innerMode,this.innerMode&&this.innerState&&(t.innerState=e.copyState(this.innerMode,this.innerState)),t.restOfLine=this.restOfLine,t.isIncludeFiltered=this.isIncludeFiltered,t.isEach=this.isEach,t.lastTag=this.lastTag,t.scriptType=this.scriptType,t.isAttrs=this.isAttrs,t.attrsNest=this.attrsNest.slice(),t.inAttributeName=this.inAttributeName,t.attributeIsType=this.attributeIsType,t.attrValue=this.attrValue,t.indentOf=this.indentOf,t.indentToken=this.indentToken,t.innerModeForLine=this.innerModeForLine,t},{startState:B,copyState:U,token:W}}),e.defineMIME("text/x-jade","jade")}); \ No newline at end of file diff --git a/static/js/mdeditor/lib/codemirror/package.json b/static/js/mdeditor/lib/codemirror/package.json new file mode 100644 index 00000000..b4a9b53f --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/package.json @@ -0,0 +1,21 @@ +{ + "name": "codemirror", + "version":"5.0.0", + "main": "lib/codemirror.js", + "description": "In-browser code editing made bearable", + "licenses": [{"type": "MIT", + "url": "http://codemirror.net/LICENSE"}], + "directories": {"lib": "./lib"}, + "scripts": {"test": "node ./test/run.js"}, + "devDependencies": {"node-static": "0.6.0", + "phantomjs": "1.9.2-5", + "blint": ">=0.1.1"}, + "bugs": "http://github.com/codemirror/CodeMirror/issues", + "keywords": ["JavaScript", "CodeMirror", "Editor"], + "homepage": "http://codemirror.net", + "maintainers":[{"name": "Marijn Haverbeke", + "email": "marijnh@gmail.com", + "web": "http://marijnhaverbeke.nl"}], + "repository": {"type": "git", + "url": "https://github.com/codemirror/CodeMirror.git"} +} diff --git a/static/js/mdeditor/lib/codemirror/theme/3024-day.css b/static/js/mdeditor/lib/codemirror/theme/3024-day.css new file mode 100644 index 00000000..35928162 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/theme/3024-day.css @@ -0,0 +1,40 @@ +/* + + Name: 3024 day + Author: Jan T. Sott (http://github.com/idleberg) + + CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror) + Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) + +*/ + +.cm-s-3024-day.CodeMirror {background: #f7f7f7; color: #3a3432;} +.cm-s-3024-day div.CodeMirror-selected {background: #d6d5d4 !important;} +.cm-s-3024-day.CodeMirror ::selection { background: #d6d5d4; } +.cm-s-3024-day.CodeMirror ::-moz-selection { background: #d9d9d9; } + +.cm-s-3024-day .CodeMirror-gutters {background: #f7f7f7; border-right: 0px;} +.cm-s-3024-day .CodeMirror-guttermarker { color: #db2d20; } +.cm-s-3024-day .CodeMirror-guttermarker-subtle { color: #807d7c; } +.cm-s-3024-day .CodeMirror-linenumber {color: #807d7c;} + +.cm-s-3024-day .CodeMirror-cursor {border-left: 1px solid #5c5855 !important;} + +.cm-s-3024-day span.cm-comment {color: #cdab53;} +.cm-s-3024-day span.cm-atom {color: #a16a94;} +.cm-s-3024-day span.cm-number {color: #a16a94;} + +.cm-s-3024-day span.cm-property, .cm-s-3024-day span.cm-attribute {color: #01a252;} +.cm-s-3024-day span.cm-keyword {color: #db2d20;} +.cm-s-3024-day span.cm-string {color: #fded02;} + +.cm-s-3024-day span.cm-variable {color: #01a252;} +.cm-s-3024-day span.cm-variable-2 {color: #01a0e4;} +.cm-s-3024-day span.cm-def {color: #e8bbd0;} +.cm-s-3024-day span.cm-bracket {color: #3a3432;} +.cm-s-3024-day span.cm-tag {color: #db2d20;} +.cm-s-3024-day span.cm-link {color: #a16a94;} +.cm-s-3024-day span.cm-error {background: #db2d20; color: #5c5855;} + +.cm-s-3024-day .CodeMirror-activeline-background {background: #e8f2ff !important;} +.cm-s-3024-day .CodeMirror-matchingbracket { text-decoration: underline; color: #a16a94 !important;} diff --git a/static/js/mdeditor/lib/codemirror/theme/3024-night.css b/static/js/mdeditor/lib/codemirror/theme/3024-night.css new file mode 100644 index 00000000..ccab9d50 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/theme/3024-night.css @@ -0,0 +1,39 @@ +/* + + Name: 3024 night + Author: Jan T. Sott (http://github.com/idleberg) + + CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror) + Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) + +*/ + +.cm-s-3024-night.CodeMirror {background: #090300; color: #d6d5d4;} +.cm-s-3024-night div.CodeMirror-selected {background: #3a3432 !important;} +.cm-s-3024-night.CodeMirror ::selection { background: rgba(58, 52, 50, .99); } +.cm-s-3024-night.CodeMirror ::-moz-selection { background: rgba(58, 52, 50, .99); } +.cm-s-3024-night .CodeMirror-gutters {background: #090300; border-right: 0px;} +.cm-s-3024-night .CodeMirror-guttermarker { color: #db2d20; } +.cm-s-3024-night .CodeMirror-guttermarker-subtle { color: #5c5855; } +.cm-s-3024-night .CodeMirror-linenumber {color: #5c5855;} + +.cm-s-3024-night .CodeMirror-cursor {border-left: 1px solid #807d7c !important;} + +.cm-s-3024-night span.cm-comment {color: #cdab53;} +.cm-s-3024-night span.cm-atom {color: #a16a94;} +.cm-s-3024-night span.cm-number {color: #a16a94;} + +.cm-s-3024-night span.cm-property, .cm-s-3024-night span.cm-attribute {color: #01a252;} +.cm-s-3024-night span.cm-keyword {color: #db2d20;} +.cm-s-3024-night span.cm-string {color: #fded02;} + +.cm-s-3024-night span.cm-variable {color: #01a252;} +.cm-s-3024-night span.cm-variable-2 {color: #01a0e4;} +.cm-s-3024-night span.cm-def {color: #e8bbd0;} +.cm-s-3024-night span.cm-bracket {color: #d6d5d4;} +.cm-s-3024-night span.cm-tag {color: #db2d20;} +.cm-s-3024-night span.cm-link {color: #a16a94;} +.cm-s-3024-night span.cm-error {background: #db2d20; color: #807d7c;} + +.cm-s-3024-night .CodeMirror-activeline-background {background: #2F2F2F !important;} +.cm-s-3024-night .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;} diff --git a/static/js/mdeditor/lib/codemirror/theme/ambiance-mobile.css b/static/js/mdeditor/lib/codemirror/theme/ambiance-mobile.css new file mode 100644 index 00000000..88d332e1 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/theme/ambiance-mobile.css @@ -0,0 +1,5 @@ +.cm-s-ambiance.CodeMirror { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} diff --git a/static/js/mdeditor/lib/codemirror/theme/ambiance.css b/static/js/mdeditor/lib/codemirror/theme/ambiance.css new file mode 100644 index 00000000..afcf15a3 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/theme/ambiance.css @@ -0,0 +1,75 @@ +/* ambiance theme for codemirror */ + +/* Color scheme */ + +.cm-s-ambiance .cm-keyword { color: #cda869; } +.cm-s-ambiance .cm-atom { color: #CF7EA9; } +.cm-s-ambiance .cm-number { color: #78CF8A; } +.cm-s-ambiance .cm-def { color: #aac6e3; } +.cm-s-ambiance .cm-variable { color: #ffb795; } +.cm-s-ambiance .cm-variable-2 { color: #eed1b3; } +.cm-s-ambiance .cm-variable-3 { color: #faded3; } +.cm-s-ambiance .cm-property { color: #eed1b3; } +.cm-s-ambiance .cm-operator {color: #fa8d6a;} +.cm-s-ambiance .cm-comment { color: #555; font-style:italic; } +.cm-s-ambiance .cm-string { color: #8f9d6a; } +.cm-s-ambiance .cm-string-2 { color: #9d937c; } +.cm-s-ambiance .cm-meta { color: #D2A8A1; } +.cm-s-ambiance .cm-qualifier { color: yellow; } +.cm-s-ambiance .cm-builtin { color: #9999cc; } +.cm-s-ambiance .cm-bracket { color: #24C2C7; } +.cm-s-ambiance .cm-tag { color: #fee4ff } +.cm-s-ambiance .cm-attribute { color: #9B859D; } +.cm-s-ambiance .cm-header {color: blue;} +.cm-s-ambiance .cm-quote { color: #24C2C7; } +.cm-s-ambiance .cm-hr { color: pink; } +.cm-s-ambiance .cm-link { color: #F4C20B; } +.cm-s-ambiance .cm-special { color: #FF9D00; } +.cm-s-ambiance .cm-error { color: #AF2018; } + +.cm-s-ambiance .CodeMirror-matchingbracket { color: #0f0; } +.cm-s-ambiance .CodeMirror-nonmatchingbracket { color: #f22; } + +.cm-s-ambiance .CodeMirror-selected { background: rgba(255, 255, 255, 0.15); } +.cm-s-ambiance.CodeMirror-focused .CodeMirror-selected { background: rgba(255, 255, 255, 0.10); } +.cm-s-ambiance.CodeMirror ::selection { background: rgba(255, 255, 255, 0.10); } +.cm-s-ambiance.CodeMirror ::-moz-selection { background: rgba(255, 255, 255, 0.10); } + +/* Editor styling */ + +.cm-s-ambiance.CodeMirror { + line-height: 1.40em; + color: #E6E1DC; + background-color: #202020; + -webkit-box-shadow: inset 0 0 10px black; + -moz-box-shadow: inset 0 0 10px black; + box-shadow: inset 0 0 10px black; +} + +.cm-s-ambiance .CodeMirror-gutters { + background: #3D3D3D; + border-right: 1px solid #4D4D4D; + box-shadow: 0 10px 20px black; +} + +.cm-s-ambiance .CodeMirror-linenumber { + text-shadow: 0px 1px 1px #4d4d4d; + color: #111; + padding: 0 5px; +} + +.cm-s-ambiance .CodeMirror-guttermarker { color: #aaa; } +.cm-s-ambiance .CodeMirror-guttermarker-subtle { color: #111; } + +.cm-s-ambiance .CodeMirror-lines .CodeMirror-cursor { + border-left: 1px solid #7991E8; +} + +.cm-s-ambiance .CodeMirror-activeline-background { + background: none repeat scroll 0% 0% rgba(255, 255, 255, 0.031); +} + +.cm-s-ambiance.CodeMirror, +.cm-s-ambiance .CodeMirror-gutters { + background-image: url("data:image/png;base64,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"); +} diff --git a/static/js/mdeditor/lib/codemirror/theme/base16-dark.css b/static/js/mdeditor/lib/codemirror/theme/base16-dark.css new file mode 100644 index 00000000..b009d2b9 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/theme/base16-dark.css @@ -0,0 +1,38 @@ +/* + + Name: Base16 Default Dark + Author: Chris Kempson (http://chriskempson.com) + + CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-chrome-devtools) + Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) + +*/ + +.cm-s-base16-dark.CodeMirror {background: #151515; color: #e0e0e0;} +.cm-s-base16-dark div.CodeMirror-selected {background: #303030 !important;} +.cm-s-base16-dark.CodeMirror ::selection { background: rgba(48, 48, 48, .99); } +.cm-s-base16-dark.CodeMirror ::-moz-selection { background: rgba(48, 48, 48, .99); } +.cm-s-base16-dark .CodeMirror-gutters {background: #151515; border-right: 0px;} +.cm-s-base16-dark .CodeMirror-guttermarker { color: #ac4142; } +.cm-s-base16-dark .CodeMirror-guttermarker-subtle { color: #505050; } +.cm-s-base16-dark .CodeMirror-linenumber {color: #505050;} +.cm-s-base16-dark .CodeMirror-cursor {border-left: 1px solid #b0b0b0 !important;} + +.cm-s-base16-dark span.cm-comment {color: #8f5536;} +.cm-s-base16-dark span.cm-atom {color: #aa759f;} +.cm-s-base16-dark span.cm-number {color: #aa759f;} + +.cm-s-base16-dark span.cm-property, .cm-s-base16-dark span.cm-attribute {color: #90a959;} +.cm-s-base16-dark span.cm-keyword {color: #ac4142;} +.cm-s-base16-dark span.cm-string {color: #f4bf75;} + +.cm-s-base16-dark span.cm-variable {color: #90a959;} +.cm-s-base16-dark span.cm-variable-2 {color: #6a9fb5;} +.cm-s-base16-dark span.cm-def {color: #d28445;} +.cm-s-base16-dark span.cm-bracket {color: #e0e0e0;} +.cm-s-base16-dark span.cm-tag {color: #ac4142;} +.cm-s-base16-dark span.cm-link {color: #aa759f;} +.cm-s-base16-dark span.cm-error {background: #ac4142; color: #b0b0b0;} + +.cm-s-base16-dark .CodeMirror-activeline-background {background: #202020 !important;} +.cm-s-base16-dark .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;} diff --git a/static/js/mdeditor/lib/codemirror/theme/base16-light.css b/static/js/mdeditor/lib/codemirror/theme/base16-light.css new file mode 100644 index 00000000..15df6d38 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/theme/base16-light.css @@ -0,0 +1,38 @@ +/* + + Name: Base16 Default Light + Author: Chris Kempson (http://chriskempson.com) + + CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-chrome-devtools) + Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) + +*/ + +.cm-s-base16-light.CodeMirror {background: #f5f5f5; color: #202020;} +.cm-s-base16-light div.CodeMirror-selected {background: #e0e0e0 !important;} +.cm-s-base16-light.CodeMirror ::selection { background: #e0e0e0; } +.cm-s-base16-light.CodeMirror ::-moz-selection { background: #e0e0e0; } +.cm-s-base16-light .CodeMirror-gutters {background: #f5f5f5; border-right: 0px;} +.cm-s-base16-light .CodeMirror-guttermarker { color: #ac4142; } +.cm-s-base16-light .CodeMirror-guttermarker-subtle { color: #b0b0b0; } +.cm-s-base16-light .CodeMirror-linenumber {color: #b0b0b0;} +.cm-s-base16-light .CodeMirror-cursor {border-left: 1px solid #505050 !important;} + +.cm-s-base16-light span.cm-comment {color: #8f5536;} +.cm-s-base16-light span.cm-atom {color: #aa759f;} +.cm-s-base16-light span.cm-number {color: #aa759f;} + +.cm-s-base16-light span.cm-property, .cm-s-base16-light span.cm-attribute {color: #90a959;} +.cm-s-base16-light span.cm-keyword {color: #ac4142;} +.cm-s-base16-light span.cm-string {color: #f4bf75;} + +.cm-s-base16-light span.cm-variable {color: #90a959;} +.cm-s-base16-light span.cm-variable-2 {color: #6a9fb5;} +.cm-s-base16-light span.cm-def {color: #d28445;} +.cm-s-base16-light span.cm-bracket {color: #202020;} +.cm-s-base16-light span.cm-tag {color: #ac4142;} +.cm-s-base16-light span.cm-link {color: #aa759f;} +.cm-s-base16-light span.cm-error {background: #ac4142; color: #505050;} + +.cm-s-base16-light .CodeMirror-activeline-background {background: #DDDCDC !important;} +.cm-s-base16-light .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;} diff --git a/static/js/mdeditor/lib/codemirror/theme/blackboard.css b/static/js/mdeditor/lib/codemirror/theme/blackboard.css new file mode 100644 index 00000000..02289b63 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/theme/blackboard.css @@ -0,0 +1,32 @@ +/* Port of TextMate's Blackboard theme */ + +.cm-s-blackboard.CodeMirror { background: #0C1021; color: #F8F8F8; } +.cm-s-blackboard .CodeMirror-selected { background: #253B76 !important; } +.cm-s-blackboard.CodeMirror ::selection { background: rgba(37, 59, 118, .99); } +.cm-s-blackboard.CodeMirror ::-moz-selection { background: rgba(37, 59, 118, .99); } +.cm-s-blackboard .CodeMirror-gutters { background: #0C1021; border-right: 0; } +.cm-s-blackboard .CodeMirror-guttermarker { color: #FBDE2D; } +.cm-s-blackboard .CodeMirror-guttermarker-subtle { color: #888; } +.cm-s-blackboard .CodeMirror-linenumber { color: #888; } +.cm-s-blackboard .CodeMirror-cursor { border-left: 1px solid #A7A7A7 !important; } + +.cm-s-blackboard .cm-keyword { color: #FBDE2D; } +.cm-s-blackboard .cm-atom { color: #D8FA3C; } +.cm-s-blackboard .cm-number { color: #D8FA3C; } +.cm-s-blackboard .cm-def { color: #8DA6CE; } +.cm-s-blackboard .cm-variable { color: #FF6400; } +.cm-s-blackboard .cm-operator { color: #FBDE2D;} +.cm-s-blackboard .cm-comment { color: #AEAEAE; } +.cm-s-blackboard .cm-string { color: #61CE3C; } +.cm-s-blackboard .cm-string-2 { color: #61CE3C; } +.cm-s-blackboard .cm-meta { color: #D8FA3C; } +.cm-s-blackboard .cm-builtin { color: #8DA6CE; } +.cm-s-blackboard .cm-tag { color: #8DA6CE; } +.cm-s-blackboard .cm-attribute { color: #8DA6CE; } +.cm-s-blackboard .cm-header { color: #FF6400; } +.cm-s-blackboard .cm-hr { color: #AEAEAE; } +.cm-s-blackboard .cm-link { color: #8DA6CE; } +.cm-s-blackboard .cm-error { background: #9D1E15; color: #F8F8F8; } + +.cm-s-blackboard .CodeMirror-activeline-background {background: #3C3636 !important;} +.cm-s-blackboard .CodeMirror-matchingbracket {outline:1px solid grey;color:white !important} \ No newline at end of file diff --git a/static/js/mdeditor/lib/codemirror/theme/cobalt.css b/static/js/mdeditor/lib/codemirror/theme/cobalt.css new file mode 100644 index 00000000..39155894 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/theme/cobalt.css @@ -0,0 +1,25 @@ +.cm-s-cobalt.CodeMirror { background: #002240; color: white; } +.cm-s-cobalt div.CodeMirror-selected { background: #b36539 !important; } +.cm-s-cobalt.CodeMirror ::selection { background: rgba(179, 101, 57, .99); } +.cm-s-cobalt.CodeMirror ::-moz-selection { background: rgba(179, 101, 57, .99); } +.cm-s-cobalt .CodeMirror-gutters { background: #002240; border-right: 1px solid #aaa; } +.cm-s-cobalt .CodeMirror-guttermarker { color: #ffee80; } +.cm-s-cobalt .CodeMirror-guttermarker-subtle { color: #d0d0d0; } +.cm-s-cobalt .CodeMirror-linenumber { color: #d0d0d0; } +.cm-s-cobalt .CodeMirror-cursor { border-left: 1px solid white !important; } + +.cm-s-cobalt span.cm-comment { color: #08f; } +.cm-s-cobalt span.cm-atom { color: #845dc4; } +.cm-s-cobalt span.cm-number, .cm-s-cobalt span.cm-attribute { color: #ff80e1; } +.cm-s-cobalt span.cm-keyword { color: #ffee80; } +.cm-s-cobalt span.cm-string { color: #3ad900; } +.cm-s-cobalt span.cm-meta { color: #ff9d00; } +.cm-s-cobalt span.cm-variable-2, .cm-s-cobalt span.cm-tag { color: #9effff; } +.cm-s-cobalt span.cm-variable-3, .cm-s-cobalt span.cm-def { color: white; } +.cm-s-cobalt span.cm-bracket { color: #d8d8d8; } +.cm-s-cobalt span.cm-builtin, .cm-s-cobalt span.cm-special { color: #ff9e59; } +.cm-s-cobalt span.cm-link { color: #845dc4; } +.cm-s-cobalt span.cm-error { color: #9d1e15; } + +.cm-s-cobalt .CodeMirror-activeline-background {background: #002D57 !important;} +.cm-s-cobalt .CodeMirror-matchingbracket {outline:1px solid grey;color:white !important} diff --git a/static/js/mdeditor/lib/codemirror/theme/colorforth.css b/static/js/mdeditor/lib/codemirror/theme/colorforth.css new file mode 100644 index 00000000..73fbf808 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/theme/colorforth.css @@ -0,0 +1,33 @@ +.cm-s-colorforth.CodeMirror { background: #000000; color: #f8f8f8; } +.cm-s-colorforth .CodeMirror-gutters { background: #0a001f; border-right: 1px solid #aaa; } +.cm-s-colorforth .CodeMirror-guttermarker { color: #FFBD40; } +.cm-s-colorforth .CodeMirror-guttermarker-subtle { color: #78846f; } +.cm-s-colorforth .CodeMirror-linenumber { color: #bababa; } +.cm-s-colorforth .CodeMirror-cursor { border-left: 1px solid white !important; } + +.cm-s-colorforth span.cm-comment { color: #ededed; } +.cm-s-colorforth span.cm-def { color: #ff1c1c; font-weight:bold; } +.cm-s-colorforth span.cm-keyword { color: #ffd900; } +.cm-s-colorforth span.cm-builtin { color: #00d95a; } +.cm-s-colorforth span.cm-variable { color: #73ff00; } +.cm-s-colorforth span.cm-string { color: #007bff; } +.cm-s-colorforth span.cm-number { color: #00c4ff; } +.cm-s-colorforth span.cm-atom { color: #606060; } + +.cm-s-colorforth span.cm-variable-2 { color: #EEE; } +.cm-s-colorforth span.cm-variable-3 { color: #DDD; } +.cm-s-colorforth span.cm-property {} +.cm-s-colorforth span.cm-operator {} + +.cm-s-colorforth span.cm-meta { color: yellow; } +.cm-s-colorforth span.cm-qualifier { color: #FFF700; } +.cm-s-colorforth span.cm-bracket { color: #cc7; } +.cm-s-colorforth span.cm-tag { color: #FFBD40; } +.cm-s-colorforth span.cm-attribute { color: #FFF700; } +.cm-s-colorforth span.cm-error { color: #f00; } + +.cm-s-colorforth .CodeMirror-selected { background: #333d53 !important; } + +.cm-s-colorforth span.cm-compilation { background: rgba(255, 255, 255, 0.12); } + +.cm-s-colorforth .CodeMirror-activeline-background {background: #253540 !important;} diff --git a/static/js/mdeditor/lib/codemirror/theme/eclipse.css b/static/js/mdeditor/lib/codemirror/theme/eclipse.css new file mode 100644 index 00000000..317218e3 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/theme/eclipse.css @@ -0,0 +1,23 @@ +.cm-s-eclipse span.cm-meta {color: #FF1717;} +.cm-s-eclipse span.cm-keyword { line-height: 1em; font-weight: bold; color: #7F0055; } +.cm-s-eclipse span.cm-atom {color: #219;} +.cm-s-eclipse span.cm-number {color: #164;} +.cm-s-eclipse span.cm-def {color: #00f;} +.cm-s-eclipse span.cm-variable {color: black;} +.cm-s-eclipse span.cm-variable-2 {color: #0000C0;} +.cm-s-eclipse span.cm-variable-3 {color: #0000C0;} +.cm-s-eclipse span.cm-property {color: black;} +.cm-s-eclipse span.cm-operator {color: black;} +.cm-s-eclipse span.cm-comment {color: #3F7F5F;} +.cm-s-eclipse span.cm-string {color: #2A00FF;} +.cm-s-eclipse span.cm-string-2 {color: #f50;} +.cm-s-eclipse span.cm-qualifier {color: #555;} +.cm-s-eclipse span.cm-builtin {color: #30a;} +.cm-s-eclipse span.cm-bracket {color: #cc7;} +.cm-s-eclipse span.cm-tag {color: #170;} +.cm-s-eclipse span.cm-attribute {color: #00c;} +.cm-s-eclipse span.cm-link {color: #219;} +.cm-s-eclipse span.cm-error {color: #f00;} + +.cm-s-eclipse .CodeMirror-activeline-background {background: #e8f2ff !important;} +.cm-s-eclipse .CodeMirror-matchingbracket {outline:1px solid grey; color:black !important;} diff --git a/static/js/mdeditor/lib/codemirror/theme/elegant.css b/static/js/mdeditor/lib/codemirror/theme/elegant.css new file mode 100644 index 00000000..dd7df7b7 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/theme/elegant.css @@ -0,0 +1,13 @@ +.cm-s-elegant span.cm-number, .cm-s-elegant span.cm-string, .cm-s-elegant span.cm-atom {color: #762;} +.cm-s-elegant span.cm-comment {color: #262; font-style: italic; line-height: 1em;} +.cm-s-elegant span.cm-meta {color: #555; font-style: italic; line-height: 1em;} +.cm-s-elegant span.cm-variable {color: black;} +.cm-s-elegant span.cm-variable-2 {color: #b11;} +.cm-s-elegant span.cm-qualifier {color: #555;} +.cm-s-elegant span.cm-keyword {color: #730;} +.cm-s-elegant span.cm-builtin {color: #30a;} +.cm-s-elegant span.cm-link {color: #762;} +.cm-s-elegant span.cm-error {background-color: #fdd;} + +.cm-s-elegant .CodeMirror-activeline-background {background: #e8f2ff !important;} +.cm-s-elegant .CodeMirror-matchingbracket {outline:1px solid grey; color:black !important;} diff --git a/static/js/mdeditor/lib/codemirror/theme/erlang-dark.css b/static/js/mdeditor/lib/codemirror/theme/erlang-dark.css new file mode 100644 index 00000000..25c7e0a2 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/theme/erlang-dark.css @@ -0,0 +1,34 @@ +.cm-s-erlang-dark.CodeMirror { background: #002240; color: white; } +.cm-s-erlang-dark div.CodeMirror-selected { background: #b36539 !important; } +.cm-s-erlang-dark.CodeMirror ::selection { background: rgba(179, 101, 57, .99); } +.cm-s-erlang-dark.CodeMirror ::-moz-selection { background: rgba(179, 101, 57, .99); } +.cm-s-erlang-dark .CodeMirror-gutters { background: #002240; border-right: 1px solid #aaa; } +.cm-s-erlang-dark .CodeMirror-guttermarker { color: white; } +.cm-s-erlang-dark .CodeMirror-guttermarker-subtle { color: #d0d0d0; } +.cm-s-erlang-dark .CodeMirror-linenumber { color: #d0d0d0; } +.cm-s-erlang-dark .CodeMirror-cursor { border-left: 1px solid white !important; } + +.cm-s-erlang-dark span.cm-atom { color: #f133f1; } +.cm-s-erlang-dark span.cm-attribute { color: #ff80e1; } +.cm-s-erlang-dark span.cm-bracket { color: #ff9d00; } +.cm-s-erlang-dark span.cm-builtin { color: #eaa; } +.cm-s-erlang-dark span.cm-comment { color: #77f; } +.cm-s-erlang-dark span.cm-def { color: #e7a; } +.cm-s-erlang-dark span.cm-keyword { color: #ffee80; } +.cm-s-erlang-dark span.cm-meta { color: #50fefe; } +.cm-s-erlang-dark span.cm-number { color: #ffd0d0; } +.cm-s-erlang-dark span.cm-operator { color: #d55; } +.cm-s-erlang-dark span.cm-property { color: #ccc; } +.cm-s-erlang-dark span.cm-qualifier { color: #ccc; } +.cm-s-erlang-dark span.cm-quote { color: #ccc; } +.cm-s-erlang-dark span.cm-special { color: #ffbbbb; } +.cm-s-erlang-dark span.cm-string { color: #3ad900; } +.cm-s-erlang-dark span.cm-string-2 { color: #ccc; } +.cm-s-erlang-dark span.cm-tag { color: #9effff; } +.cm-s-erlang-dark span.cm-variable { color: #50fe50; } +.cm-s-erlang-dark span.cm-variable-2 { color: #e0e; } +.cm-s-erlang-dark span.cm-variable-3 { color: #ccc; } +.cm-s-erlang-dark span.cm-error { color: #9d1e15; } + +.cm-s-erlang-dark .CodeMirror-activeline-background {background: #013461 !important;} +.cm-s-erlang-dark .CodeMirror-matchingbracket {outline:1px solid grey; color:white !important;} diff --git a/static/js/mdeditor/lib/codemirror/theme/lesser-dark.css b/static/js/mdeditor/lib/codemirror/theme/lesser-dark.css new file mode 100644 index 00000000..5af8b7f6 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/theme/lesser-dark.css @@ -0,0 +1,47 @@ +/* +http://lesscss.org/ dark theme +Ported to CodeMirror by Peter Kroon +*/ +.cm-s-lesser-dark { + line-height: 1.3em; +} +.cm-s-lesser-dark.CodeMirror { background: #262626; color: #EBEFE7; text-shadow: 0 -1px 1px #262626; } +.cm-s-lesser-dark div.CodeMirror-selected {background: #45443B !important;} /* 33322B*/ +.cm-s-lesser-dark.CodeMirror ::selection { background: rgba(69, 68, 59, .99); } +.cm-s-lesser-dark.CodeMirror ::-moz-selection { background: rgba(69, 68, 59, .99); } +.cm-s-lesser-dark .CodeMirror-cursor { border-left: 1px solid white !important; } +.cm-s-lesser-dark pre { padding: 0 8px; }/*editable code holder*/ + +.cm-s-lesser-dark.CodeMirror span.CodeMirror-matchingbracket { color: #7EFC7E; }/*65FC65*/ + +.cm-s-lesser-dark .CodeMirror-gutters { background: #262626; border-right:1px solid #aaa; } +.cm-s-lesser-dark .CodeMirror-guttermarker { color: #599eff; } +.cm-s-lesser-dark .CodeMirror-guttermarker-subtle { color: #777; } +.cm-s-lesser-dark .CodeMirror-linenumber { color: #777; } + +.cm-s-lesser-dark span.cm-keyword { color: #599eff; } +.cm-s-lesser-dark span.cm-atom { color: #C2B470; } +.cm-s-lesser-dark span.cm-number { color: #B35E4D; } +.cm-s-lesser-dark span.cm-def {color: white;} +.cm-s-lesser-dark span.cm-variable { color:#D9BF8C; } +.cm-s-lesser-dark span.cm-variable-2 { color: #669199; } +.cm-s-lesser-dark span.cm-variable-3 { color: white; } +.cm-s-lesser-dark span.cm-property {color: #92A75C;} +.cm-s-lesser-dark span.cm-operator {color: #92A75C;} +.cm-s-lesser-dark span.cm-comment { color: #666; } +.cm-s-lesser-dark span.cm-string { color: #BCD279; } +.cm-s-lesser-dark span.cm-string-2 {color: #f50;} +.cm-s-lesser-dark span.cm-meta { color: #738C73; } +.cm-s-lesser-dark span.cm-qualifier {color: #555;} +.cm-s-lesser-dark span.cm-builtin { color: #ff9e59; } +.cm-s-lesser-dark span.cm-bracket { color: #EBEFE7; } +.cm-s-lesser-dark span.cm-tag { color: #669199; } +.cm-s-lesser-dark span.cm-attribute {color: #00c;} +.cm-s-lesser-dark span.cm-header {color: #a0a;} +.cm-s-lesser-dark span.cm-quote {color: #090;} +.cm-s-lesser-dark span.cm-hr {color: #999;} +.cm-s-lesser-dark span.cm-link {color: #00c;} +.cm-s-lesser-dark span.cm-error { color: #9d1e15; } + +.cm-s-lesser-dark .CodeMirror-activeline-background {background: #3C3A3A !important;} +.cm-s-lesser-dark .CodeMirror-matchingbracket {outline:1px solid grey; color:white !important;} diff --git a/static/js/mdeditor/lib/codemirror/theme/mbo.css b/static/js/mdeditor/lib/codemirror/theme/mbo.css new file mode 100644 index 00000000..e3987952 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/theme/mbo.css @@ -0,0 +1,37 @@ +/****************************************************************/ +/* Based on mbonaci's Brackets mbo theme */ +/* https://github.com/mbonaci/global/blob/master/Mbo.tmTheme */ +/* Create your own: http://tmtheme-editor.herokuapp.com */ +/****************************************************************/ + +.cm-s-mbo.CodeMirror {background: #2c2c2c; color: #ffffec;} +.cm-s-mbo div.CodeMirror-selected {background: #716C62 !important;} +.cm-s-mbo.CodeMirror ::selection { background: rgba(113, 108, 98, .99); } +.cm-s-mbo.CodeMirror ::-moz-selection { background: rgba(113, 108, 98, .99); } +.cm-s-mbo .CodeMirror-gutters {background: #4e4e4e; border-right: 0px;} +.cm-s-mbo .CodeMirror-guttermarker { color: white; } +.cm-s-mbo .CodeMirror-guttermarker-subtle { color: grey; } +.cm-s-mbo .CodeMirror-linenumber {color: #dadada;} +.cm-s-mbo .CodeMirror-cursor {border-left: 1px solid #ffffec !important;} + +.cm-s-mbo span.cm-comment {color: #95958a;} +.cm-s-mbo span.cm-atom {color: #00a8c6;} +.cm-s-mbo span.cm-number {color: #00a8c6;} + +.cm-s-mbo span.cm-property, .cm-s-mbo span.cm-attribute {color: #9ddfe9;} +.cm-s-mbo span.cm-keyword {color: #ffb928;} +.cm-s-mbo span.cm-string {color: #ffcf6c;} +.cm-s-mbo span.cm-string.cm-property {color: #ffffec;} + +.cm-s-mbo span.cm-variable {color: #ffffec;} +.cm-s-mbo span.cm-variable-2 {color: #00a8c6;} +.cm-s-mbo span.cm-def {color: #ffffec;} +.cm-s-mbo span.cm-bracket {color: #fffffc; font-weight: bold;} +.cm-s-mbo span.cm-tag {color: #9ddfe9;} +.cm-s-mbo span.cm-link {color: #f54b07;} +.cm-s-mbo span.cm-error {border-bottom: #636363; color: #ffffec;} +.cm-s-mbo span.cm-qualifier {color: #ffffec;} + +.cm-s-mbo .CodeMirror-activeline-background {background: #494b41 !important;} +.cm-s-mbo .CodeMirror-matchingbracket {color: #222 !important;} +.cm-s-mbo .CodeMirror-matchingtag {background: rgba(255, 255, 255, .37);} diff --git a/static/js/mdeditor/lib/codemirror/theme/mdn-like.css b/static/js/mdeditor/lib/codemirror/theme/mdn-like.css new file mode 100644 index 00000000..93293c01 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/theme/mdn-like.css @@ -0,0 +1,46 @@ +/* + MDN-LIKE Theme - Mozilla + Ported to CodeMirror by Peter Kroon + Report bugs/issues here: https://github.com/codemirror/CodeMirror/issues + GitHub: @peterkroon + + The mdn-like theme is inspired on the displayed code examples at: https://developer.mozilla.org/en-US/docs/Web/CSS/animation + +*/ +.cm-s-mdn-like.CodeMirror { color: #999; background-color: #fff; } +.cm-s-mdn-like .CodeMirror-selected { background: #cfc !important; } +.cm-s-mdn-like.CodeMirror ::selection { background: #cfc; } +.cm-s-mdn-like.CodeMirror ::-moz-selection { background: #cfc; } + +.cm-s-mdn-like .CodeMirror-gutters { background: #f8f8f8; border-left: 6px solid rgba(0,83,159,0.65); color: #333; } +.cm-s-mdn-like .CodeMirror-linenumber { color: #aaa; margin-left: 3px; } +div.cm-s-mdn-like .CodeMirror-cursor { border-left: 2px solid #222; } + +.cm-s-mdn-like .cm-keyword { color: #6262FF; } +.cm-s-mdn-like .cm-atom { color: #F90; } +.cm-s-mdn-like .cm-number { color: #ca7841; } +.cm-s-mdn-like .cm-def { color: #8DA6CE; } +.cm-s-mdn-like span.cm-variable-2, .cm-s-mdn-like span.cm-tag { color: #690; } +.cm-s-mdn-like span.cm-variable-3, .cm-s-mdn-like span.cm-def { color: #07a; } + +.cm-s-mdn-like .cm-variable { color: #07a; } +.cm-s-mdn-like .cm-property { color: #905; } +.cm-s-mdn-like .cm-qualifier { color: #690; } + +.cm-s-mdn-like .cm-operator { color: #cda869; } +.cm-s-mdn-like .cm-comment { color:#777; font-weight:normal; } +.cm-s-mdn-like .cm-string { color:#07a; font-style:italic; } +.cm-s-mdn-like .cm-string-2 { color:#bd6b18; } /*?*/ +.cm-s-mdn-like .cm-meta { color: #000; } /*?*/ +.cm-s-mdn-like .cm-builtin { color: #9B7536; } /*?*/ +.cm-s-mdn-like .cm-tag { color: #997643; } +.cm-s-mdn-like .cm-attribute { color: #d6bb6d; } /*?*/ +.cm-s-mdn-like .cm-header { color: #FF6400; } +.cm-s-mdn-like .cm-hr { color: #AEAEAE; } +.cm-s-mdn-like .cm-link { color:#ad9361; font-style:italic; text-decoration:none; } +.cm-s-mdn-like .cm-error { border-bottom: 1px solid red; } + +div.cm-s-mdn-like .CodeMirror-activeline-background {background: #efefff;} +div.cm-s-mdn-like span.CodeMirror-matchingbracket {outline:1px solid grey; color: inherit;} + +.cm-s-mdn-like.CodeMirror { background-image: url(data:image/png;base64,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); } diff --git a/static/js/mdeditor/lib/codemirror/theme/midnight.css b/static/js/mdeditor/lib/codemirror/theme/midnight.css new file mode 100644 index 00000000..296af4f7 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/theme/midnight.css @@ -0,0 +1,47 @@ +/* Based on the theme at http://bonsaiden.github.com/JavaScript-Garden */ + +/**/ +.cm-s-midnight span.CodeMirror-matchhighlight { background: #494949; } +.cm-s-midnight.CodeMirror-focused span.CodeMirror-matchhighlight { background: #314D67 !important; } + +/**/ +.cm-s-midnight .CodeMirror-activeline-background {background: #253540 !important;} + +.cm-s-midnight.CodeMirror { + background: #0F192A; + color: #D1EDFF; +} + +.cm-s-midnight.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;} + +.cm-s-midnight div.CodeMirror-selected {background: #314D67 !important;} +.cm-s-midnight.CodeMirror ::selection { background: rgba(49, 77, 103, .99); } +.cm-s-midnight.CodeMirror ::-moz-selection { background: rgba(49, 77, 103, .99); } +.cm-s-midnight .CodeMirror-gutters {background: #0F192A; border-right: 1px solid;} +.cm-s-midnight .CodeMirror-guttermarker { color: white; } +.cm-s-midnight .CodeMirror-guttermarker-subtle { color: #d0d0d0; } +.cm-s-midnight .CodeMirror-linenumber {color: #D0D0D0;} +.cm-s-midnight .CodeMirror-cursor { + border-left: 1px solid #F8F8F0 !important; +} + +.cm-s-midnight span.cm-comment {color: #428BDD;} +.cm-s-midnight span.cm-atom {color: #AE81FF;} +.cm-s-midnight span.cm-number {color: #D1EDFF;} + +.cm-s-midnight span.cm-property, .cm-s-midnight span.cm-attribute {color: #A6E22E;} +.cm-s-midnight span.cm-keyword {color: #E83737;} +.cm-s-midnight span.cm-string {color: #1DC116;} + +.cm-s-midnight span.cm-variable {color: #FFAA3E;} +.cm-s-midnight span.cm-variable-2 {color: #FFAA3E;} +.cm-s-midnight span.cm-def {color: #4DD;} +.cm-s-midnight span.cm-bracket {color: #D1EDFF;} +.cm-s-midnight span.cm-tag {color: #449;} +.cm-s-midnight span.cm-link {color: #AE81FF;} +.cm-s-midnight span.cm-error {background: #F92672; color: #F8F8F0;} + +.cm-s-midnight .CodeMirror-matchingbracket { + text-decoration: underline; + color: white !important; +} diff --git a/static/js/mdeditor/lib/codemirror/theme/monokai.css b/static/js/mdeditor/lib/codemirror/theme/monokai.css new file mode 100644 index 00000000..6dfcc73c --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/theme/monokai.css @@ -0,0 +1,33 @@ +/* Based on Sublime Text's Monokai theme */ + +.cm-s-monokai.CodeMirror {background: #272822; color: #f8f8f2;} +.cm-s-monokai div.CodeMirror-selected {background: #49483E !important;} +.cm-s-monokai.CodeMirror ::selection { background: rgba(73, 72, 62, .99); } +.cm-s-monokai.CodeMirror ::-moz-selection { background: rgba(73, 72, 62, .99); } +.cm-s-monokai .CodeMirror-gutters {background: #272822; border-right: 0px;} +.cm-s-monokai .CodeMirror-guttermarker { color: white; } +.cm-s-monokai .CodeMirror-guttermarker-subtle { color: #d0d0d0; } +.cm-s-monokai .CodeMirror-linenumber {color: #d0d0d0;} +.cm-s-monokai .CodeMirror-cursor {border-left: 1px solid #f8f8f0 !important;} + +.cm-s-monokai span.cm-comment {color: #75715e;} +.cm-s-monokai span.cm-atom {color: #ae81ff;} +.cm-s-monokai span.cm-number {color: #ae81ff;} + +.cm-s-monokai span.cm-property, .cm-s-monokai span.cm-attribute {color: #a6e22e;} +.cm-s-monokai span.cm-keyword {color: #f92672;} +.cm-s-monokai span.cm-string {color: #e6db74;} + +.cm-s-monokai span.cm-variable {color: #a6e22e;} +.cm-s-monokai span.cm-variable-2 {color: #9effff;} +.cm-s-monokai span.cm-def {color: #fd971f;} +.cm-s-monokai span.cm-bracket {color: #f8f8f2;} +.cm-s-monokai span.cm-tag {color: #f92672;} +.cm-s-monokai span.cm-link {color: #ae81ff;} +.cm-s-monokai span.cm-error {background: #f92672; color: #f8f8f0;} + +.cm-s-monokai .CodeMirror-activeline-background {background: #373831 !important;} +.cm-s-monokai .CodeMirror-matchingbracket { + text-decoration: underline; + color: white !important; +} diff --git a/static/js/mdeditor/lib/codemirror/theme/neat.css b/static/js/mdeditor/lib/codemirror/theme/neat.css new file mode 100644 index 00000000..115083b8 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/theme/neat.css @@ -0,0 +1,12 @@ +.cm-s-neat span.cm-comment { color: #a86; } +.cm-s-neat span.cm-keyword { line-height: 1em; font-weight: bold; color: blue; } +.cm-s-neat span.cm-string { color: #a22; } +.cm-s-neat span.cm-builtin { line-height: 1em; font-weight: bold; color: #077; } +.cm-s-neat span.cm-special { line-height: 1em; font-weight: bold; color: #0aa; } +.cm-s-neat span.cm-variable { color: black; } +.cm-s-neat span.cm-number, .cm-s-neat span.cm-atom { color: #3a3; } +.cm-s-neat span.cm-meta {color: #555;} +.cm-s-neat span.cm-link { color: #3a3; } + +.cm-s-neat .CodeMirror-activeline-background {background: #e8f2ff !important;} +.cm-s-neat .CodeMirror-matchingbracket {outline:1px solid grey; color:black !important;} diff --git a/static/js/mdeditor/lib/codemirror/theme/neo.css b/static/js/mdeditor/lib/codemirror/theme/neo.css new file mode 100644 index 00000000..cecaaf28 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/theme/neo.css @@ -0,0 +1,43 @@ +/* neo theme for codemirror */ + +/* Color scheme */ + +.cm-s-neo.CodeMirror { + background-color:#ffffff; + color:#2e383c; + line-height:1.4375; +} +.cm-s-neo .cm-comment {color:#75787b} +.cm-s-neo .cm-keyword, .cm-s-neo .cm-property {color:#1d75b3} +.cm-s-neo .cm-atom,.cm-s-neo .cm-number {color:#75438a} +.cm-s-neo .cm-node,.cm-s-neo .cm-tag {color:#9c3328} +.cm-s-neo .cm-string {color:#b35e14} +.cm-s-neo .cm-variable,.cm-s-neo .cm-qualifier {color:#047d65} + + +/* Editor styling */ + +.cm-s-neo pre { + padding:0; +} + +.cm-s-neo .CodeMirror-gutters { + border:none; + border-right:10px solid transparent; + background-color:transparent; +} + +.cm-s-neo .CodeMirror-linenumber { + padding:0; + color:#e0e2e5; +} + +.cm-s-neo .CodeMirror-guttermarker { color: #1d75b3; } +.cm-s-neo .CodeMirror-guttermarker-subtle { color: #e0e2e5; } + +.cm-s-neo div.CodeMirror-cursor { + width: auto; + border: 0; + background: rgba(155,157,162,0.37); + z-index: 1; +} diff --git a/static/js/mdeditor/lib/codemirror/theme/night.css b/static/js/mdeditor/lib/codemirror/theme/night.css new file mode 100644 index 00000000..6b2ac6c7 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/theme/night.css @@ -0,0 +1,28 @@ +/* Loosely based on the Midnight Textmate theme */ + +.cm-s-night.CodeMirror { background: #0a001f; color: #f8f8f8; } +.cm-s-night div.CodeMirror-selected { background: #447 !important; } +.cm-s-night.CodeMirror ::selection { background: rgba(68, 68, 119, .99); } +.cm-s-night.CodeMirror ::-moz-selection { background: rgba(68, 68, 119, .99); } +.cm-s-night .CodeMirror-gutters { background: #0a001f; border-right: 1px solid #aaa; } +.cm-s-night .CodeMirror-guttermarker { color: white; } +.cm-s-night .CodeMirror-guttermarker-subtle { color: #bbb; } +.cm-s-night .CodeMirror-linenumber { color: #f8f8f8; } +.cm-s-night .CodeMirror-cursor { border-left: 1px solid white !important; } + +.cm-s-night span.cm-comment { color: #6900a1; } +.cm-s-night span.cm-atom { color: #845dc4; } +.cm-s-night span.cm-number, .cm-s-night span.cm-attribute { color: #ffd500; } +.cm-s-night span.cm-keyword { color: #599eff; } +.cm-s-night span.cm-string { color: #37f14a; } +.cm-s-night span.cm-meta { color: #7678e2; } +.cm-s-night span.cm-variable-2, .cm-s-night span.cm-tag { color: #99b2ff; } +.cm-s-night span.cm-variable-3, .cm-s-night span.cm-def { color: white; } +.cm-s-night span.cm-bracket { color: #8da6ce; } +.cm-s-night span.cm-comment { color: #6900a1; } +.cm-s-night span.cm-builtin, .cm-s-night span.cm-special { color: #ff9e59; } +.cm-s-night span.cm-link { color: #845dc4; } +.cm-s-night span.cm-error { color: #9d1e15; } + +.cm-s-night .CodeMirror-activeline-background {background: #1C005A !important;} +.cm-s-night .CodeMirror-matchingbracket {outline:1px solid grey; color:white !important;} diff --git a/static/js/mdeditor/lib/codemirror/theme/paraiso-dark.css b/static/js/mdeditor/lib/codemirror/theme/paraiso-dark.css new file mode 100644 index 00000000..af914b60 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/theme/paraiso-dark.css @@ -0,0 +1,38 @@ +/* + + Name: Paraíso (Dark) + Author: Jan T. Sott + + Color scheme by Jan T. Sott (https://github.com/idleberg/Paraiso-CodeMirror) + Inspired by the art of Rubens LP (http://www.rubenslp.com.br) + +*/ + +.cm-s-paraiso-dark.CodeMirror {background: #2f1e2e; color: #b9b6b0;} +.cm-s-paraiso-dark div.CodeMirror-selected {background: #41323f !important;} +.cm-s-paraiso-dark.CodeMirror ::selection { background: rgba(65, 50, 63, .99); } +.cm-s-paraiso-dark.CodeMirror ::-moz-selection { background: rgba(65, 50, 63, .99); } +.cm-s-paraiso-dark .CodeMirror-gutters {background: #2f1e2e; border-right: 0px;} +.cm-s-paraiso-dark .CodeMirror-guttermarker { color: #ef6155; } +.cm-s-paraiso-dark .CodeMirror-guttermarker-subtle { color: #776e71; } +.cm-s-paraiso-dark .CodeMirror-linenumber {color: #776e71;} +.cm-s-paraiso-dark .CodeMirror-cursor {border-left: 1px solid #8d8687 !important;} + +.cm-s-paraiso-dark span.cm-comment {color: #e96ba8;} +.cm-s-paraiso-dark span.cm-atom {color: #815ba4;} +.cm-s-paraiso-dark span.cm-number {color: #815ba4;} + +.cm-s-paraiso-dark span.cm-property, .cm-s-paraiso-dark span.cm-attribute {color: #48b685;} +.cm-s-paraiso-dark span.cm-keyword {color: #ef6155;} +.cm-s-paraiso-dark span.cm-string {color: #fec418;} + +.cm-s-paraiso-dark span.cm-variable {color: #48b685;} +.cm-s-paraiso-dark span.cm-variable-2 {color: #06b6ef;} +.cm-s-paraiso-dark span.cm-def {color: #f99b15;} +.cm-s-paraiso-dark span.cm-bracket {color: #b9b6b0;} +.cm-s-paraiso-dark span.cm-tag {color: #ef6155;} +.cm-s-paraiso-dark span.cm-link {color: #815ba4;} +.cm-s-paraiso-dark span.cm-error {background: #ef6155; color: #8d8687;} + +.cm-s-paraiso-dark .CodeMirror-activeline-background {background: #4D344A !important;} +.cm-s-paraiso-dark .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;} diff --git a/static/js/mdeditor/lib/codemirror/theme/paraiso-light.css b/static/js/mdeditor/lib/codemirror/theme/paraiso-light.css new file mode 100644 index 00000000..e198066f --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/theme/paraiso-light.css @@ -0,0 +1,38 @@ +/* + + Name: Paraíso (Light) + Author: Jan T. Sott + + Color scheme by Jan T. Sott (https://github.com/idleberg/Paraiso-CodeMirror) + Inspired by the art of Rubens LP (http://www.rubenslp.com.br) + +*/ + +.cm-s-paraiso-light.CodeMirror {background: #e7e9db; color: #41323f;} +.cm-s-paraiso-light div.CodeMirror-selected {background: #b9b6b0 !important;} +.cm-s-paraiso-light.CodeMirror ::selection { background: #b9b6b0; } +.cm-s-paraiso-light.CodeMirror ::-moz-selection { background: #b9b6b0; } +.cm-s-paraiso-light .CodeMirror-gutters {background: #e7e9db; border-right: 0px;} +.cm-s-paraiso-light .CodeMirror-guttermarker { color: black; } +.cm-s-paraiso-light .CodeMirror-guttermarker-subtle { color: #8d8687; } +.cm-s-paraiso-light .CodeMirror-linenumber {color: #8d8687;} +.cm-s-paraiso-light .CodeMirror-cursor {border-left: 1px solid #776e71 !important;} + +.cm-s-paraiso-light span.cm-comment {color: #e96ba8;} +.cm-s-paraiso-light span.cm-atom {color: #815ba4;} +.cm-s-paraiso-light span.cm-number {color: #815ba4;} + +.cm-s-paraiso-light span.cm-property, .cm-s-paraiso-light span.cm-attribute {color: #48b685;} +.cm-s-paraiso-light span.cm-keyword {color: #ef6155;} +.cm-s-paraiso-light span.cm-string {color: #fec418;} + +.cm-s-paraiso-light span.cm-variable {color: #48b685;} +.cm-s-paraiso-light span.cm-variable-2 {color: #06b6ef;} +.cm-s-paraiso-light span.cm-def {color: #f99b15;} +.cm-s-paraiso-light span.cm-bracket {color: #41323f;} +.cm-s-paraiso-light span.cm-tag {color: #ef6155;} +.cm-s-paraiso-light span.cm-link {color: #815ba4;} +.cm-s-paraiso-light span.cm-error {background: #ef6155; color: #776e71;} + +.cm-s-paraiso-light .CodeMirror-activeline-background {background: #CFD1C4 !important;} +.cm-s-paraiso-light .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;} diff --git a/static/js/mdeditor/lib/codemirror/theme/pastel-on-dark.css b/static/js/mdeditor/lib/codemirror/theme/pastel-on-dark.css new file mode 100644 index 00000000..0d06f632 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/theme/pastel-on-dark.css @@ -0,0 +1,53 @@ +/** + * Pastel On Dark theme ported from ACE editor + * @license MIT + * @copyright AtomicPages LLC 2014 + * @author Dennis Thompson, AtomicPages LLC + * @version 1.1 + * @source https://github.com/atomicpages/codemirror-pastel-on-dark-theme + */ + +.cm-s-pastel-on-dark.CodeMirror { + background: #2c2827; + color: #8F938F; + line-height: 1.5; + font-size: 14px; +} +.cm-s-pastel-on-dark div.CodeMirror-selected { background: rgba(221,240,255,0.2) !important; } +.cm-s-pastel-on-dark.CodeMirror ::selection { background: rgba(221,240,255,0.2); } +.cm-s-pastel-on-dark.CodeMirror ::-moz-selection { background: rgba(221,240,255,0.2); } + +.cm-s-pastel-on-dark .CodeMirror-gutters { + background: #34302f; + border-right: 0px; + padding: 0 3px; +} +.cm-s-pastel-on-dark .CodeMirror-guttermarker { color: white; } +.cm-s-pastel-on-dark .CodeMirror-guttermarker-subtle { color: #8F938F; } +.cm-s-pastel-on-dark .CodeMirror-linenumber { color: #8F938F; } +.cm-s-pastel-on-dark .CodeMirror-cursor { border-left: 1px solid #A7A7A7 !important; } +.cm-s-pastel-on-dark span.cm-comment { color: #A6C6FF; } +.cm-s-pastel-on-dark span.cm-atom { color: #DE8E30; } +.cm-s-pastel-on-dark span.cm-number { color: #CCCCCC; } +.cm-s-pastel-on-dark span.cm-property { color: #8F938F; } +.cm-s-pastel-on-dark span.cm-attribute { color: #a6e22e; } +.cm-s-pastel-on-dark span.cm-keyword { color: #AEB2F8; } +.cm-s-pastel-on-dark span.cm-string { color: #66A968; } +.cm-s-pastel-on-dark span.cm-variable { color: #AEB2F8; } +.cm-s-pastel-on-dark span.cm-variable-2 { color: #BEBF55; } +.cm-s-pastel-on-dark span.cm-variable-3 { color: #DE8E30; } +.cm-s-pastel-on-dark span.cm-def { color: #757aD8; } +.cm-s-pastel-on-dark span.cm-bracket { color: #f8f8f2; } +.cm-s-pastel-on-dark span.cm-tag { color: #C1C144; } +.cm-s-pastel-on-dark span.cm-link { color: #ae81ff; } +.cm-s-pastel-on-dark span.cm-qualifier,.cm-s-pastel-on-dark span.cm-builtin { color: #C1C144; } +.cm-s-pastel-on-dark span.cm-error { + background: #757aD8; + color: #f8f8f0; +} +.cm-s-pastel-on-dark .CodeMirror-activeline-background { background: rgba(255, 255, 255, 0.031) !important; } +.cm-s-pastel-on-dark .CodeMirror-matchingbracket { + border: 1px solid rgba(255,255,255,0.25); + color: #8F938F !important; + margin: -1px -1px 0 -1px; +} diff --git a/static/js/mdeditor/lib/codemirror/theme/rubyblue.css b/static/js/mdeditor/lib/codemirror/theme/rubyblue.css new file mode 100644 index 00000000..d2fc0ecd --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/theme/rubyblue.css @@ -0,0 +1,25 @@ +.cm-s-rubyblue.CodeMirror { background: #112435; color: white; } +.cm-s-rubyblue div.CodeMirror-selected { background: #38566F !important; } +.cm-s-rubyblue.CodeMirror ::selection { background: rgba(56, 86, 111, 0.99); } +.cm-s-rubyblue.CodeMirror ::-moz-selection { background: rgba(56, 86, 111, 0.99); } +.cm-s-rubyblue .CodeMirror-gutters { background: #1F4661; border-right: 7px solid #3E7087; } +.cm-s-rubyblue .CodeMirror-guttermarker { color: white; } +.cm-s-rubyblue .CodeMirror-guttermarker-subtle { color: #3E7087; } +.cm-s-rubyblue .CodeMirror-linenumber { color: white; } +.cm-s-rubyblue .CodeMirror-cursor { border-left: 1px solid white !important; } + +.cm-s-rubyblue span.cm-comment { color: #999; font-style:italic; line-height: 1em; } +.cm-s-rubyblue span.cm-atom { color: #F4C20B; } +.cm-s-rubyblue span.cm-number, .cm-s-rubyblue span.cm-attribute { color: #82C6E0; } +.cm-s-rubyblue span.cm-keyword { color: #F0F; } +.cm-s-rubyblue span.cm-string { color: #F08047; } +.cm-s-rubyblue span.cm-meta { color: #F0F; } +.cm-s-rubyblue span.cm-variable-2, .cm-s-rubyblue span.cm-tag { color: #7BD827; } +.cm-s-rubyblue span.cm-variable-3, .cm-s-rubyblue span.cm-def { color: white; } +.cm-s-rubyblue span.cm-bracket { color: #F0F; } +.cm-s-rubyblue span.cm-link { color: #F4C20B; } +.cm-s-rubyblue span.CodeMirror-matchingbracket { color:#F0F !important; } +.cm-s-rubyblue span.cm-builtin, .cm-s-rubyblue span.cm-special { color: #FF9D00; } +.cm-s-rubyblue span.cm-error { color: #AF2018; } + +.cm-s-rubyblue .CodeMirror-activeline-background {background: #173047 !important;} diff --git a/static/js/mdeditor/lib/codemirror/theme/solarized.css b/static/js/mdeditor/lib/codemirror/theme/solarized.css new file mode 100644 index 00000000..4a10b7c0 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/theme/solarized.css @@ -0,0 +1,165 @@ +/* +Solarized theme for code-mirror +http://ethanschoonover.com/solarized +*/ + +/* +Solarized color pallet +http://ethanschoonover.com/solarized/img/solarized-palette.png +*/ + +.solarized.base03 { color: #002b36; } +.solarized.base02 { color: #073642; } +.solarized.base01 { color: #586e75; } +.solarized.base00 { color: #657b83; } +.solarized.base0 { color: #839496; } +.solarized.base1 { color: #93a1a1; } +.solarized.base2 { color: #eee8d5; } +.solarized.base3 { color: #fdf6e3; } +.solarized.solar-yellow { color: #b58900; } +.solarized.solar-orange { color: #cb4b16; } +.solarized.solar-red { color: #dc322f; } +.solarized.solar-magenta { color: #d33682; } +.solarized.solar-violet { color: #6c71c4; } +.solarized.solar-blue { color: #268bd2; } +.solarized.solar-cyan { color: #2aa198; } +.solarized.solar-green { color: #859900; } + +/* Color scheme for code-mirror */ + +.cm-s-solarized { + line-height: 1.45em; + color-profile: sRGB; + rendering-intent: auto; +} +.cm-s-solarized.cm-s-dark { + color: #839496; + background-color: #002b36; + text-shadow: #002b36 0 1px; +} +.cm-s-solarized.cm-s-light { + background-color: #fdf6e3; + color: #657b83; + text-shadow: #eee8d5 0 1px; +} + +.cm-s-solarized .CodeMirror-widget { + text-shadow: none; +} + + +.cm-s-solarized .cm-keyword { color: #cb4b16 } +.cm-s-solarized .cm-atom { color: #d33682; } +.cm-s-solarized .cm-number { color: #d33682; } +.cm-s-solarized .cm-def { color: #2aa198; } + +.cm-s-solarized .cm-variable { color: #268bd2; } +.cm-s-solarized .cm-variable-2 { color: #b58900; } +.cm-s-solarized .cm-variable-3 { color: #6c71c4; } + +.cm-s-solarized .cm-property { color: #2aa198; } +.cm-s-solarized .cm-operator {color: #6c71c4;} + +.cm-s-solarized .cm-comment { color: #586e75; font-style:italic; } + +.cm-s-solarized .cm-string { color: #859900; } +.cm-s-solarized .cm-string-2 { color: #b58900; } + +.cm-s-solarized .cm-meta { color: #859900; } +.cm-s-solarized .cm-qualifier { color: #b58900; } +.cm-s-solarized .cm-builtin { color: #d33682; } +.cm-s-solarized .cm-bracket { color: #cb4b16; } +.cm-s-solarized .CodeMirror-matchingbracket { color: #859900; } +.cm-s-solarized .CodeMirror-nonmatchingbracket { color: #dc322f; } +.cm-s-solarized .cm-tag { color: #93a1a1 } +.cm-s-solarized .cm-attribute { color: #2aa198; } +.cm-s-solarized .cm-header { color: #586e75; } +.cm-s-solarized .cm-quote { color: #93a1a1; } +.cm-s-solarized .cm-hr { + color: transparent; + border-top: 1px solid #586e75; + display: block; +} +.cm-s-solarized .cm-link { color: #93a1a1; cursor: pointer; } +.cm-s-solarized .cm-special { color: #6c71c4; } +.cm-s-solarized .cm-em { + color: #999; + text-decoration: underline; + text-decoration-style: dotted; +} +.cm-s-solarized .cm-strong { color: #eee; } +.cm-s-solarized .cm-error, +.cm-s-solarized .cm-invalidchar { + color: #586e75; + border-bottom: 1px dotted #dc322f; +} + +.cm-s-solarized.cm-s-dark .CodeMirror-selected { background: #073642; } +.cm-s-solarized.cm-s-dark.CodeMirror ::selection { background: rgba(7, 54, 66, 0.99); } +.cm-s-solarized.cm-s-dark.CodeMirror ::-moz-selection { background: rgba(7, 54, 66, 0.99); } + +.cm-s-solarized.cm-s-light .CodeMirror-selected { background: #eee8d5; } +.cm-s-solarized.cm-s-light.CodeMirror ::selection { background: #eee8d5; } +.cm-s-solarized.cm-s-lightCodeMirror ::-moz-selection { background: #eee8d5; } + +/* Editor styling */ + + + +/* Little shadow on the view-port of the buffer view */ +.cm-s-solarized.CodeMirror { + -moz-box-shadow: inset 7px 0 12px -6px #000; + -webkit-box-shadow: inset 7px 0 12px -6px #000; + box-shadow: inset 7px 0 12px -6px #000; +} + +/* Gutter border and some shadow from it */ +.cm-s-solarized .CodeMirror-gutters { + border-right: 1px solid; +} + +/* Gutter colors and line number styling based of color scheme (dark / light) */ + +/* Dark */ +.cm-s-solarized.cm-s-dark .CodeMirror-gutters { + background-color: #002b36; + border-color: #00232c; +} + +.cm-s-solarized.cm-s-dark .CodeMirror-linenumber { + text-shadow: #021014 0 -1px; +} + +/* Light */ +.cm-s-solarized.cm-s-light .CodeMirror-gutters { + background-color: #fdf6e3; + border-color: #eee8d5; +} + +/* Common */ +.cm-s-solarized .CodeMirror-linenumber { + color: #586e75; + padding: 0 5px; +} +.cm-s-solarized .CodeMirror-guttermarker-subtle { color: #586e75; } +.cm-s-solarized.cm-s-dark .CodeMirror-guttermarker { color: #ddd; } +.cm-s-solarized.cm-s-light .CodeMirror-guttermarker { color: #cb4b16; } + +.cm-s-solarized .CodeMirror-gutter .CodeMirror-gutter-text { + color: #586e75; +} + +.cm-s-solarized .CodeMirror-lines .CodeMirror-cursor { + border-left: 1px solid #819090; +} + +/* +Active line. Negative margin compensates left padding of the text in the +view-port +*/ +.cm-s-solarized.cm-s-dark .CodeMirror-activeline-background { + background: rgba(255, 255, 255, 0.10); +} +.cm-s-solarized.cm-s-light .CodeMirror-activeline-background { + background: rgba(0, 0, 0, 0.10); +} diff --git a/static/js/mdeditor/lib/codemirror/theme/the-matrix.css b/static/js/mdeditor/lib/codemirror/theme/the-matrix.css new file mode 100644 index 00000000..f29b22b0 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/theme/the-matrix.css @@ -0,0 +1,30 @@ +.cm-s-the-matrix.CodeMirror { background: #000000; color: #00FF00; } +.cm-s-the-matrix div.CodeMirror-selected { background: #2D2D2D !important; } +.cm-s-the-matrix.CodeMirror ::selection { background: rgba(45, 45, 45, 0.99); } +.cm-s-the-matrix.CodeMirror ::-moz-selection { background: rgba(45, 45, 45, 0.99); } +.cm-s-the-matrix .CodeMirror-gutters { background: #060; border-right: 2px solid #00FF00; } +.cm-s-the-matrix .CodeMirror-guttermarker { color: #0f0; } +.cm-s-the-matrix .CodeMirror-guttermarker-subtle { color: white; } +.cm-s-the-matrix .CodeMirror-linenumber { color: #FFFFFF; } +.cm-s-the-matrix .CodeMirror-cursor { border-left: 1px solid #00FF00 !important; } + +.cm-s-the-matrix span.cm-keyword {color: #008803; font-weight: bold;} +.cm-s-the-matrix span.cm-atom {color: #3FF;} +.cm-s-the-matrix span.cm-number {color: #FFB94F;} +.cm-s-the-matrix span.cm-def {color: #99C;} +.cm-s-the-matrix span.cm-variable {color: #F6C;} +.cm-s-the-matrix span.cm-variable-2 {color: #C6F;} +.cm-s-the-matrix span.cm-variable-3 {color: #96F;} +.cm-s-the-matrix span.cm-property {color: #62FFA0;} +.cm-s-the-matrix span.cm-operator {color: #999} +.cm-s-the-matrix span.cm-comment {color: #CCCCCC;} +.cm-s-the-matrix span.cm-string {color: #39C;} +.cm-s-the-matrix span.cm-meta {color: #C9F;} +.cm-s-the-matrix span.cm-qualifier {color: #FFF700;} +.cm-s-the-matrix span.cm-builtin {color: #30a;} +.cm-s-the-matrix span.cm-bracket {color: #cc7;} +.cm-s-the-matrix span.cm-tag {color: #FFBD40;} +.cm-s-the-matrix span.cm-attribute {color: #FFF700;} +.cm-s-the-matrix span.cm-error {color: #FF0000;} + +.cm-s-the-matrix .CodeMirror-activeline-background {background: #040;} diff --git a/static/js/mdeditor/lib/codemirror/theme/tomorrow-night-bright.css b/static/js/mdeditor/lib/codemirror/theme/tomorrow-night-bright.css new file mode 100644 index 00000000..decb82d3 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/theme/tomorrow-night-bright.css @@ -0,0 +1,35 @@ +/* + + Name: Tomorrow Night - Bright + Author: Chris Kempson + + Port done by Gerard Braad + +*/ + +.cm-s-tomorrow-night-bright.CodeMirror {background: #000000; color: #eaeaea;} +.cm-s-tomorrow-night-bright div.CodeMirror-selected {background: #424242 !important;} +.cm-s-tomorrow-night-bright .CodeMirror-gutters {background: #000000; border-right: 0px;} +.cm-s-tomorrow-night-bright .CodeMirror-guttermarker { color: #e78c45; } +.cm-s-tomorrow-night-bright .CodeMirror-guttermarker-subtle { color: #777; } +.cm-s-tomorrow-night-bright .CodeMirror-linenumber {color: #424242;} +.cm-s-tomorrow-night-bright .CodeMirror-cursor {border-left: 1px solid #6A6A6A !important;} + +.cm-s-tomorrow-night-bright span.cm-comment {color: #d27b53;} +.cm-s-tomorrow-night-bright span.cm-atom {color: #a16a94;} +.cm-s-tomorrow-night-bright span.cm-number {color: #a16a94;} + +.cm-s-tomorrow-night-bright span.cm-property, .cm-s-tomorrow-night-bright span.cm-attribute {color: #99cc99;} +.cm-s-tomorrow-night-bright span.cm-keyword {color: #d54e53;} +.cm-s-tomorrow-night-bright span.cm-string {color: #e7c547;} + +.cm-s-tomorrow-night-bright span.cm-variable {color: #b9ca4a;} +.cm-s-tomorrow-night-bright span.cm-variable-2 {color: #7aa6da;} +.cm-s-tomorrow-night-bright span.cm-def {color: #e78c45;} +.cm-s-tomorrow-night-bright span.cm-bracket {color: #eaeaea;} +.cm-s-tomorrow-night-bright span.cm-tag {color: #d54e53;} +.cm-s-tomorrow-night-bright span.cm-link {color: #a16a94;} +.cm-s-tomorrow-night-bright span.cm-error {background: #d54e53; color: #6A6A6A;} + +.cm-s-tomorrow-night-bright .CodeMirror-activeline-background {background: #2a2a2a !important;} +.cm-s-tomorrow-night-bright .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;} diff --git a/static/js/mdeditor/lib/codemirror/theme/tomorrow-night-eighties.css b/static/js/mdeditor/lib/codemirror/theme/tomorrow-night-eighties.css new file mode 100644 index 00000000..5fca3caf --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/theme/tomorrow-night-eighties.css @@ -0,0 +1,38 @@ +/* + + Name: Tomorrow Night - Eighties + Author: Chris Kempson + + CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror) + Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) + +*/ + +.cm-s-tomorrow-night-eighties.CodeMirror {background: #000000; color: #CCCCCC;} +.cm-s-tomorrow-night-eighties div.CodeMirror-selected {background: #2D2D2D !important;} +.cm-s-tomorrow-night-eighties.CodeMirror ::selection { background: rgba(45, 45, 45, 0.99); } +.cm-s-tomorrow-night-eighties.CodeMirror ::-moz-selection { background: rgba(45, 45, 45, 0.99); } +.cm-s-tomorrow-night-eighties .CodeMirror-gutters {background: #000000; border-right: 0px;} +.cm-s-tomorrow-night-eighties .CodeMirror-guttermarker { color: #f2777a; } +.cm-s-tomorrow-night-eighties .CodeMirror-guttermarker-subtle { color: #777; } +.cm-s-tomorrow-night-eighties .CodeMirror-linenumber {color: #515151;} +.cm-s-tomorrow-night-eighties .CodeMirror-cursor {border-left: 1px solid #6A6A6A !important;} + +.cm-s-tomorrow-night-eighties span.cm-comment {color: #d27b53;} +.cm-s-tomorrow-night-eighties span.cm-atom {color: #a16a94;} +.cm-s-tomorrow-night-eighties span.cm-number {color: #a16a94;} + +.cm-s-tomorrow-night-eighties span.cm-property, .cm-s-tomorrow-night-eighties span.cm-attribute {color: #99cc99;} +.cm-s-tomorrow-night-eighties span.cm-keyword {color: #f2777a;} +.cm-s-tomorrow-night-eighties span.cm-string {color: #ffcc66;} + +.cm-s-tomorrow-night-eighties span.cm-variable {color: #99cc99;} +.cm-s-tomorrow-night-eighties span.cm-variable-2 {color: #6699cc;} +.cm-s-tomorrow-night-eighties span.cm-def {color: #f99157;} +.cm-s-tomorrow-night-eighties span.cm-bracket {color: #CCCCCC;} +.cm-s-tomorrow-night-eighties span.cm-tag {color: #f2777a;} +.cm-s-tomorrow-night-eighties span.cm-link {color: #a16a94;} +.cm-s-tomorrow-night-eighties span.cm-error {background: #f2777a; color: #6A6A6A;} + +.cm-s-tomorrow-night-eighties .CodeMirror-activeline-background {background: #343600 !important;} +.cm-s-tomorrow-night-eighties .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;} diff --git a/static/js/mdeditor/lib/codemirror/theme/twilight.css b/static/js/mdeditor/lib/codemirror/theme/twilight.css new file mode 100644 index 00000000..889a83d7 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/theme/twilight.css @@ -0,0 +1,32 @@ +.cm-s-twilight.CodeMirror { background: #141414; color: #f7f7f7; } /**/ +.cm-s-twilight .CodeMirror-selected { background: #323232 !important; } /**/ +.cm-s-twilight.CodeMirror ::selection { background: rgba(50, 50, 50, 0.99); } +.cm-s-twilight.CodeMirror ::-moz-selection { background: rgba(50, 50, 50, 0.99); } + +.cm-s-twilight .CodeMirror-gutters { background: #222; border-right: 1px solid #aaa; } +.cm-s-twilight .CodeMirror-guttermarker { color: white; } +.cm-s-twilight .CodeMirror-guttermarker-subtle { color: #aaa; } +.cm-s-twilight .CodeMirror-linenumber { color: #aaa; } +.cm-s-twilight .CodeMirror-cursor { border-left: 1px solid white !important; } + +.cm-s-twilight .cm-keyword { color: #f9ee98; } /**/ +.cm-s-twilight .cm-atom { color: #FC0; } +.cm-s-twilight .cm-number { color: #ca7841; } /**/ +.cm-s-twilight .cm-def { color: #8DA6CE; } +.cm-s-twilight span.cm-variable-2, .cm-s-twilight span.cm-tag { color: #607392; } /**/ +.cm-s-twilight span.cm-variable-3, .cm-s-twilight span.cm-def { color: #607392; } /**/ +.cm-s-twilight .cm-operator { color: #cda869; } /**/ +.cm-s-twilight .cm-comment { color:#777; font-style:italic; font-weight:normal; } /**/ +.cm-s-twilight .cm-string { color:#8f9d6a; font-style:italic; } /**/ +.cm-s-twilight .cm-string-2 { color:#bd6b18 } /*?*/ +.cm-s-twilight .cm-meta { background-color:#141414; color:#f7f7f7; } /*?*/ +.cm-s-twilight .cm-builtin { color: #cda869; } /*?*/ +.cm-s-twilight .cm-tag { color: #997643; } /**/ +.cm-s-twilight .cm-attribute { color: #d6bb6d; } /*?*/ +.cm-s-twilight .cm-header { color: #FF6400; } +.cm-s-twilight .cm-hr { color: #AEAEAE; } +.cm-s-twilight .cm-link { color:#ad9361; font-style:italic; text-decoration:none; } /**/ +.cm-s-twilight .cm-error { border-bottom: 1px solid red; } + +.cm-s-twilight .CodeMirror-activeline-background {background: #27282E !important;} +.cm-s-twilight .CodeMirror-matchingbracket {outline:1px solid grey; color:white !important;} diff --git a/static/js/mdeditor/lib/codemirror/theme/vibrant-ink.css b/static/js/mdeditor/lib/codemirror/theme/vibrant-ink.css new file mode 100644 index 00000000..8ea53597 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/theme/vibrant-ink.css @@ -0,0 +1,34 @@ +/* Taken from the popular Visual Studio Vibrant Ink Schema */ + +.cm-s-vibrant-ink.CodeMirror { background: black; color: white; } +.cm-s-vibrant-ink .CodeMirror-selected { background: #35493c !important; } +.cm-s-vibrant-ink.CodeMirror ::selection { background: rgba(53, 73, 60, 0.99); } +.cm-s-vibrant-ink.CodeMirror ::-moz-selection { background: rgba(53, 73, 60, 0.99); } + +.cm-s-vibrant-ink .CodeMirror-gutters { background: #002240; border-right: 1px solid #aaa; } +.cm-s-vibrant-ink .CodeMirror-guttermarker { color: white; } +.cm-s-vibrant-ink .CodeMirror-guttermarker-subtle { color: #d0d0d0; } +.cm-s-vibrant-ink .CodeMirror-linenumber { color: #d0d0d0; } +.cm-s-vibrant-ink .CodeMirror-cursor { border-left: 1px solid white !important; } + +.cm-s-vibrant-ink .cm-keyword { color: #CC7832; } +.cm-s-vibrant-ink .cm-atom { color: #FC0; } +.cm-s-vibrant-ink .cm-number { color: #FFEE98; } +.cm-s-vibrant-ink .cm-def { color: #8DA6CE; } +.cm-s-vibrant-ink span.cm-variable-2, .cm-s-vibrant span.cm-tag { color: #FFC66D } +.cm-s-vibrant-ink span.cm-variable-3, .cm-s-vibrant span.cm-def { color: #FFC66D } +.cm-s-vibrant-ink .cm-operator { color: #888; } +.cm-s-vibrant-ink .cm-comment { color: gray; font-weight: bold; } +.cm-s-vibrant-ink .cm-string { color: #A5C25C } +.cm-s-vibrant-ink .cm-string-2 { color: red } +.cm-s-vibrant-ink .cm-meta { color: #D8FA3C; } +.cm-s-vibrant-ink .cm-builtin { color: #8DA6CE; } +.cm-s-vibrant-ink .cm-tag { color: #8DA6CE; } +.cm-s-vibrant-ink .cm-attribute { color: #8DA6CE; } +.cm-s-vibrant-ink .cm-header { color: #FF6400; } +.cm-s-vibrant-ink .cm-hr { color: #AEAEAE; } +.cm-s-vibrant-ink .cm-link { color: blue; } +.cm-s-vibrant-ink .cm-error { border-bottom: 1px solid red; } + +.cm-s-vibrant-ink .CodeMirror-activeline-background {background: #27282E !important;} +.cm-s-vibrant-ink .CodeMirror-matchingbracket {outline:1px solid grey; color:white !important;} diff --git a/static/js/mdeditor/lib/codemirror/theme/xq-dark.css b/static/js/mdeditor/lib/codemirror/theme/xq-dark.css new file mode 100644 index 00000000..d537993e --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/theme/xq-dark.css @@ -0,0 +1,53 @@ +/* +Copyright (C) 2011 by MarkLogic Corporation +Author: Mike Brevoort + +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. +*/ +.cm-s-xq-dark.CodeMirror { background: #0a001f; color: #f8f8f8; } +.cm-s-xq-dark .CodeMirror-selected { background: #27007A !important; } +.cm-s-xq-dark.CodeMirror ::selection { background: rgba(39, 0, 122, 0.99); } +.cm-s-xq-dark.CodeMirror ::-moz-selection { background: rgba(39, 0, 122, 0.99); } +.cm-s-xq-dark .CodeMirror-gutters { background: #0a001f; border-right: 1px solid #aaa; } +.cm-s-xq-dark .CodeMirror-guttermarker { color: #FFBD40; } +.cm-s-xq-dark .CodeMirror-guttermarker-subtle { color: #f8f8f8; } +.cm-s-xq-dark .CodeMirror-linenumber { color: #f8f8f8; } +.cm-s-xq-dark .CodeMirror-cursor { border-left: 1px solid white !important; } + +.cm-s-xq-dark span.cm-keyword {color: #FFBD40;} +.cm-s-xq-dark span.cm-atom {color: #6C8CD5;} +.cm-s-xq-dark span.cm-number {color: #164;} +.cm-s-xq-dark span.cm-def {color: #FFF; text-decoration:underline;} +.cm-s-xq-dark span.cm-variable {color: #FFF;} +.cm-s-xq-dark span.cm-variable-2 {color: #EEE;} +.cm-s-xq-dark span.cm-variable-3 {color: #DDD;} +.cm-s-xq-dark span.cm-property {} +.cm-s-xq-dark span.cm-operator {} +.cm-s-xq-dark span.cm-comment {color: gray;} +.cm-s-xq-dark span.cm-string {color: #9FEE00;} +.cm-s-xq-dark span.cm-meta {color: yellow;} +.cm-s-xq-dark span.cm-qualifier {color: #FFF700;} +.cm-s-xq-dark span.cm-builtin {color: #30a;} +.cm-s-xq-dark span.cm-bracket {color: #cc7;} +.cm-s-xq-dark span.cm-tag {color: #FFBD40;} +.cm-s-xq-dark span.cm-attribute {color: #FFF700;} +.cm-s-xq-dark span.cm-error {color: #f00;} + +.cm-s-xq-dark .CodeMirror-activeline-background {background: #27282E !important;} +.cm-s-xq-dark .CodeMirror-matchingbracket {outline:1px solid grey; color:white !important;} \ No newline at end of file diff --git a/static/js/mdeditor/lib/codemirror/theme/xq-light.css b/static/js/mdeditor/lib/codemirror/theme/xq-light.css new file mode 100644 index 00000000..20b5c796 --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/theme/xq-light.css @@ -0,0 +1,43 @@ +/* +Copyright (C) 2011 by MarkLogic Corporation +Author: Mike Brevoort + +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. +*/ +.cm-s-xq-light span.cm-keyword {line-height: 1em; font-weight: bold; color: #5A5CAD; } +.cm-s-xq-light span.cm-atom {color: #6C8CD5;} +.cm-s-xq-light span.cm-number {color: #164;} +.cm-s-xq-light span.cm-def {text-decoration:underline;} +.cm-s-xq-light span.cm-variable {color: black; } +.cm-s-xq-light span.cm-variable-2 {color:black;} +.cm-s-xq-light span.cm-variable-3 {color: black; } +.cm-s-xq-light span.cm-property {} +.cm-s-xq-light span.cm-operator {} +.cm-s-xq-light span.cm-comment {color: #0080FF; font-style: italic;} +.cm-s-xq-light span.cm-string {color: red;} +.cm-s-xq-light span.cm-meta {color: yellow;} +.cm-s-xq-light span.cm-qualifier {color: grey} +.cm-s-xq-light span.cm-builtin {color: #7EA656;} +.cm-s-xq-light span.cm-bracket {color: #cc7;} +.cm-s-xq-light span.cm-tag {color: #3F7F7F;} +.cm-s-xq-light span.cm-attribute {color: #7F007F;} +.cm-s-xq-light span.cm-error {color: #f00;} + +.cm-s-xq-light .CodeMirror-activeline-background {background: #e8f2ff !important;} +.cm-s-xq-light .CodeMirror-matchingbracket {outline:1px solid grey;color:black !important;background:yellow;} \ No newline at end of file diff --git a/static/js/mdeditor/lib/codemirror/theme/zenburn.css b/static/js/mdeditor/lib/codemirror/theme/zenburn.css new file mode 100644 index 00000000..f817198a --- /dev/null +++ b/static/js/mdeditor/lib/codemirror/theme/zenburn.css @@ -0,0 +1,37 @@ +/** + * " + * Using Zenburn color palette from the Emacs Zenburn Theme + * https://github.com/bbatsov/zenburn-emacs/blob/master/zenburn-theme.el + * + * Also using parts of https://github.com/xavi/coderay-lighttable-theme + * " + * From: https://github.com/wisenomad/zenburn-lighttable-theme/blob/master/zenburn.css + */ + +.cm-s-zenburn .CodeMirror-gutters { background: #3f3f3f !important; } +.cm-s-zenburn .CodeMirror-foldgutter-open, .CodeMirror-foldgutter-folded { color: #999; } +.cm-s-zenburn .CodeMirror-cursor { border-left: 1px solid white !important; } +.cm-s-zenburn { background-color: #3f3f3f; color: #dcdccc; } +.cm-s-zenburn span.cm-builtin { color: #dcdccc; font-weight: bold; } +.cm-s-zenburn span.cm-comment { color: #7f9f7f; } +.cm-s-zenburn span.cm-keyword { color: #f0dfaf; font-weight: bold; } +.cm-s-zenburn span.cm-atom { color: #bfebbf; } +.cm-s-zenburn span.cm-def { color: #dcdccc; } +.cm-s-zenburn span.cm-variable { color: #dfaf8f; } +.cm-s-zenburn span.cm-variable-2 { color: #dcdccc; } +.cm-s-zenburn span.cm-string { color: #cc9393; } +.cm-s-zenburn span.cm-string-2 { color: #cc9393; } +.cm-s-zenburn span.cm-number { color: #dcdccc; } +.cm-s-zenburn span.cm-tag { color: #93e0e3; } +.cm-s-zenburn span.cm-property { color: #dfaf8f; } +.cm-s-zenburn span.cm-attribute { color: #dfaf8f; } +.cm-s-zenburn span.cm-qualifier { color: #7cb8bb; } +.cm-s-zenburn span.cm-meta { color: #f0dfaf; } +.cm-s-zenburn span.cm-header { color: #f0efd0; } +.cm-s-zenburn span.cm-operator { color: #f0efd0; } +.cm-s-zenburn span.CodeMirror-matchingbracket { box-sizing: border-box; background: transparent; border-bottom: 1px solid; } +.cm-s-zenburn span.CodeMirror-nonmatchingbracket { border-bottom: 1px solid; background: none; } +.cm-s-zenburn .CodeMirror-activeline { background: #000000; } +.cm-s-zenburn .CodeMirror-activeline-background { background: #000000; } +.cm-s-zenburn .CodeMirror-selected { background: #545454; } +.cm-s-zenburn .CodeMirror-focused .CodeMirror-selected { background: #4f4f4f; } diff --git a/static/js/mdeditor/lib/flowchart.min.js b/static/js/mdeditor/lib/flowchart.min.js new file mode 100644 index 00000000..78080210 --- /dev/null +++ b/static/js/mdeditor/lib/flowchart.min.js @@ -0,0 +1,5 @@ +// flowchart, v1.3.4 +// Copyright (c)2014 Adriano Raiano (adrai). +// Distributed under MIT license +// http://adrai.github.io/flowchart.js +!function(){function a(b,c){if(!b||"function"==typeof b)return c;var d={};for(var e in c)d[e]=c[e];for(e in b)b[e]&&(d[e]="object"==typeof d[e]?a(d[e],b[e]):b[e]);return d}function b(a,b){if("function"==typeof Object.create)a.super_=b,a.prototype=Object.create(b.prototype,{constructor:{value:a,enumerable:!1,writable:!0,configurable:!0}});else{a.super_=b;var c=function(){};c.prototype=b.prototype,a.prototype=new c,a.prototype.constructor=a}}function c(a,b,c){var d,e,f="M{0},{1}";for(d=2,e=2*c.length+2;e>d;d+=2)f+=" L{"+d+"},{"+(d+1)+"}";var g=[b.x,b.y];for(d=0,e=c.length;e>d;d++)g.push(c[d].x),g.push(c[d].y);var h=a.paper.path(f,g);h.attr("stroke",a.options["element-color"]),h.attr("stroke-width",a.options["line-width"]);var i=a.options.font,j=a.options["font-family"],k=a.options["font-weight"];return i&&h.attr({font:i}),j&&h.attr({"font-family":j}),k&&h.attr({"font-weight":k}),h}function d(a,b,c,d){var e,f;"[object Array]"!==Object.prototype.toString.call(c)&&(c=[c]);var g="M{0},{1}";for(e=2,f=2*c.length+2;f>e;e+=2)g+=" L{"+e+"},{"+(e+1)+"}";var h=[b.x,b.y];for(e=0,f=c.length;f>e;e++)h.push(c[e].x),h.push(c[e].y);var i=a.paper.path(g,h);i.attr({stroke:a.options["line-color"],"stroke-width":a.options["line-width"],"arrow-end":a.options["arrow-end"]});var j=a.options.font,k=a.options["font-family"],l=a.options["font-weight"];if(j&&i.attr({font:j}),k&&i.attr({"font-family":k}),l&&i.attr({"font-weight":l}),d){var m=!1,n=a.paper.text(0,0,d),o=!1,p=c[0];b.y===p.y&&(o=!0);var q=0,r=0;m?(q=b.x>p.x?b.x-(b.x-p.x)/2:p.x-(p.x-b.x)/2,r=b.y>p.y?b.y-(b.y-p.y)/2:p.y-(p.y-b.y)/2,o?(q-=n.getBBox().width/2,r-=a.options["text-margin"]):(q+=a.options["text-margin"],r-=n.getBBox().height/2)):(q=b.x,r=b.y,o?(q+=a.options["text-margin"]/2,r-=a.options["text-margin"]):(q+=a.options["text-margin"]/2,r+=a.options["text-margin"])),n.attr({"text-anchor":"start","font-size":a.options["font-size"],fill:a.options["font-color"],x:q,y:r}),j&&n.attr({font:j}),k&&n.attr({"font-family":k}),l&&n.attr({"font-weight":l})}return i}function e(a,b,c,d,e,f,g,h){var i,j,k,l,m,n={x:null,y:null,onLine1:!1,onLine2:!1};return i=(h-f)*(c-a)-(g-e)*(d-b),0===i?n:(j=b-f,k=a-e,l=(g-e)*j-(h-f)*k,m=(c-a)*j-(d-b)*k,j=l/i,k=m/i,n.x=a+j*(c-a),n.y=b+j*(d-b),j>0&&1>j&&(n.onLine1=!0),k>0&&1>k&&(n.onLine2=!0),n)}function f(a,b){b=b||{},this.paper=new Raphael(a),this.options=r.defaults(b,q),this.symbols=[],this.lines=[],this.start=null}function g(a,b,c){this.chart=a,this.group=this.chart.paper.set(),this.symbol=c,this.connectedTo=[],this.symbolType=b.symbolType,this.flowstate=b.flowstate||"future",this.next_direction=b.next&&b.direction_next?b.direction_next:void 0,this.text=this.chart.paper.text(0,0,b.text),b.key&&(this.text.node.id=b.key+"t"),this.text.node.setAttribute("class",this.getAttr("class")+"t"),this.text.attr({"text-anchor":"start",x:this.getAttr("text-margin"),fill:this.getAttr("font-color"),"font-size":this.getAttr("font-size")});var d=this.getAttr("font"),e=this.getAttr("font-family"),f=this.getAttr("font-weight");d&&this.text.attr({font:d}),e&&this.text.attr({"font-family":e}),f&&this.text.attr({"font-weight":f}),b.link&&this.text.attr("href",b.link),b.target&&this.text.attr("target",b.target);var g=this.getAttr("maxWidth");if(g){for(var h=b.text.split(" "),i="",j=0,k=h.length;k>j;j++){var l=h[j];this.text.attr("text",i+" "+l),i+=this.text.getBBox().width>g?"\n"+l:" "+l}this.text.attr("text",i.substring(1))}if(this.group.push(this.text),c){var m=this.getAttr("text-margin");c.attr({fill:this.getAttr("fill"),stroke:this.getAttr("element-color"),"stroke-width":this.getAttr("line-width"),width:this.text.getBBox().width+2*m,height:this.text.getBBox().height+2*m}),c.node.setAttribute("class",this.getAttr("class")),b.link&&c.attr("href",b.link),b.target&&c.attr("target",b.target),b.key&&(c.node.id=b.key),this.group.push(c),c.insertBefore(this.text),this.text.attr({y:c.getBBox().height/2}),this.initialize()}}function h(a,b){var c=a.paper.rect(0,0,0,0,20);b=b||{},b.text=b.text||"Start",g.call(this,a,b,c)}function i(a,b){var c=a.paper.rect(0,0,0,0,20);b=b||{},b.text=b.text||"End",g.call(this,a,b,c)}function j(a,b){var c=a.paper.rect(0,0,0,0);b=b||{},g.call(this,a,b,c)}function k(a,b){var c=a.paper.rect(0,0,0,0);b=b||{},g.call(this,a,b,c),c.attr({width:this.text.getBBox().width+4*this.getAttr("text-margin")}),this.text.attr({x:2*this.getAttr("text-margin")});var d=a.paper.rect(0,0,0,0);d.attr({x:this.getAttr("text-margin"),stroke:this.getAttr("element-color"),"stroke-width":this.getAttr("line-width"),width:this.text.getBBox().width+2*this.getAttr("text-margin"),height:this.text.getBBox().height+2*this.getAttr("text-margin"),fill:this.getAttr("fill")}),b.key&&(d.node.id=b.key+"i");var e=this.getAttr("font"),f=this.getAttr("font-family"),h=this.getAttr("font-weight");e&&d.attr({font:e}),f&&d.attr({"font-family":f}),h&&d.attr({"font-weight":h}),b.link&&d.attr("href",b.link),b.target&&d.attr("target",b.target),this.group.push(d),d.insertBefore(this.text),this.initialize()}function l(a,b){b=b||{},g.call(this,a,b),this.textMargin=this.getAttr("text-margin"),this.text.attr({x:3*this.textMargin});var d=this.text.getBBox().width+4*this.textMargin,e=this.text.getBBox().height+2*this.textMargin,f=this.textMargin,h=e/2,i={x:f,y:h},j=[{x:f-this.textMargin,y:e},{x:f-this.textMargin+d,y:e},{x:f-this.textMargin+d+2*this.textMargin,y:0},{x:f-this.textMargin+2*this.textMargin,y:0},{x:f,y:h}],k=c(a,i,j);k.attr({stroke:this.getAttr("element-color"),"stroke-width":this.getAttr("line-width"),fill:this.getAttr("fill")}),b.link&&k.attr("href",b.link),b.target&&k.attr("target",b.target),b.key&&(k.node.id=b.key),k.node.setAttribute("class",this.getAttr("class")),this.text.attr({y:k.getBBox().height/2}),this.group.push(k),k.insertBefore(this.text),this.initialize()}function m(a,b){b=b||{},g.call(this,a,b),this.textMargin=this.getAttr("text-margin"),this.yes_direction="bottom",this.no_direction="right",b.yes&&b.direction_yes&&b.no&&!b.direction_no?"right"===b.direction_yes?(this.no_direction="bottom",this.yes_direction="right"):(this.no_direction="right",this.yes_direction="bottom"):b.yes&&!b.direction_yes&&b.no&&b.direction_no?"right"===b.direction_no?(this.yes_direction="bottom",this.no_direction="right"):(this.yes_direction="right",this.no_direction="bottom"):(this.yes_direction="bottom",this.no_direction="right"),this.yes_direction=this.yes_direction||"bottom",this.no_direction=this.no_direction||"right",this.text.attr({x:2*this.textMargin});var d=this.text.getBBox().width+3*this.textMargin;d+=d/2;var e=this.text.getBBox().height+2*this.textMargin;e+=e/2,e=Math.max(.5*d,e);var f=d/4,h=e/4;this.text.attr({x:f+this.textMargin/2});var i={x:f,y:h},j=[{x:f-d/4,y:h+e/4},{x:f-d/4+d/2,y:h+e/4+e/2},{x:f-d/4+d,y:h+e/4},{x:f-d/4+d/2,y:h+e/4-e/2},{x:f-d/4,y:h+e/4}],k=c(a,i,j);k.attr({stroke:this.getAttr("element-color"),"stroke-width":this.getAttr("line-width"),fill:this.getAttr("fill")}),b.link&&k.attr("href",b.link),b.target&&k.attr("target",b.target),b.key&&(k.node.id=b.key),k.node.setAttribute("class",this.getAttr("class")),this.text.attr({y:k.getBBox().height/2}),this.group.push(k),k.insertBefore(this.text),this.initialize()}function n(a){function b(a){var b=a.indexOf("(")+1,c=a.indexOf(")");return b>=0&&c>=0?d.symbols[a.substring(0,b-1)]:d.symbols[a]}function c(a){var b="next",c=a.indexOf("(")+1,d=a.indexOf(")");return c>=0&&d>=0&&(b=D.substring(c,d),b.indexOf(",")<0&&"yes"!==b&&"no"!==b&&(b="next, "+b)),b}a=a||"",a=a.trim();for(var d={symbols:{},start:null,drawSVG:function(a,b){function c(a){if(g[a.key])return g[a.key];switch(a.symbolType){case"start":g[a.key]=new h(e,a);break;case"end":g[a.key]=new i(e,a);break;case"operation":g[a.key]=new j(e,a);break;case"inputoutput":g[a.key]=new l(e,a);break;case"subroutine":g[a.key]=new k(e,a);break;case"condition":g[a.key]=new m(e,a);break;default:return new Error("Wrong symbol type!")}return g[a.key]}var d=this;this.diagram&&this.diagram.clean();var e=new f(a,b);this.diagram=e;var g={};!function n(a,b,f){var g=c(a);return d.start===a?e.startWith(g):b&&f&&!b.pathOk&&(b instanceof m?(f.yes===a&&b.yes(g),f.no===a&&b.no(g)):b.then(g)),g.pathOk?g:(g instanceof m?(a.yes&&n(a.yes,g,a),a.no&&n(a.no,g,a)):a.next&&n(a.next,g,a),g)}(this.start),e.render()},clean:function(){this.diagram.clean()}},e=[],g=0,n=1,o=a.length;o>n;n++)if("\n"===a[n]&&"\\"!==a[n-1]){var p=a.substring(g,n);g=n+1,e.push(p.replace(/\\\n/g,"\n"))}gq;){var s=e[q];s.indexOf(": ")<0&&s.indexOf("(")<0&&s.indexOf(")")<0&&s.indexOf("->")<0&&s.indexOf("=>")<0?(e[q-1]+="\n"+s,e.splice(q,1),r--):q++}for(;e.length>0;){var t=e.splice(0,1)[0];if(t.indexOf("=>")>=0){var u,v=t.split("=>"),w={key:v[0],symbolType:v[1],text:null,link:null,target:null,flowstate:null};if(w.symbolType.indexOf(": ")>=0&&(u=w.symbolType.split(": "),w.symbolType=u[0],w.text=u[1]),w.text&&w.text.indexOf(":>")>=0?(u=w.text.split(":>"),w.text=u[0],w.link=u[1]):w.symbolType.indexOf(":>")>=0&&(u=w.symbolType.split(":>"),w.symbolType=u[0],w.link=u[1]),w.symbolType.indexOf("\n")>=0&&(w.symbolType=w.symbolType.split("\n")[0]),w.link){var x=w.link.indexOf("[")+1,y=w.link.indexOf("]");x>=0&&y>=0&&(w.target=w.link.substring(x,y),w.link=w.link.substring(0,x-1))}if(w.text&&w.text.indexOf("|")>=0){var z=w.text.split("|");w.text=z[0],w.flowstate=z[1].trim()}d.symbols[w.key]=w}else if(t.indexOf("->")>=0)for(var A=t.split("->"),B=0,C=A.length;C>B;B++){var D=A[B],E=b(D),F=c(D),G=null;if(F.indexOf(",")>=0){var H=F.split(",");F=H[0],G=H[1].trim()}if(d.start||(d.start=E),C>B+1){var I=A[B+1];E[F]=b(I),E["direction_"+F]=G,G=null}}}return d}Array.prototype.indexOf||(Array.prototype.indexOf=function(a){"use strict";if(null===this)throw new TypeError;var b=Object(this),c=b.length>>>0;if(0===c)return-1;var d=0;if(arguments.length>0&&(d=Number(arguments[1]),d!=d?d=0:0!==d&&1/0!=d&&d!=-1/0&&(d=(d>0||-1)*Math.floor(Math.abs(d)))),d>=c)return-1;for(var e=d>=0?d:Math.max(c-Math.abs(d),0);c>e;e++)if(e in b&&b[e]===a)return e;return-1}),Array.prototype.lastIndexOf||(Array.prototype.lastIndexOf=function(a){"use strict";if(null===this)throw new TypeError;var b=Object(this),c=b.length>>>0;if(0===c)return-1;var d=c;arguments.length>1&&(d=Number(arguments[1]),d!=d?d=0:0!==d&&d!=1/0&&d!=-(1/0)&&(d=(d>0||-1)*Math.floor(Math.abs(d))));for(var e=d>=0?Math.min(d,c-1):c-Math.abs(d);e>=0;e--)if(e in b&&b[e]===a)return e;return-1}),String.prototype.trim||(String.prototype.trim=function(){return this.replace(/^\s+|\s+$/g,"")});var o=this,p={};"undefined"!=typeof module&&module.exports?module.exports=p:o.flowchart=o.flowchart||p;var q={x:0,y:0,"line-width":3,"line-length":50,"text-margin":10,"font-size":14,"font-color":"black","line-color":"black","element-color":"black",fill:"white","yes-text":"yes","no-text":"no","arrow-end":"block","class":"flowchart",symbols:{start:{},end:{},condition:{},inputoutput:{},operation:{},subroutine:{}}},r={defaults:a,inherits:b};f.prototype.handle=function(a){this.symbols.indexOf(a)<=-1&&this.symbols.push(a);var b=this;return a instanceof m?(a.yes=function(c){return a.yes_symbol=c,a.no_symbol&&(a.pathOk=!0),b.handle(c)},a.no=function(c){return a.no_symbol=c,a.yes_symbol&&(a.pathOk=!0),b.handle(c)}):a.then=function(c){return a.next=c,a.pathOk=!0,b.handle(c)},a},f.prototype.startWith=function(a){return this.start=a,this.handle(a)},f.prototype.render=function(){var a,b=0,c=0,d=0,e=0,f=0,g=0;for(d=0,e=this.symbols.length;e>d;d++)a=this.symbols[d],a.width>b&&(b=a.width),a.height>c&&(c=a.height);for(d=0,e=this.symbols.length;e>d;d++)a=this.symbols[d],a.shiftX(this.options.x+(b-a.width)/2+this.options["line-width"]),a.shiftY(this.options.y+(c-a.height)/2+this.options["line-width"]);for(this.start.render(),d=0,e=this.symbols.length;e>d;d++)a=this.symbols[d],a.renderLines();for(f=this.maxXFromLine,d=0,e=this.symbols.length;e>d;d++){a=this.symbols[d];var h=a.getX()+a.width,i=a.getY()+a.height;h>f&&(f=h),i>g&&(g=i)}this.paper.setSize(f+this.options["line-width"],g+this.options["line-width"])},f.prototype.clean=function(){if(this.paper){var a=this.paper.canvas;a.parentNode.removeChild(a)}},g.prototype.getAttr=function(a){if(!this.chart)return void 0;var b,c=this.chart.options?this.chart.options[a]:void 0,d=this.chart.options.symbols?this.chart.options.symbols[this.symbolType][a]:void 0;return this.chart.options.flowstate&&this.chart.options.flowstate[this.flowstate]&&(b=this.chart.options.flowstate[this.flowstate][a]),b||d||c},g.prototype.initialize=function(){this.group.transform("t"+this.getAttr("line-width")+","+this.getAttr("line-width")),this.width=this.group.getBBox().width,this.height=this.group.getBBox().height},g.prototype.getCenter=function(){return{x:this.getX()+this.width/2,y:this.getY()+this.height/2}},g.prototype.getX=function(){return this.group.getBBox().x},g.prototype.getY=function(){return this.group.getBBox().y},g.prototype.shiftX=function(a){this.group.transform("t"+(this.getX()+a)+","+this.getY())},g.prototype.setX=function(a){this.group.transform("t"+a+","+this.getY())},g.prototype.shiftY=function(a){this.group.transform("t"+this.getX()+","+(this.getY()+a))},g.prototype.setY=function(a){this.group.transform("t"+this.getX()+","+a)},g.prototype.getTop=function(){var a=this.getY(),b=this.getX()+this.width/2;return{x:b,y:a}},g.prototype.getBottom=function(){var a=this.getY()+this.height,b=this.getX()+this.width/2;return{x:b,y:a}},g.prototype.getLeft=function(){var a=this.getY()+this.group.getBBox().height/2,b=this.getX();return{x:b,y:a}},g.prototype.getRight=function(){var a=this.getY()+this.group.getBBox().height/2,b=this.getX()+this.group.getBBox().width;return{x:b,y:a}},g.prototype.render=function(){if(this.next){var a=this.getAttr("line-length");if("right"===this.next_direction){var b=this.getRight();if(this.next.getLeft(),!this.next.isPositioned){this.next.setY(b.y-this.next.height/2),this.next.shiftX(this.group.getBBox().x+this.width+a);var c=this;!function e(){for(var b,d=!1,f=0,g=c.chart.symbols.length;g>f;f++){b=c.chart.symbols[f];var h=Math.abs(b.getCenter().x-c.next.getCenter().x);if(b.getCenter().y>c.next.getCenter().y&&h<=c.next.width/2){d=!0;break}}d&&(c.next.setX(b.getX()+b.width+a),e())}(),this.next.isPositioned=!0,this.next.render()}}else{var d=this.getBottom();this.next.getTop(),this.next.isPositioned||(this.next.shiftY(this.getY()+this.height+a),this.next.setX(d.x-this.next.width/2),this.next.isPositioned=!0,this.next.render())}}},g.prototype.renderLines=function(){this.next&&(this.next_direction?this.drawLineTo(this.next,"",this.next_direction):this.drawLineTo(this.next))},g.prototype.drawLineTo=function(a,b,c){this.connectedTo.indexOf(a)<0&&this.connectedTo.push(a);var f,g=this.getCenter().x,h=this.getCenter().y,i=(this.getTop(),this.getRight()),j=this.getBottom(),k=this.getLeft(),l=a.getCenter().x,m=a.getCenter().y,n=a.getTop(),o=a.getRight(),p=(a.getBottom(),a.getLeft()),q=g===l,r=h===m,s=m>h,t=h>m,u=g>l,v=l>g,w=0,x=this.getAttr("line-length"),y=this.getAttr("line-width");if(c&&"bottom"!==c||!q||!s)if(c&&"right"!==c||!r||!v)if(c&&"left"!==c||!r||!u)if(c&&"right"!==c||!q||!t)if(c&&"right"!==c||!q||!s)if(c&&"bottom"!==c||!u)if(c&&"bottom"!==c||!v)if(c&&"right"===c&&u)f=d(this.chart,i,[{x:i.x+x/2,y:i.y},{x:i.x+x/2,y:n.y-x/2},{x:n.x,y:n.y-x/2},{x:n.x,y:n.y}],b),this.rightStart=!0,a.topEnd=!0,w=i.x+x/2;else if(c&&"right"===c&&v)f=d(this.chart,i,[{x:n.x,y:i.y},{x:n.x,y:n.y}],b),this.rightStart=!0,a.topEnd=!0,w=i.x+x/2;else if(c&&"bottom"===c&&q&&t)f=d(this.chart,j,[{x:j.x,y:j.y+x/2},{x:i.x+x/2,y:j.y+x/2},{x:i.x+x/2,y:n.y-x/2},{x:n.x,y:n.y-x/2},{x:n.x,y:n.y}],b),this.bottomStart=!0,a.topEnd=!0,w=j.x+x/2;else if("left"===c&&q&&t){var z=k.x-x/2;p.xA;A++)for(var C,D=this.chart.lines[A],E=D.attr("path"),F=f.attr("path"),G=0,H=E.length-1;H>G;G++){var I=[];I.push(["M",E[G][1],E[G][2]]),I.push(["L",E[G+1][1],E[G+1][2]]);for(var J=I[0][1],K=I[0][2],L=I[1][1],M=I[1][2],N=0,O=F.length-1;O>N;N++){var P=[];P.push(["M",F[N][1],F[N][2]]),P.push(["L",F[N+1][1],F[N+1][2]]);var Q=P[0][1],R=P[0][2],S=P[1][1],T=P[1][2],U=e(J,K,L,M,Q,R,S,T);if(U.onLine1&&U.onLine2){var V;R===T?Q>S?(V=["L",U.x+2*y,R],F.splice(N+1,0,V),V=["C",U.x+2*y,R,U.x,R-4*y,U.x-2*y,R],F.splice(N+2,0,V),f.attr("path",F)):(V=["L",U.x-2*y,R],F.splice(N+1,0,V),V=["C",U.x-2*y,R,U.x,R-4*y,U.x+2*y,R],F.splice(N+2,0,V),f.attr("path",F)):R>T?(V=["L",Q,U.y+2*y],F.splice(N+1,0,V),V=["C",Q,U.y+2*y,Q+4*y,U.y,Q,U.y-2*y],F.splice(N+2,0,V),f.attr("path",F)):(V=["L",Q,U.y-2*y],F.splice(N+1,0,V),V=["C",Q,U.y-2*y,Q+4*y,U.y,Q,U.y+2*y],F.splice(N+2,0,V),f.attr("path",F)),N+=2,C+=2}}}this.chart.lines.push(f)}(!this.chart.maxXFromLine||this.chart.maxXFromLine&&w>this.chart.maxXFromLine)&&(this.chart.maxXFromLine=w)},r.inherits(h,g),r.inherits(i,g),r.inherits(j,g),r.inherits(k,g),r.inherits(l,g),l.prototype.getLeft=function(){var a=this.getY()+this.group.getBBox().height/2,b=this.getX()+this.textMargin;return{x:b,y:a}},l.prototype.getRight=function(){var a=this.getY()+this.group.getBBox().height/2,b=this.getX()+this.group.getBBox().width-this.textMargin;return{x:b,y:a}},r.inherits(m,g),m.prototype.render=function(){this.yes_direction&&(this[this.yes_direction+"_symbol"]=this.yes_symbol),this.no_direction&&(this[this.no_direction+"_symbol"]=this.no_symbol);var a=this.getAttr("line-length");if(this.bottom_symbol){var b=this.getBottom();this.bottom_symbol.getTop(),this.bottom_symbol.isPositioned||(this.bottom_symbol.shiftY(this.getY()+this.height+a),this.bottom_symbol.setX(b.x-this.bottom_symbol.width/2),this.bottom_symbol.isPositioned=!0,this.bottom_symbol.render())}if(this.right_symbol){var c=this.getRight();if(this.right_symbol.getLeft(),!this.right_symbol.isPositioned){this.right_symbol.setY(c.y-this.right_symbol.height/2),this.right_symbol.shiftX(this.group.getBBox().x+this.width+a);var d=this;!function e(){for(var b,c=!1,f=0,g=d.chart.symbols.length;g>f;f++){b=d.chart.symbols[f];var h=Math.abs(b.getCenter().x-d.right_symbol.getCenter().x);if(b.getCenter().y>d.right_symbol.getCenter().y&&h<=d.right_symbol.width/2){c=!0;break}}c&&(d.right_symbol.setX(b.getX()+b.width+a),e())}(),this.right_symbol.isPositioned=!0,this.right_symbol.render()}}},m.prototype.renderLines=function(){this.yes_symbol&&this.drawLineTo(this.yes_symbol,this.getAttr("yes-text"),this.yes_direction),this.no_symbol&&this.drawLineTo(this.no_symbol,this.getAttr("no-text"),this.no_direction)},p.parse=n}(); \ No newline at end of file diff --git a/static/js/mdeditor/lib/jquery.flowchart.min.js b/static/js/mdeditor/lib/jquery.flowchart.min.js new file mode 100644 index 00000000..a30a8fd1 --- /dev/null +++ b/static/js/mdeditor/lib/jquery.flowchart.min.js @@ -0,0 +1,2 @@ +/*! jQuery.flowchart.js v1.1.0 | jquery.flowchart.min.js | jQuery plugin for flowchart.js. | MIT License | By: Pandao | https://github.com/pandao/jquery.flowchart.js | 2015-03-09 */ +(function(factory){if(typeof require==="function"&&typeof exports==="object"&&typeof module==="object"){module.exports=factory}else{if(typeof define==="function"){factory(jQuery,flowchart)}else{factory($,flowchart)}}}(function(jQuery,flowchart){(function($){$.fn.flowChart=function(options){options=options||{};var defaults={"x":0,"y":0,"line-width":2,"line-length":50,"text-margin":10,"font-size":14,"font-color":"black","line-color":"black","element-color":"black","fill":"white","yes-text":"yes","no-text":"no","arrow-end":"block","symbols":{"start":{"font-color":"black","element-color":"black","fill":"white"},"end":{"class":"end-element"}},"flowstate":{"past":{"fill":"#CCCCCC","font-size":12},"current":{"fill":"black","font-color":"white","font-weight":"bold"},"future":{"fill":"white"},"request":{"fill":"blue"},"invalid":{"fill":"#444444"},"approved":{"fill":"#58C4A3","font-size":12,"yes-text":"APPROVED","no-text":"n/a"},"rejected":{"fill":"#C45879","font-size":12,"yes-text":"n/a","no-text":"REJECTED"}}};return this.each(function(){var $this=$(this);var diagram=flowchart.parse($this.text());var settings=$.extend(true,defaults,options);$this.html("");diagram.drawSVG(this,settings)})}})(jQuery)})); \ No newline at end of file diff --git a/static/js/mdeditor/lib/marked.min.js b/static/js/mdeditor/lib/marked.min.js new file mode 100644 index 00000000..5597fa44 --- /dev/null +++ b/static/js/mdeditor/lib/marked.min.js @@ -0,0 +1,9 @@ +/** + * marked v0.3.3 - a markdown parser + * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed) + * https://github.com/chjj/marked + */ +(function(){var block={newline:/^\n+/,code:/^( {4}[^\n]+\n*)+/,fences:noop,hr:/^( *[-*_]){3,} *(?:\n+|$)/,heading:/^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,nptable:noop,lheading:/^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,blockquote:/^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,list:/^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,html:/^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,def:/^ *\[([^\]]+)\]: *]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,table:noop,paragraph:/^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,text:/^[^\n]+/};block.bullet=/(?:[*+-]|\d+\.)/;block.item=/^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;block.item=replace(block.item,"gm")(/bull/g,block.bullet)();block.list=replace(block.list)(/bull/g,block.bullet)("hr","\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))")("def","\\n+(?="+block.def.source+")")();block.blockquote=replace(block.blockquote)("def",block.def)();block._tag="(?!(?:"+"a|em|strong|small|s|cite|q|dfn|abbr|data|time|code"+"|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo"+"|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b";block.html=replace(block.html)("comment",//)("closed",/<(tag)[\s\S]+?<\/\1>/)("closing",/])*?>/)(/tag/g,block._tag)();block.paragraph=replace(block.paragraph)("hr",block.hr)("heading",block.heading)("lheading",block.lheading)("blockquote",block.blockquote)("tag","<"+block._tag)("def",block.def)();block.normal=merge({},block);block.gfm=merge({},block.normal,{fences:/^ *(`{3,}|~{3,}) *(\S+)? *\n([\s\S]+?)\s*\1 *(?:\n+|$)/,paragraph:/^/});block.gfm.paragraph=replace(block.paragraph)("(?!","(?!"+block.gfm.fences.source.replace("\\1","\\2")+"|"+block.list.source.replace("\\1","\\3")+"|")();block.tables=merge({},block.gfm,{nptable:/^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,table:/^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/});function Lexer(options){this.tokens=[];this.tokens.links={};this.options=options||marked.defaults;this.rules=block.normal;if(this.options.gfm){if(this.options.tables){this.rules=block.tables}else{this.rules=block.gfm}}}Lexer.rules=block;Lexer.lex=function(src,options){var lexer=new Lexer(options);return lexer.lex(src)};Lexer.prototype.lex=function(src){src=src.replace(/\r\n|\r/g,"\n").replace(/\t/g," ").replace(/\u00a0/g," ").replace(/\u2424/g,"\n");return this.token(src,true)};Lexer.prototype.token=function(src,top,bq){var src=src.replace(/^ +$/gm,""),next,loose,cap,bull,b,item,space,i,l;while(src){if(cap=this.rules.newline.exec(src)){src=src.substring(cap[0].length);if(cap[0].length>1){this.tokens.push({type:"space"})}}if(cap=this.rules.code.exec(src)){src=src.substring(cap[0].length);cap=cap[0].replace(/^ {4}/gm,"");this.tokens.push({type:"code",text:!this.options.pedantic?cap.replace(/\n+$/,""):cap});continue}if(cap=this.rules.fences.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"code",lang:cap[2],text:cap[3]});continue}if(cap=this.rules.heading.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"heading",depth:cap[1].length,text:cap[2]});continue}if(top&&(cap=this.rules.nptable.exec(src))){src=src.substring(cap[0].length);item={type:"table",header:cap[1].replace(/^ *| *\| *$/g,"").split(/ *\| */),align:cap[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:cap[3].replace(/\n$/,"").split("\n")};for(i=0;i ?/gm,"");this.token(cap,top,true);this.tokens.push({type:"blockquote_end"});continue}if(cap=this.rules.list.exec(src)){src=src.substring(cap[0].length);bull=cap[2];this.tokens.push({type:"list_start",ordered:bull.length>1});cap=cap[0].match(this.rules.item);next=false;l=cap.length;i=0;for(;i1&&b.length>1)){src=cap.slice(i+1).join("\n")+src;i=l-1}}loose=next||/\n\n(?!\s*$)/.test(item);if(i!==l-1){next=item.charAt(item.length-1)==="\n";if(!loose){loose=next}}this.tokens.push({type:loose?"loose_item_start":"list_item_start"});this.token(item,false,bq); +this.tokens.push({type:"list_item_end"})}this.tokens.push({type:"list_end"});continue}if(cap=this.rules.html.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:this.options.sanitize?"paragraph":"html",pre:cap[1]==="pre"||cap[1]==="script"||cap[1]==="style",text:cap[0]});continue}if((!bq&&top)&&(cap=this.rules.def.exec(src))){src=src.substring(cap[0].length);this.tokens.links[cap[1].toLowerCase()]={href:cap[2],title:cap[3]};continue}if(top&&(cap=this.rules.table.exec(src))){src=src.substring(cap[0].length);item={type:"table",header:cap[1].replace(/^ *| *\| *$/g,"").split(/ *\| */),align:cap[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:cap[3].replace(/(?: *\| *)?\n$/,"").split("\n")};for(i=0;i])/,autolink:/^<([^ >]+(@|:\/)[^ >]+)>/,url:noop,tag:/^|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,link:/^!?\[(inside)\]\(href\)/,reflink:/^!?\[(inside)\]\s*\[([^\]]*)\]/,nolink:/^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,strong:/^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,em:/^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,code:/^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,br:/^ {2,}\n(?!\s*$)/,del:noop,text:/^[\s\S]+?(?=[\\?(?:\s+['"]([\s\S]*?)['"])?\s*/;inline.link=replace(inline.link)("inside",inline._inside)("href",inline._href)();inline.reflink=replace(inline.reflink)("inside",inline._inside)();inline.normal=merge({},inline);inline.pedantic=merge({},inline.normal,{strong:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,em:/^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/});inline.gfm=merge({},inline.normal,{escape:replace(inline.escape)("])","~|])")(),url:/^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,del:/^~~(?=\S)([\s\S]*?\S)~~/,text:replace(inline.text)("]|","~]|")("|","|https?://|")()});inline.breaks=merge({},inline.gfm,{br:replace(inline.br)("{2,}","*")(),text:replace(inline.gfm.text)("{2,}","*")()});function InlineLexer(links,options){this.options=options||marked.defaults;this.links=links;this.rules=inline.normal;this.renderer=this.options.renderer||new Renderer;this.renderer.options=this.options;if(!this.links){throw new Error("Tokens array requires a `links` property.")}if(this.options.gfm){if(this.options.breaks){this.rules=inline.breaks}else{this.rules=inline.gfm}}else{if(this.options.pedantic){this.rules=inline.pedantic}}}InlineLexer.rules=inline;InlineLexer.output=function(src,links,options){var inline=new InlineLexer(links,options);return inline.output(src)};InlineLexer.prototype.output=function(src){var out="",link,text,href,cap;while(src){if(cap=this.rules.escape.exec(src)){src=src.substring(cap[0].length);out+=cap[1];continue}if(cap=this.rules.autolink.exec(src)){src=src.substring(cap[0].length);if(cap[2]==="@"){text=cap[1].charAt(6)===":"?this.mangle(cap[1].substring(7)):this.mangle(cap[1]);href=this.mangle("mailto:")+text}else{text=escape(cap[1]);href=text}out+=this.renderer.link(href,null,text);continue}if(!this.inLink&&(cap=this.rules.url.exec(src))){src=src.substring(cap[0].length);text=escape(cap[1]);href=text;out+=this.renderer.link(href,null,text);continue}if(cap=this.rules.tag.exec(src)){if(!this.inLink&&/^/i.test(cap[0])){this.inLink=false}}src=src.substring(cap[0].length);out+=this.options.sanitize?escape(cap[0]):cap[0];continue}if(cap=this.rules.link.exec(src)){src=src.substring(cap[0].length);this.inLink=true;out+=this.outputLink(cap,{href:cap[2],title:cap[3]});this.inLink=false;continue}if((cap=this.rules.reflink.exec(src))||(cap=this.rules.nolink.exec(src))){src=src.substring(cap[0].length);link=(cap[2]||cap[1]).replace(/\s+/g," ");link=this.links[link.toLowerCase()];if(!link||!link.href){out+=cap[0].charAt(0);src=cap[0].substring(1)+src;continue}this.inLink=true;out+=this.outputLink(cap,link);this.inLink=false;continue}if(cap=this.rules.strong.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.strong(this.output(cap[2]||cap[1]));continue}if(cap=this.rules.em.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.em(this.output(cap[2]||cap[1]));continue +}if(cap=this.rules.code.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.codespan(escape(cap[2],true));continue}if(cap=this.rules.br.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.br();continue}if(cap=this.rules.del.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.del(this.output(cap[1]));continue}if(cap=this.rules.text.exec(src)){src=src.substring(cap[0].length);out+=escape(this.smartypants(cap[0]));continue}if(src){throw new Error("Infinite loop on byte: "+src.charCodeAt(0))}}return out};InlineLexer.prototype.outputLink=function(cap,link){var href=escape(link.href),title=link.title?escape(link.title):null;return cap[0].charAt(0)!=="!"?this.renderer.link(href,title,this.output(cap[1])):this.renderer.image(href,title,escape(cap[1]))};InlineLexer.prototype.smartypants=function(text){if(!this.options.smartypants){return text}return text.replace(/--/g,"\u2014").replace(/(^|[-\u2014/(\[{"\s])'/g,"$1\u2018").replace(/'/g,"\u2019").replace(/(^|[-\u2014/(\[{\u2018\s])"/g,"$1\u201c").replace(/"/g,"\u201d").replace(/\.{3}/g,"\u2026")};InlineLexer.prototype.mangle=function(text){var out="",l=text.length,i=0,ch;for(;i0.5){ch="x"+ch.toString(16)}out+="&#"+ch+";"}return out};function Renderer(options){this.options=options||{}}Renderer.prototype.code=function(code,lang,escaped){if(this.options.highlight){var out=this.options.highlight(code,lang);if(out!=null&&out!==code){escaped=true;code=out}}if(!lang){return"
    "+(escaped?code:escape(code,true))+"\n
    "}return'
    '+(escaped?code:escape(code,true))+"\n
    \n"};Renderer.prototype.blockquote=function(quote){return"
    \n"+quote+"
    \n"};Renderer.prototype.html=function(html){return html};Renderer.prototype.heading=function(text,level,raw){return"'+text+"\n"};Renderer.prototype.hr=function(){return this.options.xhtml?"
    \n":"
    \n"};Renderer.prototype.list=function(body,ordered){var type=ordered?"ol":"ul";return"<"+type+">\n"+body+"\n"};Renderer.prototype.listitem=function(text){return"
  • "+text+"
  • \n"};Renderer.prototype.paragraph=function(text){return"

    "+text+"

    \n"};Renderer.prototype.table=function(header,body){return"\n"+"\n"+header+"\n"+"\n"+body+"\n"+"
    \n"};Renderer.prototype.tablerow=function(content){return"\n"+content+"\n"};Renderer.prototype.tablecell=function(content,flags){var type=flags.header?"th":"td";var tag=flags.align?"<"+type+' style="text-align:'+flags.align+'">':"<"+type+">";return tag+content+"\n"};Renderer.prototype.strong=function(text){return""+text+""};Renderer.prototype.em=function(text){return""+text+""};Renderer.prototype.codespan=function(text){return""+text+""};Renderer.prototype.br=function(){return this.options.xhtml?"
    ":"
    "};Renderer.prototype.del=function(text){return""+text+""};Renderer.prototype.link=function(href,title,text){if(this.options.sanitize){try{var prot=decodeURIComponent(unescape(href)).replace(/[^\w:]/g,"").toLowerCase()}catch(e){return""}if(prot.indexOf("javascript:")===0||prot.indexOf("vbscript:")===0){return""}}var out='
    ";return out};Renderer.prototype.image=function(href,title,text){var out=''+text+'":">";return out};function Parser(options){this.tokens=[];this.token=null;this.options=options||marked.defaults;this.options.renderer=this.options.renderer||new Renderer;this.renderer=this.options.renderer;this.renderer.options=this.options}Parser.parse=function(src,options,renderer){var parser=new Parser(options,renderer);return parser.parse(src)};Parser.prototype.parse=function(src){this.inline=new InlineLexer(src.links,this.options,this.renderer);this.tokens=src.reverse();var out="";while(this.next()){out+=this.tok()}return out};Parser.prototype.next=function(){return this.token=this.tokens.pop()};Parser.prototype.peek=function(){return this.tokens[this.tokens.length-1]||0};Parser.prototype.parseText=function(){var body=this.token.text;while(this.peek().type==="text"){body+="\n"+this.next().text}return this.inline.output(body)};Parser.prototype.tok=function(){switch(this.token.type){case"space":return"";case"hr":return this.renderer.hr();case"heading":return this.renderer.heading(this.inline.output(this.token.text),this.token.depth,this.token.text);case"code":return this.renderer.code(this.token.text,this.token.lang,this.token.escaped);case"table":var header="",body="",i,row,cell,flags,j;cell="";for(i=0;i/g,">").replace(/"/g,""").replace(/'/g,"'")}function unescape(html){return html.replace(/&([#\w]+);/g,function(_,n){n=n.toLowerCase();if(n==="colon"){return":"}if(n.charAt(0)==="#"){return n.charAt(1)==="x"?String.fromCharCode(parseInt(n.substring(2),16)):String.fromCharCode(+n.substring(1))}return""})}function replace(regex,opt){regex=regex.source;opt=opt||"";return function self(name,val){if(!name){return new RegExp(regex,opt)}val=val.source||val;val=val.replace(/(^|[^\[])\^/g,"$1");regex=regex.replace(name,val);return self}}function noop(){}noop.exec=noop;function merge(obj){var i=1,target,key;for(;iAn error occured:

    "+escape(e.message+"",true)+"
    "}throw e}}marked.options=marked.setOptions=function(opt){merge(marked.defaults,opt);return marked};marked.defaults={gfm:true,tables:true,breaks:false,pedantic:false,sanitize:false,smartLists:false,silent:false,highlight:null,langPrefix:"lang-",smartypants:false,headerPrefix:"",renderer:new Renderer,xhtml:false};marked.Parser=Parser;marked.parser=Parser.parse;marked.Renderer=Renderer;marked.Lexer=Lexer;marked.lexer=Lexer.lex;marked.InlineLexer=InlineLexer;marked.inlineLexer=InlineLexer.output;marked.parse=marked;if(typeof module!=="undefined"&&typeof exports==="object"){module.exports=marked}else{if(typeof define==="function"&&define.amd){define(function(){return marked})}else{this.marked=marked}}}).call(function(){return this||(typeof window!=="undefined"?window:global)}()); \ No newline at end of file diff --git a/static/js/mdeditor/lib/prettify.min.js b/static/js/mdeditor/lib/prettify.min.js new file mode 100644 index 00000000..056f9689 --- /dev/null +++ b/static/js/mdeditor/lib/prettify.min.js @@ -0,0 +1,15 @@ +// Copyright (C) 2006 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var IN_GLOBAL_SCOPE=true;window["PR_SHOULD_USE_CONTINUATION"]=true;var prettyPrintOne;var prettyPrint;(function(){var P=window;var i=["break,continue,do,else,for,if,return,while"];var u=[i,"auto,case,char,const,default,"+"double,enum,extern,float,goto,inline,int,long,register,short,signed,"+"sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"];var p=[u,"catch,class,delete,false,import,"+"new,operator,private,protected,public,this,throw,true,try,typeof"];var l=[p,"alignof,align_union,asm,axiom,bool,"+"concept,concept_map,const_cast,constexpr,decltype,delegate,"+"dynamic_cast,explicit,export,friend,generic,late_check,"+"mutable,namespace,nullptr,property,reinterpret_cast,static_assert,"+"static_cast,template,typeid,typename,using,virtual,where"];var y=[p,"abstract,assert,boolean,byte,extends,final,finally,implements,import,"+"instanceof,interface,null,native,package,strictfp,super,synchronized,"+"throws,transient"];var U=[y,"as,base,by,checked,decimal,delegate,descending,dynamic,event,"+"fixed,foreach,from,group,implicit,in,internal,into,is,let,"+"lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,"+"sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,"+"var,virtual,where"];var r="all,and,by,catch,class,else,extends,false,finally,"+"for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,"+"throw,true,try,unless,until,when,while,yes";var x=[p,"debugger,eval,export,function,get,null,set,undefined,var,with,"+"Infinity,NaN"];var s="caller,delete,die,do,dump,elsif,eval,exit,foreach,for,"+"goto,if,import,last,local,my,next,no,our,print,package,redo,require,"+"sub,undef,unless,until,use,wantarray,while,BEGIN,END";var K=[i,"and,as,assert,class,def,del,"+"elif,except,exec,finally,from,global,import,in,is,lambda,"+"nonlocal,not,or,pass,print,raise,try,with,yield,"+"False,True,None"];var g=[i,"alias,and,begin,case,class,"+"def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,"+"rescue,retry,self,super,then,true,undef,unless,until,when,yield,"+"BEGIN,END"];var z=[i,"as,assert,const,copy,drop,"+"enum,extern,fail,false,fn,impl,let,log,loop,match,mod,move,mut,priv,"+"pub,pure,ref,self,static,struct,true,trait,type,unsafe,use"];var J=[i,"case,done,elif,esac,eval,fi,"+"function,in,local,set,then,until"];var C=[l,U,x,s,K,g,J];var e=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)\b/;var E="str";var B="kwd";var j="com";var R="typ";var I="lit";var N="pun";var H="pln";var m="tag";var G="dec";var L="src";var S="atn";var n="atv";var Q="nocode";var O="(?:^^\\.?|[+-]|[!=]=?=?|\\#|%=?|&&?=?|\\(|\\*=?|[+\\-]=|->|\\/=?|::?|<>?>?=?|,|;|\\?|@|\\[|~|{|\\^\\^?=?|\\|\\|?=?|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*";function k(ac){var ag=0;var V=false;var af=false;for(var Y=0,X=ac.length;Y122)){if(!(an<65||aj>90)){ai.push([Math.max(65,aj)|32,Math.min(an,90)|32])}if(!(an<97||aj>122)){ai.push([Math.max(97,aj)&~32,Math.min(an,122)&~32])}}}}ai.sort(function(ax,aw){return(ax[0]-aw[0])||(aw[1]-ax[1])});var al=[];var ar=[];for(var au=0;auav[0]){if(av[1]+1>av[0]){ap.push("-")}ap.push(W(av[1]))}}ap.push("]");return ap.join("")}function Z(ao){var am=ao.source.match(new RegExp("(?:"+"\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]"+"|\\\\u[A-Fa-f0-9]{4}"+"|\\\\x[A-Fa-f0-9]{2}"+"|\\\\[0-9]+"+"|\\\\[^ux0-9]"+"|\\(\\?[:!=]"+"|[\\(\\)\\^]"+"|[^\\x5B\\x5C\\(\\)\\^]+"+")","g"));var ak=am.length;var aq=[];for(var an=0,ap=0;an=2&&al==="["){am[an]=aa(aj)}else{if(al!=="\\"){am[an]=aj.replace(/[a-zA-Z]/g,function(ar){var at=ar.charCodeAt(0);return"["+String.fromCharCode(at&~32,at|32)+"]"})}}}}return am.join("")}var ad=[];for(var Y=0,X=ac.length;Y=0;){V[af.charAt(ah)]=ab}}var ai=ab[1];var ad=""+ai;if(!aj.hasOwnProperty(ad)){ak.push(ai);aj[ad]=null}}ak.push(/[\0-\uffff]/);Y=k(ak)})();var aa=W.length;var Z=function(ak){var ac=ak.sourceCode,ab=ak.basePos;var ag=[ab,H];var ai=0;var aq=ac.match(Y)||[];var am={};for(var ah=0,au=aq.length;ah=5&&"lang-"===at.substring(0,5);if(ap&&!(al&&typeof al[1]==="string")){ap=false;at=L}if(!ap){am[aj]=at}}var ae=ai;ai+=aj.length;if(!ap){ag.push(ab+ae,at)}else{var ao=al[1];var an=aj.indexOf(ao);var af=an+ao.length;if(al[2]){af=aj.length-al[2].length;an=af-ao.length}var av=at.substring(5);D(ab+ae,aj.substring(0,an),Z,ag);D(ab+ae+an,ao,q(av,ao),ag);D(ab+ae+af,aj.substring(af),Z,ag)}}ak.decorations=ag};return Z}function h(af){var X=[],ab=[];if(af["tripleQuotedStrings"]){X.push([E,/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,null,"'\""])}else{if(af["multiLineStrings"]){X.push([E,/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,null,"'\"`"])}else{X.push([E,/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,null,"\"'"])}}if(af["verbatimStrings"]){ab.push([E,/^@\"(?:[^\"]|\"\")*(?:\"|$)/,null])}var ad=af["hashComments"];if(ad){if(af["cStyleComments"]){if(ad>1){X.push([j,/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,null,"#"])}else{X.push([j,/^#(?:(?:define|e(?:l|nd)if|else|error|ifn?def|include|line|pragma|undef|warning)\b|[^\r\n]*)/,null,"#"])}ab.push([E,/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h(?:h|pp|\+\+)?|[a-z]\w*)>/,null])}else{X.push([j,/^#[^\r\n]*/,null,"#"])}}if(af["cStyleComments"]){ab.push([j,/^\/\/[^\r\n]*/,null]);ab.push([j,/^\/\*[\s\S]*?(?:\*\/|$)/,null])}var W=af["regexLiterals"];if(W){var Y=W>1?"":"\n\r";var aa=Y?".":"[\\S\\s]";var Z=("/(?=[^/*"+Y+"])"+"(?:[^/\\x5B\\x5C"+Y+"]"+"|\\x5C"+aa+"|\\x5B(?:[^\\x5C\\x5D"+Y+"]"+"|\\x5C"+aa+")*(?:\\x5D|$))+"+"/");ab.push(["lang-regex",RegExp("^"+O+"("+Z+")")])}var ae=af["types"];if(ae){ab.push([R,ae])}var ac=(""+af["keywords"]).replace(/^ | $/g,"");if(ac.length){ab.push([B,new RegExp("^(?:"+ac.replace(/[\s,]+/g,"|")+")\\b"),null])}X.push([H,/^\s+/,null," \r\n\t\xA0"]);var V="^.[^\\s\\w.$@'\"`/\\\\]*";if(af["regexLiterals"]){V+="(?!s*/)"}ab.push([I,/^@[a-z_$][a-z_$@0-9]*/i,null],[R,/^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/,null],[H,/^[a-z_$][a-z_$@0-9]*/i,null],[I,new RegExp("^(?:"+"0x[a-f0-9]+"+"|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)"+"(?:e[+\\-]?\\d+)?"+")"+"[a-z]*","i"),null,"0123456789"],[H,/^\\[\s\S]?/,null],[N,new RegExp(V),null]);return f(X,ab)}var M=h({"keywords":C,"hashComments":true,"cStyleComments":true,"multiLineStrings":true,"regexLiterals":true});function T(X,ai,ab){var W=/(?:^|\s)nocode(?:\s|$)/;var ad=/\r\n?|\n/;var ae=X.ownerDocument;var ah=ae.createElement("li");while(X.firstChild){ah.appendChild(X.firstChild)}var Y=[ah];function ag(ao){var an=ao.nodeType;if(an==1&&!W.test(ao.className)){if("br"===ao.nodeName){af(ao);if(ao.parentNode){ao.parentNode.removeChild(ao)}}else{for(var aq=ao.firstChild;aq;aq=aq.nextSibling){ag(aq)}}}else{if((an==3||an==4)&&ab){var ap=ao.nodeValue;var al=ap.match(ad);if(al){var ak=ap.substring(0,al.index);ao.nodeValue=ak;var aj=ap.substring(al.index+al[0].length);if(aj){var am=ao.parentNode;am.insertBefore(ae.createTextNode(aj),ao.nextSibling)}af(ao);if(!ak){ao.parentNode.removeChild(ao)}}}}}function af(am){while(!am.nextSibling){am=am.parentNode;if(!am){return}}function ak(an,au){var at=au?an.cloneNode(false):an;var aq=an.parentNode;if(aq){var ar=ak(aq,1);var ap=an.nextSibling;ar.appendChild(at);for(var ao=ap;ao;ao=ap){ap=ao.nextSibling;ar.appendChild(ao)}}return at}var aj=ak(am.nextSibling,0);for(var al;(al=aj.parentNode)&&al.nodeType===1;){aj=al}Y.push(aj)}for(var aa=0;aa=V){ak+=2}if(Z>=at){ad+=2}}}finally{if(av){av.style.display=al}}}var t={};function c(X,Y){for(var V=Y.length;--V>=0;){var W=Y[V];if(!t.hasOwnProperty(W)){t[W]=X}else{if(P["console"]){console["warn"]("cannot override language handler %s",W)}}}}function q(W,V){if(!(W&&t.hasOwnProperty(W))){W=/^\s*]*(?:>|$)/],[j,/^<\!--[\s\S]*?(?:-\->|$)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],[N,/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);c(f([[H,/^[\s]+/,null," \t\r\n"],[n,/^(?:\"[^\"]*\"?|\'[^\']*\'?)/,null,"\"'"]],[[m,/^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],[S,/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],[N,/^[=<>\/]+/],["lang-js",/^on\w+\s*=\s*\"([^\"]+)\"/i],["lang-js",/^on\w+\s*=\s*\'([^\']+)\'/i],["lang-js",/^on\w+\s*=\s*([^\"\'>\s]+)/i],["lang-css",/^style\s*=\s*\"([^\"]+)\"/i],["lang-css",/^style\s*=\s*\'([^\']+)\'/i],["lang-css",/^style\s*=\s*([^\"\'>\s]+)/i]]),["in.tag"]);c(f([],[[n,/^[\s\S]+/]]),["uq.val"]);c(h({"keywords":l,"hashComments":true,"cStyleComments":true,"types":e}),["c","cc","cpp","cxx","cyc","m"]);c(h({"keywords":"null,true,false"}),["json"]);c(h({"keywords":U,"hashComments":true,"cStyleComments":true,"verbatimStrings":true,"types":e}),["cs"]);c(h({"keywords":y,"cStyleComments":true}),["java"]);c(h({"keywords":J,"hashComments":true,"multiLineStrings":true}),["bash","bsh","csh","sh"]);c(h({"keywords":K,"hashComments":true,"multiLineStrings":true,"tripleQuotedStrings":true}),["cv","py","python"]);c(h({"keywords":s,"hashComments":true,"multiLineStrings":true,"regexLiterals":2}),["perl","pl","pm"]);c(h({"keywords":g,"hashComments":true,"multiLineStrings":true,"regexLiterals":true}),["rb","ruby"]);c(h({"keywords":x,"cStyleComments":true,"regexLiterals":true}),["javascript","js"]);c(h({"keywords":r,"hashComments":3,"cStyleComments":true,"multilineStrings":true,"tripleQuotedStrings":true,"regexLiterals":true}),["coffee"]);c(h({"keywords":z,"cStyleComments":true,"multilineStrings":true}),["rc","rs","rust"]);c(f([],[[E,/^[\s\S]+/]]),["regex"]);function d(Y){var X=Y.langExtension;try{var V=b(Y.sourceNode,Y.pre);var W=V.sourceCode;Y.sourceCode=W;Y.spans=V.spans;Y.basePos=0;q(X,W)(Y);F(Y)}catch(Z){if(P["console"]){console["log"](Z&&Z["stack"]||Z)}}}function A(Z,Y,X){var V=document.createElement("div");V.innerHTML="
    "+Z+"
    ";V=V.firstChild;if(X){T(V,X,true)}var W={langExtension:Y,numberLines:X,sourceNode:V,pre:1};d(W);return V.innerHTML}function w(al,ab){var ah=ab||document.body;var ao=ah.ownerDocument||document;function aa(aq){return ah.getElementsByTagName(aq)}var ad=[aa("pre"),aa("code"),aa("xmp")];var ae=[];for(var ak=0;akp;p++)"zIndex"in h[p]&&(l.push(h[p].zIndex),h[p].zIndex<0&&(m[h[p].zIndex]=h[p]));for(l.sort(i);l[j]<0;)if(e=m[l[j++]],n.push(e.apply(d,g)),c)return c=f,n;for(p=0;q>p;p++)if(e=h[p],"zIndex"in e)if(e.zIndex==l[j]){if(n.push(e.apply(d,g)),c)break;do if(j++,e=m[l[j]],e&&n.push(e.apply(d,g)),c)break;while(e)}else m[e.zIndex]=e;else if(n.push(e.apply(d,g)),c)break;return c=f,b=o,n.length?n:null};k._events=j,k.listeners=function(a){var b,c,d,e,h,i,k,l,m=a.split(f),n=j,o=[n],p=[];for(e=0,h=m.length;h>e;e++){for(l=[],i=0,k=o.length;k>i;i++)for(n=o[i].n,c=[n[m[e]],n[g]],d=2;d--;)b=c[d],b&&(l.push(b),p=p.concat(b.f||[]));o=l}return p},k.on=function(a,b){if(a=String(a),"function"!=typeof b)return function(){};for(var c=a.split(f),d=j,e=0,g=c.length;g>e;e++)d=d.n,d=d.hasOwnProperty(c[e])&&d[c[e]]||(d[c[e]]={n:{}});for(d.f=d.f||[],e=0,g=d.f.length;g>e;e++)if(d.f[e]==b)return h;return d.f.push(b),function(a){+a==+a&&(b.zIndex=+a)}},k.f=function(a){var b=[].slice.call(arguments,1);return function(){k.apply(null,[a,null].concat(b).concat([].slice.call(arguments,0)))}},k.stop=function(){c=1},k.nt=function(a){return a?new RegExp("(?:\\.|\\/|^)"+a+"(?:\\.|\\/|$)").test(b):b},k.nts=function(){return b.split(f)},k.off=k.unbind=function(a,b){if(!a)return void(k._events=j={n:{}});var c,d,h,i,l,m,n,o=a.split(f),p=[j];for(i=0,l=o.length;l>i;i++)for(m=0;mi;i++)for(c=p[i];c.n;){if(b){if(c.f){for(m=0,n=c.f.length;n>m;m++)if(c.f[m]==b){c.f.splice(m,1);break}!c.f.length&&delete c.f}for(d in c.n)if(c.n[e](d)&&c.n[d].f){var q=c.n[d].f;for(m=0,n=q.length;n>m;m++)if(q[m]==b){q.splice(m,1);break}!q.length&&delete c.n[d].f}}else{delete c.f;for(d in c.n)c.n[e](d)&&c.n[d].f&&delete c.n[d].f}c=c.n}},k.once=function(a,b){var c=function(){return k.unbind(a,c),b.apply(this,arguments)};return k.on(a,c)},k.version=d,k.toString=function(){return"You are running Eve "+d},"undefined"!=typeof module&&module.exports?module.exports=k:"undefined"!=typeof define?define("eve",[],function(){return k}):a.eve=k}(window||this),function(a,b){"function"==typeof define&&define.amd?define(["eve"],function(c){return b(a,c)}):b(a,a.eve||"function"==typeof require&&require("eve"))}(this,function(a,b){function c(a){if(c.is(a,"function"))return u?a():b.on("raphael.DOMload",a);if(c.is(a,V))return c._engine.create[D](c,a.splice(0,3+c.is(a[0],T))).add(a);var d=Array.prototype.slice.call(arguments,0);if(c.is(d[d.length-1],"function")){var e=d.pop();return u?e.call(c._engine.create[D](c,d)):b.on("raphael.DOMload",function(){e.call(c._engine.create[D](c,d))})}return c._engine.create[D](c,arguments)}function d(a){if("function"==typeof a||Object(a)!==a)return a;var b=new a.constructor;for(var c in a)a[z](c)&&(b[c]=d(a[c]));return b}function e(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return a.push(a.splice(c,1)[0])}function f(a,b,c){function d(){var f=Array.prototype.slice.call(arguments,0),g=f.join("␀"),h=d.cache=d.cache||{},i=d.count=d.count||[];return h[z](g)?(e(i,g),c?c(h[g]):h[g]):(i.length>=1e3&&delete h[i.shift()],i.push(g),h[g]=a[D](b,f),c?c(h[g]):h[g])}return d}function g(){return this.hex}function h(a,b){for(var c=[],d=0,e=a.length;e-2*!b>d;d+=2){var f=[{x:+a[d-2],y:+a[d-1]},{x:+a[d],y:+a[d+1]},{x:+a[d+2],y:+a[d+3]},{x:+a[d+4],y:+a[d+5]}];b?d?e-4==d?f[3]={x:+a[0],y:+a[1]}:e-2==d&&(f[2]={x:+a[0],y:+a[1]},f[3]={x:+a[2],y:+a[3]}):f[0]={x:+a[e-2],y:+a[e-1]}:e-4==d?f[3]=f[2]:d||(f[0]={x:+a[d],y:+a[d+1]}),c.push(["C",(-f[0].x+6*f[1].x+f[2].x)/6,(-f[0].y+6*f[1].y+f[2].y)/6,(f[1].x+6*f[2].x-f[3].x)/6,(f[1].y+6*f[2].y-f[3].y)/6,f[2].x,f[2].y])}return c}function i(a,b,c,d,e){var f=-3*b+9*c-9*d+3*e,g=a*f+6*b-12*c+6*d;return a*g-3*b+3*c}function j(a,b,c,d,e,f,g,h,j){null==j&&(j=1),j=j>1?1:0>j?0:j;for(var k=j/2,l=12,m=[-.1252,.1252,-.3678,.3678,-.5873,.5873,-.7699,.7699,-.9041,.9041,-.9816,.9816],n=[.2491,.2491,.2335,.2335,.2032,.2032,.1601,.1601,.1069,.1069,.0472,.0472],o=0,p=0;l>p;p++){var q=k*m[p]+k,r=i(q,a,c,e,g),s=i(q,b,d,f,h),t=r*r+s*s;o+=n[p]*N.sqrt(t)}return k*o}function k(a,b,c,d,e,f,g,h,i){if(!(0>i||j(a,b,c,d,e,f,g,h)o;)m/=2,n+=(i>k?1:-1)*m,k=j(a,b,c,d,e,f,g,h,n);return n}}function l(a,b,c,d,e,f,g,h){if(!(O(a,c)O(e,g)||O(b,d)O(f,h))){var i=(a*d-b*c)*(e-g)-(a-c)*(e*h-f*g),j=(a*d-b*c)*(f-h)-(b-d)*(e*h-f*g),k=(a-c)*(f-h)-(b-d)*(e-g);if(k){var l=i/k,m=j/k,n=+l.toFixed(2),o=+m.toFixed(2);if(!(n<+P(a,c).toFixed(2)||n>+O(a,c).toFixed(2)||n<+P(e,g).toFixed(2)||n>+O(e,g).toFixed(2)||o<+P(b,d).toFixed(2)||o>+O(b,d).toFixed(2)||o<+P(f,h).toFixed(2)||o>+O(f,h).toFixed(2)))return{x:l,y:m}}}}function m(a,b,d){var e=c.bezierBBox(a),f=c.bezierBBox(b);if(!c.isBBoxIntersect(e,f))return d?0:[];for(var g=j.apply(0,a),h=j.apply(0,b),i=O(~~(g/5),1),k=O(~~(h/5),1),m=[],n=[],o={},p=d?0:[],q=0;i+1>q;q++){var r=c.findDotsAtSegment.apply(c,a.concat(q/i));m.push({x:r.x,y:r.y,t:q/i})}for(q=0;k+1>q;q++)r=c.findDotsAtSegment.apply(c,b.concat(q/k)),n.push({x:r.x,y:r.y,t:q/k});for(q=0;i>q;q++)for(var s=0;k>s;s++){var t=m[q],u=m[q+1],v=n[s],w=n[s+1],x=Q(u.x-t.x)<.001?"y":"x",y=Q(w.x-v.x)<.001?"y":"x",z=l(t.x,t.y,u.x,u.y,v.x,v.y,w.x,w.y);if(z){if(o[z.x.toFixed(4)]==z.y.toFixed(4))continue;o[z.x.toFixed(4)]=z.y.toFixed(4);var A=t.t+Q((z[x]-t[x])/(u[x]-t[x]))*(u.t-t.t),B=v.t+Q((z[y]-v[y])/(w[y]-v[y]))*(w.t-v.t);A>=0&&1.001>=A&&B>=0&&1.001>=B&&(d?p++:p.push({x:z.x,y:z.y,t1:P(A,1),t2:P(B,1)}))}}return p}function n(a,b,d){a=c._path2curve(a),b=c._path2curve(b);for(var e,f,g,h,i,j,k,l,n,o,p=d?0:[],q=0,r=a.length;r>q;q++){var s=a[q];if("M"==s[0])e=i=s[1],f=j=s[2];else{"C"==s[0]?(n=[e,f].concat(s.slice(1)),e=n[6],f=n[7]):(n=[e,f,e,f,i,j,i,j],e=i,f=j);for(var t=0,u=b.length;u>t;t++){var v=b[t];if("M"==v[0])g=k=v[1],h=l=v[2];else{"C"==v[0]?(o=[g,h].concat(v.slice(1)),g=o[6],h=o[7]):(o=[g,h,g,h,k,l,k,l],g=k,h=l);var w=m(n,o,d);if(d)p+=w;else{for(var x=0,y=w.length;y>x;x++)w[x].segment1=q,w[x].segment2=t,w[x].bez1=n,w[x].bez2=o;p=p.concat(w)}}}}}return p}function o(a,b,c,d,e,f){null!=a?(this.a=+a,this.b=+b,this.c=+c,this.d=+d,this.e=+e,this.f=+f):(this.a=1,this.b=0,this.c=0,this.d=1,this.e=0,this.f=0)}function p(){return this.x+H+this.y+H+this.width+" × "+this.height}function q(a,b,c,d,e,f){function g(a){return((l*a+k)*a+j)*a}function h(a,b){var c=i(a,b);return((o*c+n)*c+m)*c}function i(a,b){var c,d,e,f,h,i;for(e=a,i=0;8>i;i++){if(f=g(e)-a,Q(f)e)return c;if(e>d)return d;for(;d>c;){if(f=g(e),Q(f-a)f?c=e:d=e,e=(d-c)/2+c}return e}var j=3*b,k=3*(d-b)-j,l=1-j-k,m=3*c,n=3*(e-c)-m,o=1-m-n;return h(a,1/(200*f))}function r(a,b){var c=[],d={};if(this.ms=b,this.times=1,a){for(var e in a)a[z](e)&&(d[_(e)]=a[e],c.push(_(e)));c.sort(lb)}this.anim=d,this.top=c[c.length-1],this.percents=c}function s(a,d,e,f,g,h){e=_(e);var i,j,k,l,m,n,p=a.ms,r={},s={},t={};if(f)for(v=0,x=ic.length;x>v;v++){var u=ic[v];if(u.el.id==d.id&&u.anim==a){u.percent!=e?(ic.splice(v,1),k=1):j=u,d.attr(u.totalOrigin);break}}else f=+s;for(var v=0,x=a.percents.length;x>v;v++){if(a.percents[v]==e||a.percents[v]>f*a.top){e=a.percents[v],m=a.percents[v-1]||0,p=p/a.top*(e-m),l=a.percents[v+1],i=a.anim[e];break}f&&d.attr(a.anim[a.percents[v]])}if(i){if(j)j.initstatus=f,j.start=new Date-j.ms*f;else{for(var y in i)if(i[z](y)&&(db[z](y)||d.paper.customAttributes[z](y)))switch(r[y]=d.attr(y),null==r[y]&&(r[y]=cb[y]),s[y]=i[y],db[y]){case T:t[y]=(s[y]-r[y])/p;break;case"colour":r[y]=c.getRGB(r[y]);var A=c.getRGB(s[y]);t[y]={r:(A.r-r[y].r)/p,g:(A.g-r[y].g)/p,b:(A.b-r[y].b)/p};break;case"path":var B=Kb(r[y],s[y]),C=B[1];for(r[y]=B[0],t[y]=[],v=0,x=r[y].length;x>v;v++){t[y][v]=[0];for(var D=1,F=r[y][v].length;F>D;D++)t[y][v][D]=(C[v][D]-r[y][v][D])/p}break;case"transform":var G=d._,H=Pb(G[y],s[y]);if(H)for(r[y]=H.from,s[y]=H.to,t[y]=[],t[y].real=!0,v=0,x=r[y].length;x>v;v++)for(t[y][v]=[r[y][v][0]],D=1,F=r[y][v].length;F>D;D++)t[y][v][D]=(s[y][v][D]-r[y][v][D])/p;else{var K=d.matrix||new o,L={_:{transform:G.transform},getBBox:function(){return d.getBBox(1)}};r[y]=[K.a,K.b,K.c,K.d,K.e,K.f],Nb(L,s[y]),s[y]=L._.transform,t[y]=[(L.matrix.a-K.a)/p,(L.matrix.b-K.b)/p,(L.matrix.c-K.c)/p,(L.matrix.d-K.d)/p,(L.matrix.e-K.e)/p,(L.matrix.f-K.f)/p]}break;case"csv":var M=I(i[y])[J](w),N=I(r[y])[J](w);if("clip-rect"==y)for(r[y]=N,t[y]=[],v=N.length;v--;)t[y][v]=(M[v]-r[y][v])/p;s[y]=M;break;default:for(M=[][E](i[y]),N=[][E](r[y]),t[y]=[],v=d.paper.customAttributes[y].length;v--;)t[y][v]=((M[v]||0)-(N[v]||0))/p}var O=i.easing,P=c.easing_formulas[O];if(!P)if(P=I(O).match(Z),P&&5==P.length){var Q=P;P=function(a){return q(a,+Q[1],+Q[2],+Q[3],+Q[4],p)}}else P=nb;if(n=i.start||a.start||+new Date,u={anim:a,percent:e,timestamp:n,start:n+(a.del||0),status:0,initstatus:f||0,stop:!1,ms:p,easing:P,from:r,diff:t,to:s,el:d,callback:i.callback,prev:m,next:l,repeat:h||a.times,origin:d.attr(),totalOrigin:g},ic.push(u),f&&!j&&!k&&(u.stop=!0,u.start=new Date-p*f,1==ic.length))return kc();k&&(u.start=new Date-u.ms*f),1==ic.length&&jc(kc)}b("raphael.anim.start."+d.id,d,a)}}function t(a){for(var b=0;be;e++)for(i=a[e],f=1,h=i.length;h>f;f+=2)c=b.x(i[f],i[f+1]),d=b.y(i[f],i[f+1]),i[f]=c,i[f+1]=d;return a};if(c._g=A,c.type=A.win.SVGAngle||A.doc.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure","1.1")?"SVG":"VML","VML"==c.type){var sb,tb=A.doc.createElement("div");if(tb.innerHTML='',sb=tb.firstChild,sb.style.behavior="url(#default#VML)",!sb||"object"!=typeof sb.adj)return c.type=G;tb=null}c.svg=!(c.vml="VML"==c.type),c._Paper=C,c.fn=v=C.prototype=c.prototype,c._id=0,c._oid=0,c.is=function(a,b){return b=M.call(b),"finite"==b?!Y[z](+a):"array"==b?a instanceof Array:"null"==b&&null===a||b==typeof a&&null!==a||"object"==b&&a===Object(a)||"array"==b&&Array.isArray&&Array.isArray(a)||W.call(a).slice(8,-1).toLowerCase()==b},c.angle=function(a,b,d,e,f,g){if(null==f){var h=a-d,i=b-e;return h||i?(180+180*N.atan2(-i,-h)/S+360)%360:0}return c.angle(a,b,f,g)-c.angle(d,e,f,g)},c.rad=function(a){return a%360*S/180},c.deg=function(a){return 180*a/S%360},c.snapTo=function(a,b,d){if(d=c.is(d,"finite")?d:10,c.is(a,V)){for(var e=a.length;e--;)if(Q(a[e]-b)<=d)return a[e]}else{a=+a;var f=b%a;if(d>f)return b-f;if(f>a-d)return b-f+a}return b};c.createUUID=function(a,b){return function(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(a,b).toUpperCase()}}(/[xy]/g,function(a){var b=16*N.random()|0,c="x"==a?b:3&b|8;return c.toString(16)});c.setWindow=function(a){b("raphael.setWindow",c,A.win,a),A.win=a,A.doc=A.win.document,c._engine.initWin&&c._engine.initWin(A.win)};var ub=function(a){if(c.vml){var b,d=/^\s+|\s+$/g;try{var e=new ActiveXObject("htmlfile");e.write(""),e.close(),b=e.body}catch(g){b=createPopup().document.body}var h=b.createTextRange();ub=f(function(a){try{b.style.color=I(a).replace(d,G);var c=h.queryCommandValue("ForeColor");return c=(255&c)<<16|65280&c|(16711680&c)>>>16,"#"+("000000"+c.toString(16)).slice(-6)}catch(e){return"none"}})}else{var i=A.doc.createElement("i");i.title="Raphaël Colour Picker",i.style.display="none",A.doc.body.appendChild(i),ub=f(function(a){return i.style.color=a,A.doc.defaultView.getComputedStyle(i,G).getPropertyValue("color")})}return ub(a)},vb=function(){return"hsb("+[this.h,this.s,this.b]+")"},wb=function(){return"hsl("+[this.h,this.s,this.l]+")"},xb=function(){return this.hex},yb=function(a,b,d){if(null==b&&c.is(a,"object")&&"r"in a&&"g"in a&&"b"in a&&(d=a.b,b=a.g,a=a.r),null==b&&c.is(a,U)){var e=c.getRGB(a);a=e.r,b=e.g,d=e.b}return(a>1||b>1||d>1)&&(a/=255,b/=255,d/=255),[a,b,d]},zb=function(a,b,d,e){a*=255,b*=255,d*=255;var f={r:a,g:b,b:d,hex:c.rgb(a,b,d),toString:xb};return c.is(e,"finite")&&(f.opacity=e),f};c.color=function(a){var b;return c.is(a,"object")&&"h"in a&&"s"in a&&"b"in a?(b=c.hsb2rgb(a),a.r=b.r,a.g=b.g,a.b=b.b,a.hex=b.hex):c.is(a,"object")&&"h"in a&&"s"in a&&"l"in a?(b=c.hsl2rgb(a),a.r=b.r,a.g=b.g,a.b=b.b,a.hex=b.hex):(c.is(a,"string")&&(a=c.getRGB(a)),c.is(a,"object")&&"r"in a&&"g"in a&&"b"in a?(b=c.rgb2hsl(a),a.h=b.h,a.s=b.s,a.l=b.l,b=c.rgb2hsb(a),a.v=b.b):(a={hex:"none"},a.r=a.g=a.b=a.h=a.s=a.v=a.l=-1)),a.toString=xb,a},c.hsb2rgb=function(a,b,c,d){this.is(a,"object")&&"h"in a&&"s"in a&&"b"in a&&(c=a.b,b=a.s,d=a.o,a=a.h),a*=360;var e,f,g,h,i;return a=a%360/60,i=c*b,h=i*(1-Q(a%2-1)),e=f=g=c-i,a=~~a,e+=[i,h,0,0,h,i][a],f+=[h,i,i,h,0,0][a],g+=[0,0,h,i,i,h][a],zb(e,f,g,d)},c.hsl2rgb=function(a,b,c,d){this.is(a,"object")&&"h"in a&&"s"in a&&"l"in a&&(c=a.l,b=a.s,a=a.h),(a>1||b>1||c>1)&&(a/=360,b/=100,c/=100),a*=360;var e,f,g,h,i;return a=a%360/60,i=2*b*(.5>c?c:1-c),h=i*(1-Q(a%2-1)),e=f=g=c-i/2,a=~~a,e+=[i,h,0,0,h,i][a],f+=[h,i,i,h,0,0][a],g+=[0,0,h,i,i,h][a],zb(e,f,g,d)},c.rgb2hsb=function(a,b,c){c=yb(a,b,c),a=c[0],b=c[1],c=c[2];var d,e,f,g;return f=O(a,b,c),g=f-P(a,b,c),d=0==g?null:f==a?(b-c)/g:f==b?(c-a)/g+2:(a-b)/g+4,d=(d+360)%6*60/360,e=0==g?0:g/f,{h:d,s:e,b:f,toString:vb}},c.rgb2hsl=function(a,b,c){c=yb(a,b,c),a=c[0],b=c[1],c=c[2];var d,e,f,g,h,i;return g=O(a,b,c),h=P(a,b,c),i=g-h,d=0==i?null:g==a?(b-c)/i:g==b?(c-a)/i+2:(a-b)/i+4,d=(d+360)%6*60/360,f=(g+h)/2,e=0==i?0:.5>f?i/(2*f):i/(2-2*f),{h:d,s:e,l:f,toString:wb}},c._path2string=function(){return this.join(",").replace(gb,"$1")};c._preload=function(a,b){var c=A.doc.createElement("img");c.style.cssText="position:absolute;left:-9999em;top:-9999em",c.onload=function(){b.call(this),this.onload=null,A.doc.body.removeChild(this)},c.onerror=function(){A.doc.body.removeChild(this)},A.doc.body.appendChild(c),c.src=a};c.getRGB=f(function(a){if(!a||(a=I(a)).indexOf("-")+1)return{r:-1,g:-1,b:-1,hex:"none",error:1,toString:g};if("none"==a)return{r:-1,g:-1,b:-1,hex:"none",toString:g};!(fb[z](a.toLowerCase().substring(0,2))||"#"==a.charAt())&&(a=ub(a));var b,d,e,f,h,i,j=a.match(X);return j?(j[2]&&(e=ab(j[2].substring(5),16),d=ab(j[2].substring(3,5),16),b=ab(j[2].substring(1,3),16)),j[3]&&(e=ab((h=j[3].charAt(3))+h,16),d=ab((h=j[3].charAt(2))+h,16),b=ab((h=j[3].charAt(1))+h,16)),j[4]&&(i=j[4][J](eb),b=_(i[0]),"%"==i[0].slice(-1)&&(b*=2.55),d=_(i[1]),"%"==i[1].slice(-1)&&(d*=2.55),e=_(i[2]),"%"==i[2].slice(-1)&&(e*=2.55),"rgba"==j[1].toLowerCase().slice(0,4)&&(f=_(i[3])),i[3]&&"%"==i[3].slice(-1)&&(f/=100)),j[5]?(i=j[5][J](eb),b=_(i[0]),"%"==i[0].slice(-1)&&(b*=2.55),d=_(i[1]),"%"==i[1].slice(-1)&&(d*=2.55),e=_(i[2]),"%"==i[2].slice(-1)&&(e*=2.55),("deg"==i[0].slice(-3)||"°"==i[0].slice(-1))&&(b/=360),"hsba"==j[1].toLowerCase().slice(0,4)&&(f=_(i[3])),i[3]&&"%"==i[3].slice(-1)&&(f/=100),c.hsb2rgb(b,d,e,f)):j[6]?(i=j[6][J](eb),b=_(i[0]),"%"==i[0].slice(-1)&&(b*=2.55),d=_(i[1]),"%"==i[1].slice(-1)&&(d*=2.55),e=_(i[2]),"%"==i[2].slice(-1)&&(e*=2.55),("deg"==i[0].slice(-3)||"°"==i[0].slice(-1))&&(b/=360),"hsla"==j[1].toLowerCase().slice(0,4)&&(f=_(i[3])),i[3]&&"%"==i[3].slice(-1)&&(f/=100),c.hsl2rgb(b,d,e,f)):(j={r:b,g:d,b:e,toString:g},j.hex="#"+(16777216|e|d<<8|b<<16).toString(16).slice(1),c.is(f,"finite")&&(j.opacity=f),j)):{r:-1,g:-1,b:-1,hex:"none",error:1,toString:g}},c),c.hsb=f(function(a,b,d){return c.hsb2rgb(a,b,d).hex}),c.hsl=f(function(a,b,d){return c.hsl2rgb(a,b,d).hex}),c.rgb=f(function(a,b,c){return"#"+(16777216|c|b<<8|a<<16).toString(16).slice(1)}),c.getColor=function(a){var b=this.getColor.start=this.getColor.start||{h:0,s:1,b:a||.75},c=this.hsb2rgb(b.h,b.s,b.b);return b.h+=.075,b.h>1&&(b.h=0,b.s-=.2,b.s<=0&&(this.getColor.start={h:0,s:1,b:b.b})),c.hex},c.getColor.reset=function(){delete this.start},c.parsePathString=function(a){if(!a)return null;var b=Ab(a);if(b.arr)return Cb(b.arr);var d={a:7,c:6,h:1,l:2,m:2,r:4,q:4,s:4,t:2,v:1,z:0},e=[];return c.is(a,V)&&c.is(a[0],V)&&(e=Cb(a)),e.length||I(a).replace(hb,function(a,b,c){var f=[],g=b.toLowerCase();if(c.replace(jb,function(a,b){b&&f.push(+b)}),"m"==g&&f.length>2&&(e.push([b][E](f.splice(0,2))),g="l",b="m"==b?"l":"L"),"r"==g)e.push([b][E](f));else for(;f.length>=d[g]&&(e.push([b][E](f.splice(0,d[g]))),d[g]););}),e.toString=c._path2string,b.arr=Cb(e),e},c.parseTransformString=f(function(a){if(!a)return null;var b=[];return c.is(a,V)&&c.is(a[0],V)&&(b=Cb(a)),b.length||I(a).replace(ib,function(a,c,d){{var e=[];M.call(c)}d.replace(jb,function(a,b){b&&e.push(+b)}),b.push([c][E](e))}),b.toString=c._path2string,b});var Ab=function(a){var b=Ab.ps=Ab.ps||{};return b[a]?b[a].sleep=100:b[a]={sleep:100},setTimeout(function(){for(var c in b)b[z](c)&&c!=a&&(b[c].sleep--,!b[c].sleep&&delete b[c])}),b[a]};c.findDotsAtSegment=function(a,b,c,d,e,f,g,h,i){var j=1-i,k=R(j,3),l=R(j,2),m=i*i,n=m*i,o=k*a+3*l*i*c+3*j*i*i*e+n*g,p=k*b+3*l*i*d+3*j*i*i*f+n*h,q=a+2*i*(c-a)+m*(e-2*c+a),r=b+2*i*(d-b)+m*(f-2*d+b),s=c+2*i*(e-c)+m*(g-2*e+c),t=d+2*i*(f-d)+m*(h-2*f+d),u=j*a+i*c,v=j*b+i*d,w=j*e+i*g,x=j*f+i*h,y=90-180*N.atan2(q-s,r-t)/S;return(q>s||t>r)&&(y+=180),{x:o,y:p,m:{x:q,y:r},n:{x:s,y:t},start:{x:u,y:v},end:{x:w,y:x},alpha:y}},c.bezierBBox=function(a,b,d,e,f,g,h,i){c.is(a,"array")||(a=[a,b,d,e,f,g,h,i]);var j=Jb.apply(null,a);return{x:j.min.x,y:j.min.y,x2:j.max.x,y2:j.max.y,width:j.max.x-j.min.x,height:j.max.y-j.min.y}},c.isPointInsideBBox=function(a,b,c){return b>=a.x&&b<=a.x2&&c>=a.y&&c<=a.y2},c.isBBoxIntersect=function(a,b){var d=c.isPointInsideBBox;return d(b,a.x,a.y)||d(b,a.x2,a.y)||d(b,a.x,a.y2)||d(b,a.x2,a.y2)||d(a,b.x,b.y)||d(a,b.x2,b.y)||d(a,b.x,b.y2)||d(a,b.x2,b.y2)||(a.xb.x||b.xa.x)&&(a.yb.y||b.ya.y)},c.pathIntersection=function(a,b){return n(a,b)},c.pathIntersectionNumber=function(a,b){return n(a,b,1)},c.isPointInsidePath=function(a,b,d){var e=c.pathBBox(a);return c.isPointInsideBBox(e,b,d)&&n(a,[["M",b,d],["H",e.x2+10]],1)%2==1},c._removedFactory=function(a){return function(){b("raphael.log",null,"Raphaël: you are calling to method “"+a+"” of removed object",a)}};var Bb=c.pathBBox=function(a){var b=Ab(a);if(b.bbox)return d(b.bbox);if(!a)return{x:0,y:0,width:0,height:0,x2:0,y2:0};a=Kb(a);for(var c,e=0,f=0,g=[],h=[],i=0,j=a.length;j>i;i++)if(c=a[i],"M"==c[0])e=c[1],f=c[2],g.push(e),h.push(f);else{var k=Jb(e,f,c[1],c[2],c[3],c[4],c[5],c[6]);g=g[E](k.min.x,k.max.x),h=h[E](k.min.y,k.max.y),e=c[5],f=c[6]}var l=P[D](0,g),m=P[D](0,h),n=O[D](0,g),o=O[D](0,h),p=n-l,q=o-m,r={x:l,y:m,x2:n,y2:o,width:p,height:q,cx:l+p/2,cy:m+q/2};return b.bbox=d(r),r},Cb=function(a){var b=d(a);return b.toString=c._path2string,b},Db=c._pathToRelative=function(a){var b=Ab(a);if(b.rel)return Cb(b.rel);c.is(a,V)&&c.is(a&&a[0],V)||(a=c.parsePathString(a));var d=[],e=0,f=0,g=0,h=0,i=0;"M"==a[0][0]&&(e=a[0][1],f=a[0][2],g=e,h=f,i++,d.push(["M",e,f]));for(var j=i,k=a.length;k>j;j++){var l=d[j]=[],m=a[j];if(m[0]!=M.call(m[0]))switch(l[0]=M.call(m[0]),l[0]){case"a":l[1]=m[1],l[2]=m[2],l[3]=m[3],l[4]=m[4],l[5]=m[5],l[6]=+(m[6]-e).toFixed(3),l[7]=+(m[7]-f).toFixed(3);break;case"v":l[1]=+(m[1]-f).toFixed(3);break;case"m":g=m[1],h=m[2];default:for(var n=1,o=m.length;o>n;n++)l[n]=+(m[n]-(n%2?e:f)).toFixed(3)}else{l=d[j]=[],"m"==m[0]&&(g=m[1]+e,h=m[2]+f);for(var p=0,q=m.length;q>p;p++)d[j][p]=m[p]}var r=d[j].length;switch(d[j][0]){case"z":e=g,f=h;break;case"h":e+=+d[j][r-1];break;case"v":f+=+d[j][r-1];break;default:e+=+d[j][r-2],f+=+d[j][r-1]}}return d.toString=c._path2string,b.rel=Cb(d),d},Eb=c._pathToAbsolute=function(a){var b=Ab(a);if(b.abs)return Cb(b.abs);if(c.is(a,V)&&c.is(a&&a[0],V)||(a=c.parsePathString(a)),!a||!a.length)return[["M",0,0]];var d=[],e=0,f=0,g=0,i=0,j=0;"M"==a[0][0]&&(e=+a[0][1],f=+a[0][2],g=e,i=f,j++,d[0]=["M",e,f]);for(var k,l,m=3==a.length&&"M"==a[0][0]&&"R"==a[1][0].toUpperCase()&&"Z"==a[2][0].toUpperCase(),n=j,o=a.length;o>n;n++){if(d.push(k=[]),l=a[n],l[0]!=bb.call(l[0]))switch(k[0]=bb.call(l[0]),k[0]){case"A":k[1]=l[1],k[2]=l[2],k[3]=l[3],k[4]=l[4],k[5]=l[5],k[6]=+(l[6]+e),k[7]=+(l[7]+f);break;case"V":k[1]=+l[1]+f;break;case"H":k[1]=+l[1]+e;break;case"R":for(var p=[e,f][E](l.slice(1)),q=2,r=p.length;r>q;q++)p[q]=+p[q]+e,p[++q]=+p[q]+f;d.pop(),d=d[E](h(p,m));break;case"M":g=+l[1]+e,i=+l[2]+f;default:for(q=1,r=l.length;r>q;q++)k[q]=+l[q]+(q%2?e:f)}else if("R"==l[0])p=[e,f][E](l.slice(1)),d.pop(),d=d[E](h(p,m)),k=["R"][E](l.slice(-2));else for(var s=0,t=l.length;t>s;s++)k[s]=l[s];switch(k[0]){case"Z":e=g,f=i;break;case"H":e=k[1];break;case"V":f=k[1];break;case"M":g=k[k.length-2],i=k[k.length-1];default:e=k[k.length-2],f=k[k.length-1]}}return d.toString=c._path2string,b.abs=Cb(d),d},Fb=function(a,b,c,d){return[a,b,c,d,c,d]},Gb=function(a,b,c,d,e,f){var g=1/3,h=2/3;return[g*a+h*c,g*b+h*d,g*e+h*c,g*f+h*d,e,f]},Hb=function(a,b,c,d,e,g,h,i,j,k){var l,m=120*S/180,n=S/180*(+e||0),o=[],p=f(function(a,b,c){var d=a*N.cos(c)-b*N.sin(c),e=a*N.sin(c)+b*N.cos(c);return{x:d,y:e}});if(k)y=k[0],z=k[1],w=k[2],x=k[3];else{l=p(a,b,-n),a=l.x,b=l.y,l=p(i,j,-n),i=l.x,j=l.y;var q=(N.cos(S/180*e),N.sin(S/180*e),(a-i)/2),r=(b-j)/2,s=q*q/(c*c)+r*r/(d*d);s>1&&(s=N.sqrt(s),c=s*c,d=s*d);var t=c*c,u=d*d,v=(g==h?-1:1)*N.sqrt(Q((t*u-t*r*r-u*q*q)/(t*r*r+u*q*q))),w=v*c*r/d+(a+i)/2,x=v*-d*q/c+(b+j)/2,y=N.asin(((b-x)/d).toFixed(9)),z=N.asin(((j-x)/d).toFixed(9));y=w>a?S-y:y,z=w>i?S-z:z,0>y&&(y=2*S+y),0>z&&(z=2*S+z),h&&y>z&&(y-=2*S),!h&&z>y&&(z-=2*S)}var A=z-y;if(Q(A)>m){var B=z,C=i,D=j;z=y+m*(h&&z>y?1:-1),i=w+c*N.cos(z),j=x+d*N.sin(z),o=Hb(i,j,c,d,e,0,h,C,D,[z,B,w,x])}A=z-y;var F=N.cos(y),G=N.sin(y),H=N.cos(z),I=N.sin(z),K=N.tan(A/4),L=4/3*c*K,M=4/3*d*K,O=[a,b],P=[a+L*G,b-M*F],R=[i+L*I,j-M*H],T=[i,j];if(P[0]=2*O[0]-P[0],P[1]=2*O[1]-P[1],k)return[P,R,T][E](o);o=[P,R,T][E](o).join()[J](",");for(var U=[],V=0,W=o.length;W>V;V++)U[V]=V%2?p(o[V-1],o[V],n).y:p(o[V],o[V+1],n).x;return U},Ib=function(a,b,c,d,e,f,g,h,i){var j=1-i;return{x:R(j,3)*a+3*R(j,2)*i*c+3*j*i*i*e+R(i,3)*g,y:R(j,3)*b+3*R(j,2)*i*d+3*j*i*i*f+R(i,3)*h}},Jb=f(function(a,b,c,d,e,f,g,h){var i,j=e-2*c+a-(g-2*e+c),k=2*(c-a)-2*(e-c),l=a-c,m=(-k+N.sqrt(k*k-4*j*l))/2/j,n=(-k-N.sqrt(k*k-4*j*l))/2/j,o=[b,h],p=[a,g];return Q(m)>"1e12"&&(m=.5),Q(n)>"1e12"&&(n=.5),m>0&&1>m&&(i=Ib(a,b,c,d,e,f,g,h,m),p.push(i.x),o.push(i.y)),n>0&&1>n&&(i=Ib(a,b,c,d,e,f,g,h,n),p.push(i.x),o.push(i.y)),j=f-2*d+b-(h-2*f+d),k=2*(d-b)-2*(f-d),l=b-d,m=(-k+N.sqrt(k*k-4*j*l))/2/j,n=(-k-N.sqrt(k*k-4*j*l))/2/j,Q(m)>"1e12"&&(m=.5),Q(n)>"1e12"&&(n=.5),m>0&&1>m&&(i=Ib(a,b,c,d,e,f,g,h,m),p.push(i.x),o.push(i.y)),n>0&&1>n&&(i=Ib(a,b,c,d,e,f,g,h,n),p.push(i.x),o.push(i.y)),{min:{x:P[D](0,p),y:P[D](0,o)},max:{x:O[D](0,p),y:O[D](0,o)}}}),Kb=c._path2curve=f(function(a,b){var c=!b&&Ab(a);if(!b&&c.curve)return Cb(c.curve);for(var d=Eb(a),e=b&&Eb(b),f={x:0,y:0,bx:0,by:0,X:0,Y:0,qx:null,qy:null},g={x:0,y:0,bx:0,by:0,X:0,Y:0,qx:null,qy:null},h=(function(a,b,c){var d,e,f={T:1,Q:1};if(!a)return["C",b.x,b.y,b.x,b.y,b.x,b.y];switch(!(a[0]in f)&&(b.qx=b.qy=null),a[0]){case"M":b.X=a[1],b.Y=a[2];break;case"A":a=["C"][E](Hb[D](0,[b.x,b.y][E](a.slice(1))));break;case"S":"C"==c||"S"==c?(d=2*b.x-b.bx,e=2*b.y-b.by):(d=b.x,e=b.y),a=["C",d,e][E](a.slice(1));break;case"T":"Q"==c||"T"==c?(b.qx=2*b.x-b.qx,b.qy=2*b.y-b.qy):(b.qx=b.x,b.qy=b.y),a=["C"][E](Gb(b.x,b.y,b.qx,b.qy,a[1],a[2]));break;case"Q":b.qx=a[1],b.qy=a[2],a=["C"][E](Gb(b.x,b.y,a[1],a[2],a[3],a[4]));break;case"L":a=["C"][E](Fb(b.x,b.y,a[1],a[2]));break;case"H":a=["C"][E](Fb(b.x,b.y,a[1],b.y));break;case"V":a=["C"][E](Fb(b.x,b.y,b.x,a[1]));break;case"Z":a=["C"][E](Fb(b.x,b.y,b.X,b.Y))}return a}),i=function(a,b){if(a[b].length>7){a[b].shift();for(var c=a[b];c.length;)k[b]="A",e&&(l[b]="A"),a.splice(b++,0,["C"][E](c.splice(0,6)));a.splice(b,1),p=O(d.length,e&&e.length||0)}},j=function(a,b,c,f,g){a&&b&&"M"==a[g][0]&&"M"!=b[g][0]&&(b.splice(g,0,["M",f.x,f.y]),c.bx=0,c.by=0,c.x=a[g][1],c.y=a[g][2],p=O(d.length,e&&e.length||0))},k=[],l=[],m="",n="",o=0,p=O(d.length,e&&e.length||0);p>o;o++){d[o]&&(m=d[o][0]),"C"!=m&&(k[o]=m,o&&(n=k[o-1])),d[o]=h(d[o],f,n),"A"!=k[o]&&"C"==m&&(k[o]="C"),i(d,o),e&&(e[o]&&(m=e[o][0]),"C"!=m&&(l[o]=m,o&&(n=l[o-1])),e[o]=h(e[o],g,n),"A"!=l[o]&&"C"==m&&(l[o]="C"),i(e,o)),j(d,e,f,g,o),j(e,d,g,f,o);var q=d[o],r=e&&e[o],s=q.length,t=e&&r.length;f.x=q[s-2],f.y=q[s-1],f.bx=_(q[s-4])||f.x,f.by=_(q[s-3])||f.y,g.bx=e&&(_(r[t-4])||g.x),g.by=e&&(_(r[t-3])||g.y),g.x=e&&r[t-2],g.y=e&&r[t-1]}return e||(c.curve=Cb(d)),e?[d,e]:d},null,Cb),Lb=(c._parseDots=f(function(a){for(var b=[],d=0,e=a.length;e>d;d++){var f={},g=a[d].match(/^([^:]*):?([\d\.]*)/);if(f.color=c.getRGB(g[1]),f.color.error)return null;f.color=f.color.hex,g[2]&&(f.offset=g[2]+"%"),b.push(f)}for(d=1,e=b.length-1;e>d;d++)if(!b[d].offset){for(var h=_(b[d-1].offset||0),i=0,j=d+1;e>j;j++)if(b[j].offset){i=b[j].offset;break}i||(i=100,j=e),i=_(i);for(var k=(i-h)/(j-d+1);j>d;d++)h+=k,b[d].offset=h+"%"}return b}),c._tear=function(a,b){a==b.top&&(b.top=a.prev),a==b.bottom&&(b.bottom=a.next),a.next&&(a.next.prev=a.prev),a.prev&&(a.prev.next=a.next)}),Mb=(c._tofront=function(a,b){b.top!==a&&(Lb(a,b),a.next=null,a.prev=b.top,b.top.next=a,b.top=a)},c._toback=function(a,b){b.bottom!==a&&(Lb(a,b),a.next=b.bottom,a.prev=null,b.bottom.prev=a,b.bottom=a)},c._insertafter=function(a,b,c){Lb(a,c),b==c.top&&(c.top=a),b.next&&(b.next.prev=a),a.next=b.next,a.prev=b,b.next=a},c._insertbefore=function(a,b,c){Lb(a,c),b==c.bottom&&(c.bottom=a),b.prev&&(b.prev.next=a),a.prev=b.prev,b.prev=a,a.next=b},c.toMatrix=function(a,b){var c=Bb(a),d={_:{transform:G},getBBox:function(){return c}};return Nb(d,b),d.matrix}),Nb=(c.transformPath=function(a,b){return rb(a,Mb(a,b))},c._extractTransform=function(a,b){if(null==b)return a._.transform;b=I(b).replace(/\.{3}|\u2026/g,a._.transform||G);var d=c.parseTransformString(b),e=0,f=0,g=0,h=1,i=1,j=a._,k=new o;if(j.transform=d||[],d)for(var l=0,m=d.length;m>l;l++){var n,p,q,r,s,t=d[l],u=t.length,v=I(t[0]).toLowerCase(),w=t[0]!=v,x=w?k.invert():0;"t"==v&&3==u?w?(n=x.x(0,0),p=x.y(0,0),q=x.x(t[1],t[2]),r=x.y(t[1],t[2]),k.translate(q-n,r-p)):k.translate(t[1],t[2]):"r"==v?2==u?(s=s||a.getBBox(1),k.rotate(t[1],s.x+s.width/2,s.y+s.height/2),e+=t[1]):4==u&&(w?(q=x.x(t[2],t[3]),r=x.y(t[2],t[3]),k.rotate(t[1],q,r)):k.rotate(t[1],t[2],t[3]),e+=t[1]):"s"==v?2==u||3==u?(s=s||a.getBBox(1),k.scale(t[1],t[u-1],s.x+s.width/2,s.y+s.height/2),h*=t[1],i*=t[u-1]):5==u&&(w?(q=x.x(t[3],t[4]),r=x.y(t[3],t[4]),k.scale(t[1],t[2],q,r)):k.scale(t[1],t[2],t[3],t[4]),h*=t[1],i*=t[2]):"m"==v&&7==u&&k.add(t[1],t[2],t[3],t[4],t[5],t[6]),j.dirtyT=1,a.matrix=k}a.matrix=k,j.sx=h,j.sy=i,j.deg=e,j.dx=f=k.e,j.dy=g=k.f,1==h&&1==i&&!e&&j.bbox?(j.bbox.x+=+f,j.bbox.y+=+g):j.dirtyT=1}),Ob=function(a){var b=a[0];switch(b.toLowerCase()){case"t":return[b,0,0];case"m":return[b,1,0,0,1,0,0];case"r":return 4==a.length?[b,0,a[2],a[3]]:[b,0];case"s":return 5==a.length?[b,1,1,a[3],a[4]]:3==a.length?[b,1,1]:[b,1]}},Pb=c._equaliseTransform=function(a,b){b=I(b).replace(/\.{3}|\u2026/g,a),a=c.parseTransformString(a)||[],b=c.parseTransformString(b)||[]; +for(var d,e,f,g,h=O(a.length,b.length),i=[],j=[],k=0;h>k;k++){if(f=a[k]||Ob(b[k]),g=b[k]||Ob(f),f[0]!=g[0]||"r"==f[0].toLowerCase()&&(f[2]!=g[2]||f[3]!=g[3])||"s"==f[0].toLowerCase()&&(f[3]!=g[3]||f[4]!=g[4]))return;for(i[k]=[],j[k]=[],d=0,e=O(f.length,g.length);e>d;d++)d in f&&(i[k][d]=f[d]),d in g&&(j[k][d]=g[d])}return{from:i,to:j}};c._getContainer=function(a,b,d,e){var f;return f=null!=e||c.is(a,"object")?a:A.doc.getElementById(a),null!=f?f.tagName?null==b?{container:f,width:f.style.pixelWidth||f.offsetWidth,height:f.style.pixelHeight||f.offsetHeight}:{container:f,width:b,height:d}:{container:1,x:a,y:b,width:d,height:e}:void 0},c.pathToRelative=Db,c._engine={},c.path2curve=Kb,c.matrix=function(a,b,c,d,e,f){return new o(a,b,c,d,e,f)},function(a){function b(a){return a[0]*a[0]+a[1]*a[1]}function d(a){var c=N.sqrt(b(a));a[0]&&(a[0]/=c),a[1]&&(a[1]/=c)}a.add=function(a,b,c,d,e,f){var g,h,i,j,k=[[],[],[]],l=[[this.a,this.c,this.e],[this.b,this.d,this.f],[0,0,1]],m=[[a,c,e],[b,d,f],[0,0,1]];for(a&&a instanceof o&&(m=[[a.a,a.c,a.e],[a.b,a.d,a.f],[0,0,1]]),g=0;3>g;g++)for(h=0;3>h;h++){for(j=0,i=0;3>i;i++)j+=l[g][i]*m[i][h];k[g][h]=j}this.a=k[0][0],this.b=k[1][0],this.c=k[0][1],this.d=k[1][1],this.e=k[0][2],this.f=k[1][2]},a.invert=function(){var a=this,b=a.a*a.d-a.b*a.c;return new o(a.d/b,-a.b/b,-a.c/b,a.a/b,(a.c*a.f-a.d*a.e)/b,(a.b*a.e-a.a*a.f)/b)},a.clone=function(){return new o(this.a,this.b,this.c,this.d,this.e,this.f)},a.translate=function(a,b){this.add(1,0,0,1,a,b)},a.scale=function(a,b,c,d){null==b&&(b=a),(c||d)&&this.add(1,0,0,1,c,d),this.add(a,0,0,b,0,0),(c||d)&&this.add(1,0,0,1,-c,-d)},a.rotate=function(a,b,d){a=c.rad(a),b=b||0,d=d||0;var e=+N.cos(a).toFixed(9),f=+N.sin(a).toFixed(9);this.add(e,f,-f,e,b,d),this.add(1,0,0,1,-b,-d)},a.x=function(a,b){return a*this.a+b*this.c+this.e},a.y=function(a,b){return a*this.b+b*this.d+this.f},a.get=function(a){return+this[I.fromCharCode(97+a)].toFixed(4)},a.toString=function(){return c.svg?"matrix("+[this.get(0),this.get(1),this.get(2),this.get(3),this.get(4),this.get(5)].join()+")":[this.get(0),this.get(2),this.get(1),this.get(3),0,0].join()},a.toFilter=function(){return"progid:DXImageTransform.Microsoft.Matrix(M11="+this.get(0)+", M12="+this.get(2)+", M21="+this.get(1)+", M22="+this.get(3)+", Dx="+this.get(4)+", Dy="+this.get(5)+", sizingmethod='auto expand')"},a.offset=function(){return[this.e.toFixed(4),this.f.toFixed(4)]},a.split=function(){var a={};a.dx=this.e,a.dy=this.f;var e=[[this.a,this.c],[this.b,this.d]];a.scalex=N.sqrt(b(e[0])),d(e[0]),a.shear=e[0][0]*e[1][0]+e[0][1]*e[1][1],e[1]=[e[1][0]-e[0][0]*a.shear,e[1][1]-e[0][1]*a.shear],a.scaley=N.sqrt(b(e[1])),d(e[1]),a.shear/=a.scaley;var f=-e[0][1],g=e[1][1];return 0>g?(a.rotate=c.deg(N.acos(g)),0>f&&(a.rotate=360-a.rotate)):a.rotate=c.deg(N.asin(f)),a.isSimple=!(+a.shear.toFixed(9)||a.scalex.toFixed(9)!=a.scaley.toFixed(9)&&a.rotate),a.isSuperSimple=!+a.shear.toFixed(9)&&a.scalex.toFixed(9)==a.scaley.toFixed(9)&&!a.rotate,a.noRotation=!+a.shear.toFixed(9)&&!a.rotate,a},a.toTransformString=function(a){var b=a||this[J]();return b.isSimple?(b.scalex=+b.scalex.toFixed(4),b.scaley=+b.scaley.toFixed(4),b.rotate=+b.rotate.toFixed(4),(b.dx||b.dy?"t"+[b.dx,b.dy]:G)+(1!=b.scalex||1!=b.scaley?"s"+[b.scalex,b.scaley,0,0]:G)+(b.rotate?"r"+[b.rotate,0,0]:G)):"m"+[this.get(0),this.get(1),this.get(2),this.get(3),this.get(4),this.get(5)]}}(o.prototype);var Qb=navigator.userAgent.match(/Version\/(.*?)\s/)||navigator.userAgent.match(/Chrome\/(\d+)/);v.safari="Apple Computer, Inc."==navigator.vendor&&(Qb&&Qb[1]<4||"iP"==navigator.platform.slice(0,2))||"Google Inc."==navigator.vendor&&Qb&&Qb[1]<8?function(){var a=this.rect(-99,-99,this.width+99,this.height+99).attr({stroke:"none"});setTimeout(function(){a.remove()})}:mb;for(var Rb=function(){this.returnValue=!1},Sb=function(){return this.originalEvent.preventDefault()},Tb=function(){this.cancelBubble=!0},Ub=function(){return this.originalEvent.stopPropagation()},Vb=function(a){var b=A.doc.documentElement.scrollTop||A.doc.body.scrollTop,c=A.doc.documentElement.scrollLeft||A.doc.body.scrollLeft;return{x:a.clientX+c,y:a.clientY+b}},Wb=function(){return A.doc.addEventListener?function(a,b,c,d){var e=function(a){var b=Vb(a);return c.call(d,a,b.x,b.y)};if(a.addEventListener(b,e,!1),F&&L[b]){var f=function(b){for(var e=Vb(b),f=b,g=0,h=b.targetTouches&&b.targetTouches.length;h>g;g++)if(b.targetTouches[g].target==a){b=b.targetTouches[g],b.originalEvent=f,b.preventDefault=Sb,b.stopPropagation=Ub;break}return c.call(d,b,e.x,e.y)};a.addEventListener(L[b],f,!1)}return function(){return a.removeEventListener(b,e,!1),F&&L[b]&&a.removeEventListener(L[b],f,!1),!0}}:A.doc.attachEvent?function(a,b,c,d){var e=function(a){a=a||A.win.event;var b=A.doc.documentElement.scrollTop||A.doc.body.scrollTop,e=A.doc.documentElement.scrollLeft||A.doc.body.scrollLeft,f=a.clientX+e,g=a.clientY+b;return a.preventDefault=a.preventDefault||Rb,a.stopPropagation=a.stopPropagation||Tb,c.call(d,a,f,g)};a.attachEvent("on"+b,e);var f=function(){return a.detachEvent("on"+b,e),!0};return f}:void 0}(),Xb=[],Yb=function(a){for(var c,d=a.clientX,e=a.clientY,f=A.doc.documentElement.scrollTop||A.doc.body.scrollTop,g=A.doc.documentElement.scrollLeft||A.doc.body.scrollLeft,h=Xb.length;h--;){if(c=Xb[h],F&&a.touches){for(var i,j=a.touches.length;j--;)if(i=a.touches[j],i.identifier==c.el._drag.id){d=i.clientX,e=i.clientY,(a.originalEvent?a.originalEvent:a).preventDefault();break}}else a.preventDefault();var k,l=c.el.node,m=l.nextSibling,n=l.parentNode,o=l.style.display;A.win.opera&&n.removeChild(l),l.style.display="none",k=c.el.paper.getElementByPoint(d,e),l.style.display=o,A.win.opera&&(m?n.insertBefore(l,m):n.appendChild(l)),k&&b("raphael.drag.over."+c.el.id,c.el,k),d+=g,e+=f,b("raphael.drag.move."+c.el.id,c.move_scope||c.el,d-c.el._drag.x,e-c.el._drag.y,d,e,a)}},Zb=function(a){c.unmousemove(Yb).unmouseup(Zb);for(var d,e=Xb.length;e--;)d=Xb[e],d.el._drag={},b("raphael.drag.end."+d.el.id,d.end_scope||d.start_scope||d.move_scope||d.el,a);Xb=[]},$b=c.el={},_b=K.length;_b--;)!function(a){c[a]=$b[a]=function(b,d){return c.is(b,"function")&&(this.events=this.events||[],this.events.push({name:a,f:b,unbind:Wb(this.shape||this.node||A.doc,a,b,d||this)})),this},c["un"+a]=$b["un"+a]=function(b){for(var d=this.events||[],e=d.length;e--;)d[e].name!=a||!c.is(b,"undefined")&&d[e].f!=b||(d[e].unbind(),d.splice(e,1),!d.length&&delete this.events);return this}}(K[_b]);$b.data=function(a,d){var e=kb[this.id]=kb[this.id]||{};if(0==arguments.length)return e;if(1==arguments.length){if(c.is(a,"object")){for(var f in a)a[z](f)&&this.data(f,a[f]);return this}return b("raphael.data.get."+this.id,this,e[a],a),e[a]}return e[a]=d,b("raphael.data.set."+this.id,this,d,a),this},$b.removeData=function(a){return null==a?kb[this.id]={}:kb[this.id]&&delete kb[this.id][a],this},$b.getData=function(){return d(kb[this.id]||{})},$b.hover=function(a,b,c,d){return this.mouseover(a,c).mouseout(b,d||c)},$b.unhover=function(a,b){return this.unmouseover(a).unmouseout(b)};var ac=[];$b.drag=function(a,d,e,f,g,h){function i(i){(i.originalEvent||i).preventDefault();var j=i.clientX,k=i.clientY,l=A.doc.documentElement.scrollTop||A.doc.body.scrollTop,m=A.doc.documentElement.scrollLeft||A.doc.body.scrollLeft;if(this._drag.id=i.identifier,F&&i.touches)for(var n,o=i.touches.length;o--;)if(n=i.touches[o],this._drag.id=n.identifier,n.identifier==this._drag.id){j=n.clientX,k=n.clientY;break}this._drag.x=j+m,this._drag.y=k+l,!Xb.length&&c.mousemove(Yb).mouseup(Zb),Xb.push({el:this,move_scope:f,start_scope:g,end_scope:h}),d&&b.on("raphael.drag.start."+this.id,d),a&&b.on("raphael.drag.move."+this.id,a),e&&b.on("raphael.drag.end."+this.id,e),b("raphael.drag.start."+this.id,g||f||this,i.clientX+m,i.clientY+l,i)}return this._drag={},ac.push({el:this,start:i}),this.mousedown(i),this},$b.onDragOver=function(a){a?b.on("raphael.drag.over."+this.id,a):b.unbind("raphael.drag.over."+this.id)},$b.undrag=function(){for(var a=ac.length;a--;)ac[a].el==this&&(this.unmousedown(ac[a].start),ac.splice(a,1),b.unbind("raphael.drag.*."+this.id));!ac.length&&c.unmousemove(Yb).unmouseup(Zb),Xb=[]},v.circle=function(a,b,d){var e=c._engine.circle(this,a||0,b||0,d||0);return this.__set__&&this.__set__.push(e),e},v.rect=function(a,b,d,e,f){var g=c._engine.rect(this,a||0,b||0,d||0,e||0,f||0);return this.__set__&&this.__set__.push(g),g},v.ellipse=function(a,b,d,e){var f=c._engine.ellipse(this,a||0,b||0,d||0,e||0);return this.__set__&&this.__set__.push(f),f},v.path=function(a){a&&!c.is(a,U)&&!c.is(a[0],V)&&(a+=G);var b=c._engine.path(c.format[D](c,arguments),this);return this.__set__&&this.__set__.push(b),b},v.image=function(a,b,d,e,f){var g=c._engine.image(this,a||"about:blank",b||0,d||0,e||0,f||0);return this.__set__&&this.__set__.push(g),g},v.text=function(a,b,d){var e=c._engine.text(this,a||0,b||0,I(d));return this.__set__&&this.__set__.push(e),e},v.set=function(a){!c.is(a,"array")&&(a=Array.prototype.splice.call(arguments,0,arguments.length));var b=new mc(a);return this.__set__&&this.__set__.push(b),b.paper=this,b.type="set",b},v.setStart=function(a){this.__set__=a||this.set()},v.setFinish=function(){var a=this.__set__;return delete this.__set__,a},v.getSize=function(){var a=this.canvas.parentNode;return{width:a.offsetWidth,height:a.offsetHeight}},v.setSize=function(a,b){return c._engine.setSize.call(this,a,b)},v.setViewBox=function(a,b,d,e,f){return c._engine.setViewBox.call(this,a,b,d,e,f)},v.top=v.bottom=null,v.raphael=c;var bc=function(a){var b=a.getBoundingClientRect(),c=a.ownerDocument,d=c.body,e=c.documentElement,f=e.clientTop||d.clientTop||0,g=e.clientLeft||d.clientLeft||0,h=b.top+(A.win.pageYOffset||e.scrollTop||d.scrollTop)-f,i=b.left+(A.win.pageXOffset||e.scrollLeft||d.scrollLeft)-g;return{y:h,x:i}};v.getElementByPoint=function(a,b){var c=this,d=c.canvas,e=A.doc.elementFromPoint(a,b);if(A.win.opera&&"svg"==e.tagName){var f=bc(d),g=d.createSVGRect();g.x=a-f.x,g.y=b-f.y,g.width=g.height=1;var h=d.getIntersectionList(g,null);h.length&&(e=h[h.length-1])}if(!e)return null;for(;e.parentNode&&e!=d.parentNode&&!e.raphael;)e=e.parentNode;return e==c.canvas.parentNode&&(e=d),e=e&&e.raphael?c.getById(e.raphaelid):null},v.getElementsByBBox=function(a){var b=this.set();return this.forEach(function(d){c.isBBoxIntersect(d.getBBox(),a)&&b.push(d)}),b},v.getById=function(a){for(var b=this.bottom;b;){if(b.id==a)return b;b=b.next}return null},v.forEach=function(a,b){for(var c=this.bottom;c;){if(a.call(b,c)===!1)return this;c=c.next}return this},v.getElementsByPoint=function(a,b){var c=this.set();return this.forEach(function(d){d.isPointInside(a,b)&&c.push(d)}),c},$b.isPointInside=function(a,b){var d=this.realPath=qb[this.type](this);return this.attr("transform")&&this.attr("transform").length&&(d=c.transformPath(d,this.attr("transform"))),c.isPointInsidePath(d,a,b)},$b.getBBox=function(a){if(this.removed)return{};var b=this._;return a?((b.dirty||!b.bboxwt)&&(this.realPath=qb[this.type](this),b.bboxwt=Bb(this.realPath),b.bboxwt.toString=p,b.dirty=0),b.bboxwt):((b.dirty||b.dirtyT||!b.bbox)&&((b.dirty||!this.realPath)&&(b.bboxwt=0,this.realPath=qb[this.type](this)),b.bbox=Bb(rb(this.realPath,this.matrix)),b.bbox.toString=p,b.dirty=b.dirtyT=0),b.bbox)},$b.clone=function(){if(this.removed)return null;var a=this.paper[this.type]().attr(this.attr());return this.__set__&&this.__set__.push(a),a},$b.glow=function(a){if("text"==this.type)return null;a=a||{};var b={width:(a.width||10)+(+this.attr("stroke-width")||1),fill:a.fill||!1,opacity:a.opacity||.5,offsetx:a.offsetx||0,offsety:a.offsety||0,color:a.color||"#000"},c=b.width/2,d=this.paper,e=d.set(),f=this.realPath||qb[this.type](this);f=this.matrix?rb(f,this.matrix):f;for(var g=1;c+1>g;g++)e.push(d.path(f).attr({stroke:b.color,fill:b.fill?b.color:"none","stroke-linejoin":"round","stroke-linecap":"round","stroke-width":+(b.width/c*g).toFixed(3),opacity:+(b.opacity/c).toFixed(3)}));return e.insertBefore(this).translate(b.offsetx,b.offsety)};var cc=function(a,b,d,e,f,g,h,i,l){return null==l?j(a,b,d,e,f,g,h,i):c.findDotsAtSegment(a,b,d,e,f,g,h,i,k(a,b,d,e,f,g,h,i,l))},dc=function(a,b){return function(d,e,f){d=Kb(d);for(var g,h,i,j,k,l="",m={},n=0,o=0,p=d.length;p>o;o++){if(i=d[o],"M"==i[0])g=+i[1],h=+i[2];else{if(j=cc(g,h,i[1],i[2],i[3],i[4],i[5],i[6]),n+j>e){if(b&&!m.start){if(k=cc(g,h,i[1],i[2],i[3],i[4],i[5],i[6],e-n),l+=["C"+k.start.x,k.start.y,k.m.x,k.m.y,k.x,k.y],f)return l;m.start=l,l=["M"+k.x,k.y+"C"+k.n.x,k.n.y,k.end.x,k.end.y,i[5],i[6]].join(),n+=j,g=+i[5],h=+i[6];continue}if(!a&&!b)return k=cc(g,h,i[1],i[2],i[3],i[4],i[5],i[6],e-n),{x:k.x,y:k.y,alpha:k.alpha}}n+=j,g=+i[5],h=+i[6]}l+=i.shift()+i}return m.end=l,k=a?n:b?m:c.findDotsAtSegment(g,h,i[0],i[1],i[2],i[3],i[4],i[5],1),k.alpha&&(k={x:k.x,y:k.y,alpha:k.alpha}),k}},ec=dc(1),fc=dc(),gc=dc(0,1);c.getTotalLength=ec,c.getPointAtLength=fc,c.getSubpath=function(a,b,c){if(this.getTotalLength(a)-c<1e-6)return gc(a,b).end;var d=gc(a,c,1);return b?gc(d,b).end:d},$b.getTotalLength=function(){var a=this.getPath();if(a)return this.node.getTotalLength?this.node.getTotalLength():ec(a)},$b.getPointAtLength=function(a){var b=this.getPath();if(b)return fc(b,a)},$b.getPath=function(){var a,b=c._getPath[this.type];if("text"!=this.type&&"set"!=this.type)return b&&(a=b(this)),a},$b.getSubpath=function(a,b){var d=this.getPath();if(d)return c.getSubpath(d,a,b)};var hc=c.easing_formulas={linear:function(a){return a},"<":function(a){return R(a,1.7)},">":function(a){return R(a,.48)},"<>":function(a){var b=.48-a/1.04,c=N.sqrt(.1734+b*b),d=c-b,e=R(Q(d),1/3)*(0>d?-1:1),f=-c-b,g=R(Q(f),1/3)*(0>f?-1:1),h=e+g+.5;return 3*(1-h)*h*h+h*h*h},backIn:function(a){var b=1.70158;return a*a*((b+1)*a-b)},backOut:function(a){a-=1;var b=1.70158;return a*a*((b+1)*a+b)+1},elastic:function(a){return a==!!a?a:R(2,-10*a)*N.sin(2*(a-.075)*S/.3)+1},bounce:function(a){var b,c=7.5625,d=2.75;return 1/d>a?b=c*a*a:2/d>a?(a-=1.5/d,b=c*a*a+.75):2.5/d>a?(a-=2.25/d,b=c*a*a+.9375):(a-=2.625/d,b=c*a*a+.984375),b}};hc.easeIn=hc["ease-in"]=hc["<"],hc.easeOut=hc["ease-out"]=hc[">"],hc.easeInOut=hc["ease-in-out"]=hc["<>"],hc["back-in"]=hc.backIn,hc["back-out"]=hc.backOut;var ic=[],jc=a.requestAnimationFrame||a.webkitRequestAnimationFrame||a.mozRequestAnimationFrame||a.oRequestAnimationFrame||a.msRequestAnimationFrame||function(a){setTimeout(a,16)},kc=function(){for(var a=+new Date,d=0;dh))if(i>h){var q=j(h/i);for(var r in k)if(k[z](r)){switch(db[r]){case T:f=+k[r]+q*i*l[r];break;case"colour":f="rgb("+[lc($(k[r].r+q*i*l[r].r)),lc($(k[r].g+q*i*l[r].g)),lc($(k[r].b+q*i*l[r].b))].join(",")+")";break;case"path":f=[];for(var t=0,u=k[r].length;u>t;t++){f[t]=[k[r][t][0]];for(var v=1,w=k[r][t].length;w>v;v++)f[t][v]=+k[r][t][v]+q*i*l[r][t][v];f[t]=f[t].join(H)}f=f.join(H);break;case"transform":if(l[r].real)for(f=[],t=0,u=k[r].length;u>t;t++)for(f[t]=[k[r][t][0]],v=1,w=k[r][t].length;w>v;v++)f[t][v]=k[r][t][v]+q*i*l[r][t][v];else{var x=function(a){return+k[r][a]+q*i*l[r][a]};f=[["m",x(0),x(1),x(2),x(3),x(4),x(5)]]}break;case"csv":if("clip-rect"==r)for(f=[],t=4;t--;)f[t]=+k[r][t]+q*i*l[r][t];break;default:var y=[][E](k[r]);for(f=[],t=n.paper.customAttributes[r].length;t--;)f[t]=+y[t]+q*i*l[r][t]}o[r]=f}n.attr(o),function(a,c,d){setTimeout(function(){b("raphael.anim.frame."+a,c,d)})}(n.id,n,e.anim)}else{if(function(a,d,e){setTimeout(function(){b("raphael.anim.frame."+d.id,d,e),b("raphael.anim.finish."+d.id,d,e),c.is(a,"function")&&a.call(d)})}(e.callback,n,e.anim),n.attr(m),ic.splice(d--,1),e.repeat>1&&!e.next){for(g in m)m[z](g)&&(p[g]=e.totalOrigin[g]);e.el.attr(p),s(e.anim,e.el,e.anim.percents[0],null,e.totalOrigin,e.repeat-1)}e.next&&!e.stop&&s(e.anim,e.el,e.next,null,e.totalOrigin,e.repeat)}}}c.svg&&n&&n.paper&&n.paper.safari(),ic.length&&jc(kc)},lc=function(a){return a>255?255:0>a?0:a};$b.animateWith=function(a,b,d,e,f,g){var h=this;if(h.removed)return g&&g.call(h),h;var i=d instanceof r?d:c.animation(d,e,f,g);s(i,h,i.percents[0],null,h.attr());for(var j=0,k=ic.length;k>j;j++)if(ic[j].anim==b&&ic[j].el==a){ic[k-1].start=ic[j].start;break}return h},$b.onAnimation=function(a){return a?b.on("raphael.anim.frame."+this.id,a):b.unbind("raphael.anim.frame."+this.id),this},r.prototype.delay=function(a){var b=new r(this.anim,this.ms);return b.times=this.times,b.del=+a||0,b},r.prototype.repeat=function(a){var b=new r(this.anim,this.ms);return b.del=this.del,b.times=N.floor(O(a,0))||1,b},c.animation=function(a,b,d,e){if(a instanceof r)return a;(c.is(d,"function")||!d)&&(e=e||d||null,d=null),a=Object(a),b=+b||0;var f,g,h={};for(g in a)a[z](g)&&_(g)!=g&&_(g)+"%"!=g&&(f=!0,h[g]=a[g]);if(f)return d&&(h.easing=d),e&&(h.callback=e),new r({100:h},b);if(e){var i=0;for(var j in a){var k=ab(j);a[z](j)&&k>i&&(i=k)}i+="%",!a[i].callback&&(a[i].callback=e)}return new r(a,b)},$b.animate=function(a,b,d,e){var f=this;if(f.removed)return e&&e.call(f),f;var g=a instanceof r?a:c.animation(a,b,d,e);return s(g,f,g.percents[0],null,f.attr()),f},$b.setTime=function(a,b){return a&&null!=b&&this.status(a,P(b,a.ms)/a.ms),this},$b.status=function(a,b){var c,d,e=[],f=0;if(null!=b)return s(a,this,-1,P(b,1)),this;for(c=ic.length;c>f;f++)if(d=ic[f],d.el.id==this.id&&(!a||d.anim==a)){if(a)return d.status;e.push({anim:d.anim,status:d.status})}return a?0:e},$b.pause=function(a){for(var c=0;cb;b++)!a[b]||a[b].constructor!=$b.constructor&&a[b].constructor!=mc||(this[this.items.length]=this.items[this.items.length]=a[b],this.length++)},nc=mc.prototype;nc.push=function(){for(var a,b,c=0,d=arguments.length;d>c;c++)a=arguments[c],!a||a.constructor!=$b.constructor&&a.constructor!=mc||(b=this.items.length,this[b]=this.items[b]=a,this.length++);return this},nc.pop=function(){return this.length&&delete this[this.length--],this.items.pop()},nc.forEach=function(a,b){for(var c=0,d=this.items.length;d>c;c++)if(a.call(b,this.items[c],c)===!1)return this;return this};for(var oc in $b)$b[z](oc)&&(nc[oc]=function(a){return function(){var b=arguments;return this.forEach(function(c){c[a][D](c,b)})}}(oc));return nc.attr=function(a,b){if(a&&c.is(a,V)&&c.is(a[0],"object"))for(var d=0,e=a.length;e>d;d++)this.items[d].attr(a[d]);else for(var f=0,g=this.items.length;g>f;f++)this.items[f].attr(a,b);return this},nc.clear=function(){for(;this.length;)this.pop()},nc.splice=function(a,b){a=0>a?O(this.length+a,0):a,b=O(0,P(this.length-a,b));var c,d=[],e=[],f=[];for(c=2;cc;c++)e.push(this[a+c]);for(;cc?f[c]:d[c-g];for(c=this.items.length=this.length-=b-g;this[c];)delete this[c++];return new mc(e)},nc.exclude=function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]==a)return this.splice(b,1),!0},nc.animate=function(a,b,d,e){(c.is(d,"function")||!d)&&(e=d||null);var f,g,h=this.items.length,i=h,j=this;if(!h)return this;e&&(g=function(){!--h&&e.call(j)}),d=c.is(d,U)?d:g;var k=c.animation(a,b,d,g);for(f=this.items[--i].animate(k);i--;)this.items[i]&&!this.items[i].removed&&this.items[i].animateWith(f,k,k),this.items[i]&&!this.items[i].removed||h--;return this},nc.insertAfter=function(a){for(var b=this.items.length;b--;)this.items[b].insertAfter(a);return this},nc.getBBox=function(){for(var a=[],b=[],c=[],d=[],e=this.items.length;e--;)if(!this.items[e].removed){var f=this.items[e].getBBox();a.push(f.x),b.push(f.y),c.push(f.x+f.width),d.push(f.y+f.height)}return a=P[D](0,a),b=P[D](0,b),c=O[D](0,c),d=O[D](0,d),{x:a,y:b,x2:c,y2:d,width:c-a,height:d-b}},nc.clone=function(a){a=this.paper.set();for(var b=0,c=this.items.length;c>b;b++)a.push(this.items[b].clone());return a},nc.toString=function(){return"Raphaël‘s set"},nc.glow=function(a){var b=this.paper.set();return this.forEach(function(c){var d=c.glow(a);null!=d&&d.forEach(function(a){b.push(a)})}),b},nc.isPointInside=function(a,b){var c=!1;return this.forEach(function(d){return d.isPointInside(a,b)?(c=!0,!1):void 0}),c},c.registerFont=function(a){if(!a.face)return a;this.fonts=this.fonts||{};var b={w:a.w,face:{},glyphs:{}},c=a.face["font-family"];for(var d in a.face)a.face[z](d)&&(b.face[d]=a.face[d]);if(this.fonts[c]?this.fonts[c].push(b):this.fonts[c]=[b],!a.svg){b.face["units-per-em"]=ab(a.face["units-per-em"],10);for(var e in a.glyphs)if(a.glyphs[z](e)){var f=a.glyphs[e];if(b.glyphs[e]={w:f.w,k:{},d:f.d&&"M"+f.d.replace(/[mlcxtrv]/g,function(a){return{l:"L",c:"C",x:"z",t:"m",r:"l",v:"c"}[a]||"M"})+"z"},f.k)for(var g in f.k)f[z](g)&&(b.glyphs[e].k[g]=f.k[g])}}return a},v.getFont=function(a,b,d,e){if(e=e||"normal",d=d||"normal",b=+b||{normal:400,bold:700,lighter:300,bolder:800}[b]||400,c.fonts){var f=c.fonts[a];if(!f){var g=new RegExp("(^|\\s)"+a.replace(/[^\w\d\s+!~.:_-]/g,G)+"(\\s|$)","i");for(var h in c.fonts)if(c.fonts[z](h)&&g.test(h)){f=c.fonts[h];break}}var i;if(f)for(var j=0,k=f.length;k>j&&(i=f[j],i.face["font-weight"]!=b||i.face["font-style"]!=d&&i.face["font-style"]||i.face["font-stretch"]!=e);j++);return i}},v.print=function(a,b,d,e,f,g,h,i){g=g||"middle",h=O(P(h||0,1),-1),i=O(P(i||1,3),1);var j,k=I(d)[J](G),l=0,m=0,n=G;if(c.is(e,"string")&&(e=this.getFont(e)),e){j=(f||16)/e.face["units-per-em"];for(var o=e.face.bbox[J](w),p=+o[0],q=o[3]-o[1],r=0,s=+o[1]+("baseline"==g?q+ +e.face.descent:q/2),t=0,u=k.length;u>t;t++){if("\n"==k[t])l=0,x=0,m=0,r+=q*i;else{var v=m&&e.glyphs[k[t-1]]||{},x=e.glyphs[k[t]];l+=m?(v.w||e.w)+(v.k&&v.k[k[t]]||0)+e.w*h:0,m=1}x&&x.d&&(n+=c.transformPath(x.d,["t",l*j,r*j,"s",j,j,p,s,"t",(a-p)/j,(b-s)/j]))}}return this.path(n).attr({fill:"#000",stroke:"none"})},v.add=function(a){if(c.is(a,"array"))for(var b,d=this.set(),e=0,f=a.length;f>e;e++)b=a[e]||{},x[z](b.type)&&d.push(this[b.type]().attr(b));return d},c.format=function(a,b){var d=c.is(b,V)?[0][E](b):arguments;return a&&c.is(a,U)&&d.length-1&&(a=a.replace(y,function(a,b){return null==d[++b]?G:d[b]})),a||G},c.fullfill=function(){var a=/\{([^\}]+)\}/g,b=/(?:(?:^|\.)(.+?)(?=\[|\.|$|\()|\[('|")(.+?)\2\])(\(\))?/g,c=function(a,c,d){var e=d;return c.replace(b,function(a,b,c,d,f){b=b||d,e&&(b in e&&(e=e[b]),"function"==typeof e&&f&&(e=e()))}),e=(null==e||e==d?a:e)+""};return function(b,d){return String(b).replace(a,function(a,b){return c(a,b,d)})}}(),c.ninja=function(){return B.was?A.win.Raphael=B.is:delete Raphael,c},c.st=nc,b.on("raphael.DOMload",function(){u=!0}),function(a,b,d){function e(){/in/.test(a.readyState)?setTimeout(e,9):c.eve("raphael.DOMload")}null==a.readyState&&a.addEventListener&&(a.addEventListener(b,d=function(){a.removeEventListener(b,d,!1),a.readyState="complete"},!1),a.readyState="loading"),e()}(document,"DOMContentLoaded"),function(){if(c.svg){var a="hasOwnProperty",b=String,d=parseFloat,e=parseInt,f=Math,g=f.max,h=f.abs,i=f.pow,j=/[, ]+/,k=c.eve,l="",m=" ",n="http://www.w3.org/1999/xlink",o={block:"M5,0 0,2.5 5,5z",classic:"M5,0 0,2.5 5,5 3.5,3 3.5,2z",diamond:"M2.5,0 5,2.5 2.5,5 0,2.5z",open:"M6,1 1,3.5 6,6",oval:"M2.5,0A2.5,2.5,0,0,1,2.5,5 2.5,2.5,0,0,1,2.5,0z"},p={};c.toString=function(){return"Your browser supports SVG.\nYou are running Raphaël "+this.version};var q=function(d,e){if(e){"string"==typeof d&&(d=q(d));for(var f in e)e[a](f)&&("xlink:"==f.substring(0,6)?d.setAttributeNS(n,f.substring(6),b(e[f])):d.setAttribute(f,b(e[f])))}else d=c._g.doc.createElementNS("http://www.w3.org/2000/svg",d),d.style&&(d.style.webkitTapHighlightColor="rgba(0,0,0,0)");return d},r=function(a,e){var j="linear",k=a.id+e,m=.5,n=.5,o=a.node,p=a.paper,r=o.style,s=c._g.doc.getElementById(k);if(!s){if(e=b(e).replace(c._radial_gradient,function(a,b,c){if(j="radial",b&&c){m=d(b),n=d(c);var e=2*(n>.5)-1;i(m-.5,2)+i(n-.5,2)>.25&&(n=f.sqrt(.25-i(m-.5,2))*e+.5)&&.5!=n&&(n=n.toFixed(5)-1e-5*e)}return l}),e=e.split(/\s*\-\s*/),"linear"==j){var t=e.shift();if(t=-d(t),isNaN(t))return null;var u=[0,0,f.cos(c.rad(t)),f.sin(c.rad(t))],v=1/(g(h(u[2]),h(u[3]))||1);u[2]*=v,u[3]*=v,u[2]<0&&(u[0]=-u[2],u[2]=0),u[3]<0&&(u[1]=-u[3],u[3]=0)}var w=c._parseDots(e);if(!w)return null;if(k=k.replace(/[\(\)\s,\xb0#]/g,"_"),a.gradient&&k!=a.gradient.id&&(p.defs.removeChild(a.gradient),delete a.gradient),!a.gradient){s=q(j+"Gradient",{id:k}),a.gradient=s,q(s,"radial"==j?{fx:m,fy:n}:{x1:u[0],y1:u[1],x2:u[2],y2:u[3],gradientTransform:a.matrix.invert()}),p.defs.appendChild(s);for(var x=0,y=w.length;y>x;x++)s.appendChild(q("stop",{offset:w[x].offset?w[x].offset:x?"100%":"0%","stop-color":w[x].color||"#fff"}))}}return q(o,{fill:"url("+document.location+"#"+k+")",opacity:1,"fill-opacity":1}),r.fill=l,r.opacity=1,r.fillOpacity=1,1},s=function(a){var b=a.getBBox(1);q(a.pattern,{patternTransform:a.matrix.invert()+" translate("+b.x+","+b.y+")"})},t=function(d,e,f){if("path"==d.type){for(var g,h,i,j,k,m=b(e).toLowerCase().split("-"),n=d.paper,r=f?"end":"start",s=d.node,t=d.attrs,u=t["stroke-width"],v=m.length,w="classic",x=3,y=3,z=5;v--;)switch(m[v]){case"block":case"classic":case"oval":case"diamond":case"open":case"none":w=m[v];break;case"wide":y=5;break;case"narrow":y=2;break;case"long":x=5;break;case"short":x=2}if("open"==w?(x+=2,y+=2,z+=2,i=1,j=f?4:1,k={fill:"none",stroke:t.stroke}):(j=i=x/2,k={fill:t.stroke,stroke:"none"}),d._.arrows?f?(d._.arrows.endPath&&p[d._.arrows.endPath]--,d._.arrows.endMarker&&p[d._.arrows.endMarker]--):(d._.arrows.startPath&&p[d._.arrows.startPath]--,d._.arrows.startMarker&&p[d._.arrows.startMarker]--):d._.arrows={},"none"!=w){var A="raphael-marker-"+w,B="raphael-marker-"+r+w+x+y+"-obj"+d.id;c._g.doc.getElementById(A)?p[A]++:(n.defs.appendChild(q(q("path"),{"stroke-linecap":"round",d:o[w],id:A})),p[A]=1);var C,D=c._g.doc.getElementById(B);D?(p[B]++,C=D.getElementsByTagName("use")[0]):(D=q(q("marker"),{id:B,markerHeight:y,markerWidth:x,orient:"auto",refX:j,refY:y/2}),C=q(q("use"),{"xlink:href":"#"+A,transform:(f?"rotate(180 "+x/2+" "+y/2+") ":l)+"scale("+x/z+","+y/z+")","stroke-width":(1/((x/z+y/z)/2)).toFixed(4)}),D.appendChild(C),n.defs.appendChild(D),p[B]=1),q(C,k);var E=i*("diamond"!=w&&"oval"!=w);f?(g=d._.arrows.startdx*u||0,h=c.getTotalLength(t.path)-E*u):(g=E*u,h=c.getTotalLength(t.path)-(d._.arrows.enddx*u||0)),k={},k["marker-"+r]="url(#"+B+")",(h||g)&&(k.d=c.getSubpath(t.path,g,h)),q(s,k),d._.arrows[r+"Path"]=A,d._.arrows[r+"Marker"]=B,d._.arrows[r+"dx"]=E,d._.arrows[r+"Type"]=w,d._.arrows[r+"String"]=e}else f?(g=d._.arrows.startdx*u||0,h=c.getTotalLength(t.path)-g):(g=0,h=c.getTotalLength(t.path)-(d._.arrows.enddx*u||0)),d._.arrows[r+"Path"]&&q(s,{d:c.getSubpath(t.path,g,h)}),delete d._.arrows[r+"Path"],delete d._.arrows[r+"Marker"],delete d._.arrows[r+"dx"],delete d._.arrows[r+"Type"],delete d._.arrows[r+"String"];for(k in p)if(p[a](k)&&!p[k]){var F=c._g.doc.getElementById(k);F&&F.parentNode.removeChild(F)}}},u={"":[0],none:[0],"-":[3,1],".":[1,1],"-.":[3,1,1,1],"-..":[3,1,1,1,1,1],". ":[1,3],"- ":[4,3],"--":[8,3],"- .":[4,3,1,3],"--.":[8,3,1,3],"--..":[8,3,1,3,1,3]},v=function(a,c,d){if(c=u[b(c).toLowerCase()]){for(var e=a.attrs["stroke-width"]||"1",f={round:e,square:e,butt:0}[a.attrs["stroke-linecap"]||d["stroke-linecap"]]||0,g=[],h=c.length;h--;)g[h]=c[h]*e+(h%2?1:-1)*f;q(a.node,{"stroke-dasharray":g.join(",")})}},w=function(d,f){var i=d.node,k=d.attrs,m=i.style.visibility;i.style.visibility="hidden";for(var o in f)if(f[a](o)){if(!c._availableAttrs[a](o))continue;var p=f[o];switch(k[o]=p,o){case"blur":d.blur(p);break;case"title":var u=i.getElementsByTagName("title");if(u.length&&(u=u[0]))u.firstChild.nodeValue=p;else{u=q("title");var w=c._g.doc.createTextNode(p);u.appendChild(w),i.appendChild(u)}break;case"href":case"target":var x=i.parentNode;if("a"!=x.tagName.toLowerCase()){var z=q("a");x.insertBefore(z,i),z.appendChild(i),x=z}"target"==o?x.setAttributeNS(n,"show","blank"==p?"new":p):x.setAttributeNS(n,o,p);break;case"cursor":i.style.cursor=p;break;case"transform":d.transform(p);break;case"arrow-start":t(d,p);break;case"arrow-end":t(d,p,1);break;case"clip-rect":var A=b(p).split(j);if(4==A.length){d.clip&&d.clip.parentNode.parentNode.removeChild(d.clip.parentNode);var B=q("clipPath"),C=q("rect");B.id=c.createUUID(),q(C,{x:A[0],y:A[1],width:A[2],height:A[3]}),B.appendChild(C),d.paper.defs.appendChild(B),q(i,{"clip-path":"url(#"+B.id+")"}),d.clip=C}if(!p){var D=i.getAttribute("clip-path");if(D){var E=c._g.doc.getElementById(D.replace(/(^url\(#|\)$)/g,l));E&&E.parentNode.removeChild(E),q(i,{"clip-path":l}),delete d.clip}}break;case"path":"path"==d.type&&(q(i,{d:p?k.path=c._pathToAbsolute(p):"M0,0"}),d._.dirty=1,d._.arrows&&("startString"in d._.arrows&&t(d,d._.arrows.startString),"endString"in d._.arrows&&t(d,d._.arrows.endString,1)));break;case"width":if(i.setAttribute(o,p),d._.dirty=1,!k.fx)break;o="x",p=k.x;case"x":k.fx&&(p=-k.x-(k.width||0));case"rx":if("rx"==o&&"rect"==d.type)break;case"cx":i.setAttribute(o,p),d.pattern&&s(d),d._.dirty=1;break;case"height":if(i.setAttribute(o,p),d._.dirty=1,!k.fy)break;o="y",p=k.y;case"y":k.fy&&(p=-k.y-(k.height||0));case"ry":if("ry"==o&&"rect"==d.type)break;case"cy":i.setAttribute(o,p),d.pattern&&s(d),d._.dirty=1;break;case"r":"rect"==d.type?q(i,{rx:p,ry:p}):i.setAttribute(o,p),d._.dirty=1;break;case"src":"image"==d.type&&i.setAttributeNS(n,"href",p);break;case"stroke-width":(1!=d._.sx||1!=d._.sy)&&(p/=g(h(d._.sx),h(d._.sy))||1),i.setAttribute(o,p),k["stroke-dasharray"]&&v(d,k["stroke-dasharray"],f),d._.arrows&&("startString"in d._.arrows&&t(d,d._.arrows.startString),"endString"in d._.arrows&&t(d,d._.arrows.endString,1));break;case"stroke-dasharray":v(d,p,f);break;case"fill":var F=b(p).match(c._ISURL);if(F){B=q("pattern");var G=q("image");B.id=c.createUUID(),q(B,{x:0,y:0,patternUnits:"userSpaceOnUse",height:1,width:1}),q(G,{x:0,y:0,"xlink:href":F[1]}),B.appendChild(G),function(a){c._preload(F[1],function(){var b=this.offsetWidth,c=this.offsetHeight;q(a,{width:b,height:c}),q(G,{width:b,height:c}),d.paper.safari()})}(B),d.paper.defs.appendChild(B),q(i,{fill:"url(#"+B.id+")"}),d.pattern=B,d.pattern&&s(d);break}var H=c.getRGB(p);if(H.error){if(("circle"==d.type||"ellipse"==d.type||"r"!=b(p).charAt())&&r(d,p)){if("opacity"in k||"fill-opacity"in k){var I=c._g.doc.getElementById(i.getAttribute("fill").replace(/^url\(#|\)$/g,l));if(I){var J=I.getElementsByTagName("stop");q(J[J.length-1],{"stop-opacity":("opacity"in k?k.opacity:1)*("fill-opacity"in k?k["fill-opacity"]:1)})}}k.gradient=p,k.fill="none";break}}else delete f.gradient,delete k.gradient,!c.is(k.opacity,"undefined")&&c.is(f.opacity,"undefined")&&q(i,{opacity:k.opacity}),!c.is(k["fill-opacity"],"undefined")&&c.is(f["fill-opacity"],"undefined")&&q(i,{"fill-opacity":k["fill-opacity"]});H[a]("opacity")&&q(i,{"fill-opacity":H.opacity>1?H.opacity/100:H.opacity});case"stroke":H=c.getRGB(p),i.setAttribute(o,H.hex),"stroke"==o&&H[a]("opacity")&&q(i,{"stroke-opacity":H.opacity>1?H.opacity/100:H.opacity}),"stroke"==o&&d._.arrows&&("startString"in d._.arrows&&t(d,d._.arrows.startString),"endString"in d._.arrows&&t(d,d._.arrows.endString,1));break;case"gradient":("circle"==d.type||"ellipse"==d.type||"r"!=b(p).charAt())&&r(d,p);break; +case"opacity":k.gradient&&!k[a]("stroke-opacity")&&q(i,{"stroke-opacity":p>1?p/100:p});case"fill-opacity":if(k.gradient){I=c._g.doc.getElementById(i.getAttribute("fill").replace(/^url\(#|\)$/g,l)),I&&(J=I.getElementsByTagName("stop"),q(J[J.length-1],{"stop-opacity":p}));break}default:"font-size"==o&&(p=e(p,10)+"px");var K=o.replace(/(\-.)/g,function(a){return a.substring(1).toUpperCase()});i.style[K]=p,d._.dirty=1,i.setAttribute(o,p)}}y(d,f),i.style.visibility=m},x=1.2,y=function(d,f){if("text"==d.type&&(f[a]("text")||f[a]("font")||f[a]("font-size")||f[a]("x")||f[a]("y"))){var g=d.attrs,h=d.node,i=h.firstChild?e(c._g.doc.defaultView.getComputedStyle(h.firstChild,l).getPropertyValue("font-size"),10):10;if(f[a]("text")){for(g.text=f.text;h.firstChild;)h.removeChild(h.firstChild);for(var j,k=b(f.text).split("\n"),m=[],n=0,o=k.length;o>n;n++)j=q("tspan"),n&&q(j,{dy:i*x,x:g.x}),j.appendChild(c._g.doc.createTextNode(k[n])),h.appendChild(j),m[n]=j}else for(m=h.getElementsByTagName("tspan"),n=0,o=m.length;o>n;n++)n?q(m[n],{dy:i*x,x:g.x}):q(m[0],{dy:0});q(h,{x:g.x,y:g.y}),d._.dirty=1;var p=d._getBBox(),r=g.y-(p.y+p.height/2);r&&c.is(r,"finite")&&q(m[0],{dy:r})}},z=function(a){return a.parentNode&&"a"===a.parentNode.tagName.toLowerCase()?a.parentNode:a};Element=function(a,b){this[0]=this.node=a,a.raphael=!0,this.id=c._oid++,a.raphaelid=this.id,this.matrix=c.matrix(),this.realPath=null,this.paper=b,this.attrs=this.attrs||{},this._={transform:[],sx:1,sy:1,deg:0,dx:0,dy:0,dirty:1},!b.bottom&&(b.bottom=this),this.prev=b.top,b.top&&(b.top.next=this),b.top=this,this.next=null},$b=c.el,Element.prototype=$b,$b.constructor=Element,c._engine.path=function(a,b){var c=q("path");b.canvas&&b.canvas.appendChild(c);var d=new Element(c,b);return d.type="path",w(d,{fill:"none",stroke:"#000",path:a}),d},$b.rotate=function(a,c,e){if(this.removed)return this;if(a=b(a).split(j),a.length-1&&(c=d(a[1]),e=d(a[2])),a=d(a[0]),null==e&&(c=e),null==c||null==e){var f=this.getBBox(1);c=f.x+f.width/2,e=f.y+f.height/2}return this.transform(this._.transform.concat([["r",a,c,e]])),this},$b.scale=function(a,c,e,f){if(this.removed)return this;if(a=b(a).split(j),a.length-1&&(c=d(a[1]),e=d(a[2]),f=d(a[3])),a=d(a[0]),null==c&&(c=a),null==f&&(e=f),null==e||null==f)var g=this.getBBox(1);return e=null==e?g.x+g.width/2:e,f=null==f?g.y+g.height/2:f,this.transform(this._.transform.concat([["s",a,c,e,f]])),this},$b.translate=function(a,c){return this.removed?this:(a=b(a).split(j),a.length-1&&(c=d(a[1])),a=d(a[0])||0,c=+c||0,this.transform(this._.transform.concat([["t",a,c]])),this)},$b.transform=function(b){var d=this._;if(null==b)return d.transform;if(c._extractTransform(this,b),this.clip&&q(this.clip,{transform:this.matrix.invert()}),this.pattern&&s(this),this.node&&q(this.node,{transform:this.matrix}),1!=d.sx||1!=d.sy){var e=this.attrs[a]("stroke-width")?this.attrs["stroke-width"]:1;this.attr({"stroke-width":e})}return this},$b.hide=function(){return!this.removed&&this.paper.safari(this.node.style.display="none"),this},$b.show=function(){return!this.removed&&this.paper.safari(this.node.style.display=""),this},$b.remove=function(){var a=z(this.node);if(!this.removed&&a.parentNode){var b=this.paper;b.__set__&&b.__set__.exclude(this),k.unbind("raphael.*.*."+this.id),this.gradient&&b.defs.removeChild(this.gradient),c._tear(this,b),a.parentNode.removeChild(a),this.removeData();for(var d in this)this[d]="function"==typeof this[d]?c._removedFactory(d):null;this.removed=!0}},$b._getBBox=function(){if("none"==this.node.style.display){this.show();var a=!0}var b,c=!1;this.paper.canvas.parentElement?b=this.paper.canvas.parentElement.style:this.paper.canvas.parentNode&&(b=this.paper.canvas.parentNode.style),b&&"none"==b.display&&(c=!0,b.display="");var d={};try{d=this.node.getBBox()}catch(e){d={x:this.node.clientLeft,y:this.node.clientTop,width:this.node.clientWidth,height:this.node.clientHeight}}finally{d=d||{},c&&(b.display="none")}return a&&this.hide(),d},$b.attr=function(b,d){if(this.removed)return this;if(null==b){var e={};for(var f in this.attrs)this.attrs[a](f)&&(e[f]=this.attrs[f]);return e.gradient&&"none"==e.fill&&(e.fill=e.gradient)&&delete e.gradient,e.transform=this._.transform,e}if(null==d&&c.is(b,"string")){if("fill"==b&&"none"==this.attrs.fill&&this.attrs.gradient)return this.attrs.gradient;if("transform"==b)return this._.transform;for(var g=b.split(j),h={},i=0,l=g.length;l>i;i++)b=g[i],h[b]=b in this.attrs?this.attrs[b]:c.is(this.paper.customAttributes[b],"function")?this.paper.customAttributes[b].def:c._availableAttrs[b];return l-1?h:h[g[0]]}if(null==d&&c.is(b,"array")){for(h={},i=0,l=b.length;l>i;i++)h[b[i]]=this.attr(b[i]);return h}if(null!=d){var m={};m[b]=d}else null!=b&&c.is(b,"object")&&(m=b);for(var n in m)k("raphael.attr."+n+"."+this.id,this,m[n]);for(n in this.paper.customAttributes)if(this.paper.customAttributes[a](n)&&m[a](n)&&c.is(this.paper.customAttributes[n],"function")){var o=this.paper.customAttributes[n].apply(this,[].concat(m[n]));this.attrs[n]=m[n];for(var p in o)o[a](p)&&(m[p]=o[p])}return w(this,m),this},$b.toFront=function(){if(this.removed)return this;var a=z(this.node);a.parentNode.appendChild(a);var b=this.paper;return b.top!=this&&c._tofront(this,b),this},$b.toBack=function(){if(this.removed)return this;var a=z(this.node),b=a.parentNode;b.insertBefore(a,b.firstChild),c._toback(this,this.paper);this.paper;return this},$b.insertAfter=function(a){if(this.removed||!a)return this;var b=z(this.node),d=z(a.node||a[a.length-1].node);return d.nextSibling?d.parentNode.insertBefore(b,d.nextSibling):d.parentNode.appendChild(b),c._insertafter(this,a,this.paper),this},$b.insertBefore=function(a){if(this.removed||!a)return this;var b=z(this.node),d=z(a.node||a[0].node);return d.parentNode.insertBefore(b,d),c._insertbefore(this,a,this.paper),this},$b.blur=function(a){var b=this;if(0!==+a){var d=q("filter"),e=q("feGaussianBlur");b.attrs.blur=a,d.id=c.createUUID(),q(e,{stdDeviation:+a||1.5}),d.appendChild(e),b.paper.defs.appendChild(d),b._blur=d,q(b.node,{filter:"url(#"+d.id+")"})}else b._blur&&(b._blur.parentNode.removeChild(b._blur),delete b._blur,delete b.attrs.blur),b.node.removeAttribute("filter");return b},c._engine.circle=function(a,b,c,d){var e=q("circle");a.canvas&&a.canvas.appendChild(e);var f=new Element(e,a);return f.attrs={cx:b,cy:c,r:d,fill:"none",stroke:"#000"},f.type="circle",q(e,f.attrs),f},c._engine.rect=function(a,b,c,d,e,f){var g=q("rect");a.canvas&&a.canvas.appendChild(g);var h=new Element(g,a);return h.attrs={x:b,y:c,width:d,height:e,rx:f||0,ry:f||0,fill:"none",stroke:"#000"},h.type="rect",q(g,h.attrs),h},c._engine.ellipse=function(a,b,c,d,e){var f=q("ellipse");a.canvas&&a.canvas.appendChild(f);var g=new Element(f,a);return g.attrs={cx:b,cy:c,rx:d,ry:e,fill:"none",stroke:"#000"},g.type="ellipse",q(f,g.attrs),g},c._engine.image=function(a,b,c,d,e,f){var g=q("image");q(g,{x:c,y:d,width:e,height:f,preserveAspectRatio:"none"}),g.setAttributeNS(n,"href",b),a.canvas&&a.canvas.appendChild(g);var h=new Element(g,a);return h.attrs={x:c,y:d,width:e,height:f,src:b},h.type="image",h},c._engine.text=function(a,b,d,e){var f=q("text");a.canvas&&a.canvas.appendChild(f);var g=new Element(f,a);return g.attrs={x:b,y:d,"text-anchor":"middle",text:e,"font-family":c._availableAttrs["font-family"],"font-size":c._availableAttrs["font-size"],stroke:"none",fill:"#000"},g.type="text",w(g,g.attrs),g},c._engine.setSize=function(a,b){return this.width=a||this.width,this.height=b||this.height,this.canvas.setAttribute("width",this.width),this.canvas.setAttribute("height",this.height),this._viewBox&&this.setViewBox.apply(this,this._viewBox),this},c._engine.create=function(){var a=c._getContainer.apply(0,arguments),b=a&&a.container,d=a.x,e=a.y,f=a.width,g=a.height;if(!b)throw new Error("SVG container not found.");var h,i=q("svg"),j="overflow:hidden;";return d=d||0,e=e||0,f=f||512,g=g||342,q(i,{height:g,version:1.1,width:f,xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink"}),1==b?(i.style.cssText=j+"position:absolute;left:"+d+"px;top:"+e+"px",c._g.doc.body.appendChild(i),h=1):(i.style.cssText=j+"position:relative",b.firstChild?b.insertBefore(i,b.firstChild):b.appendChild(i)),b=new c._Paper,b.width=f,b.height=g,b.canvas=i,b.clear(),b._left=b._top=0,h&&(b.renderfix=function(){}),b.renderfix(),b},c._engine.setViewBox=function(a,b,c,d,e){k("raphael.setViewBox",this,this._viewBox,[a,b,c,d,e]);var f,h,i=this.getSize(),j=g(c/i.width,d/i.height),l=this.top,n=e?"xMidYMid meet":"xMinYMin";for(null==a?(this._vbSize&&(j=1),delete this._vbSize,f="0 0 "+this.width+m+this.height):(this._vbSize=j,f=a+m+b+m+c+m+d),q(this.canvas,{viewBox:f,preserveAspectRatio:n});j&&l;)h="stroke-width"in l.attrs?l.attrs["stroke-width"]:1,l.attr({"stroke-width":h}),l._.dirty=1,l._.dirtyT=1,l=l.prev;return this._viewBox=[a,b,c,d,!!e],this},c.prototype.renderfix=function(){var a,b=this.canvas,c=b.style;try{a=b.getScreenCTM()||b.createSVGMatrix()}catch(d){a=b.createSVGMatrix()}var e=-a.e%1,f=-a.f%1;(e||f)&&(e&&(this._left=(this._left+e)%1,c.left=this._left+"px"),f&&(this._top=(this._top+f)%1,c.top=this._top+"px"))},c.prototype.clear=function(){c.eve("raphael.clear",this);for(var a=this.canvas;a.firstChild;)a.removeChild(a.firstChild);this.bottom=this.top=null,(this.desc=q("desc")).appendChild(c._g.doc.createTextNode("Created with Raphaël "+c.version)),a.appendChild(this.desc),a.appendChild(this.defs=q("defs"))},c.prototype.remove=function(){k("raphael.remove",this),this.canvas.parentNode&&this.canvas.parentNode.removeChild(this.canvas);for(var a in this)this[a]="function"==typeof this[a]?c._removedFactory(a):null};var A=c.st;for(var B in $b)$b[a](B)&&!A[a](B)&&(A[B]=function(a){return function(){var b=arguments;return this.forEach(function(c){c[a].apply(c,b)})}}(B))}}(),function(){if(c.vml){var a="hasOwnProperty",b=String,d=parseFloat,e=Math,f=e.round,g=e.max,h=e.min,i=e.abs,j="fill",k=/[, ]+/,l=c.eve,m=" progid:DXImageTransform.Microsoft",n=" ",o="",p={M:"m",L:"l",C:"c",Z:"x",m:"t",l:"r",c:"v",z:"x"},q=/([clmz]),?([^clmz]*)/gi,r=/ progid:\S+Blur\([^\)]+\)/g,s=/-?[^,\s-]+/g,t="position:absolute;left:0;top:0;width:1px;height:1px;behavior:url(#default#VML)",u=21600,v={path:1,rect:1,image:1},w={circle:1,ellipse:1},x=function(a){var d=/[ahqstv]/gi,e=c._pathToAbsolute;if(b(a).match(d)&&(e=c._path2curve),d=/[clmz]/g,e==c._pathToAbsolute&&!b(a).match(d)){var g=b(a).replace(q,function(a,b,c){var d=[],e="m"==b.toLowerCase(),g=p[b];return c.replace(s,function(a){e&&2==d.length&&(g+=d+p["m"==b?"l":"L"],d=[]),d.push(f(a*u))}),g+d});return g}var h,i,j=e(a);g=[];for(var k=0,l=j.length;l>k;k++){h=j[k],i=j[k][0].toLowerCase(),"z"==i&&(i="x");for(var m=1,r=h.length;r>m;m++)i+=f(h[m]*u)+(m!=r-1?",":o);g.push(i)}return g.join(n)},y=function(a,b,d){var e=c.matrix();return e.rotate(-a,.5,.5),{dx:e.x(b,d),dy:e.y(b,d)}},z=function(a,b,c,d,e,f){var g=a._,h=a.matrix,k=g.fillpos,l=a.node,m=l.style,o=1,p="",q=u/b,r=u/c;if(m.visibility="hidden",b&&c){if(l.coordsize=i(q)+n+i(r),m.rotation=f*(0>b*c?-1:1),f){var s=y(f,d,e);d=s.dx,e=s.dy}if(0>b&&(p+="x"),0>c&&(p+=" y")&&(o=-1),m.flip=p,l.coordorigin=d*-q+n+e*-r,k||g.fillsize){var t=l.getElementsByTagName(j);t=t&&t[0],l.removeChild(t),k&&(s=y(f,h.x(k[0],k[1]),h.y(k[0],k[1])),t.position=s.dx*o+n+s.dy*o),g.fillsize&&(t.size=g.fillsize[0]*i(b)+n+g.fillsize[1]*i(c)),l.appendChild(t)}m.visibility="visible"}};c.toString=function(){return"Your browser doesn’t support SVG. Falling down to VML.\nYou are running Raphaël "+this.version};var A=function(a,c,d){for(var e=b(c).toLowerCase().split("-"),f=d?"end":"start",g=e.length,h="classic",i="medium",j="medium";g--;)switch(e[g]){case"block":case"classic":case"oval":case"diamond":case"open":case"none":h=e[g];break;case"wide":case"narrow":j=e[g];break;case"long":case"short":i=e[g]}var k=a.node.getElementsByTagName("stroke")[0];k[f+"arrow"]=h,k[f+"arrowlength"]=i,k[f+"arrowwidth"]=j},B=function(e,i){e.attrs=e.attrs||{};var l=e.node,m=e.attrs,p=l.style,q=v[e.type]&&(i.x!=m.x||i.y!=m.y||i.width!=m.width||i.height!=m.height||i.cx!=m.cx||i.cy!=m.cy||i.rx!=m.rx||i.ry!=m.ry||i.r!=m.r),r=w[e.type]&&(m.cx!=i.cx||m.cy!=i.cy||m.r!=i.r||m.rx!=i.rx||m.ry!=i.ry),s=e;for(var t in i)i[a](t)&&(m[t]=i[t]);if(q&&(m.path=c._getPath[e.type](e),e._.dirty=1),i.href&&(l.href=i.href),i.title&&(l.title=i.title),i.target&&(l.target=i.target),i.cursor&&(p.cursor=i.cursor),"blur"in i&&e.blur(i.blur),(i.path&&"path"==e.type||q)&&(l.path=x(~b(m.path).toLowerCase().indexOf("r")?c._pathToAbsolute(m.path):m.path),e._.dirty=1,"image"==e.type&&(e._.fillpos=[m.x,m.y],e._.fillsize=[m.width,m.height],z(e,1,1,0,0,0))),"transform"in i&&e.transform(i.transform),r){var y=+m.cx,B=+m.cy,D=+m.rx||+m.r||0,E=+m.ry||+m.r||0;l.path=c.format("ar{0},{1},{2},{3},{4},{1},{4},{1}x",f((y-D)*u),f((B-E)*u),f((y+D)*u),f((B+E)*u),f(y*u)),e._.dirty=1}if("clip-rect"in i){var G=b(i["clip-rect"]).split(k);if(4==G.length){G[2]=+G[2]+ +G[0],G[3]=+G[3]+ +G[1];var H=l.clipRect||c._g.doc.createElement("div"),I=H.style;I.clip=c.format("rect({1}px {2}px {3}px {0}px)",G),l.clipRect||(I.position="absolute",I.top=0,I.left=0,I.width=e.paper.width+"px",I.height=e.paper.height+"px",l.parentNode.insertBefore(H,l),H.appendChild(l),l.clipRect=H)}i["clip-rect"]||l.clipRect&&(l.clipRect.style.clip="auto")}if(e.textpath){var J=e.textpath.style;i.font&&(J.font=i.font),i["font-family"]&&(J.fontFamily='"'+i["font-family"].split(",")[0].replace(/^['"]+|['"]+$/g,o)+'"'),i["font-size"]&&(J.fontSize=i["font-size"]),i["font-weight"]&&(J.fontWeight=i["font-weight"]),i["font-style"]&&(J.fontStyle=i["font-style"])}if("arrow-start"in i&&A(s,i["arrow-start"]),"arrow-end"in i&&A(s,i["arrow-end"],1),null!=i.opacity||null!=i["stroke-width"]||null!=i.fill||null!=i.src||null!=i.stroke||null!=i["stroke-width"]||null!=i["stroke-opacity"]||null!=i["fill-opacity"]||null!=i["stroke-dasharray"]||null!=i["stroke-miterlimit"]||null!=i["stroke-linejoin"]||null!=i["stroke-linecap"]){var K=l.getElementsByTagName(j),L=!1;if(K=K&&K[0],!K&&(L=K=F(j)),"image"==e.type&&i.src&&(K.src=i.src),i.fill&&(K.on=!0),(null==K.on||"none"==i.fill||null===i.fill)&&(K.on=!1),K.on&&i.fill){var M=b(i.fill).match(c._ISURL);if(M){K.parentNode==l&&l.removeChild(K),K.rotate=!0,K.src=M[1],K.type="tile";var N=e.getBBox(1);K.position=N.x+n+N.y,e._.fillpos=[N.x,N.y],c._preload(M[1],function(){e._.fillsize=[this.offsetWidth,this.offsetHeight]})}else K.color=c.getRGB(i.fill).hex,K.src=o,K.type="solid",c.getRGB(i.fill).error&&(s.type in{circle:1,ellipse:1}||"r"!=b(i.fill).charAt())&&C(s,i.fill,K)&&(m.fill="none",m.gradient=i.fill,K.rotate=!1)}if("fill-opacity"in i||"opacity"in i){var O=((+m["fill-opacity"]+1||2)-1)*((+m.opacity+1||2)-1)*((+c.getRGB(i.fill).o+1||2)-1);O=h(g(O,0),1),K.opacity=O,K.src&&(K.color="none")}l.appendChild(K);var P=l.getElementsByTagName("stroke")&&l.getElementsByTagName("stroke")[0],Q=!1;!P&&(Q=P=F("stroke")),(i.stroke&&"none"!=i.stroke||i["stroke-width"]||null!=i["stroke-opacity"]||i["stroke-dasharray"]||i["stroke-miterlimit"]||i["stroke-linejoin"]||i["stroke-linecap"])&&(P.on=!0),("none"==i.stroke||null===i.stroke||null==P.on||0==i.stroke||0==i["stroke-width"])&&(P.on=!1);var R=c.getRGB(i.stroke);P.on&&i.stroke&&(P.color=R.hex),O=((+m["stroke-opacity"]+1||2)-1)*((+m.opacity+1||2)-1)*((+R.o+1||2)-1);var S=.75*(d(i["stroke-width"])||1);if(O=h(g(O,0),1),null==i["stroke-width"]&&(S=m["stroke-width"]),i["stroke-width"]&&(P.weight=S),S&&1>S&&(O*=S)&&(P.weight=1),P.opacity=O,i["stroke-linejoin"]&&(P.joinstyle=i["stroke-linejoin"]||"miter"),P.miterlimit=i["stroke-miterlimit"]||8,i["stroke-linecap"]&&(P.endcap="butt"==i["stroke-linecap"]?"flat":"square"==i["stroke-linecap"]?"square":"round"),"stroke-dasharray"in i){var T={"-":"shortdash",".":"shortdot","-.":"shortdashdot","-..":"shortdashdotdot",". ":"dot","- ":"dash","--":"longdash","- .":"dashdot","--.":"longdashdot","--..":"longdashdotdot"};P.dashstyle=T[a](i["stroke-dasharray"])?T[i["stroke-dasharray"]]:o}Q&&l.appendChild(P)}if("text"==s.type){s.paper.canvas.style.display=o;var U=s.paper.span,V=100,W=m.font&&m.font.match(/\d+(?:\.\d*)?(?=px)/);p=U.style,m.font&&(p.font=m.font),m["font-family"]&&(p.fontFamily=m["font-family"]),m["font-weight"]&&(p.fontWeight=m["font-weight"]),m["font-style"]&&(p.fontStyle=m["font-style"]),W=d(m["font-size"]||W&&W[0])||10,p.fontSize=W*V+"px",s.textpath.string&&(U.innerHTML=b(s.textpath.string).replace(/"));var X=U.getBoundingClientRect();s.W=m.w=(X.right-X.left)/V,s.H=m.h=(X.bottom-X.top)/V,s.X=m.x,s.Y=m.y+s.H/2,("x"in i||"y"in i)&&(s.path.v=c.format("m{0},{1}l{2},{1}",f(m.x*u),f(m.y*u),f(m.x*u)+1));for(var Y=["x","y","text","font","font-family","font-weight","font-style","font-size"],Z=0,$=Y.length;$>Z;Z++)if(Y[Z]in i){s._.dirty=1;break}switch(m["text-anchor"]){case"start":s.textpath.style["v-text-align"]="left",s.bbx=s.W/2;break;case"end":s.textpath.style["v-text-align"]="right",s.bbx=-s.W/2;break;default:s.textpath.style["v-text-align"]="center",s.bbx=0}s.textpath.style["v-text-kern"]=!0}},C=function(a,f,g){a.attrs=a.attrs||{};var h=(a.attrs,Math.pow),i="linear",j=".5 .5";if(a.attrs.gradient=f,f=b(f).replace(c._radial_gradient,function(a,b,c){return i="radial",b&&c&&(b=d(b),c=d(c),h(b-.5,2)+h(c-.5,2)>.25&&(c=e.sqrt(.25-h(b-.5,2))*(2*(c>.5)-1)+.5),j=b+n+c),o}),f=f.split(/\s*\-\s*/),"linear"==i){var k=f.shift();if(k=-d(k),isNaN(k))return null}var l=c._parseDots(f);if(!l)return null;if(a=a.shape||a.node,l.length){a.removeChild(g),g.on=!0,g.method="none",g.color=l[0].color,g.color2=l[l.length-1].color;for(var m=[],p=0,q=l.length;q>p;p++)l[p].offset&&m.push(l[p].offset+n+l[p].color);g.colors=m.length?m.join():"0% "+g.color,"radial"==i?(g.type="gradientTitle",g.focus="100%",g.focussize="0 0",g.focusposition=j,g.angle=0):(g.type="gradient",g.angle=(270-k)%360),a.appendChild(g)}return 1},D=function(a,b){this[0]=this.node=a,a.raphael=!0,this.id=c._oid++,a.raphaelid=this.id,this.X=0,this.Y=0,this.attrs={},this.paper=b,this.matrix=c.matrix(),this._={transform:[],sx:1,sy:1,dx:0,dy:0,deg:0,dirty:1,dirtyT:1},!b.bottom&&(b.bottom=this),this.prev=b.top,b.top&&(b.top.next=this),b.top=this,this.next=null},E=c.el;D.prototype=E,E.constructor=D,E.transform=function(a){if(null==a)return this._.transform;var d,e=this.paper._viewBoxShift,f=e?"s"+[e.scale,e.scale]+"-1-1t"+[e.dx,e.dy]:o;e&&(d=a=b(a).replace(/\.{3}|\u2026/g,this._.transform||o)),c._extractTransform(this,f+a);var g,h=this.matrix.clone(),i=this.skew,j=this.node,k=~b(this.attrs.fill).indexOf("-"),l=!b(this.attrs.fill).indexOf("url(");if(h.translate(1,1),l||k||"image"==this.type)if(i.matrix="1 0 0 1",i.offset="0 0",g=h.split(),k&&g.noRotation||!g.isSimple){j.style.filter=h.toFilter();var m=this.getBBox(),p=this.getBBox(1),q=m.x-p.x,r=m.y-p.y;j.coordorigin=q*-u+n+r*-u,z(this,1,1,q,r,0)}else j.style.filter=o,z(this,g.scalex,g.scaley,g.dx,g.dy,g.rotate);else j.style.filter=o,i.matrix=b(h),i.offset=h.offset();return null!==d&&(this._.transform=d,c._extractTransform(this,d)),this},E.rotate=function(a,c,e){if(this.removed)return this;if(null!=a){if(a=b(a).split(k),a.length-1&&(c=d(a[1]),e=d(a[2])),a=d(a[0]),null==e&&(c=e),null==c||null==e){var f=this.getBBox(1);c=f.x+f.width/2,e=f.y+f.height/2}return this._.dirtyT=1,this.transform(this._.transform.concat([["r",a,c,e]])),this}},E.translate=function(a,c){return this.removed?this:(a=b(a).split(k),a.length-1&&(c=d(a[1])),a=d(a[0])||0,c=+c||0,this._.bbox&&(this._.bbox.x+=a,this._.bbox.y+=c),this.transform(this._.transform.concat([["t",a,c]])),this)},E.scale=function(a,c,e,f){if(this.removed)return this;if(a=b(a).split(k),a.length-1&&(c=d(a[1]),e=d(a[2]),f=d(a[3]),isNaN(e)&&(e=null),isNaN(f)&&(f=null)),a=d(a[0]),null==c&&(c=a),null==f&&(e=f),null==e||null==f)var g=this.getBBox(1);return e=null==e?g.x+g.width/2:e,f=null==f?g.y+g.height/2:f,this.transform(this._.transform.concat([["s",a,c,e,f]])),this._.dirtyT=1,this},E.hide=function(){return!this.removed&&(this.node.style.display="none"),this},E.show=function(){return!this.removed&&(this.node.style.display=o),this},E.auxGetBBox=c.el.getBBox,E.getBBox=function(){var a=this.auxGetBBox();if(this.paper&&this.paper._viewBoxShift){var b={},c=1/this.paper._viewBoxShift.scale;return b.x=a.x-this.paper._viewBoxShift.dx,b.x*=c,b.y=a.y-this.paper._viewBoxShift.dy,b.y*=c,b.width=a.width*c,b.height=a.height*c,b.x2=b.x+b.width,b.y2=b.y+b.height,b}return a},E._getBBox=function(){return this.removed?{}:{x:this.X+(this.bbx||0)-this.W/2,y:this.Y-this.H,width:this.W,height:this.H}},E.remove=function(){if(!this.removed&&this.node.parentNode){this.paper.__set__&&this.paper.__set__.exclude(this),c.eve.unbind("raphael.*.*."+this.id),c._tear(this,this.paper),this.node.parentNode.removeChild(this.node),this.shape&&this.shape.parentNode.removeChild(this.shape);for(var a in this)this[a]="function"==typeof this[a]?c._removedFactory(a):null;this.removed=!0}},E.attr=function(b,d){if(this.removed)return this;if(null==b){var e={};for(var f in this.attrs)this.attrs[a](f)&&(e[f]=this.attrs[f]);return e.gradient&&"none"==e.fill&&(e.fill=e.gradient)&&delete e.gradient,e.transform=this._.transform,e}if(null==d&&c.is(b,"string")){if(b==j&&"none"==this.attrs.fill&&this.attrs.gradient)return this.attrs.gradient;for(var g=b.split(k),h={},i=0,m=g.length;m>i;i++)b=g[i],h[b]=b in this.attrs?this.attrs[b]:c.is(this.paper.customAttributes[b],"function")?this.paper.customAttributes[b].def:c._availableAttrs[b];return m-1?h:h[g[0]]}if(this.attrs&&null==d&&c.is(b,"array")){for(h={},i=0,m=b.length;m>i;i++)h[b[i]]=this.attr(b[i]);return h}var n;null!=d&&(n={},n[b]=d),null==d&&c.is(b,"object")&&(n=b);for(var o in n)l("raphael.attr."+o+"."+this.id,this,n[o]);if(n){for(o in this.paper.customAttributes)if(this.paper.customAttributes[a](o)&&n[a](o)&&c.is(this.paper.customAttributes[o],"function")){var p=this.paper.customAttributes[o].apply(this,[].concat(n[o]));this.attrs[o]=n[o];for(var q in p)p[a](q)&&(n[q]=p[q])}n.text&&"text"==this.type&&(this.textpath.string=n.text),B(this,n)}return this},E.toFront=function(){return!this.removed&&this.node.parentNode.appendChild(this.node),this.paper&&this.paper.top!=this&&c._tofront(this,this.paper),this},E.toBack=function(){return this.removed?this:(this.node.parentNode.firstChild!=this.node&&(this.node.parentNode.insertBefore(this.node,this.node.parentNode.firstChild),c._toback(this,this.paper)),this)},E.insertAfter=function(a){return this.removed?this:(a.constructor==c.st.constructor&&(a=a[a.length-1]),a.node.nextSibling?a.node.parentNode.insertBefore(this.node,a.node.nextSibling):a.node.parentNode.appendChild(this.node),c._insertafter(this,a,this.paper),this)},E.insertBefore=function(a){return this.removed?this:(a.constructor==c.st.constructor&&(a=a[0]),a.node.parentNode.insertBefore(this.node,a.node),c._insertbefore(this,a,this.paper),this)},E.blur=function(a){var b=this.node.runtimeStyle,d=b.filter;return d=d.replace(r,o),0!==+a?(this.attrs.blur=a,b.filter=d+n+m+".Blur(pixelradius="+(+a||1.5)+")",b.margin=c.format("-{0}px 0 0 -{0}px",f(+a||1.5))):(b.filter=d,b.margin=0,delete this.attrs.blur),this},c._engine.path=function(a,b){var c=F("shape");c.style.cssText=t,c.coordsize=u+n+u,c.coordorigin=b.coordorigin;var d=new D(c,b),e={fill:"none",stroke:"#000"};a&&(e.path=a),d.type="path",d.path=[],d.Path=o,B(d,e),b.canvas.appendChild(c);var f=F("skew");return f.on=!0,c.appendChild(f),d.skew=f,d.transform(o),d},c._engine.rect=function(a,b,d,e,f,g){var h=c._rectPath(b,d,e,f,g),i=a.path(h),j=i.attrs;return i.X=j.x=b,i.Y=j.y=d,i.W=j.width=e,i.H=j.height=f,j.r=g,j.path=h,i.type="rect",i},c._engine.ellipse=function(a,b,c,d,e){{var f=a.path();f.attrs}return f.X=b-d,f.Y=c-e,f.W=2*d,f.H=2*e,f.type="ellipse",B(f,{cx:b,cy:c,rx:d,ry:e}),f},c._engine.circle=function(a,b,c,d){{var e=a.path();e.attrs}return e.X=b-d,e.Y=c-d,e.W=e.H=2*d,e.type="circle",B(e,{cx:b,cy:c,r:d}),e},c._engine.image=function(a,b,d,e,f,g){var h=c._rectPath(d,e,f,g),i=a.path(h).attr({stroke:"none"}),k=i.attrs,l=i.node,m=l.getElementsByTagName(j)[0];return k.src=b,i.X=k.x=d,i.Y=k.y=e,i.W=k.width=f,i.H=k.height=g,k.path=h,i.type="image",m.parentNode==l&&l.removeChild(m),m.rotate=!0,m.src=b,m.type="tile",i._.fillpos=[d,e],i._.fillsize=[f,g],l.appendChild(m),z(i,1,1,0,0,0),i},c._engine.text=function(a,d,e,g){var h=F("shape"),i=F("path"),j=F("textpath");d=d||0,e=e||0,g=g||"",i.v=c.format("m{0},{1}l{2},{1}",f(d*u),f(e*u),f(d*u)+1),i.textpathok=!0,j.string=b(g),j.on=!0,h.style.cssText=t,h.coordsize=u+n+u,h.coordorigin="0 0";var k=new D(h,a),l={fill:"#000",stroke:"none",font:c._availableAttrs.font,text:g};k.shape=h,k.path=i,k.textpath=j,k.type="text",k.attrs.text=b(g),k.attrs.x=d,k.attrs.y=e,k.attrs.w=1,k.attrs.h=1,B(k,l),h.appendChild(j),h.appendChild(i),a.canvas.appendChild(h);var m=F("skew");return m.on=!0,h.appendChild(m),k.skew=m,k.transform(o),k},c._engine.setSize=function(a,b){var d=this.canvas.style;return this.width=a,this.height=b,a==+a&&(a+="px"),b==+b&&(b+="px"),d.width=a,d.height=b,d.clip="rect(0 "+a+" "+b+" 0)",this._viewBox&&c._engine.setViewBox.apply(this,this._viewBox),this},c._engine.setViewBox=function(a,b,d,e,f){c.eve("raphael.setViewBox",this,this._viewBox,[a,b,d,e,f]);var g,h,i=this.getSize(),j=i.width,k=i.height;return f&&(g=k/e,h=j/d,j>d*g&&(a-=(j-d*g)/2/g),k>e*h&&(b-=(k-e*h)/2/h)),this._viewBox=[a,b,d,e,!!f],this._viewBoxShift={dx:-a,dy:-b,scale:size},this.forEach(function(a){a.transform("...")}),this};var F;c._engine.initWin=function(a){var b=a.document;b.styleSheets.length<31?b.createStyleSheet().addRule(".rvml","behavior:url(#default#VML)"):b.styleSheets[0].addRule(".rvml","behavior:url(#default#VML)");try{!b.namespaces.rvml&&b.namespaces.add("rvml","urn:schemas-microsoft-com:vml"),F=function(a){return b.createElement("')}}catch(c){F=function(a){return b.createElement("<"+a+' xmlns="urn:schemas-microsoft.com:vml" class="rvml">')}}},c._engine.initWin(c._g.win),c._engine.create=function(){var a=c._getContainer.apply(0,arguments),b=a.container,d=a.height,e=a.width,f=a.x,g=a.y;if(!b)throw new Error("VML container not found.");var h=new c._Paper,i=h.canvas=c._g.doc.createElement("div"),j=i.style;return f=f||0,g=g||0,e=e||512,d=d||342,h.width=e,h.height=d,e==+e&&(e+="px"),d==+d&&(d+="px"),h.coordsize=1e3*u+n+1e3*u,h.coordorigin="0 0",h.span=c._g.doc.createElement("span"),h.span.style.cssText="position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;",i.appendChild(h.span),j.cssText=c.format("top:0;left:0;width:{0};height:{1};display:inline-block;position:relative;clip:rect(0 {0} {1} 0);overflow:hidden",e,d),1==b?(c._g.doc.body.appendChild(i),j.left=f+"px",j.top=g+"px",j.position="absolute"):b.firstChild?b.insertBefore(i,b.firstChild):b.appendChild(i),h.renderfix=function(){},h},c.prototype.clear=function(){c.eve("raphael.clear",this),this.canvas.innerHTML=o,this.span=c._g.doc.createElement("span"),this.span.style.cssText="position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;display:inline;",this.canvas.appendChild(this.span),this.bottom=this.top=null},c.prototype.remove=function(){c.eve("raphael.remove",this),this.canvas.parentNode.removeChild(this.canvas);for(var a in this)this[a]="function"==typeof this[a]?c._removedFactory(a):null;return!0};var G=c.st;for(var H in E)E[a](H)&&!G[a](H)&&(G[H]=function(a){return function(){var b=arguments;return this.forEach(function(c){c[a].apply(c,b)})}}(H))}}(),B.was?A.win.Raphael=c:Raphael=c,"object"==typeof exports&&(module.exports=c),c}); \ No newline at end of file diff --git a/static/js/mdeditor/lib/sequence-diagram.min.js b/static/js/mdeditor/lib/sequence-diagram.min.js new file mode 100644 index 00000000..521b7820 --- /dev/null +++ b/static/js/mdeditor/lib/sequence-diagram.min.js @@ -0,0 +1,7 @@ +/** js sequence diagrams 1.0.4 + * http://bramp.github.io/js-sequence-diagrams/ + * (c) 2012-2013 Andrew Brampton (bramp.net) + * @license Simplified BSD license. + */ +!function(){"use strict";function Diagram(){this.title=void 0,this.actors=[],this.signals=[]}function ParseError(message,hash){_.extend(this,hash),this.name="ParseError",this.message=message||""}Diagram.prototype.getActor=function(alias){var s=/^(.+) as (\S+)$/i.exec(alias.trim());s?(name=s[1].trim(),alias=s[2].trim()):name=alias.trim(),name=name.replace(/\\n/gm,"\n");var i,actors=this.actors;for(i in actors)if(actors[i].alias==alias)return actors[i];return i=actors.push(new Diagram.Actor(alias,name,actors.length)),actors[i-1]},Diagram.prototype.setTitle=function(title){this.title=title},Diagram.prototype.addSignal=function(signal){this.signals.push(signal)},Diagram.Actor=function(alias,name,index){this.alias=alias,this.name=name,this.index=index},Diagram.Signal=function(actorA,signaltype,actorB,message){this.type="Signal",this.actorA=actorA,this.actorB=actorB,this.linetype=3&signaltype,this.arrowtype=3&signaltype>>2,this.message=message},Diagram.Signal.prototype.isSelf=function(){return this.actorA.index==this.actorB.index},Diagram.Note=function(actor,placement,message){if(this.type="Note",this.actor=actor,this.placement=placement,this.message=message,this.hasManyActors()&&actor[0]==actor[1])throw new Error("Note should be over two different actors")},Diagram.Note.prototype.hasManyActors=function(){return _.isArray(this.actor)},Diagram.LINETYPE={SOLID:0,DOTTED:1},Diagram.ARROWTYPE={FILLED:0,OPEN:1},Diagram.PLACEMENT={LEFTOF:0,RIGHTOF:1,OVER:2};var grammar=function(){function Parser(){this.yy={}}var parser={trace:function(){},yy:{},symbols_:{error:2,start:3,document:4,EOF:5,line:6,statement:7,NL:8,participant:9,actor:10,signal:11,note_statement:12,title:13,message:14,note:15,placement:16,over:17,actor_pair:18,",":19,left_of:20,right_of:21,signaltype:22,ACTOR:23,linetype:24,arrowtype:25,LINE:26,DOTLINE:27,ARROW:28,OPENARROW:29,MESSAGE:30,$accept:0,$end:1},terminals_:{2:"error",5:"EOF",8:"NL",9:"participant",13:"title",15:"note",17:"over",19:",",20:"left_of",21:"right_of",23:"ACTOR",26:"LINE",27:"DOTLINE",28:"ARROW",29:"OPENARROW",30:"MESSAGE"},productions_:[0,[3,2],[4,0],[4,2],[6,1],[6,1],[7,2],[7,1],[7,1],[7,2],[12,4],[12,4],[18,1],[18,3],[16,1],[16,1],[11,4],[10,1],[22,2],[22,1],[24,1],[24,1],[25,1],[25,1],[14,1]],performAction:function(yytext,yyleng,yylineno,yy,yystate,$$){var $0=$$.length-1;switch(yystate){case 1:return yy;case 4:break;case 6:$$[$0];break;case 7:yy.addSignal($$[$0]);break;case 8:yy.addSignal($$[$0]);break;case 9:yy.setTitle($$[$0]);break;case 10:this.$=new Diagram.Note($$[$0-1],$$[$0-2],$$[$0]);break;case 11:this.$=new Diagram.Note($$[$0-1],Diagram.PLACEMENT.OVER,$$[$0]);break;case 12:this.$=$$[$0];break;case 13:this.$=[$$[$0-2],$$[$0]];break;case 14:this.$=Diagram.PLACEMENT.LEFTOF;break;case 15:this.$=Diagram.PLACEMENT.RIGHTOF;break;case 16:this.$=new Diagram.Signal($$[$0-3],$$[$0-2],$$[$0-1],$$[$0]);break;case 17:this.$=yy.getActor($$[$0]);break;case 18:this.$=$$[$0-1]|$$[$0]<<2;break;case 19:this.$=$$[$0];break;case 20:this.$=Diagram.LINETYPE.SOLID;break;case 21:this.$=Diagram.LINETYPE.DOTTED;break;case 22:this.$=Diagram.ARROWTYPE.FILLED;break;case 23:this.$=Diagram.ARROWTYPE.OPEN;break;case 24:this.$=$$[$0].substring(1).trim().replace(/\\n/gm,"\n")}},table:[{3:1,4:2,5:[2,2],8:[2,2],9:[2,2],13:[2,2],15:[2,2],23:[2,2]},{1:[3]},{5:[1,3],6:4,7:5,8:[1,6],9:[1,7],10:11,11:8,12:9,13:[1,10],15:[1,12],23:[1,13]},{1:[2,1]},{5:[2,3],8:[2,3],9:[2,3],13:[2,3],15:[2,3],23:[2,3]},{5:[2,4],8:[2,4],9:[2,4],13:[2,4],15:[2,4],23:[2,4]},{5:[2,5],8:[2,5],9:[2,5],13:[2,5],15:[2,5],23:[2,5]},{10:14,23:[1,13]},{5:[2,7],8:[2,7],9:[2,7],13:[2,7],15:[2,7],23:[2,7]},{5:[2,8],8:[2,8],9:[2,8],13:[2,8],15:[2,8],23:[2,8]},{14:15,30:[1,16]},{22:17,24:18,26:[1,19],27:[1,20]},{16:21,17:[1,22],20:[1,23],21:[1,24]},{5:[2,17],8:[2,17],9:[2,17],13:[2,17],15:[2,17],19:[2,17],23:[2,17],26:[2,17],27:[2,17],30:[2,17]},{5:[2,6],8:[2,6],9:[2,6],13:[2,6],15:[2,6],23:[2,6]},{5:[2,9],8:[2,9],9:[2,9],13:[2,9],15:[2,9],23:[2,9]},{5:[2,24],8:[2,24],9:[2,24],13:[2,24],15:[2,24],23:[2,24]},{10:25,23:[1,13]},{23:[2,19],25:26,28:[1,27],29:[1,28]},{23:[2,20],28:[2,20],29:[2,20]},{23:[2,21],28:[2,21],29:[2,21]},{10:29,23:[1,13]},{10:31,18:30,23:[1,13]},{23:[2,14]},{23:[2,15]},{14:32,30:[1,16]},{23:[2,18]},{23:[2,22]},{23:[2,23]},{14:33,30:[1,16]},{14:34,30:[1,16]},{19:[1,35],30:[2,12]},{5:[2,16],8:[2,16],9:[2,16],13:[2,16],15:[2,16],23:[2,16]},{5:[2,10],8:[2,10],9:[2,10],13:[2,10],15:[2,10],23:[2,10]},{5:[2,11],8:[2,11],9:[2,11],13:[2,11],15:[2,11],23:[2,11]},{10:36,23:[1,13]},{30:[2,13]}],defaultActions:{3:[2,1],23:[2,14],24:[2,15],26:[2,18],27:[2,22],28:[2,23],36:[2,13]},parseError:function(str,hash){if(!hash.recoverable)throw new Error(str);this.trace(str)},parse:function(input){function lex(){var token;return token=self.lexer.lex()||EOF,"number"!=typeof token&&(token=self.symbols_[token]||token),token}var self=this,stack=[0],vstack=[null],lstack=[],table=this.table,yytext="",yylineno=0,yyleng=0,recovering=0,TERROR=2,EOF=1;this.lexer.setInput(input),this.lexer.yy=this.yy,this.yy.lexer=this.lexer,this.yy.parser=this,"undefined"==typeof this.lexer.yylloc&&(this.lexer.yylloc={});var yyloc=this.lexer.yylloc;lstack.push(yyloc);var ranges=this.lexer.options&&this.lexer.options.ranges;this.parseError="function"==typeof this.yy.parseError?this.yy.parseError:Object.getPrototypeOf(this).parseError;for(var symbol,preErrorSymbol,state,action,r,p,len,newState,expected,yyval={};;){if(state=stack[stack.length-1],this.defaultActions[state]?action=this.defaultActions[state]:((null===symbol||"undefined"==typeof symbol)&&(symbol=lex()),action=table[state]&&table[state][symbol]),"undefined"==typeof action||!action.length||!action[0]){var errStr="";expected=[];for(p in table[state])this.terminals_[p]&&p>TERROR&&expected.push("'"+this.terminals_[p]+"'");errStr=this.lexer.showPosition?"Parse error on line "+(yylineno+1)+":\n"+this.lexer.showPosition()+"\nExpecting "+expected.join(", ")+", got '"+(this.terminals_[symbol]||symbol)+"'":"Parse error on line "+(yylineno+1)+": Unexpected "+(symbol==EOF?"end of input":"'"+(this.terminals_[symbol]||symbol)+"'"),this.parseError(errStr,{text:this.lexer.match,token:this.terminals_[symbol]||symbol,line:this.lexer.yylineno,loc:yyloc,expected:expected})}if(action[0]instanceof Array&&action.length>1)throw new Error("Parse Error: multiple actions possible at state: "+state+", token: "+symbol);switch(action[0]){case 1:stack.push(symbol),vstack.push(this.lexer.yytext),lstack.push(this.lexer.yylloc),stack.push(action[1]),symbol=null,preErrorSymbol?(symbol=preErrorSymbol,preErrorSymbol=null):(yyleng=this.lexer.yyleng,yytext=this.lexer.yytext,yylineno=this.lexer.yylineno,yyloc=this.lexer.yylloc,recovering>0&&recovering--);break;case 2:if(len=this.productions_[action[1]][1],yyval.$=vstack[vstack.length-len],yyval._$={first_line:lstack[lstack.length-(len||1)].first_line,last_line:lstack[lstack.length-1].last_line,first_column:lstack[lstack.length-(len||1)].first_column,last_column:lstack[lstack.length-1].last_column},ranges&&(yyval._$.range=[lstack[lstack.length-(len||1)].range[0],lstack[lstack.length-1].range[1]]),r=this.performAction.call(yyval,yytext,yyleng,yylineno,this.yy,action[1],vstack,lstack),"undefined"!=typeof r)return r;len&&(stack=stack.slice(0,2*-1*len),vstack=vstack.slice(0,-1*len),lstack=lstack.slice(0,-1*len)),stack.push(this.productions_[action[1]][0]),vstack.push(yyval.$),lstack.push(yyval._$),newState=table[stack[stack.length-2]][stack[stack.length-1]],stack.push(newState);break;case 3:return!0}}return!0}},lexer=function(){var lexer={EOF:1,parseError:function(str,hash){if(!this.yy.parser)throw new Error(str);this.yy.parser.parseError(str,hash)},setInput:function(input){return this._input=input,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var ch=this._input[0];this.yytext+=ch,this.yyleng++,this.offset++,this.match+=ch,this.matched+=ch;var lines=ch.match(/(?:\r\n?|\n).*/g);return lines?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),ch},unput:function(ch){var len=ch.length,lines=ch.split(/(?:\r\n?|\n)/g);this._input=ch+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-len-1),this.offset-=len;var oldLines=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),lines.length-1&&(this.yylineno-=lines.length-1);var r=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:lines?(lines.length===oldLines.length?this.yylloc.first_column:0)+oldLines[oldLines.length-lines.length].length-lines[0].length:this.yylloc.first_column-len},this.options.ranges&&(this.yylloc.range=[r[0],r[0]+this.yyleng-len]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},less:function(n){this.unput(this.match.slice(n))},pastInput:function(){var past=this.matched.substr(0,this.matched.length-this.match.length);return(past.length>20?"...":"")+past.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var next=this.match;return next.length<20&&(next+=this._input.substr(0,20-next.length)),(next.substr(0,20)+(next.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var pre=this.pastInput(),c=new Array(pre.length+1).join("-");return pre+this.upcomingInput()+"\n"+c+"^"},test_match:function(match,indexed_rule){var token,lines,backup;if(this.options.backtrack_lexer&&(backup={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(backup.yylloc.range=this.yylloc.range.slice(0))),lines=match[0].match(/(?:\r\n?|\n).*/g),lines&&(this.yylineno+=lines.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:lines?lines[lines.length-1].length-lines[lines.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+match[0].length},this.yytext+=match[0],this.match+=match[0],this.matches=match,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(match[0].length),this.matched+=match[0],token=this.performAction.call(this,this.yy,this,indexed_rule,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),token)return token;if(this._backtrack){for(var k in backup)this[k]=backup[k];return!1}return!1},next:function(){if(this.done)return this.EOF;this._input||(this.done=!0);var token,match,tempMatch,index;this._more||(this.yytext="",this.match="");for(var rules=this._currentRules(),i=0;imatch[0].length)){if(match=tempMatch,index=i,this.options.backtrack_lexer){if(token=this.test_match(tempMatch,rules[i]),token!==!1)return token;if(this._backtrack){match=!1;continue}return!1}if(!this.options.flex)break}return match?(token=this.test_match(match,rules[index]),token!==!1?token:!1):""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){var r=this.next();return r?r:this.lex()},begin:function(condition){this.conditionStack.push(condition)},popState:function(){var n=this.conditionStack.length-1;return n>0?this.conditionStack.pop():this.conditionStack[0]},_currentRules:function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},topState:function(n){return n=this.conditionStack.length-1-Math.abs(n||0),n>=0?this.conditionStack[n]:"INITIAL"},pushState:function(condition){this.begin(condition)},stateStackSize:function(){return this.conditionStack.length},options:{"case-insensitive":!0},performAction:function(yy,yy_,$avoiding_name_collisions,YY_START){switch($avoiding_name_collisions){case 0:return 8;case 1:break;case 2:break;case 3:return 9;case 4:return 20;case 5:return 21;case 6:return 17;case 7:return 15;case 8:return 13;case 9:return 19;case 10:return 23;case 11:return 27;case 12:return 26;case 13:return 29;case 14:return 28;case 15:return 30;case 16:return 5;case 17:return"INVALID"}},rules:[/^(?:[\n]+)/i,/^(?:\s+)/i,/^(?:#[^\n]*)/i,/^(?:participant\b)/i,/^(?:left of\b)/i,/^(?:right of\b)/i,/^(?:over\b)/i,/^(?:note\b)/i,/^(?:title\b)/i,/^(?:,)/i,/^(?:[^\->:\n,]+)/i,/^(?:--)/i,/^(?:-)/i,/^(?:>>)/i,/^(?:>)/i,/^(?:[^#\n]+)/i,/^(?:$)/i,/^(?:.)/i],conditions:{INITIAL:{rules:[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17],inclusive:!0}}};return lexer}();return parser.lexer=lexer,Parser.prototype=parser,parser.Parser=Parser,new Parser}();"undefined"!=typeof require&&"undefined"!=typeof exports&&(exports.parser=grammar,exports.Parser=grammar.Parser,exports.parse=function(){return grammar.parse.apply(grammar,arguments)},exports.main=function(args){args[1]||(console.log("Usage: "+args[0]+" FILE"),process.exit(1));var source=require("fs").readFileSync(require("path").normalize(args[1]),"utf8");return exports.parser.parse(source)},"undefined"!=typeof module&&require.main===module&&exports.main(process.argv.slice(1))),ParseError.prototype=new Error,Diagram.ParseError=ParseError,grammar.parseError=function(message,hash){throw new ParseError(message,hash)},Diagram.parse=function(input){return grammar.yy=new Diagram,grammar.parse(input)},this.Diagram=Diagram}.call(this),"undefined"!=typeof jQuery&&function($){$.fn.sequenceDiagram=function(options){return this.each(function(){var $this=$(this),diagram=Diagram.parse($this.text());$this.html(""),diagram.drawSVG(this,options)})}}(jQuery),Raphael.registerFont({w:209,face:{"font-family":"daniel","font-weight":700,"font-stretch":"normal","units-per-em":"360","panose-1":"2 11 8 0 0 0 0 0 0 0",ascent:"288",descent:"-72","x-height":"7",bbox:"-92.0373 -310.134 632 184.967","underline-thickness":"3.51562","underline-position":"-21.6211","unicode-range":"U+0009-U+F002"},glyphs:{" ":{w:179}," ":{w:179},"!":{d:"66,-306v9,3,18,11,19,24v-18,73,-20,111,-37,194v0,10,2,34,-12,34v-12,0,-18,-9,-18,-28v0,-85,23,-136,38,-214v1,-7,4,-10,10,-10xm25,-30v15,-1,28,34,5,35v-11,-1,-38,-36,-5,-35",w:115},'"':{d:"91,-214v-32,3,-25,-40,-20,-68v3,-16,7,-25,12,-27v35,13,14,56,8,95xm8,-231v4,-31,1,-40,18,-75v37,7,11,51,11,79v-3,3,-4,8,-5,13v-17,4,-16,-10,-24,-17",w:117},"#":{d:"271,-64v-30,26,-96,-7,-102,51v-6,2,-13,2,-24,-2v-2,-11,10,-21,2,-28v-14,5,-48,0,-48,22v0,23,-11,14,-29,10v-7,-6,6,-19,-1,-24r-32,4v-19,-8,-15,-24,5,-28r33,-6v4,0,24,-23,11,-27v-26,0,-63,14,-74,-10v3,-1,9,-17,16,-10v15,-8,81,4,89,-30v8,-14,16,-34,24,-38v23,9,24,38,5,49v37,24,55,-38,72,-43v19,10,20,23,-1,45v2,8,23,1,29,4v3,3,6,6,10,11v-14,13,-20,12,-45,12v-17,0,-16,17,-19,29v18,-7,49,3,67,-2v4,0,8,4,12,11xm161,-104v-30,-1,-44,10,-44,37v14,1,24,0,40,-5v0,-1,3,-10,8,-26v0,-4,-1,-6,-4,-6",w:285},$:{d:"164,-257v29,4,1,42,-3,50v5,5,38,13,41,24v8,4,6,15,-2,21v-18,3,-36,-17,-49,-17v-17,1,-31,40,-28,48v5,4,8,8,9,10v13,1,35,37,28,44v-10,21,-36,20,-65,28v-10,10,-12,40,-17,51v-9,-3,-28,1,-18,-17v0,-13,5,-24,-1,-35v-18,1,-59,-10,-42,-29v21,0,56,16,55,-16v5,-4,9,-18,9,-26v-14,-15,-55,-41,-53,-65v2,-33,56,-19,98,-26v10,-14,31,-43,38,-45xm93,-152v11,-10,15,-15,14,-29v-17,-3,-37,1,-43,6v10,12,20,19,29,23xm111,-103v-8,1,-11,12,-10,22v10,0,28,2,27,-8v0,-4,-13,-15,-17,-14",w:225},"%":{d:"181,-96v24,-7,67,-13,104,1v14,18,21,19,22,44v-13,43,-99,61,-146,36v-9,-9,-22,-11,-32,-29v0,-27,24,-53,52,-52xm139,-185v-9,68,-138,73,-131,-5v0,-3,3,-9,9,-17v13,1,27,1,17,-16v5,-39,63,0,93,-6v36,1,80,-9,102,11v15,32,12,32,-8,56v-16,21,-103,78,-152,125r-14,28v-23,11,-25,-7,-29,-20v34,-71,133,-98,171,-162v-13,-12,-52,-5,-61,1v0,1,1,3,3,5xm38,-190v0,34,55,29,70,8v0,-14,-20,-11,-32,-14v-14,-3,-24,-9,-40,-10v1,0,5,11,2,16xm172,-53v12,27,90,18,102,-5v-18,-7,-32,-10,-40,-10v-29,3,-57,-4,-62,15",w:308},"&":{d:"145,-82v17,-8,47,-15,71,-26v13,2,25,12,9,23v-23,7,-40,16,-53,27r0,6v13,8,30,21,36,38v0,8,-4,12,-11,12v-19,0,-43,-39,-59,-44v-30,12,-65,29,-97,32v-32,3,-45,-41,-23,-63v21,-20,52,-26,70,-48v-4,-31,-12,-47,9,-73v13,-16,20,-29,23,-39v15,-15,32,-22,51,-22v30,9,62,64,32,96v-2,3,-47,42,-69,48v-15,8,-11,9,0,22v6,7,10,11,11,11xm114,-138v25,-13,62,-38,74,-62v0,-9,-10,-31,-20,-29v-28,7,-60,42,-60,75v0,10,2,15,6,16xm99,-91v-18,10,-54,18,-59,45v26,5,61,-12,77,-22v-1,-5,-13,-23,-18,-23",w:253},"'":{d:"36,-182v-36,7,-34,-61,-17,-80v15,1,21,19,21,20r-1,-1v0,0,-1,12,-5,35v1,5,3,17,2,26",w:63},"(":{d:"130,-306v13,2,23,43,-1,43v-49,43,-77,77,-90,148v5,49,27,67,64,101v4,14,5,6,2,19r-15,0v-35,-17,-79,-58,-79,-120v0,-58,66,-176,119,-191",w:120},")":{d:"108,-138v-2,73,-48,120,-98,153v-17,-5,-16,-20,-6,-31v52,-64,73,-62,74,-135v1,-42,-40,-98,-58,-128v0,-5,-1,-12,-2,-22v18,-18,25,0,42,27v25,39,50,66,48,136",w:120},"*":{d:"121,-271v15,-5,36,-8,40,9v-5,10,-31,19,-47,31v0,11,34,43,14,53v-18,8,-24,-24,-34,-20v-4,10,-4,19,-12,41v-25,7,-15,-30,-17,-47v-13,-1,-17,9,-46,30r-10,0v-20,-32,37,-43,54,-64v-10,-11,-36,-33,-16,-51v3,0,14,8,33,24v8,-10,26,-39,32,-42v14,7,15,23,9,36",w:177},"+":{d:"163,-64v-7,22,-65,2,-77,21v-2,10,-6,21,-11,35v-20,4,-21,-12,-19,-29v3,-23,-44,6,-39,-27v-8,-22,36,-8,49,-18v8,-13,6,-36,24,-40v19,-4,14,32,11,39v18,3,19,2,54,8v2,1,5,5,8,11",w:170},",":{d:"25,63v-26,21,-48,-2,-22,-24v14,-12,35,-40,35,-69v3,-2,3,-11,12,-9v35,17,5,88,-25,102",w:97},"-":{d:"57,-94v19,4,55,-5,54,17v-15,23,-54,20,-91,15v-4,2,-13,-10,-11,-16v-1,-22,28,-15,48,-16",w:124},".":{d:"40,-48v21,20,21,44,-4,44v-33,0,-26,-24,-10,-44r14,0",w:67},"/":{d:"21,20v-22,-45,21,-95,41,-126v38,-57,115,-158,193,-201v2,0,4,3,7,11v11,29,-15,34,-25,55v-81,56,-189,208,-197,261r-19,0",w:275},0:{d:"78,-237v70,-47,269,-41,270,59v0,34,-11,53,-29,76v-13,35,-30,32,-85,64v-6,2,-10,6,-7,8v-73,14,-98,38,-173,1v-7,-13,-52,-48,-46,-88v9,-57,27,-75,70,-120xm123,-38v100,0,202,-46,195,-153v-32,-55,-144,-73,-211,-35v-16,34,-68,54,-53,108v6,25,1,22,-3,39v6,24,41,41,72,41",w:353},1:{d:"39,-208v0,-14,6,-59,29,-39v3,4,6,13,10,24r-22,128r8,87v-4,6,-9,3,-16,2v-44,-38,-9,-137,-9,-202",w:93},2:{d:"88,-35v47,-10,119,-24,168,-9v0,12,-23,13,-35,16v1,1,3,1,5,1v-74,8,-118,23,-194,23v-14,0,-20,-13,-21,-28v55,-40,83,-61,123,-104v26,-13,65,-67,71,-102v-1,-9,-11,-16,-22,-16v-20,-1,-120,29,-156,49v-10,-2,-30,-20,-10,-28v50,-21,111,-51,178,-48v25,10,44,22,36,39v12,30,-19,64,-34,83v-39,48,-37,39,-115,109v0,5,-3,8,-8,11v4,3,8,4,14,4",w:265},3:{d:"188,-282v34,-10,74,25,47,51v-19,32,-55,50,-92,70v28,14,116,25,108,70v8,14,-49,40,-63,48v-29,9,-130,22,-168,42v-6,-5,-19,-7,-12,-22v56,-36,175,-21,210,-76v-9,-20,-88,-42,-97,-33v-20,-1,-41,2,-56,-7r5,-21v56,-25,103,-36,137,-78v1,-1,2,-5,4,-11v-15,-14,-56,7,-79,0v-10,9,-73,22,-92,31v-11,-4,-28,-23,-13,-30v50,-22,96,-26,154,-37v0,-1,8,3,7,3",w:260},4:{d:"79,-249v-7,17,-29,75,-33,96v0,6,3,8,8,8v43,-2,111,6,141,-6v17,-47,20,-100,63,-148v9,4,16,7,21,10v-17,31,-44,95,-51,141v7,4,24,-4,23,10v-1,16,-29,12,-31,23v-10,22,-9,69,-7,103v-3,2,-7,5,-10,9v-47,-11,-23,-74,-16,-114v0,-4,-2,-6,-7,-6v-65,2,-89,13,-162,4v-22,-22,-2,-53,5,-76v16,-15,17,-57,35,-70v6,-1,21,11,21,16",w:267},5:{d:"185,-272v30,7,45,-8,53,18v1,16,-17,18,-34,14v0,0,-95,-11,-129,1v-6,9,-24,33,-29,54v76,10,171,5,214,47v11,11,22,30,5,52v-14,12,-30,14,-34,27v-26,11,-141,63,-157,60v-16,-2,-25,-19,-4,-27v48,-18,128,-39,170,-86v4,-14,-65,-41,-85,-41r-92,0v-10,-4,-66,-1,-57,-23v0,-23,23,-51,35,-83v11,-28,133,-10,144,-13",w:284},6:{d:"70,-64v9,-51,63,-74,123,-71v43,2,109,3,111,41r-25,47v0,1,1,2,2,3v-5,0,-39,10,-41,20v-15,3,-22,4,-22,11v-39,1,-77,20,-119,13v-42,-7,-35,-9,-77,-46v-56,-118,94,-201,176,-229v7,0,21,8,20,15v-2,17,-23,15,-43,24v-69,31,-119,72,-134,145v-5,25,36,68,78,64v59,-6,128,-18,153,-61v-7,-14,-13,-9,-32,-21v-67,-15,-118,-5,-150,43r0,12v-13,4,-17,-3,-20,-10",w:310},7:{d:"37,-228v33,-14,173,-17,181,-19v28,-1,24,31,9,45v-17,15,-45,49,-59,69v-17,26,-55,67,-61,113v-10,13,-9,14,-14,20v-33,-13,-20,-25,-11,-53v16,-48,73,-115,109,-156v2,-7,5,-14,-10,-12v-26,4,-54,6,-76,13v-23,-5,-83,31,-94,-9v2,-8,18,-19,26,-11",w:245},8:{d:"57,-236v40,-50,166,-51,213,-10v22,28,10,63,-22,78r-35,17v8,5,54,24,53,44v-5,14,-4,33,-18,42v-13,13,-35,18,-44,34v-60,27,-190,49,-194,-42v7,-41,17,-54,59,-70r0,-4v-32,-9,-73,-62,-26,-85v4,0,8,-2,14,-4xm142,-160v24,-2,160,-31,99,-72v-28,-18,-108,-33,-146,-5v-16,12,-28,30,-33,59v24,12,37,20,80,18xm41,-62v30,65,189,6,199,-37v3,-14,-60,-30,-74,-30v-70,0,-118,10,-125,67",w:290},9:{d:"11,-192v15,-49,119,-61,161,-23v16,15,27,55,11,79v-20,62,-51,79,-96,118v-10,4,-45,27,-50,6v9,-15,66,-52,98,-99v-7,-7,-8,-3,-25,0v-49,-11,-96,-25,-99,-81xm145,-131v7,-5,13,-34,13,-41v-2,-51,-104,-38,-114,-6v-2,10,37,35,46,35v23,1,43,-1,55,12",w:198},":":{d:"39,-125v15,-8,40,-1,40,15v0,15,-6,22,-19,22v-13,0,-29,-21,-21,-37xm66,-17v-8,27,-51,19,-46,-8v-1,-6,8,-22,14,-20v29,0,30,6,32,28",w:95},";":{d:"56,-93v2,-30,37,-22,40,2v0,2,-1,7,-3,15v-13,8,-15,6,-27,4xm64,-44v11,-11,30,-4,32,14v-21,39,-63,71,-92,85v-5,0,-11,-2,-18,-8v11,-23,36,-36,50,-61v11,-7,19,-20,28,-30",w:107},"<":{d:"166,-202v12,0,29,15,24,29v0,4,-119,64,-120,73v15,21,89,64,91,86v2,29,-18,12,-30,15v-27,-29,-59,-54,-95,-75v-18,-10,-25,-13,-24,-41",w:176},"=":{d:"125,-121v18,7,55,-9,69,14v0,17,-45,26,-135,26v-18,0,-27,-7,-27,-21v-1,-37,60,-5,93,-19xm138,-71v20,0,48,-1,50,16v-13,24,-86,32,-131,29v-29,-2,-43,-10,-43,-24v-7,-23,36,-14,39,-17v27,6,57,-4,85,-4",w:196},">":{d:"4,-14v20,-48,77,-59,118,-94v-16,-19,-58,-52,-81,-75v-11,-7,-15,-38,-1,-40v33,16,83,71,121,105v26,23,-6,35,-41,53v-29,16,-56,28,-73,54v-21,15,-16,20,-34,15v-3,0,-9,-16,-9,-18",w:174},"?":{d:"105,-291v57,-13,107,-4,107,39v0,67,-136,85,-155,137v-1,6,10,23,-4,23v-23,1,-33,-35,-23,-57v31,-41,124,-60,149,-103v-8,-21,-72,-5,-88,-1v-23,6,-59,39,-71,8v0,0,-1,0,1,-17v10,-4,45,-20,84,-29xm80,-25v-6,4,-8,39,-24,22v-24,3,-22,-21,-13,-35v17,-7,29,5,37,13",w:216},"@":{d:"218,-207v23,8,42,14,47,37v44,68,-27,137,-87,85r1,0v0,2,-59,19,-61,17v-35,0,-42,-47,-17,-68r0,-4v-19,-1,-45,37,-49,40v-37,76,58,72,121,62v11,-2,34,-13,36,3v-14,31,-69,31,-114,33v-51,2,-99,-41,-80,-92v2,-30,22,-40,42,-63v35,-20,91,-53,161,-50xm217,-101v23,0,35,-19,35,-41v0,-43,-75,-41,-102,-19v36,3,55,16,62,41v-6,5,-6,19,5,19xm127,-110v8,5,51,-15,28,-16v-4,0,-25,4,-28,16",w:291},A:{d:"97,-81v-23,-10,-39,38,-52,60v-8,6,-8,6,-22,18v-22,-7,-23,-37,-4,-49v7,-8,11,-15,15,-23r-1,1v-14,-26,23,-29,31,-40v1,-1,15,-29,26,-36v17,-31,39,-58,54,-92v16,-20,20,-51,41,-66v29,5,34,62,45,92v9,64,21,103,49,155v-3,25,-44,11,-54,0v-34,-12,-97,-29,-128,-20xm107,-118v20,6,80,10,111,17v6,-7,-4,-15,-7,-24v-11,-28,-9,-92,-30,-117v-9,9,-19,44,-34,55v-9,23,-27,40,-40,69",w:294},B:{d:"256,-179v41,10,115,34,91,91v-6,3,-14,12,-19,20v-37,19,-50,34,-63,25v-9,10,-12,11,-34,13r3,-3v-4,-4,-12,-4,-18,0v0,0,2,2,5,4v-21,14,-26,6,-44,15v-4,0,-7,-2,-8,-5v-6,11,-20,-5,-18,11v-36,4,-91,35,-114,4v-7,-62,-10,-138,4,-199v-1,-19,-37,2,-37,-27v0,-8,2,-13,6,-15v68,-31,231,-92,311,-39v8,12,12,20,12,25v-8,42,-32,49,-77,80xm79,-160v72,-17,135,-39,184,-70v20,-13,31,-23,31,-27v1,-6,-30,-13,-38,-12v-54,0,-116,13,-186,41v11,21,1,48,9,68xm262,-43v0,-4,3,-6,-4,-5v0,1,1,2,4,5xm211,-140v-34,7,-94,24,-139,15v-6,20,-4,56,-4,82v0,29,43,1,56,2v48,-11,108,-25,154,-48v20,-10,32,-17,32,-25v0,-18,-33,-26,-99,-26xm195,-20v6,1,6,-2,5,-7v-3,2,-7,2,-5,7",w:364},C:{d:"51,-114v-12,75,96,76,166,71r145,-10v9,2,9,5,9,18v-37,18,-85,28,-109,22v-18,10,-47,10,-71,10v-29,0,-68,1,-105,-11v-6,-1,-10,-3,-10,-8v-33,-13,-48,-33,-66,-59v-19,-114,146,-150,224,-177v35,0,88,-31,99,7v-1,29,-49,14,-76,28v-55,8,-115,35,-175,71v-13,8,-23,21,-31,38",w:376},D:{d:"312,-78v-2,1,-3,7,-10,5v6,-3,10,-4,10,-5xm4,-252v2,-27,83,-38,106,-39v130,-7,267,1,291,109v0,0,-2,8,-3,25v-5,9,-4,28,-23,34v-4,4,-2,5,-7,0v-3,3,-15,7,-5,10v0,0,-10,14,-13,2v-11,1,-8,5,-20,14v1,2,7,3,9,1v-4,13,-22,13,-11,4v0,-3,1,-6,-3,-5v-40,29,-103,38,-141,65v10,6,22,-7,34,-3v-41,20,-127,44,-171,46v-21,1,-47,-33,-11,-39v15,-2,43,-6,56,-11v-16,-101,-5,-130,9,-207v2,0,4,-1,6,-3v-16,-17,-91,38,-103,-3xm297,-69v-7,3,-17,8,-25,7v1,1,3,2,5,2v-4,2,-11,5,-23,9v4,-11,30,-21,43,-18xm240,-51v10,0,12,2,0,6r0,-6xm220,-36v-1,-3,4,-6,6,-3v0,1,-2,1,-6,3xm125,-48v16,6,137,-46,155,-53v29,-18,101,-44,82,-93v-21,-53,-84,-61,-168,-67v-20,7,-50,3,-77,8v33,54,-12,132,8,205xm159,-22v-4,-1,-15,-5,-15,2v7,-1,12,-2,15,-2",w:381},E:{d:"45,-219v-19,-36,34,-41,63,-36v44,-10,133,-8,194,-15v3,2,38,11,52,15v-73,19,-171,21,-246,38v-9,11,-16,32,-20,61v35,11,133,-6,183,3v1,6,2,7,3,14v-46,24,-118,16,-193,27v-15,13,-22,52,-22,66v60,1,121,-20,188,-20v22,10,53,-7,74,5v16,29,-23,26,-43,32v-73,4,-139,13,-216,27r-52,-10v-4,-22,23,-69,26,-98v-3,0,-10,-15,-12,-24v20,-12,34,-23,35,-67v2,-1,5,-5,5,-7v0,-4,-14,-11,-19,-11",w:353},F:{d:"270,-258v13,2,59,6,48,34v-78,-3,-143,1,-212,22v-10,16,-21,43,-24,69r145,-9v8,3,29,-3,16,21v-14,-1,-59,13,-60,7v-12,13,-67,18,-108,21v-2,1,-4,3,-7,6v-2,23,-8,43,-7,69v1,28,-30,11,-40,5r10,-80r-26,-14v5,-10,10,-33,28,-25v21,-3,15,-46,26,-59v-1,-3,-32,-13,-28,-24v2,-22,45,-16,59,-30v47,4,99,-14,151,-9v5,-3,25,-3,29,-4",w:236},G:{d:"311,-168v53,0,94,57,74,110v-31,37,-71,34,-136,52v-13,-7,-41,10,-57,7v-73,-1,-122,-17,-162,-59v-49,-51,-24,-80,5,-130v35,-61,138,-93,214,-106v16,4,42,-1,40,21v-5,40,-39,2,-73,21v-76,19,-162,65,-177,142v28,103,237,76,312,29v2,-3,3,-7,3,-13v-10,-35,-37,-43,-87,-45v-16,-13,-53,-9,-78,1v-4,-3,-5,-7,-5,-11v17,-29,73,-17,108,-24v12,4,18,5,19,5",w:391},H:{d:"300,-268v18,12,19,32,4,51v-35,44,-34,140,-46,217v-1,5,-5,13,-11,12v-6,1,-19,-14,-18,-27r7,-106v-28,7,-76,22,-116,14v-18,2,-36,6,-55,3v-43,-8,-14,53,-33,75v-29,1,-26,-67,-21,-97v5,-31,28,-73,43,-98v2,2,7,3,14,3v13,33,-11,48,-13,78v61,4,118,2,176,2v8,0,13,-6,15,-20v4,-47,21,-87,54,-107",w:288},I:{d:"63,-266v34,10,-4,105,-8,128r-24,126v-2,2,-3,1,-9,6v-12,-10,-12,-15,-12,-47v0,-93,9,-156,28,-188v10,-17,19,-25,25,-25",w:79},J:{d:"235,-291v26,11,31,104,31,142v0,37,-2,95,-32,126v-33,34,-121,26,-167,1v-18,-11,-54,-29,-59,-59v0,-3,5,-15,16,-14v31,36,90,57,162,51v63,-30,56,-148,32,-226v-1,-16,11,-13,17,-21",w:282},K:{d:"212,-219v17,-5,80,-60,80,-19v0,9,-2,14,-5,16r-132,78v-34,23,-54,32,-21,50v39,21,74,23,124,41v5,2,7,5,7,9v-4,24,-55,15,-79,8v-67,-19,-98,-36,-116,-83v9,-24,38,-35,66,-61v7,-4,49,-30,76,-39xm47,-194v11,-20,11,-45,31,-55v2,2,4,3,6,0v29,39,-21,96,-18,128v-17,24,-15,62,-29,113v-4,3,-10,7,-19,11v-12,-13,-10,-28,-8,-53v3,-31,17,-79,37,-144",w:270},L:{d:"84,-43v58,0,179,-27,242,-4v3,17,-29,24,-40,26v-85,-4,-202,46,-268,3v-24,-16,-2,-33,-4,-57v26,-76,38,-108,86,-191v14,-7,26,-50,45,-32v6,22,5,31,-12,46v-20,39,-50,82,-67,142v-7,6,-19,46,-19,54v0,9,12,13,37,13",w:331},M:{d:"174,-236v-1,52,-11,92,-7,143v10,5,15,-12,22,-18v42,-55,90,-130,136,-174r15,-18v42,2,32,53,11,80v-12,58,-54,143,-34,210v0,3,-3,12,-9,10v-31,-5,-32,-57,-27,-92v4,-27,12,-58,25,-93v-5,-10,5,-19,6,-30v-46,44,-66,110,-129,172v-11,10,-18,15,-22,15v-34,6,-28,-103,-28,-152v-28,22,-65,119,-96,170v-9,15,-34,3,-31,-19v30,-64,91,-177,139,-229v12,-1,29,13,29,25",w:343},N:{d:"248,-20v-3,17,-37,18,-43,3v-24,-35,-53,-145,-80,-203v-32,40,-55,120,-92,174v-13,3,-26,-13,-27,-22r87,-171v4,-13,20,-57,42,-32v42,48,46,139,82,198v29,-45,46,-88,65,-153v12,-19,23,-42,38,-60v27,-1,14,18,4,44v-6,46,-32,68,-37,121v-15,29,-33,69,-39,101",w:307},O:{d:"240,-268v85,1,163,29,150,125v13,7,-12,18,-5,26v-23,63,-133,112,-228,124v-80,-16,-171,-56,-148,-153v11,-47,20,-43,53,-83v17,-9,39,-22,73,-29v45,-10,81,-10,105,-10xm363,-156v16,-51,-62,-85,-111,-79v-25,-11,-50,8,-81,0v-15,10,-70,16,-85,31v6,20,-27,24,-39,45v-42,75,40,128,115,128v56,0,209,-71,201,-125",w:383},P:{d:"70,-225v-7,-12,-36,16,-49,19v-4,0,-9,-5,-14,-17v21,-47,114,-55,172,-59v41,-3,132,33,99,87v-21,34,-72,59,-144,80v-2,16,-79,3,-74,46v3,25,-5,47,-10,68v-22,-1,-23,-29,-22,-56v2,-25,-20,-32,-8,-50v21,-5,10,-35,25,-57v6,-28,14,-48,25,-61xm71,-229v47,14,-2,50,-1,99v41,-3,113,-37,173,-76v5,-9,8,-14,8,-15v-28,-47,-125,-29,-180,-8",w:252},Q:{d:"374,-217v20,59,-11,127,-48,156r30,38v-1,6,-8,16,-14,9v-3,0,-19,-9,-47,-26v-72,35,-173,75,-236,12v-70,-40,-67,-213,26,-217r8,5v24,-20,72,-48,112,-38v21,-4,22,-1,50,-2v66,-2,94,20,119,63xm296,-88v13,5,61,-49,63,-84v4,-62,-54,-78,-119,-76v-14,-6,-49,5,-71,3v-42,16,-89,41,-93,94v-9,11,1,25,-7,38v-12,-19,-7,-67,-1,-88v-56,30,-37,137,19,155v27,17,92,19,119,0v12,-2,29,-9,52,-20v2,-2,3,-3,3,-6v-11,-12,-46,-27,-54,-56v0,-13,3,-19,9,-19v18,1,60,52,80,59",w:379},R:{d:"100,-275v96,-23,196,-10,208,78v-3,18,-17,52,-49,62v-14,20,-54,23,-79,40v-2,0,-14,2,-36,6v-40,8,-30,14,-3,33v37,27,52,30,118,55v16,6,31,23,12,27v-58,-2,-104,-29,-143,-61v-14,-3,-16,-15,-39,-27v-23,-19,-28,-12,-15,-38v63,-19,111,-15,163,-53v27,-20,43,-36,43,-49v0,-64,-120,-62,-173,-38v-9,4,-38,9,-40,18v-10,32,-16,70,-13,116v-10,21,-8,47,-6,75v2,31,-9,29,-27,22v-9,-55,5,-140,15,-190v-8,-6,-24,10,-24,-11v0,-34,16,-34,42,-55v2,-1,17,-4,46,-10",w:297},S:{d:"13,-3v-7,-3,-22,-18,-5,-22v68,-15,119,-32,154,-45v51,-19,39,-34,3,-53v-46,-25,-82,-30,-121,-64v-33,-29,-50,-35,-25,-58v37,-20,119,-29,181,-29v29,0,44,6,44,18v-9,26,-62,6,-104,14v-17,2,-72,6,-92,16v37,53,132,58,180,111v8,9,11,20,11,30v-4,17,-23,35,-42,34v-21,16,-17,1,-49,17v-14,7,-41,9,-56,20v-25,-3,-49,10,-79,11",w:234},T:{d:"141,-3v-36,-6,1,-49,-3,-79v10,-19,6,-35,15,-64r26,-85v-51,-9,-100,10,-141,14v-16,2,-30,-26,-11,-32v26,-8,143,-8,179,-19r12,6v67,-2,142,-1,200,-1v8,0,14,3,19,10v-18,16,-74,3,-103,14v-48,-4,-60,4,-113,7v-42,22,-36,130,-58,187v1,12,-9,44,-22,42",w:277},U:{d:"365,-262v13,56,-22,104,-36,141v-19,22,-30,38,-57,56v-4,18,-60,35,-78,50v-53,28,-142,0,-161,-34v-31,-56,-37,-108,-11,-164v17,-33,29,-50,48,-29v-2,2,-3,7,-4,13v-44,36,-38,149,7,174v30,26,55,19,102,4v56,-17,66,-34,120,-76v12,-24,56,-68,46,-122r0,-16v0,1,-1,3,-1,6v4,-13,11,-10,25,-3",w:368},V:{d:"246,-258v21,-22,31,-26,44,-8v1,1,-12,22,-28,35v-15,25,-41,38,-56,69v-13,15,-20,31,-28,57v-15,13,-11,29,-27,72v3,21,-5,24,-27,27v-33,-45,-54,-118,-84,-167v-5,-26,-18,-50,-25,-76v-3,-12,24,-8,29,-5v8,13,18,52,26,70r52,115v9,-2,4,-9,10,-21r25,-47v25,-44,46,-76,89,-121",w:234},W:{d:"31,-213v16,46,17,106,41,151v31,-35,49,-89,76,-127v30,-15,39,27,52,56v10,22,21,48,35,67v2,0,4,-1,5,-3v16,-28,50,-76,79,-121v14,-21,40,-63,64,-83r5,8v-30,58,-76,110,-97,173v-18,28,-25,37,-33,63v-11,1,-16,25,-30,15v-21,-31,-44,-89,-62,-131v0,-2,-1,-3,-5,-5v-17,11,-16,36,-31,50v-20,33,-20,84,-68,94v-24,-19,-23,-81,-39,-111v-1,-15,-29,-94,-10,-108v9,2,12,5,18,12",w:331},X:{d:"143,-183v43,-25,69,-36,126,-62v22,-10,86,-10,56,21v-51,3,-158,61,-154,64v10,15,41,30,50,52v27,17,46,60,70,82v9,14,-6,30,-24,20v-35,-43,-75,-100,-116,-132v-48,13,-100,47,-118,94v-1,49,-26,34,-27,4v-1,-26,13,-27,17,-48v22,-27,68,-55,90,-77v-9,-12,-60,-39,-79,-57v-6,-10,-6,-25,12,-25",w:312},Y:{d:"216,-240v19,-14,42,10,22,26v-54,66,-121,109,-156,197v-8,21,-11,15,-30,4v3,-37,27,-61,33,-76v12,-12,15,-19,32,-42v-8,-6,-40,5,-45,5v-48,-6,-69,-65,-56,-113v14,0,13,-1,24,7v2,33,12,75,42,73v36,-2,102,-57,134,-81",w:189},Z:{d:"60,-255v66,12,200,-34,240,21v-13,42,-63,62,-98,89v-19,15,-47,33,-82,55v-25,16,-47,32,-66,47v58,24,129,-6,208,-6v23,0,36,12,13,19v-33,2,-53,5,-86,10v-32,18,-88,15,-135,15v-9,-1,-55,-1,-48,-29v1,-24,30,-24,40,-41v64,-50,151,-86,208,-147v-38,-17,-155,12,-198,-4v0,0,-11,-33,4,-29",w:310},"[":{d:"72,-258r-15,250v30,4,55,-3,80,-6v7,-1,8,17,9,23v-28,15,-73,23,-121,21v-7,0,-10,-6,-10,-17v0,-60,25,-193,22,-288v0,-16,13,-20,33,-19v9,-3,34,-12,51,-12v16,0,15,16,19,29v-16,7,-48,10,-68,19",w:151},"\\":{d:"21,38v-20,-21,9,-72,13,-90v44,-78,113,-189,200,-253v2,0,5,4,7,12v11,31,-13,36,-24,58v-74,61,-174,219,-180,273r-16,0",w:257},"]":{d:"133,-258v-23,-13,-84,6,-85,-32v0,-10,5,-15,14,-15v0,0,30,2,90,7v10,1,15,13,15,36v2,7,-8,59,-13,112r-11,125v-9,48,9,90,-59,71v-20,-4,-39,-1,-59,-4v-5,-10,-25,-12,-14,-30v8,-3,61,-13,78,-8v14,1,8,-7,10,-17v15,-69,21,-166,34,-245",w:171},"^":{d:"68,-306v20,15,47,36,58,60v-1,4,0,7,-9,7v-26,0,-47,-38,-49,-32v-15,9,-41,50,-54,30v-2,-31,17,-23,33,-51v8,-9,15,-14,21,-14",w:135},_:{d:"11,15v-8,33,18,45,50,34r205,2r197,-5v11,-5,14,-9,7,-28v-95,-21,-258,-10,-376,-10v-25,0,-72,-3,-83,7",w:485},"`":{d:"75,-264v16,8,56,14,39,43v-30,-8,-65,-23,-105,-44v-1,-3,-3,-28,5,-25v16,5,44,17,61,26",w:129},a:{d:"124,-56v10,4,59,41,65,50v1,7,-6,17,-12,17r-60,-30v-22,2,-42,21,-65,19v-33,4,-68,-67,-15,-81v41,-27,96,-39,110,9v0,6,-4,12,-11,16v-33,-25,-67,-5,-88,12v10,16,61,-18,76,-12",w:196},b:{d:"80,-140v69,1,123,0,134,52v5,26,-71,71,-97,70v-11,11,-88,22,-94,22v-11,-3,-26,-18,-6,-24v19,-5,-2,-19,-1,-35v1,-18,11,-36,-5,-47v-6,-17,-6,-21,14,-32v6,-45,18,-89,28,-124v2,-7,8,-12,17,-15v5,3,10,11,16,28v-12,27,-13,63,-23,96v0,6,6,9,17,9xm87,-107v-40,-9,-31,31,-39,54v8,15,0,25,12,22v30,-8,60,-18,88,-32v39,-18,49,-33,-1,-42v-20,-4,-45,-7,-60,-2",w:217},c:{d:"128,-123v29,-7,37,29,12,33v-27,-4,-40,6,-79,25v-8,4,-13,11,-16,22v30,32,91,3,134,11v5,13,-8,26,-22,19v-51,25,-139,28,-150,-30v6,-50,69,-82,121,-80",w:194},d:{d:"224,-201v0,-35,-17,-111,24,-94v7,86,-2,119,0,197v-4,2,-8,21,-18,16v-62,-7,-154,-8,-185,29v6,17,28,26,51,26v16,0,100,-15,132,-18v7,5,-6,20,-10,22v-24,8,-122,42,-163,25v-32,-5,-62,-53,-36,-80v35,-37,118,-46,198,-43v1,-22,7,-49,7,-80",w:265},e:{d:"4,-57v0,-58,51,-71,110,-74v33,-1,45,16,59,35v1,14,2,39,-7,42v-24,-2,-73,13,-99,11v-2,2,-2,3,-2,3v0,3,12,8,37,15v21,0,69,9,31,22v-9,14,-34,6,-56,6v-27,-5,-73,-28,-73,-60xm123,-102v-22,2,-68,5,-65,26v24,-2,66,5,79,-6v-5,-13,-1,-13,-14,-20",w:182},f:{d:"6,-59v6,-29,53,-4,53,-43v0,-64,29,-118,84,-150v45,-25,167,-24,155,51v-1,2,-7,6,0,6r-10,2v-45,-58,-165,-39,-186,39v-7,26,-11,42,-9,62v44,8,95,-21,135,-7v-12,25,-39,21,-76,30v-19,5,-18,7,-54,19v-2,8,15,32,17,35v-6,25,-26,26,-40,-5r-15,-24v-41,10,-44,12,-54,-15",w:234},g:{d:"132,-97v30,27,21,75,30,117v-12,31,-11,66,-36,103v-32,46,-105,83,-167,39v-31,-21,-49,-29,-51,-75v-2,-37,77,-50,121,-57v37,-6,68,-10,95,-11v7,-6,3,-32,4,-46v0,0,-1,1,-1,2v0,-18,-5,-31,-14,-45v-44,5,-79,20,-94,-18v3,-54,73,-54,125,-50v12,7,12,13,4,25v-30,-11,-76,8,-90,20v23,3,50,-16,74,-4xm-34,121v60,53,168,1,159,-86v-47,-7,-93,24,-142,30v-12,7,-45,19,-42,29v0,10,8,19,25,27",w:188},h:{d:"100,-310v11,-2,10,19,11,20v-11,52,-40,133,-53,189v-6,30,-9,37,-9,47v27,0,113,-34,143,-34v42,0,31,47,39,79v0,4,-5,17,-16,16v4,2,11,3,4,6v-24,-1,-28,-34,-25,-64v-1,-1,-2,-3,-5,-5v-51,0,-110,38,-162,51v-9,1,-15,-15,-16,-23v17,-89,39,-141,71,-264v0,-9,6,-19,18,-18",w:251},i:{d:"62,-209v7,18,9,23,-5,38v-23,-6,-21,-18,-11,-36v2,0,8,-1,16,-2xm34,-7v-18,-21,-8,-73,-1,-106v7,-10,20,-8,23,6v-1,36,7,72,-2,104v-8,2,-8,0,-20,-4",w:80},j:{d:"88,-191v5,28,-18,40,-28,21v0,-20,12,-29,28,-21xm82,-99v28,-1,16,35,16,61v0,60,-19,150,-35,202v-12,8,-19,31,-35,16v-32,-7,-43,-19,-56,-44r2,-17v11,4,49,45,61,18v10,-55,27,-107,30,-171v0,-16,0,-59,17,-65",w:120},k:{d:"59,-66v33,26,114,37,155,62v8,-4,22,-2,19,-17v0,-4,-12,-11,-30,-24v-36,-25,-54,-22,-99,-33v14,-21,119,-13,103,-63r-16,-7r-123,47r25,-93v-3,-15,16,-49,18,-81v1,-15,-21,-14,-25,-3v-31,82,-49,168,-75,257v2,2,22,30,27,10v2,-5,4,-9,9,-11v4,-16,4,-15,12,-44",w:236},l:{d:"66,-300v21,-6,37,23,30,55v-10,51,-28,135,-28,208v0,11,6,36,-13,37v-29,-5,-30,-48,-25,-83r28,-177v-6,-17,1,-29,8,-40",w:102},m:{d:"348,-59v-2,21,0,57,3,73v-17,3,-30,-1,-32,-16v-8,-7,-5,-44,-13,-70v-35,3,-82,49,-111,70v-12,8,-40,4,-39,-15r2,-56v-1,-13,4,-28,-8,-29v-35,8,-79,72,-115,87v-6,2,-20,-18,-21,-22v1,-20,14,-105,39,-64r8,15v17,-14,72,-56,93,-54v27,3,49,40,43,80v24,-2,66,-55,124,-53v11,14,28,23,27,54",w:368},n:{d:"121,-136v37,6,62,54,62,111v0,32,-16,25,-31,17v-18,-30,-5,-45,-22,-85v-37,-13,-71,55,-92,65v-20,-3,-39,-39,-21,-62v2,-12,3,-15,11,-30v12,-8,20,11,29,12",w:194},o:{d:"108,-139v52,-24,104,18,104,63v0,59,-66,67,-114,83v-52,-2,-115,-50,-80,-105v23,-18,52,-35,90,-41xm45,-60v16,54,125,16,131,-23v-12,-59,-129,-8,-131,23",w:217},p:{d:"82,14v-10,12,-8,117,-24,142v-15,2,-19,0,-29,-13v0,-76,9,-113,22,-192v14,-27,35,-6,37,13v0,8,-3,21,-7,38v2,2,3,2,4,2v26,-9,116,-33,126,-72v-7,-17,-24,-33,-49,-31v-40,3,-116,13,-116,47v-5,7,-2,17,-16,20v-17,-12,-18,-20,-12,-38v8,-25,74,-61,110,-59v55,-15,113,15,118,70v-15,52,-84,79,-146,83v-5,0,-11,-4,-18,-10",w:251},q:{d:"144,-147v27,-8,89,-3,97,31v-9,29,-42,-4,-73,1v-32,6,-118,20,-111,49v0,7,13,13,21,13v21,0,78,-24,104,-34v2,0,9,8,22,21v1,1,1,2,1,5v-27,90,-22,70,-43,203v11,15,-15,54,-33,33v-6,-8,-10,-20,-3,-28v1,-72,5,-114,15,-172v-35,3,-35,10,-59,8v-41,-4,-98,-41,-56,-85v33,-34,59,-27,118,-45",w:248},r:{d:"242,-117v2,22,5,10,-14,23v-73,-7,-166,-23,-174,56v-8,6,-3,20,-8,36v-29,10,-40,-9,-33,-46v6,-31,7,-69,32,-55v58,-37,66,-42,175,-19v3,5,15,4,22,5",w:229},s:{d:"154,-151v19,1,27,24,13,32v-4,1,-22,4,-53,7v-16,8,-22,-2,-39,9v23,21,89,16,96,62v-13,24,-85,35,-124,42v-9,-3,-18,-3,-27,0v-6,-4,-21,-16,-8,-25v30,-6,83,-13,102,-24v-17,-16,-80,-33,-97,-48v-3,-2,-4,-7,-4,-15v-6,-6,3,-13,15,-18v22,-9,94,-23,126,-22",w:188},t:{d:"85,-150v10,-41,35,-126,65,-134v4,1,24,19,11,36v-17,22,-29,57,-36,104v26,8,50,-7,73,5v14,0,22,3,22,9v-1,19,-44,18,-57,23v-10,1,-46,0,-54,10v-10,24,-4,67,-20,98v-21,-3,-26,1,-26,-20v0,-9,2,-36,8,-81v-15,-13,-81,9,-77,-27v4,-38,71,6,91,-23",w:194},u:{d:"207,-136v-1,-2,11,-14,14,-13v6,0,10,7,10,22v-3,40,-23,56,-40,82v-13,19,-62,43,-93,43v-67,-2,-111,-75,-71,-133v26,-3,21,29,19,49v-1,27,26,44,57,42v41,-2,93,-55,104,-92",w:242},v:{d:"24,-127r52,71v42,-16,70,-54,124,-65v5,4,8,7,8,11v-8,19,-4,8,-33,32v0,1,-1,3,-1,5v-61,45,-93,68,-97,68v-40,-15,-50,-72,-68,-100v6,-14,10,-22,15,-22",w:214},w:{d:"15,-139v38,-2,27,57,45,86v30,2,67,-66,101,-78v26,6,36,69,60,78v47,-35,51,-54,119,-104v3,0,7,-2,15,-4v19,23,-9,28,-21,49v-33,28,-68,90,-107,109v-10,6,-52,-47,-72,-71v-20,17,-85,74,-97,73v-38,7,-41,-98,-52,-122v0,-1,3,-7,9,-16",w:325},x:{d:"95,-124v22,-13,78,-32,99,-31v16,0,23,6,23,18v0,22,-17,11,-49,21v-3,0,-45,20,-42,24v0,1,2,4,8,10v20,24,49,41,44,80v-35,3,-27,-9,-60,-44v-40,-43,-37,-26,-79,9v-1,1,-2,3,-3,8v-12,8,-28,10,-27,-11v-6,-8,45,-65,48,-65v-17,-21,-61,-52,-24,-68v9,0,48,37,62,49",w:223},y:{d:"44,-65v22,33,70,4,99,-8v5,-4,28,-15,41,-31r17,0v25,47,-26,70,-40,114v-5,4,-9,8,-10,21v-16,12,-11,33,-27,51v-5,18,-12,43,-23,71v-1,-1,-2,34,-18,29v-12,1,-22,-12,-22,-23v20,-70,24,-65,68,-177v-47,16,-111,8,-116,-39v-11,-13,-7,-62,8,-62v18,0,22,26,23,54",w:216},z:{d:"189,-43v9,-1,46,-6,41,12v0,7,-5,13,-15,14v-45,6,-148,24,-181,13v0,-3,-5,-8,-14,-15v5,-44,66,-46,90,-85v-15,-18,-84,21,-84,-14v0,-10,5,-17,14,-18v33,-3,79,-13,109,-3v4,-2,14,11,12,15v0,23,-26,51,-78,84v28,10,73,-3,106,-3",w:244},"{":{d:"94,-303v27,-9,90,-14,79,26v-20,17,-55,-5,-87,13v-4,1,-6,4,-6,8v33,42,31,44,7,85v-6,10,-13,16,-13,13v5,6,17,17,15,31r-33,78v7,35,28,49,57,63r49,0v7,42,-51,41,-86,20v-43,-13,-51,-51,-56,-89v-2,-25,25,-54,27,-71v-3,-4,-46,-5,-41,-21v2,-10,-3,-29,11,-25v2,0,51,-17,52,-38v4,-3,-25,-23,-25,-49v0,-41,8,-30,50,-44",w:179},"|":{d:"30,-308v26,5,14,50,15,80v5,78,-8,153,-3,225v-2,15,-1,31,-11,36v-8,-3,-25,-22,-25,-32r9,-183v0,-40,0,-78,1,-112v0,-4,9,-15,14,-14",w:63},"}":{d:"47,-298v34,-17,118,-18,112,36v6,25,-76,98,-69,103v4,16,39,7,44,28v7,34,-34,17,-37,39v8,29,49,83,23,123v-15,23,-43,26,-73,46v-34,8,-43,11,-49,-17v1,-15,30,-15,33,-20v24,-12,70,-27,55,-61v-14,-33,-37,-68,-19,-103v-46,-50,46,-100,60,-141v-10,-16,-68,6,-77,-12",w:143},"~":{d:"7,-254v2,-6,59,-50,67,-46v11,-1,35,19,46,26v5,0,27,-10,66,-31v21,8,-1,25,-7,38v-27,21,-48,31,-65,31v-24,-11,-37,-39,-65,-9v-7,7,-26,36,-42,11v3,-5,-3,-17,0,-20",w:199},"Ä":{d:"161,-217v20,53,23,124,54,170v-2,20,-34,9,-42,0v-27,-12,-78,-18,-101,-18v-26,6,-29,51,-54,63v-18,-4,-19,-30,-3,-38v5,-9,15,-16,8,-29v1,-12,23,-9,26,-19v6,-10,11,-20,20,-27r70,-121v12,-4,16,4,22,19xm82,-91v17,3,62,7,86,13v-13,-33,-13,-80,-29,-109v-15,30,-38,63,-57,96xm187,-259v0,8,-4,13,-12,13v-18,0,-21,-20,-16,-34v18,-1,28,2,28,21xm90,-284v7,3,28,11,28,18v0,9,-9,18,-18,17v-17,0,-25,-24,-10,-35"},"Å":{d:"161,-217v20,53,23,124,54,170v-2,20,-34,9,-42,0v-27,-12,-78,-18,-101,-18v-26,6,-29,51,-54,63v-18,-4,-19,-30,-3,-38v5,-9,15,-16,8,-29v1,-12,23,-9,26,-19v6,-10,11,-20,20,-27r70,-121v12,-4,16,4,22,19xm82,-91v17,3,62,7,86,13v-13,-33,-13,-80,-29,-109v-15,30,-38,63,-57,96xm112,-239v-31,-17,-9,-61,29,-56v12,2,22,3,33,12v24,39,-30,62,-62,44xm119,-262v2,14,41,8,41,-4v0,-4,-8,-6,-24,-9v-10,-2,-17,10,-17,13"},"Ç":{d:"48,-108v-12,70,90,71,159,67r138,-9v9,-1,7,9,7,17v-37,16,-80,27,-103,21v-14,9,-40,3,-67,9v-30,0,-64,1,-100,-10v-6,-1,-10,-4,-10,-8v-32,-12,-46,-31,-63,-56v-16,-61,47,-103,83,-121v82,-42,118,-45,200,-60v21,-4,36,34,11,37v-90,11,-148,31,-225,77v-12,8,-23,20,-30,36xm172,18v29,4,47,14,53,35v-2,7,-14,31,-27,31v-28,7,-55,9,-84,14v-18,-5,-13,-32,7,-32v21,0,55,-5,69,-13v-16,-14,-63,10,-50,-35v9,-10,1,-27,23,-29v7,8,11,16,9,29",w:331},"É":{d:"49,-160v1,-4,-10,-9,-15,-8v-15,-35,32,-30,57,-31r142,-8v2,1,30,7,40,10v-52,16,-133,17,-190,30v-7,9,-12,24,-15,47v26,10,102,-6,141,3v1,3,1,6,2,10v-36,18,-92,12,-149,21v-11,9,-16,41,-16,51v55,-1,111,-21,168,-13v15,-8,48,1,31,18v-53,16,-130,13,-198,29r-39,-8v-4,-19,17,-53,20,-76v-1,0,-7,-11,-9,-18v18,-7,22,-28,30,-57xm133,-248v27,-11,48,-32,59,-14v3,11,-79,52,-88,53v-14,1,-16,-11,-12,-21v10,-4,23,-11,41,-18",w:252},"Ñ":{d:"224,-182v1,-17,15,-24,22,-38v20,0,13,10,3,33v-3,36,-25,52,-28,94v-10,24,-30,55,-29,82r-19,7v-32,-8,-36,-70,-58,-111v-2,-23,-7,-27,-19,-54v-28,36,-41,93,-71,133v-9,5,-20,-9,-20,-17r73,-149v9,-24,31,-5,36,7v19,41,31,98,53,139v22,-35,34,-69,50,-118v2,-3,3,-3,7,-8xm203,-257v22,-8,41,-24,65,-26v3,11,-8,9,-7,21v-26,20,-46,31,-59,31v-2,3,-49,-27,-49,-29v-11,0,-32,31,-46,32v-11,-2,-12,-21,-4,-23v4,-6,28,-30,48,-34v17,-4,43,28,52,28",w:219},"Ö":{d:"62,-184v78,-31,249,-50,238,74v-6,65,-102,105,-179,115v-77,-7,-152,-71,-101,-149v2,-5,24,-33,42,-40xm279,-120v14,-38,-47,-64,-85,-61v-20,-9,-41,7,-62,0v-11,7,-54,12,-66,24v0,20,-51,35,-38,66v-1,43,50,67,96,67v44,0,162,-55,155,-96xm197,-229v0,8,-4,13,-12,13v-17,0,-19,-19,-16,-34v18,-1,29,1,28,21xm101,-254v7,3,28,9,27,18v1,8,-8,17,-17,17v-18,0,-26,-24,-10,-35",w:273},"Ü":{d:"281,-202v6,67,-30,121,-71,152v-3,14,-47,26,-60,39v-41,20,-110,1,-125,-26v-24,-44,-28,-84,-8,-127v12,-26,23,-38,37,-22v-2,2,-3,5,-3,10v-34,26,-29,116,5,134v22,32,86,-1,109,-8v38,-28,104,-64,97,-149v2,-10,7,-8,19,-3xm197,-227v0,8,-4,13,-12,13v-18,0,-21,-20,-16,-34v18,-1,28,2,28,21xm101,-252v7,3,27,10,27,18v0,8,-9,18,-18,17v-18,-1,-24,-25,-9,-35",w:262},"á":{d:"118,-53v10,4,55,41,62,47v0,7,-5,16,-12,16r-57,-28v-20,3,-40,19,-61,18v-10,2,-43,-17,-42,-36v0,-14,7,-40,27,-41v39,-26,92,-36,104,9v0,6,-2,11,-9,15v-32,-24,-64,-6,-84,11v8,15,58,-17,72,-11xm32,-117v24,-3,85,-55,101,-32v3,11,-80,53,-89,53v-13,2,-14,-10,-12,-21",w:173},"à":{d:"118,-53v10,4,55,41,62,47v0,7,-5,16,-12,16r-57,-28v-20,3,-40,19,-61,18v-10,2,-43,-17,-42,-36v0,-14,7,-40,27,-41v39,-26,92,-36,104,9v0,6,-2,11,-9,15v-32,-24,-64,-6,-84,11v8,15,58,-17,72,-11xm99,-137v7,6,56,14,37,40v-28,-7,-62,-21,-100,-41v-2,-3,-2,-26,5,-23v16,4,42,17,58,24",w:173},"â":{d:"118,-53v10,4,55,41,62,47v0,7,-5,16,-12,16r-57,-28v-20,3,-40,19,-61,18v-10,2,-43,-17,-42,-36v0,-14,7,-40,27,-41v39,-26,92,-36,104,9v0,6,-2,11,-9,15v-32,-24,-64,-6,-84,11v8,15,58,-17,72,-11xm147,-97v-27,-6,-39,-26,-60,-37v-21,7,-38,46,-65,23v-2,-5,-3,-10,-4,-14v18,-4,43,-31,61,-42v28,5,40,21,62,36v12,8,18,17,18,25v0,6,-4,9,-12,9",w:173},"ä":{d:"118,-53v10,4,55,41,62,47v0,7,-5,16,-12,16r-57,-28v-20,3,-40,19,-61,18v-32,5,-66,-64,-15,-77v39,-26,92,-36,104,9v0,6,-3,11,-9,15v-32,-24,-64,-6,-84,11v8,15,58,-17,72,-11xm142,-119v0,8,-4,13,-12,13v-18,0,-21,-20,-16,-34v18,-1,28,2,28,21xm46,-144v7,3,28,9,27,18v1,8,-9,18,-18,17v-18,-1,-25,-25,-9,-35",w:173},"ã":{d:"118,-53v10,4,55,41,62,47v0,7,-5,16,-12,16r-57,-28v-20,3,-40,19,-61,18v-10,2,-43,-17,-42,-36v0,-14,7,-40,27,-41v39,-26,92,-36,104,9v0,6,-2,11,-9,15v-32,-24,-64,-6,-84,11v8,15,58,-17,72,-11xm114,-136v22,-8,41,-24,64,-26v3,11,-7,10,-7,21v-26,20,-45,30,-58,30v-3,3,-49,-26,-49,-28v-10,-1,-32,35,-51,31v-12,-32,8,-29,32,-51v24,-21,54,20,69,23",w:173},"å":{d:"118,-53v10,4,55,41,62,47v0,7,-5,16,-12,16r-57,-28v-20,3,-40,19,-61,18v-10,2,-43,-17,-42,-36v0,-14,7,-40,27,-41v39,-26,92,-36,104,9v0,6,-2,11,-9,15v-32,-24,-64,-6,-84,11v8,15,58,-17,72,-11xm54,-101v-37,-20,-9,-71,34,-65v13,1,25,3,38,13v27,45,-34,73,-72,52xm61,-128v4,20,48,7,49,-5v0,-5,-9,-7,-28,-10v-12,-2,-21,11,-21,15",w:173},"ç":{d:"108,-118v30,-6,56,21,25,33v-24,-6,-39,5,-75,23v-7,4,-12,12,-15,22v31,28,86,3,128,9v3,28,-29,16,-44,28v-53,15,-106,10,-120,-37v0,-48,62,-70,101,-78xm92,18v23,4,45,12,48,32v-2,6,-12,28,-25,28v-24,6,-50,10,-77,13v-16,-4,-11,-28,7,-29v17,-1,51,-4,63,-12v-14,-15,-57,10,-46,-32v9,-8,0,-25,21,-26v6,6,12,14,9,26",w:171},"é":{d:"108,-124v42,-3,70,39,50,73v-22,-1,-70,12,-94,10v-1,1,-2,3,-2,3v0,3,12,7,35,14v18,0,64,7,30,21v-10,14,-31,6,-53,6v-26,-7,-70,-26,-70,-58v0,-54,48,-65,104,-69xm130,-78v-2,-35,-66,-13,-77,3v16,6,62,6,77,-3xm76,-169v26,-11,48,-32,59,-14v3,10,-80,53,-89,53v-14,1,-14,-10,-12,-21v15,-7,16,-7,42,-18",w:161},"è":{d:"108,-124v42,-3,70,39,50,73v-22,-1,-70,12,-94,10v-1,1,-2,3,-2,3v0,3,12,7,35,14v18,0,64,7,30,21v-10,14,-31,6,-53,6v-26,-7,-70,-26,-70,-58v0,-54,48,-65,104,-69xm130,-78v-2,-35,-66,-13,-77,3v16,6,62,6,77,-3xm95,-166v7,6,54,14,37,40v-28,-7,-62,-21,-100,-41v-3,-3,-3,-26,5,-24v16,5,42,18,58,25",w:161},"ê":{d:"108,-124v42,-3,70,39,50,73v-22,-1,-70,12,-94,10v-1,1,-2,3,-2,3v0,3,12,7,35,14v18,0,64,7,30,21v-10,14,-31,6,-53,6v-26,-7,-70,-26,-70,-58v0,-54,48,-65,104,-69xm130,-78v-2,-35,-66,-13,-77,3v16,6,62,6,77,-3xm145,-129v-27,-6,-39,-26,-60,-37v-8,0,-10,4,-14,10v-11,15,-51,34,-56,0v17,-4,44,-32,61,-43v28,5,41,21,63,36v12,8,17,17,17,25v0,6,-3,9,-11,9",w:161},"ë":{d:"108,-124v42,-3,70,39,50,73v-22,-1,-70,12,-94,10r-3,3v0,3,12,7,36,14v18,0,64,7,30,21v-10,14,-31,6,-53,6v-26,-7,-67,-27,-71,-58v7,-52,48,-65,105,-69xm130,-78v-2,-35,-66,-13,-77,3v16,6,62,6,77,-3xm140,-144v0,8,-4,12,-12,12v-18,0,-19,-19,-16,-33v18,-1,29,1,28,21xm44,-169v7,3,28,9,28,17v0,9,-9,18,-18,18v-18,0,-25,-24,-10,-35",w:161},"í":{d:"59,-98v20,4,15,53,10,95v-6,1,-11,2,-19,-4v1,-7,-12,-18,-10,-24v4,-22,-4,-65,19,-67xm50,-139v27,-11,49,-32,59,-14v3,11,-80,53,-89,53v-14,1,-14,-12,-11,-22v15,-7,14,-6,41,-17",w:105},"ì":{d:"57,-98v22,5,13,50,11,95v-7,1,-11,2,-20,-4v1,-7,-12,-18,-10,-24v4,-22,-2,-64,19,-67xm70,-139v14,10,54,14,37,41v-28,-7,-61,-22,-99,-42v-3,-2,-3,-25,5,-23v15,5,41,17,57,24",w:109},"î":{d:"72,-98v20,5,12,51,10,95v-6,2,-13,1,-20,-4v1,-8,-12,-18,-10,-24v4,-22,-3,-65,20,-67xm134,-94v-26,-7,-39,-25,-60,-37v-7,0,-9,4,-13,10v-14,15,-51,34,-56,-1v18,-4,45,-33,61,-43v27,6,40,22,62,37v12,8,18,17,18,25v0,6,-4,9,-12,9",w:143},"ï":{d:"55,-97v19,5,15,53,10,95v-17,5,-26,-14,-30,-28v6,-20,-3,-65,20,-67xm110,-118v0,8,-4,13,-12,13v-17,0,-19,-19,-16,-34v18,-1,29,1,28,21xm14,-143v6,3,28,8,28,17v0,9,-9,18,-18,18v-18,0,-25,-24,-10,-35",w:107},"ñ":{d:"115,-129v34,6,59,50,59,105v0,31,-15,24,-30,17v-15,-29,-5,-42,-20,-81v-35,-13,-68,52,-88,61v-20,-4,-38,-36,-19,-59v0,-12,3,-14,10,-28v11,-8,18,11,27,12xm117,-166v22,-7,41,-23,64,-26v3,11,-7,10,-7,21v-26,20,-45,30,-58,30v-3,3,-49,-26,-49,-28v-10,-1,-32,35,-51,31v-5,-12,-8,-16,0,-23v4,-6,28,-29,48,-33v17,-3,43,28,53,28",w:171},"ó":{d:"102,-132v50,-20,99,16,99,60v0,54,-60,64,-108,79v-50,-2,-110,-48,-76,-100v22,-17,49,-33,85,-39xm136,-104v-34,0,-91,27,-94,47v16,51,125,16,125,-22v0,-17,-10,-25,-31,-25xm49,-154v24,-3,85,-55,101,-32v3,11,-80,53,-89,53v-14,0,-13,-8,-12,-21",w:191},"ò":{d:"102,-132v50,-20,99,16,99,60v0,54,-60,64,-108,79v-50,-2,-110,-48,-76,-100v22,-17,49,-33,85,-39xm136,-104v-34,0,-91,27,-94,47v16,51,125,16,125,-22v0,-17,-10,-25,-31,-25xm115,-181v14,10,51,13,37,40v-28,-7,-62,-21,-100,-41v-3,-2,-3,-26,5,-23v16,5,42,17,58,24",w:191},"ô":{d:"102,-132v50,-20,99,16,99,60v0,54,-60,64,-108,79v-50,-2,-110,-48,-76,-100v22,-17,49,-33,85,-39xm136,-104v-34,0,-91,27,-94,47v16,51,125,16,125,-22v0,-17,-10,-25,-31,-25xm110,-177v-22,6,-38,45,-65,22v-2,-4,-3,-9,-4,-13v18,-4,43,-32,61,-43v27,6,40,21,62,36v12,9,18,17,18,25v1,11,-15,10,-23,7",w:191},"ö":{d:"102,-132v50,-20,99,16,99,60v0,54,-60,64,-108,79v-50,-2,-110,-48,-76,-100v22,-17,49,-33,85,-39xm136,-104v-34,0,-91,27,-94,47v16,51,125,16,125,-22v0,-17,-10,-25,-31,-25xm161,-160v0,8,-4,13,-12,13v-17,0,-19,-19,-16,-34v18,-1,29,1,28,21xm65,-185v7,3,28,9,28,18v0,7,-9,18,-18,17v-18,1,-25,-24,-10,-35",w:191},"õ":{d:"102,-132v50,-20,99,16,99,60v0,54,-60,64,-108,79v-50,-2,-110,-48,-76,-100v22,-17,49,-33,85,-39xm136,-104v-34,0,-91,27,-94,47v16,51,125,16,125,-22v0,-17,-10,-25,-31,-25xm58,-199v26,-21,54,18,69,22v4,0,15,-5,34,-13v22,-9,21,-16,31,-13v3,11,-9,9,-7,22v-26,20,-46,30,-59,30v-2,4,-49,-28,-49,-29v-11,0,-32,31,-46,32v-12,-3,-13,-21,-4,-23v4,-6,14,-15,31,-28",w:191},"ú":{d:"196,-129v-1,-4,12,-13,15,-13v6,0,8,7,8,21v0,24,-7,25,-13,45v-7,7,-14,21,-24,29v-9,24,-61,45,-89,45v-63,0,-105,-72,-67,-126v24,-3,19,27,18,46v-1,26,23,42,54,40v38,-3,88,-51,98,-87xm106,-174v26,-11,48,-32,59,-14v3,11,-81,53,-89,54v-13,1,-15,-12,-11,-22v15,-7,14,-7,41,-18",w:213},"ù":{d:"196,-129v-1,-4,12,-13,15,-13v6,0,8,7,8,21v0,24,-7,25,-13,45v-7,7,-14,21,-24,29v-9,24,-61,45,-89,45v-63,0,-105,-72,-67,-126v24,-3,19,27,18,46v-1,26,23,42,54,40v38,-3,88,-51,98,-87xm126,-166v7,6,56,14,37,40v-28,-7,-62,-22,-100,-42v-2,-3,-2,-26,5,-23v16,4,42,18,58,25",w:213},"û":{d:"196,-129v-1,-4,12,-13,15,-13v6,0,8,7,8,21v0,24,-7,25,-13,45v-7,7,-14,21,-24,29v-9,24,-61,45,-89,45v-63,0,-105,-72,-67,-126v24,-3,19,27,18,46v-1,26,23,42,54,40v38,-3,88,-51,98,-87xm172,-143v-27,-6,-39,-26,-60,-37v-8,0,-10,4,-14,10v-11,15,-49,35,-56,0v17,-4,44,-32,61,-43v27,6,41,21,63,36v12,9,17,17,17,25v0,6,-3,9,-11,9",w:213},"ü":{d:"196,-129v-1,-4,12,-13,15,-13v6,0,8,7,8,21v0,24,-7,25,-13,45v-7,7,-14,21,-24,29v-9,24,-61,45,-89,45v-63,0,-105,-72,-67,-126v24,-3,19,27,18,46v-1,26,23,42,54,40v38,-3,88,-51,98,-87xm168,-161v0,8,-3,13,-11,13v-17,0,-20,-19,-17,-34v18,-1,29,1,28,21xm72,-186v7,3,29,9,28,18v0,7,-9,18,-18,17v-18,1,-25,-24,-10,-35",w:213},"†":{d:"22,-286v15,6,5,-20,19,-19v9,-3,15,21,17,22v6,1,12,3,20,6v3,10,5,16,-9,16v-34,-10,-6,51,-34,52v-20,-7,11,-47,-15,-49v-14,3,-25,-5,-17,-24v7,-2,14,-4,19,-4",w:77},"°":{d:"106,-268v0,36,-35,38,-51,46v-48,5,-60,-58,-25,-78v33,-11,76,-9,76,32xm38,-257v16,7,39,2,38,-17v-13,-9,-28,-1,-32,11v-5,3,-7,0,-6,6",w:114},"¢":{d:"105,-188v13,-12,14,-18,26,-15v7,23,7,15,-3,49v6,0,18,14,17,20v-3,5,-12,19,-26,13v-14,1,-14,5,-16,21v10,10,46,-13,38,18v-9,17,-23,16,-54,20v-17,16,-4,55,-29,60v-37,-10,19,-64,-24,-71v-20,-10,-37,-47,-6,-62v23,-20,73,-4,77,-53xm65,-101v4,-9,7,-8,3,-13v-14,4,-22,10,-3,13",w:154},"£":{d:"153,-170v3,22,62,0,49,39v-18,6,-31,12,-58,9v-12,-1,-17,30,-23,39v19,26,50,56,91,35v9,-2,27,-13,27,4v0,27,-27,39,-58,42v-32,-5,-59,-19,-78,-39v-6,1,-35,44,-57,39v-25,0,-37,-15,-37,-46v0,-41,43,-53,73,-50v4,1,12,-18,12,-21v-7,-15,-49,0,-44,-30v-2,-31,31,-16,60,-19v16,-30,25,-119,93,-113v16,2,75,16,50,44v-4,5,-7,7,-12,8v-18,-12,-32,-18,-41,-18v-35,-1,-38,52,-47,77xm43,-45v4,5,12,-2,11,-9v-1,2,-12,1,-11,9",w:242},"§":{d:"141,-115v12,10,29,36,28,56v-4,68,-129,69,-152,16v-1,-12,-10,-22,8,-23v17,3,47,21,67,23v16,1,40,-8,38,-21v-8,-49,-119,-30,-117,-85v1,-28,15,-45,-3,-64v-1,-53,55,-61,103,-62v15,-5,6,-5,20,-2v16,17,23,27,23,30v-1,26,-29,7,-45,7v-21,0,-51,2,-62,17v19,14,87,8,97,43v18,14,16,57,-5,65xm64,-147r57,17v10,-28,-22,-43,-47,-44v-25,-1,-35,19,-10,27",w:174},"•":{d:"130,-114v0,47,-124,54,-120,-8r6,-31v44,-28,64,-34,104,0v8,6,10,20,10,39",w:139},"¶":{d:"121,-237v21,-9,44,-13,63,-1v-1,7,5,6,7,11r-4,190v-2,33,4,39,-15,40v-16,1,-10,-20,-10,-33r4,-161v0,-17,-1,-34,-16,-25v2,10,1,23,1,35v-9,46,-6,75,-15,156v-3,4,-7,5,-12,5v-17,-10,-3,-89,-10,-115v-43,14,-98,10,-101,-29v-4,-53,59,-63,104,-75v3,1,4,2,4,2xm95,-204v2,9,-30,50,1,50v35,0,23,-13,29,-43v0,-1,-2,-7,-4,-15v-12,-1,-14,2,-26,8",w:206},"ß":{d:"33,10v-29,4,-28,-32,-16,-70v18,-58,17,-137,56,-176v12,-24,46,-58,82,-43v20,8,47,24,47,54v0,30,-62,59,-67,90v33,23,56,33,63,63v-18,21,-22,36,-48,54v-24,17,-27,41,-53,16v-2,-19,7,-35,24,-42v15,-13,26,-22,34,-40v-13,-17,-78,-29,-56,-70v-3,-27,64,-54,66,-86v-8,-25,-41,-4,-52,8v-29,30,-47,83,-51,141v-17,25,-8,71,-29,101"},"®":{d:"75,-194v78,-29,116,9,130,84v-2,42,-22,47,-57,67v-74,20,-161,-19,-129,-110v6,-18,29,-34,57,-40xm46,-86v51,36,84,21,129,-15v7,-15,0,-39,-10,-49v-13,-37,-49,-26,-86,-18v-28,7,-49,46,-33,82xm72,-123v-5,-43,68,-57,75,-14v-17,26,-18,17,3,32v2,25,-25,18,-45,7r-4,-4v-1,8,-3,20,-12,24v-10,-3,-21,-34,-17,-45xm112,-135v-10,-1,-20,13,-9,14v6,-6,9,-11,9,-14",w:217},"©":{d:"102,-29v-74,5,-124,-84,-70,-140v22,-22,53,-35,97,-38v46,-4,88,49,74,100v0,44,-51,75,-101,78xm96,-66v42,-3,75,-23,75,-69v0,-23,-4,-38,-44,-38v-16,0,-33,6,-49,20v36,-4,55,-12,62,20v-5,16,-49,1,-50,21v10,15,53,-14,54,11v0,18,-14,27,-42,27v-22,1,-46,-11,-46,-31v0,-25,7,-39,20,-44v-1,-1,-2,-2,-3,-2v-51,22,-32,89,23,85",w:217},"™":{d:"213,-307v28,9,11,49,7,75v-1,4,-4,6,-11,6v-7,1,-11,-14,-11,-34v-14,-6,-34,34,-46,28v-2,0,-10,-9,-24,-27v-10,7,-3,36,-27,31v-15,-24,-3,-27,1,-48v-6,-7,-27,-1,-31,3v-3,14,-7,30,-11,51v-5,10,-29,9,-24,-12v-5,-8,1,-18,3,-35v-13,6,-33,2,-29,-18v20,-17,64,-17,100,-19v28,-1,29,30,45,39v11,-6,35,-32,58,-40",w:239},"´":{d:"52,-284v29,-11,50,-34,62,-14v3,12,-86,54,-94,56v-14,0,-16,-12,-12,-23v11,-5,25,-11,44,-19",w:120},"¨":{d:"124,-259v0,9,-4,13,-12,13v-18,0,-22,-21,-17,-35v19,-1,30,1,29,22xm23,-285v7,2,30,9,29,18v1,10,-9,19,-18,19v-19,0,-28,-26,-11,-37",w:136},"≠":{d:"48,-130v29,11,49,-57,60,-50v25,6,7,27,-1,46v22,5,29,7,21,22v-18,2,-48,-1,-50,15v9,8,53,-7,54,10v-4,22,-46,20,-72,24v-7,13,-18,32,-34,57v-8,6,-15,-3,-13,-14v-1,-9,15,-39,14,-45v-30,5,-24,-17,-13,-25v12,-1,36,4,29,-13v-14,0,-47,6,-36,-12v0,-18,27,-13,41,-15",w:140},"Æ":{d:"335,-259v0,30,-102,12,-122,34v10,21,2,79,16,100v24,-6,59,-13,86,-16v23,-2,32,21,13,26r-103,29v-3,22,-4,38,8,43v28,-5,60,-6,86,-14v5,-1,14,7,14,11v6,16,-90,40,-107,40v-29,0,-39,-19,-32,-46v-2,-4,0,-26,-9,-28v-29,2,-58,6,-88,6v-31,0,-40,74,-82,73v-18,-23,4,-37,12,-50v40,-65,112,-126,165,-207v20,-17,69,-11,112,-13v21,0,31,4,31,12xm123,-111v28,1,44,-2,67,-10v-4,-22,5,-49,-7,-65v-3,6,-65,61,-60,75",w:348},"Ø":{d:"76,-211v41,-13,100,-22,140,-3v26,-19,40,-29,44,-29v10,0,15,7,15,20v0,15,-23,23,-30,35v23,39,29,114,-21,139v-36,19,-102,35,-147,18v-14,-5,-29,29,-46,35v-25,-13,-19,-24,3,-56v-9,-17,-28,-27,-28,-60v0,-38,23,-72,70,-99xm107,-66v55,15,125,-12,123,-70v0,-16,-5,-25,-13,-29r-110,95r0,4xm39,-108v-1,3,17,31,22,27v8,-6,109,-90,123,-106v-15,-11,-43,1,-63,2v-33,10,-80,35,-82,77",w:270},"∞":{d:"322,-72v-4,22,-54,41,-76,41v-43,0,-83,-17,-114,-35v-46,19,-125,53,-128,-18v-1,-14,10,-22,13,-35v29,-10,62,-31,97,-4v37,28,47,5,75,-8v40,-19,73,-10,114,1v13,1,18,55,19,58xm228,-69v15,0,62,-12,61,-25v-19,-23,-89,-10,-105,11v0,2,1,4,2,4v28,6,42,10,42,10xm75,-102v-13,2,-41,4,-44,19v0,4,3,7,10,7v21,0,40,-6,54,-17v-9,-6,-16,-9,-20,-9",w:330},"±":{d:"93,-163v-7,46,76,-4,46,47v-14,6,-27,13,-38,8v-24,2,-14,28,-28,44r-14,0v-7,-12,-5,-15,-7,-33v-12,-7,-41,-1,-37,-24v2,-11,23,-17,36,-14r28,-38v4,0,9,4,14,10xm113,-27v-12,18,-58,27,-85,24v-16,2,-22,-23,-13,-36v28,-7,85,-11,98,12",w:151},"≤":{d:"73,-109v10,15,87,16,87,42v0,11,-5,16,-13,16v-36,-11,-69,-24,-109,-31v-18,-8,-18,-13,-9,-36v59,-56,93,-83,101,-83v16,0,18,17,14,28v-27,24,-42,35,-71,64xm10,-29v35,-12,117,-26,148,-3v1,2,-5,19,-8,18r-124,15v-16,2,-26,-18,-16,-30",w:168},"≥":{d:"115,-174v20,7,53,36,20,57v-19,11,-91,68,-82,59v-18,3,-25,-22,-13,-31v15,-10,14,-10,70,-51r-50,-37v-5,-4,-5,-27,4,-28v16,7,40,17,51,31xm14,-32v33,-10,86,-14,127,-10v12,12,5,23,-11,27v-49,9,-82,13,-99,13v-22,0,-24,-16,-17,-30",w:163},"¥":{d:"31,-248v30,-3,64,64,74,59v37,-22,77,-65,107,-82v20,-11,34,18,21,32v-28,19,-52,38,-70,57v-18,8,-40,21,-35,60v2,19,39,7,64,7v25,0,16,21,2,27v-36,16,-46,8,-68,18v6,11,101,-20,66,24v-21,11,-42,12,-75,20v-2,1,-5,6,-10,18v-8,3,-11,10,-24,8v-7,-17,-2,-18,-9,-26v-13,5,-39,3,-53,-2v-10,-17,-7,-27,0,-34v23,-1,45,1,64,-5v-11,-7,-28,-4,-64,-6v-13,-8,-15,-24,-6,-35v33,-2,102,9,76,-37v-14,-14,-33,-38,-60,-66v-10,-10,-8,-28,0,-37",w:219},"µ":{d:"123,-114v41,0,54,-9,127,-17v12,-2,20,-6,25,-12v5,-78,43,-127,119,-138v38,-5,46,23,55,48v-5,5,2,4,2,12v-2,47,-72,81,-129,95v-17,4,-12,32,-2,39v30,-5,24,0,99,4v14,9,14,20,-1,23v-17,3,-71,-1,-85,13v1,19,18,35,-3,47v-1,-6,-10,-7,-16,-5v-3,-3,-20,-37,-29,-41v-15,8,-50,22,-49,-9v1,-19,2,-27,28,-26v24,1,13,-12,8,-30v-22,1,-64,16,-111,23v-50,7,-17,47,-17,57v0,10,-5,15,-13,15v-20,-9,-27,-30,-33,-55v-20,-17,-52,8,-85,-6v-2,-10,-13,-26,4,-29v32,-6,41,-1,65,-7v-17,-74,-4,-173,69,-180v55,-20,130,8,131,65v-11,9,-10,2,-29,-11v-33,-23,-37,-26,-76,-25v-41,13,-69,38,-67,100v0,34,4,50,13,50xm317,-152v29,-6,106,-43,106,-71v0,-23,-24,-25,-42,-17v-31,1,-74,48,-64,88",w:462},"∂":{d:"456,-113v55,-37,119,-8,176,5v-19,37,-104,-5,-144,18v-5,64,-45,87,-130,87v-43,0,-70,-8,-96,-21v-54,15,-146,29,-209,10v-18,-11,-43,-26,-46,-53v-1,-9,28,-48,51,-46v55,-10,55,-8,101,-8v29,0,17,-26,23,-56v4,-19,4,-74,34,-49v4,42,-7,83,-10,124v0,4,-11,10,-34,17v-29,-1,-45,-4,-74,1v-10,2,-57,3,-52,18v30,43,132,30,190,18v2,-10,-7,-19,-5,-28v5,-36,31,-59,74,-56v27,2,71,4,70,35v-1,30,-37,41,-58,57v35,13,131,15,135,-23v2,-19,-5,-36,4,-50xm262,-85v0,3,13,28,19,25v7,0,48,-13,61,-29v-10,-17,-71,-17,-80,4",w:640},"∑":{d:"235,-95v-3,-59,120,-41,160,-28v3,-2,15,-3,14,4v1,3,-16,19,-21,18r-97,4v-25,5,-18,18,-23,56v-16,14,-25,24,-36,18v-83,32,-154,29,-212,-17v-45,-68,41,-114,107,-119v50,-4,59,66,22,85v-16,8,-61,10,-79,15v36,27,185,24,165,-36xm128,-119v-23,-3,-43,4,-53,15v13,5,46,-4,53,-15",w:414},"∏":{d:"243,-190v7,-18,27,-19,38,6v0,2,-5,8,-14,16v-8,-9,-27,-4,-24,-22xm221,-111v55,-7,60,22,45,64v5,23,17,47,-22,47v-35,0,-18,-40,-15,-70v-2,-19,-35,-13,-52,-18v-2,0,-13,1,-34,3v-4,0,-10,11,-13,31v-3,20,1,43,-11,54v-12,-4,-13,-5,-21,-3v-13,-13,-3,-25,-12,-41v7,-6,12,-22,10,-39v-23,-8,-79,15,-87,-21v12,-28,78,-4,101,-20r36,-96v8,-19,17,-28,27,-28v10,0,15,6,15,18v-6,32,-31,62,-38,109v25,10,47,-1,71,10",w:282},"π":{d:"247,-240v-3,5,-14,12,-21,6v-41,5,-71,-4,-85,37v-6,7,-21,42,-25,61v28,12,104,-16,129,24v8,11,12,24,12,38v-7,17,-2,99,-40,68v-9,-23,-5,-47,-1,-73v3,-24,-40,-24,-50,-19v-4,0,-18,2,-44,6v-30,-6,-16,49,-33,58v-19,-11,-14,2,-29,-10v8,-71,20,-114,43,-170v-24,-2,-49,4,-73,7v-30,3,-32,-33,-7,-36r184,-22v17,-1,40,13,40,25",w:265},"∫":{d:"62,-151v-7,-70,20,-130,63,-150v28,1,39,10,70,23v20,8,6,33,-6,35v-29,-13,-45,-20,-49,-20v-20,-4,-45,51,-43,70v8,60,5,129,5,189v0,62,-27,93,-79,93v-37,-1,-71,-14,-63,-57v21,0,79,34,91,-2v16,-3,14,-64,21,-85v-2,-31,-1,-74,-10,-96",w:156},"ª":{d:"6,-265v1,-31,58,-53,80,-22v-11,14,25,28,25,36v-2,8,-15,12,-27,10v-22,-29,-68,19,-78,-24xm52,-281v-8,1,-24,10,-9,13v11,1,24,-10,9,-13",w:117},"º":{d:"13,-273v1,-31,56,-41,83,-18v36,8,14,48,-9,52v-35,6,-64,-5,-74,-34xm81,-269v-7,-7,-20,-11,-29,-6v5,13,13,11,29,6",w:128},"Ω":{d:"121,-111v9,16,43,-5,54,5v28,-4,62,8,81,-5v48,-33,166,-28,160,44v15,34,-51,53,-88,53v-34,0,-53,-21,-71,-37v-15,7,-32,-4,-28,-22v-26,-4,-93,-6,-108,8v8,17,5,37,12,54v-1,15,-18,15,-31,10v-9,-15,-20,-39,-19,-63v-20,-9,-73,15,-79,-18v4,-28,50,-11,77,-24v12,-99,36,-168,137,-178v35,5,64,20,67,57v0,13,-14,18,-20,5v-15,-35,-83,-31,-104,4v-26,20,-39,82,-40,107xm334,-45v15,2,51,-14,53,-22v-7,-20,-36,-31,-69,-29v-8,-1,-39,6,-37,14v-3,10,44,38,53,37",w:424},"æ":{d:"145,-44r33,7v2,42,-59,29,-85,16v-6,7,-35,24,-48,15v-19,2,-35,-21,-33,-37v2,-24,5,-19,28,-36v-6,-8,-45,3,-33,-21v21,-22,58,-12,85,-1v6,-5,35,-28,45,-15v20,-4,36,17,36,35v0,23,-4,21,-28,37xm111,-72v12,3,49,-16,19,-17v-5,0,-20,12,-19,17xm74,-50v-14,-4,-48,16,-19,17v4,1,19,-14,19,-17",w:184},"ø":{d:"76,-136v17,7,33,-8,51,0v9,-6,21,-13,36,-21v23,22,-13,31,3,50v11,13,4,21,14,35v-4,5,-1,14,-4,23v-14,23,-45,41,-84,39v-12,2,-29,28,-41,38v-2,-11,-34,-10,-15,-30v3,-7,5,-11,5,-11v-15,-24,-60,-54,-22,-89v23,-21,25,-32,57,-34xm102,-54v18,1,50,-19,30,-32v-12,7,-22,18,-30,32xm85,-92v-14,3,-26,8,-38,17v2,20,17,13,26,0v6,-8,12,-13,12,-17",w:188},"¿":{d:"181,-247v3,1,31,2,29,15v-4,22,-37,27,-41,4v1,-5,7,-20,12,-19xm161,-34v-45,-1,-105,19,-124,51v0,11,18,17,54,17v39,0,82,-13,112,4v-10,35,-58,31,-100,31v-47,0,-80,-10,-99,-31v-10,-56,22,-73,64,-90v8,-3,32,-9,74,-18v21,-15,7,-62,22,-92v-1,-5,-1,-11,4,-12v16,0,24,7,24,22v-8,30,-8,73,-17,111v-3,5,-7,7,-14,7",w:213},"¡":{d:"86,-197v8,16,-7,41,-24,25v-11,-11,-4,-16,-3,-29v13,0,15,-2,27,4xm46,-107v4,-8,11,-16,23,-7v19,26,-5,57,-6,87v-7,0,-5,18,-9,28v0,14,-17,52,-11,70v-2,7,-15,28,-25,12v-4,-6,-15,-7,-6,-16v2,-39,14,-96,34,-174",w:95},"¬":{d:"141,-99v47,7,103,-3,149,6v14,24,18,15,10,39v-10,34,-7,31,-26,76v-4,6,-15,8,-16,21v-4,2,-4,1,-13,5v-22,-33,-4,-33,16,-104v-5,-9,-28,-4,-38,-6r-183,4v-14,0,-41,-29,-17,-36v31,-9,82,5,118,-5",w:315},"√":{d:"364,-218v43,-21,80,-51,104,-32v-3,19,-24,21,-44,40v-41,15,-78,53,-136,78r-137,98v-20,16,-79,66,-91,68v-3,1,-25,-11,-24,-13v-4,-28,-43,-61,-30,-85v26,-15,42,19,58,32r295,-188v0,1,2,2,5,2",w:474},"ƒ":{d:"115,-262v-23,6,-39,63,-38,96v1,3,57,2,54,16v1,22,-45,15,-51,30v3,34,12,68,10,103v14,17,-18,53,-28,63v-48,8,-89,5,-95,-37v20,-5,77,21,83,-18v17,-29,-4,-61,0,-98v0,-5,-3,-10,-7,-17v-33,4,-43,-17,-25,-37v10,-4,27,5,27,-10v0,-43,15,-77,32,-109v12,-7,16,-22,38,-20v11,1,51,35,25,55v-9,1,-16,-17,-25,-17",w:145},"≈":{d:"133,-112v21,15,48,-30,78,-17v3,3,5,7,5,9v-8,30,-47,45,-76,45v-19,0,-64,-48,-90,-21r-29,20v-6,-1,-17,-16,-15,-32v24,-17,70,-42,107,-21v4,4,10,9,20,17xm138,-57v28,2,48,-25,76,-26v13,30,-21,42,-40,53v-41,24,-77,-15,-114,-23v-15,14,-46,32,-49,-1v-3,-9,27,-28,54,-30",w:223},"∆":{d:"18,-1v-24,-30,8,-48,25,-71v14,-19,34,-28,40,-56v20,-35,29,-14,57,4v9,39,43,62,57,102v0,16,-34,17,-50,14v-28,2,-72,4,-129,7xm139,-47r-22,-52v-12,-5,-12,15,-24,27v-7,6,-14,16,-23,28v23,1,36,-1,69,-3",w:199},"«":{d:"191,-64v16,6,87,37,53,63v-39,-9,-71,-28,-107,-40v-14,-13,-13,-34,10,-47v27,-15,48,-55,84,-62v9,-2,21,10,21,18r-13,21v-16,5,-44,22,-51,41v0,4,1,6,3,6xm71,-65v17,6,87,35,55,62v-39,-8,-66,-27,-108,-40v-14,-13,-13,-36,10,-46v23,-18,50,-56,84,-63v9,-2,21,10,21,18r-13,22v-20,6,-32,17,-51,37v0,3,-1,11,2,10",w:265},"»":{d:"120,-129v9,-33,48,-10,64,5v9,20,86,52,50,86v-36,11,-66,31,-107,40v-6,-7,-9,-13,-9,-17v-2,-13,50,-46,63,-46v11,-18,-33,-42,-48,-47xm1,-128v10,-33,46,-8,64,6v8,19,86,50,51,85v-40,13,-69,30,-108,40v-6,-7,-8,-12,-8,-16v-2,-14,50,-46,63,-47v7,-13,-9,-20,-19,-30v-10,-9,-20,-15,-30,-17",w:252},"…":{d:"244,-24v-1,21,-38,32,-41,3v-2,-19,23,-22,34,-17v0,7,0,15,7,14xm113,-24v0,-22,28,-21,38,-8v5,34,-39,40,-38,8xm35,-2v-10,-2,-36,-17,-18,-29v-1,-15,17,-17,31,-6v7,17,6,33,-13,35",w:258}," ":{w:179},"À":{d:"161,-217v20,53,23,124,54,170v-2,20,-34,9,-42,0v-27,-12,-78,-18,-101,-18v-26,6,-29,51,-54,63v-18,-4,-19,-30,-3,-38v5,-9,15,-16,8,-29v1,-12,23,-9,26,-19v6,-10,11,-20,20,-27r70,-121v12,-4,16,4,22,19xm82,-91v17,3,62,7,86,13v-13,-33,-13,-80,-29,-109v-15,30,-38,63,-57,96xm150,-268v14,10,54,14,37,41v-28,-7,-62,-22,-100,-42v-2,-3,-2,-26,5,-23v16,4,42,17,58,24"},"Ã":{d:"161,-217v20,53,23,124,54,170v-2,20,-34,9,-42,0v-27,-12,-78,-18,-101,-18v-26,6,-29,51,-54,63v-18,-4,-19,-30,-3,-38v5,-9,15,-16,8,-29v1,-12,23,-9,26,-19v6,-10,11,-20,20,-27r70,-121v12,-4,16,4,22,19xm82,-91v17,3,62,7,86,13v-13,-33,-13,-80,-29,-109v-15,30,-38,63,-57,96xm100,-285v26,-19,54,19,69,22v4,0,15,-5,34,-13v23,-9,22,-17,31,-12v3,11,-9,9,-7,21v-26,20,-46,30,-59,30v-3,3,-50,-26,-49,-29v-12,1,-31,35,-51,32v-3,-8,-5,-14,-5,-18v10,-9,16,-17,37,-33"},"Õ":{d:"62,-184v78,-31,249,-50,238,74v-6,65,-102,105,-179,115v-77,-7,-152,-71,-101,-149v2,-5,24,-33,42,-40xm279,-120v14,-38,-47,-64,-85,-61v-20,-9,-41,7,-62,0v-11,7,-54,12,-66,24v0,20,-51,35,-38,66v-1,43,50,67,96,67v44,0,162,-55,155,-96xm116,-270v26,-19,54,19,69,22v4,0,15,-5,34,-13v23,-10,22,-16,31,-12v3,11,-8,9,-7,21v-45,28,-47,42,-88,16v-29,-19,-12,-20,-43,2v-8,5,-12,18,-23,15v-13,-3,-12,-20,-4,-23v4,-6,14,-15,31,-28",w:273},"Œ":{d:"247,-243v71,4,161,-7,245,-8v17,0,27,6,27,17v-8,27,-70,14,-104,23v-3,1,-52,0,-65,7r0,4v16,16,17,29,17,65v32,10,74,-14,99,16v-14,25,-76,17,-127,24v-17,18,-55,32,-75,51v85,0,128,-3,204,-11v15,-2,21,11,20,29v-78,24,-177,12,-270,24v-24,3,-24,-29,-48,-15v-46,7,-70,4,-105,-4v-19,-18,-42,-22,-52,-55v-10,-34,0,-47,12,-78v-18,-59,48,-78,105,-84v17,-18,103,-13,117,-5xm125,-45v76,-9,186,-43,209,-105v-26,-67,-137,-83,-217,-54v3,34,-45,25,-60,58v-41,48,5,108,68,101",w:492},"œ":{d:"185,-54v25,28,107,-17,104,33v-12,12,-60,14,-87,14v0,0,1,1,2,1v-11,1,-39,-9,-50,-17v-28,17,-75,32,-114,7v-22,-14,-34,-11,-34,-41v0,-36,33,-49,48,-75v29,-16,72,-3,95,11v12,-9,48,-27,59,-26v30,0,64,15,65,40v0,7,-6,20,-20,37v-29,1,-44,11,-68,16xm226,-106v-21,-7,-41,-2,-48,13v14,1,42,-7,48,-13xm132,-87v-21,-35,-94,11,-92,24v-2,14,43,21,61,21v25,0,36,-20,31,-45",w:295},"–":{d:"6,-66v-8,-72,79,-21,146,-39v37,-10,79,7,111,0v9,8,14,13,14,17v2,26,-72,13,-99,21v-83,4,-124,21,-172,1",w:282},"—":{d:"175,-106v86,-9,201,1,286,-1v11,6,13,11,6,30v-118,15,-246,10,-377,10v-25,0,-73,3,-82,-8r-2,-26v11,-13,32,-9,52,-7v38,3,84,-5,117,2",w:485},"“":{d:"66,-261v-21,5,-37,51,-22,77v0,4,-2,6,-7,6v-31,-9,-38,-62,-12,-94v12,-15,21,-28,31,-34v16,-1,19,24,22,34v10,-11,22,-32,43,-23v-2,8,4,16,5,19v-6,11,-51,53,-29,74v-12,21,-30,5,-33,-17v-6,-13,9,-28,2,-42",w:118},"”":{d:"120,-294v12,3,30,26,19,34v2,15,-40,70,-55,66v-40,-10,10,-51,14,-64v3,-3,8,-31,22,-36xm70,-306v14,3,26,34,16,49v-19,30,-31,45,-58,59v-12,-11,-33,-17,-7,-36v13,-19,36,-27,36,-59v0,-5,9,-13,13,-13",w:148},"‘":{d:"73,-262v-10,7,-41,39,-38,69v-15,13,-27,-16,-28,-28v-2,-20,51,-83,66,-83v20,0,25,41,0,42",w:95},"’":{d:"74,-300v13,31,-1,99,-44,101v-13,0,-19,-5,-19,-15v6,-10,31,-34,35,-59v2,-11,1,-32,11,-32v6,0,11,2,17,5",w:90},"÷":{d:"167,-158v-4,3,-7,9,-10,20v-23,4,-34,-8,-29,-31v14,-6,18,1,39,11xm78,-72v-53,11,-53,12,-69,-15v-1,-12,11,-17,22,-14v71,-13,151,-18,230,-24v11,1,21,16,23,28v-28,20,-90,11,-126,16v-36,5,-62,5,-80,9xm123,-40v19,-17,41,-1,41,17v0,13,-6,19,-17,19v-15,0,-29,-14,-24,-36",w:293},"◊":{d:"76,-158v48,-8,64,11,100,36v28,19,-5,39,-22,54v-15,13,-40,32,-48,49v-17,5,-12,0,-27,-16v-6,-6,-86,-31,-68,-53r2,-9v27,-23,48,-44,63,-61xm93,-65v12,-2,35,-31,41,-38v-5,-10,-16,-14,-34,-24v-12,12,-36,29,-40,44v19,11,30,18,33,18",w:199},"ÿ":{d:"118,85v-11,11,-11,38,-22,61v-2,-1,-2,31,-17,27v-11,0,-21,-10,-21,-22v20,-66,23,-61,64,-168v-22,1,-38,16,-58,4v-22,4,-51,-16,-51,-42v-11,-13,-7,-59,7,-58v16,1,21,24,22,51v21,33,66,5,94,-7v4,-3,26,-14,38,-29r17,0v23,44,-23,59,-34,102v-6,9,-13,9,-13,26v-15,6,-12,33,-27,48v0,2,1,4,1,7xm158,-136v0,8,-4,13,-12,13v-18,0,-21,-20,-16,-34v18,-1,29,1,28,21xm62,-161v7,3,28,9,27,18v1,8,-8,17,-17,17v-18,0,-26,-24,-10,-35",w:190},"Ÿ":{d:"176,-189v35,20,-25,54,-39,72v-26,34,-57,57,-74,104v-10,15,-4,14,-23,3r0,-10v19,-44,27,-46,50,-81v-9,-5,-24,4,-34,4v-38,0,-54,-50,-44,-87v21,-5,18,19,22,35v4,18,15,27,29,27v41,0,60,-39,113,-67xm153,-222v0,8,-3,12,-11,12v-18,0,-21,-19,-16,-33v18,-1,28,2,27,21xm57,-247v8,2,29,9,28,17v0,21,-37,24,-36,1v0,-7,2,-13,8,-18",w:135},"⁄":{d:"193,-305v7,6,17,31,3,41v-10,7,-12,13,-21,25v-79,56,-190,209,-197,260r-18,0v-23,-19,9,-70,15,-85v52,-83,121,-179,218,-241",w:120},"¤":{d:"308,-133r-200,16v-2,1,-6,4,-10,10v70,-2,144,-14,211,-8v3,0,8,4,13,8v-1,4,-3,9,-9,17v-57,11,-164,6,-219,25v26,32,112,25,173,25v9,0,35,2,35,19v0,9,-4,13,-12,14v-115,12,-146,23,-211,-19v-12,-4,-22,-9,-25,-27v-6,-29,-61,3,-43,-49v17,-1,36,7,42,-12v-32,7,-36,-39,-11,-40v29,14,63,-25,73,-30v52,-25,72,-44,142,-44v23,0,21,41,-1,39v-35,-3,-61,9,-102,31v2,2,5,4,8,4v18,-6,101,-9,115,-9v7,0,55,13,31,30",w:312},"€":{d:"308,-133r-200,16v-2,1,-6,4,-10,10v70,-2,144,-14,211,-8v3,0,8,4,13,8v-1,4,-3,9,-9,17v-57,11,-164,6,-219,25v26,32,112,25,173,25v9,0,35,2,35,19v0,9,-4,13,-12,14v-115,12,-146,23,-211,-19v-12,-4,-22,-9,-25,-27v-6,-29,-61,3,-43,-49v17,-1,36,7,42,-12v-32,7,-36,-39,-11,-40v29,14,63,-25,73,-30v52,-25,72,-44,142,-44v23,0,21,41,-1,39v-35,-3,-61,9,-102,31v2,2,5,4,8,4v18,-6,101,-9,115,-9v7,0,55,13,31,30",w:312},"‹":{d:"64,-107v9,17,86,17,87,43v0,11,-4,16,-13,16v-36,-11,-70,-22,-109,-31v-19,-4,-18,-14,-9,-36v59,-56,93,-84,101,-84v17,0,19,20,13,29",w:159},"›":{d:"41,-181v26,27,112,44,70,91r-82,60v-20,3,-25,-23,-13,-32r70,-51r-66,-46v-5,-6,-4,-28,5,-29v4,2,9,4,16,7",w:137},"":{d:"74,-74v-6,-24,-70,8,-68,-27v0,-6,6,-20,20,-18v44,6,45,-9,42,-49v7,-40,26,-114,90,-104v48,-2,63,-1,90,30v11,25,4,14,2,44v-7,17,-54,9,-49,-7r8,-21v-5,-13,-22,-9,-43,-11v-56,-6,-63,45,-67,92v-2,21,5,23,22,22v37,-1,80,-9,113,-1v13,31,-9,82,-22,106v-13,10,-26,-6,-22,-25r11,-46v0,-3,-2,-6,-6,-6v-19,0,-47,3,-83,9v-6,1,-9,4,-8,11r12,59v-1,9,-11,30,-23,18v-18,-18,-15,-59,-19,-76",w:272},"":{d:"43,-61v-21,4,-36,2,-39,-15v-4,-35,41,-8,34,-47v4,-59,12,-99,46,-124v11,-42,157,-47,149,13v1,7,-7,15,-13,15v-18,-7,-19,-26,-47,-23v-34,3,-65,6,-79,37v-12,27,-22,52,-21,91v13,9,31,-11,45,-4v32,-15,50,-6,94,-13v12,-30,19,-79,36,-133v1,-5,5,-8,12,-8v44,18,-18,106,-12,144v-9,22,-1,73,-16,104v2,28,-23,28,-37,16v1,-26,9,-48,11,-75v0,-6,-3,-9,-9,-9v-43,0,-83,8,-119,24v8,40,17,33,-7,56v-20,-9,-21,-19,-28,-49",w:283},"‡":{d:"102,-284v16,2,42,-2,33,18v-7,15,-42,1,-38,30v3,3,31,1,30,11v4,15,-29,19,-36,24v-2,18,-4,24,-16,29r-25,-26v-25,7,-53,3,-42,-25v4,-10,70,0,51,-22v-17,4,-41,12,-39,-15v-5,-16,39,-18,44,-20v4,-2,7,-10,10,-24v19,-3,23,6,28,20",w:145},"∙":{d:"57,-77v6,18,-7,21,-19,23v-34,6,-25,-40,-9,-43v18,-3,29,8,28,20",w:67},"‚":{d:"25,63v-26,21,-48,-2,-22,-24v14,-12,35,-40,35,-69v3,-2,3,-11,12,-9v35,17,5,88,-25,102",w:97},"„":{d:"25,63v-26,21,-48,-2,-22,-24v11,-9,36,-41,35,-69v3,-2,4,-12,12,-9v36,14,5,89,-25,102xm84,64v-24,20,-45,-1,-21,-24v21,-20,32,-35,35,-69v3,-2,3,-11,12,-9v36,17,9,86,-26,102",w:135},"‰":{d:"398,-131v58,-1,87,13,72,65v-1,30,-66,63,-99,65v-56,3,-99,-58,-62,-102v2,2,5,2,8,2v20,-16,51,-17,81,-30xm202,-279v33,0,94,-24,95,18v-7,31,-33,27,-54,55v-36,32,-71,74,-112,99v-18,18,-40,34,-51,58v-19,14,-25,37,-56,40v-17,2,-25,-29,-10,-40v15,-11,40,-37,52,-52r87,-72v-51,13,-100,6,-116,-27v1,-5,-6,-30,-9,-36v-3,-5,22,-41,27,-39v29,2,16,34,5,49v0,15,14,23,42,23v42,0,59,-31,28,-38v-17,-4,-53,3,-50,-23v0,-7,1,-12,4,-16v16,-9,36,4,49,5v0,0,23,-4,69,-4xm222,-118v33,-2,55,18,50,57v-29,36,-48,45,-96,50v-27,-5,-56,-17,-58,-51v13,-37,64,-43,104,-56xm335,-61v13,44,101,7,108,-31v-11,-3,-20,-4,-30,-4v-18,-1,-82,18,-78,35xm225,-244v-18,0,-29,-1,-46,3v7,15,6,28,0,43v15,-14,34,-30,46,-46xm164,-53v26,5,59,-10,76,-26v-17,-16,-49,2,-67,14v1,8,-8,6,-9,12",w:485},"Â":{d:"161,-217v20,53,23,124,54,170v-2,20,-34,9,-42,0v-27,-12,-78,-18,-101,-18v-26,6,-29,51,-54,63v-18,-4,-19,-30,-3,-38v5,-9,15,-16,8,-29v1,-12,23,-9,26,-19v6,-10,11,-20,20,-27r70,-121v12,-4,16,4,22,19xm82,-91v17,3,62,7,86,13v-13,-33,-13,-80,-29,-109v-15,30,-38,63,-57,96xm202,-219v-27,-6,-40,-26,-61,-37v-21,7,-39,46,-65,23v-2,-4,-3,-10,-4,-14v19,-4,43,-32,61,-43v27,6,40,22,62,37v12,8,18,17,18,25v0,6,-3,9,-11,9"},"Ê":{d:"49,-160v1,-4,-10,-9,-15,-8v-15,-35,32,-30,57,-31r142,-8v2,1,30,7,40,10v-52,16,-133,17,-190,30v-7,9,-12,24,-15,47v26,10,102,-6,141,3v1,3,1,6,2,10v-36,18,-92,12,-149,21v-11,9,-16,41,-16,51v55,-1,111,-21,168,-13v15,-8,48,1,31,18v-53,16,-130,13,-198,29r-39,-8v-4,-19,17,-53,20,-76v-1,0,-7,-11,-9,-18v18,-7,22,-28,30,-57xm199,-211v-27,-6,-39,-26,-60,-37v-21,7,-40,47,-65,22v-2,-7,-2,-7,-4,-13v18,-5,44,-31,61,-43v27,6,41,22,62,37v12,9,18,17,18,25v0,6,-4,9,-12,9",w:252},"Á":{d:"161,-217v20,53,23,124,54,170v-2,20,-34,9,-42,0v-27,-12,-78,-18,-101,-18v-26,6,-29,51,-54,63v-18,-4,-19,-30,-3,-38v5,-9,15,-16,8,-29v1,-12,23,-9,26,-19v6,-10,11,-20,20,-27r70,-121v12,-4,16,4,22,19xm82,-91v17,3,62,7,86,13v-13,-33,-13,-80,-29,-109v-15,30,-38,63,-57,96xm84,-250v31,-5,83,-53,100,-31v0,5,-11,15,-35,28v-16,5,-51,28,-53,25v-14,1,-16,-11,-12,-22"},"Ë":{d:"49,-160v1,-4,-10,-9,-15,-8v-15,-35,32,-30,57,-31r142,-8v2,1,30,7,40,10v-52,16,-133,17,-190,30v-7,9,-12,24,-15,47v26,10,102,-6,141,3v1,3,1,6,2,10v-36,18,-92,12,-149,21v-11,9,-17,41,-17,51v55,0,112,-21,169,-13v15,-8,48,1,31,18v-53,16,-130,13,-198,29r-39,-8v-3,-21,17,-53,20,-76v-1,0,-7,-11,-9,-18v18,-7,22,-28,30,-57xm191,-236v0,8,-4,13,-12,13v-17,0,-19,-19,-16,-34v18,-1,29,1,28,21xm95,-261v7,3,29,9,28,18v0,7,-9,17,-18,17v-18,0,-26,-25,-10,-35",w:252},"È":{d:"49,-160v1,-4,-10,-9,-15,-8v-15,-35,32,-30,57,-31r142,-8v2,1,30,7,40,10v-52,16,-133,17,-190,30v-7,9,-12,24,-15,47v26,10,102,-6,141,3v1,3,1,6,2,10v-36,18,-92,12,-149,21v-11,9,-16,41,-16,51v55,-1,111,-21,168,-13v15,-8,48,1,31,18v-53,16,-130,13,-198,29r-39,-8v-4,-19,17,-53,20,-76v-1,0,-7,-11,-9,-18v18,-7,22,-28,30,-57xm184,-236v6,9,5,13,0,23v-28,-7,-62,-21,-100,-41v-3,-2,-3,-27,5,-23v34,11,60,25,95,41",w:252},"Í":{d:"26,-5v-9,-6,-9,-12,-9,-36v0,-71,7,-119,21,-144v8,-13,14,-20,19,-20v28,19,-7,89,-10,120v-2,21,-8,47,-14,76v-2,1,-2,0,-7,4xm6,-233v31,-6,83,-53,101,-31v2,11,-80,53,-89,53v-14,1,-14,-11,-12,-22",w:104},"Î":{d:"53,-9v-15,7,-16,-3,-16,-32v0,-71,7,-119,21,-144v8,-13,14,-20,19,-20v28,19,-7,89,-10,120v-2,21,-8,47,-14,76xm137,-209v-27,-6,-40,-26,-61,-37v-8,0,-9,4,-13,10v-11,13,-50,37,-56,0v18,-5,43,-32,61,-43v28,5,40,21,62,36v12,9,18,17,18,25v0,6,-4,9,-11,9",w:144},"Ï":{d:"33,-5v-9,-6,-9,-12,-9,-36v0,-71,8,-119,22,-144v8,-13,14,-20,19,-20v27,20,-11,87,-10,120r-15,76v-1,1,-4,2,-7,4xm111,-222v0,8,-4,12,-12,12v-18,0,-19,-19,-16,-33v18,-1,29,1,28,21xm15,-247v8,2,29,9,28,17v0,21,-37,24,-36,1v0,-7,2,-13,8,-18",w:110},"Ì":{d:"33,-5v-9,-6,-9,-12,-9,-36v0,-71,8,-119,22,-144v8,-13,14,-20,19,-20v27,20,-11,87,-10,120r-15,76v-1,1,-4,2,-7,4xm72,-247v7,6,55,15,36,40v-28,-7,-61,-21,-99,-41v-3,-2,-3,-27,5,-23v18,3,41,17,58,24",w:111},"Ó":{d:"62,-184v78,-31,249,-50,238,74v-6,65,-102,105,-179,115v-77,-7,-152,-71,-101,-149v2,-5,24,-33,42,-40xm279,-120v14,-38,-47,-64,-85,-61v-20,-9,-41,7,-62,0v-11,7,-54,12,-66,24v0,20,-51,35,-38,66v-1,43,50,67,96,67v44,0,162,-55,155,-96xm142,-250v27,-11,47,-32,59,-14v2,11,-80,53,-89,53v-13,1,-15,-11,-12,-21v10,-5,24,-11,42,-18",w:273},"Ô":{d:"62,-184v78,-31,249,-50,238,74v-6,65,-102,105,-179,115v-77,-7,-152,-71,-101,-149v2,-5,24,-33,42,-40xm279,-120v14,-38,-47,-64,-85,-61v-20,-9,-41,7,-62,0v-11,7,-54,12,-66,24v0,20,-51,35,-38,66v-1,43,50,67,96,67v44,0,162,-55,155,-96xm157,-282v17,18,52,34,54,63v-24,12,-52,-36,-53,-29r-42,34v-23,-4,-6,-31,5,-34v1,1,27,-37,36,-34",w:273},"":{d:"231,-188v31,-74,91,-99,188,-116v28,1,6,39,1,51v-20,52,-100,91,-148,126v2,4,6,7,12,10v42,-42,181,-41,166,46v-1,8,-19,8,-28,5v-43,1,-168,42,-106,86v15,16,33,28,61,39v0,10,0,17,-6,22v-8,8,-35,26,-78,51v-52,7,-128,22,-154,-17v-23,-35,-99,-35,-117,-77v-29,-68,25,-149,75,-175v44,-23,89,5,135,13v14,-26,2,-39,-1,-64",w:461},"Ò":{d:"62,-184v78,-31,249,-50,238,74v-6,65,-102,105,-179,115v-77,-7,-152,-71,-101,-149v2,-5,24,-33,42,-40xm279,-120v14,-38,-47,-64,-85,-61v-20,-9,-41,7,-62,0v-11,7,-54,12,-66,24v0,20,-51,35,-38,66v-1,43,50,67,96,67v44,0,162,-55,155,-96xm161,-262v14,10,52,13,37,41v-28,-7,-62,-21,-100,-41v-3,-3,-3,-26,5,-24v16,5,42,17,58,24",w:273},"Ú":{d:"281,-202v6,67,-30,121,-71,152v-3,14,-47,26,-60,39v-41,20,-110,1,-125,-26v-24,-44,-28,-84,-8,-127v12,-26,23,-38,37,-22v-2,2,-3,5,-3,10v-34,26,-30,116,5,134v22,32,86,-1,109,-8v38,-28,104,-64,97,-149v2,-10,7,-8,19,-3xm194,-265v3,-1,11,4,11,6v3,12,-81,52,-89,54v-14,0,-13,-9,-12,-22",w:262},"Û":{d:"281,-202v6,67,-30,121,-71,152v-3,14,-47,26,-60,39v-41,20,-110,1,-125,-26v-24,-44,-28,-84,-8,-127v12,-26,23,-38,37,-22v-2,2,-3,5,-3,10v-34,26,-30,116,5,134v22,32,86,-1,109,-8v38,-28,104,-64,97,-149v2,-10,7,-8,19,-3xm150,-266v24,11,58,27,73,46v0,5,-3,6,-10,6v-28,2,-61,-30,-63,-25v-10,0,-57,40,-69,23v3,-10,-8,-15,8,-19v17,-1,34,-29,61,-31",w:262},"Ù":{d:"281,-202v6,67,-30,121,-71,152v-3,14,-47,26,-60,39v-41,20,-110,1,-125,-26v-24,-44,-28,-84,-8,-127v12,-26,23,-38,37,-22v-2,2,-3,5,-3,10v-34,26,-30,116,5,134v22,32,86,-1,109,-8v38,-28,104,-64,97,-149v2,-10,7,-8,19,-3xm151,-243v14,10,54,14,37,41v-28,-7,-61,-22,-99,-42v-3,-2,-4,-25,4,-23v16,5,42,17,58,24",w:262},"ı":{d:"43,-103v21,4,16,56,11,100v-7,2,-11,1,-20,-5v0,-7,-13,-18,-11,-25v4,-23,-3,-68,20,-70",w:80},"ˆ":{d:"144,-220v-29,0,-41,-27,-63,-39v-8,0,-11,5,-15,11v-17,12,-32,31,-54,13v-2,-5,-3,-9,-4,-14v20,-5,45,-33,64,-45v28,6,43,23,65,38v12,9,19,19,19,27v0,6,-4,9,-12,9",w:165},"˜":{d:"47,-300v26,-21,57,19,72,23v4,0,16,-5,36,-14v24,-10,22,-16,32,-13v3,12,-7,11,-7,23v-27,21,-48,32,-62,32v-3,2,-52,-27,-51,-31v-12,-2,-34,40,-54,33v-4,-13,-8,-18,1,-24v5,-7,16,-15,33,-29",w:186},"¯":{d:"63,-295v28,-7,73,10,105,7v11,1,6,8,5,19v-37,21,-72,11,-136,11v-23,0,-31,-14,-27,-36v12,-15,40,0,53,-1",w:183},"˘":{d:"65,-269v20,-11,45,-31,74,-36v20,30,-42,40,-59,66v-5,6,-11,8,-18,8v-8,-3,-45,-32,-51,-54v5,-24,14,-13,34,1",w:158},"˙":{d:"23,-302v15,-13,32,1,32,18v1,22,-36,29,-39,4v0,0,3,-7,7,-22",w:70},"˚":{d:"23,-225v-43,-24,-11,-85,41,-78v16,2,31,4,46,17v32,54,-41,86,-87,61xm33,-257v2,20,57,11,57,-6v0,-6,-11,-9,-33,-12v-14,-2,-24,13,-24,18",w:123},"¸":{d:"74,16v32,2,49,14,55,36v-3,7,-14,31,-29,33v-28,4,-57,11,-88,14v-19,-6,-13,-31,8,-33v20,-1,59,-5,73,-14v-17,-14,-68,8,-53,-37v9,-10,2,-28,24,-30v8,8,13,17,10,31",w:129},"˝":{d:"91,-249v15,-11,38,-53,57,-29v0,9,0,14,-3,23v-2,3,-20,22,-54,55v-5,5,-10,8,-16,8v-17,2,-6,-22,-7,-31v-1,0,-2,0,-4,1v-17,21,-29,31,-50,27v-5,-18,-3,-15,3,-27v23,-27,40,-46,48,-59v7,-12,31,3,29,9v-1,14,-3,24,-13,31v4,4,9,-1,10,-8",w:151},"˛":{d:"82,-5v-8,12,-16,55,-21,75v0,4,2,7,7,7v6,0,22,-7,50,-20v8,0,12,7,12,20v-2,22,-6,14,-27,30v-15,12,-26,16,-30,16v-47,-8,-59,-14,-56,-75v8,-27,12,-54,25,-77v19,-21,35,15,40,24",w:138},"ˇ":{d:"39,-286v33,46,63,-4,96,-16v6,0,9,6,9,19v0,24,-49,46,-77,46v-32,0,-52,-28,-59,-48v0,-25,23,-17,31,-1",w:153},"\r":{w:179}}}),function(){"use strict"; +function AssertException(message){this.message=message}function assert(exp,message){if(!exp)throw new AssertException(message)}function getCenterX(box){return box.x+box.width/2}function getCenterY(box){return box.y+box.height/2}var DIAGRAM_MARGIN=10,ACTOR_MARGIN=10,ACTOR_PADDING=10,SIGNAL_MARGIN=5,SIGNAL_PADDING=5,NOTE_MARGIN=10,NOTE_PADDING=5,NOTE_OVERLAP=15,TITLE_MARGIN=0,TITLE_PADDING=5,SELF_SIGNAL_WIDTH=20,PLACEMENT=Diagram.PLACEMENT,LINETYPE=Diagram.LINETYPE,ARROWTYPE=Diagram.ARROWTYPE,LINE={stroke:"#000","stroke-width":2},RECT={fill:"#fff"};AssertException.prototype.toString=function(){return"AssertException: "+this.message},String.prototype.trim||(String.prototype.trim=function(){return this.replace(/^\s+|\s+$/g,"")}),Raphael.fn.line=function(x1,y1,x2,y2){return assert(_.all([x1,x2,y1,y2],_.isFinite),"x1,x2,y1,y2 must be numeric"),this.path("M{0},{1} L{2},{3}",x1,y1,x2,y2)},Raphael.fn.wobble=function(x1,y1,x2,y2){assert(_.all([x1,x2,y1,y2],_.isFinite),"x1,x2,y1,y2 must be numeric");var wobble=Math.sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1))/25,r1=Math.random(),r2=Math.random(),xfactor=Math.random()>.5?wobble:-wobble,yfactor=Math.random()>.5?wobble:-wobble,p1={x:(x2-x1)*r1+x1+xfactor,y:(y2-y1)*r1+y1+yfactor},p2={x:(x2-x1)*r2+x1-xfactor,y:(y2-y1)*r2+y1-yfactor};return"C"+p1.x+","+p1.y+" "+p2.x+","+p2.y+" "+x2+","+y2},Raphael.fn.text_bbox=function(text,font){var p;font._obj?p=this.print_center(0,0,text,font._obj,font["font-size"]):(p=this.text(0,0,text),p.attr(font));var bb=p.getBBox();return p.remove(),bb},Raphael.fn.handRect=function(x,y,w,h){return assert(_.all([x,y,w,h],_.isFinite),"x, y, w, h must be numeric"),this.path("M"+x+","+y+this.wobble(x,y,x+w,y)+this.wobble(x+w,y,x+w,y+h)+this.wobble(x+w,y+h,x,y+h)+this.wobble(x,y+h,x,y)).attr(RECT)},Raphael.fn.handLine=function(x1,y1,x2,y2){return assert(_.all([x1,x2,y1,y2],_.isFinite),"x1,x2,y1,y2 must be numeric"),this.path("M"+x1+","+y1+this.wobble(x1,y1,x2,y2))},Raphael.fn.print_center=function(x,y,string,font,size,letter_spacing){var path=this.print(x,y,string,font,size,"baseline",letter_spacing),bb=path.getBBox(),dx=x-bb.x-bb.width/2,dy=y-bb.y-bb.height/2,m=new Raphael.matrix;return m.translate(dx,dy),path.attr("path",Raphael.mapPath(path.attr("path"),m))};var BaseTheme=function(diagram){this.init(diagram)};_.extend(BaseTheme.prototype,{init:function(diagram){this.diagram=diagram,this._paper=void 0,this._font=void 0,this._title=void 0,this._actors_height=0,this._signals_height=0;var a=this.arrow_types={};a[ARROWTYPE.FILLED]="block",a[ARROWTYPE.OPEN]="open";var l=this.line_types={};l[LINETYPE.SOLID]="",l[LINETYPE.DOTTED]="-"},init_paper:function(container){this._paper=new Raphael(container,320,200)},init_font:function(){},draw_line:function(x1,y1,x2,y2){return this._paper.line(x1,y1,x2,y2)},draw_rect:function(x,y,w,h){return this._paper.rect(x,y,w,h)},draw:function(container){var diagram=this.diagram;this.init_paper(container),this.init_font(),this.layout();var title_height=this._title?this._title.height:0;this._paper.setStart(),this._paper.setSize(diagram.width,diagram.height);var y=DIAGRAM_MARGIN+title_height;this.draw_title(),this.draw_actors(y),this.draw_signals(y+this._actors_height),this._paper.setFinish()},layout:function(){function actor_ensure_distance(a,b,d){assert(b>a,"a must be less than or equal to b"),0>a?(b=actors[b],b.x=Math.max(d-b.width/2,b.x)):b>=actors.length?(a=actors[a],a.padding_right=Math.max(d,a.padding_right)):(a=actors[a],a.distances[b]=Math.max(d,a.distances[b]?a.distances[b]:0))}var diagram=this.diagram,paper=this._paper,font=this._font,actors=diagram.actors,signals=diagram.signals;if(diagram.width=0,diagram.height=0,diagram.title){var title=this._title={},bb=paper.text_bbox(diagram.title,font);title.text_bb=bb,title.message=diagram.title,title.width=bb.width+2*(TITLE_PADDING+TITLE_MARGIN),title.height=bb.height+2*(TITLE_PADDING+TITLE_MARGIN),title.x=DIAGRAM_MARGIN,title.y=DIAGRAM_MARGIN,diagram.width+=title.width,diagram.height+=title.height}_.each(actors,function(a){var bb=paper.text_bbox(a.name,font);a.text_bb=bb,a.x=0,a.y=0,a.width=bb.width+2*(ACTOR_PADDING+ACTOR_MARGIN),a.height=bb.height+2*(ACTOR_PADDING+ACTOR_MARGIN),a.distances=[],a.padding_right=0,this._actors_height=Math.max(a.height,this._actors_height)},this),_.each(signals,function(s){var a,b,bb=paper.text_bbox(s.message,font);s.text_bb=bb,s.width=bb.width,s.height=bb.height;var extra_width=0;if("Signal"==s.type)s.width+=2*(SIGNAL_MARGIN+SIGNAL_PADDING),s.height+=2*(SIGNAL_MARGIN+SIGNAL_PADDING),s.isSelf()?(a=s.actorA.index,b=a+1,s.width+=SELF_SIGNAL_WIDTH):(a=Math.min(s.actorA.index,s.actorB.index),b=Math.max(s.actorA.index,s.actorB.index));else{if("Note"!=s.type)throw new Error("Unhandled signal type:"+s.type);if(s.width+=2*(NOTE_MARGIN+NOTE_PADDING),s.height+=2*(NOTE_MARGIN+NOTE_PADDING),extra_width=2*ACTOR_MARGIN,s.placement==PLACEMENT.LEFTOF)b=s.actor.index,a=b-1;else if(s.placement==PLACEMENT.RIGHTOF)a=s.actor.index,b=a+1;else if(s.placement==PLACEMENT.OVER&&s.hasManyActors())a=Math.min(s.actor[0].index,s.actor[1].index),b=Math.max(s.actor[0].index,s.actor[1].index),extra_width=-(2*NOTE_PADDING+2*NOTE_OVERLAP);else if(s.placement==PLACEMENT.OVER)return a=s.actor.index,actor_ensure_distance(a-1,a,s.width/2),actor_ensure_distance(a,a+1,s.width/2),this._signals_height+=s.height,void 0}actor_ensure_distance(a,b,s.width+extra_width),this._signals_height+=s.height},this);var actors_x=0;return _.each(actors,function(a){a.x=Math.max(actors_x,a.x),_.each(a.distances,function(distance,b){"undefined"!=typeof distance&&(b=actors[b],distance=Math.max(distance,a.width/2,b.width/2),b.x=Math.max(b.x,a.x+a.width/2+distance-b.width/2))}),actors_x=a.x+a.width+a.padding_right},this),diagram.width=Math.max(actors_x,diagram.width),diagram.width+=2*DIAGRAM_MARGIN,diagram.height+=2*DIAGRAM_MARGIN+2*this._actors_height+this._signals_height,this},draw_title:function(){var title=this._title;title&&this.draw_text_box(title,title.message,TITLE_MARGIN,TITLE_PADDING,this._font)},draw_actors:function(offsetY){var y=offsetY;_.each(this.diagram.actors,function(a){this.draw_actor(a,y,this._actors_height),this.draw_actor(a,y+this._actors_height+this._signals_height,this._actors_height);var aX=getCenterX(a),line=this.draw_line(aX,y+this._actors_height-ACTOR_MARGIN,aX,y+this._actors_height+ACTOR_MARGIN+this._signals_height);line.attr(LINE)},this)},draw_actor:function(actor,offsetY,height){actor.y=offsetY,actor.height=height,this.draw_text_box(actor,actor.name,ACTOR_MARGIN,ACTOR_PADDING,this._font)},draw_signals:function(offsetY){var y=offsetY;_.each(this.diagram.signals,function(s){"Signal"==s.type?s.isSelf()?this.draw_self_signal(s,y):this.draw_signal(s,y):"Note"==s.type&&this.draw_note(s,y),y+=s.height},this)},draw_self_signal:function(signal,offsetY){assert(signal.isSelf(),"signal must be a self signal");var text_bb=signal.text_bb,aX=getCenterX(signal.actorA),x=aX+SELF_SIGNAL_WIDTH+SIGNAL_PADDING-text_bb.x,y=offsetY+signal.height/2;this.draw_text(x,y,signal.message,this._font);var line,attr=_.extend({},LINE,{"stroke-dasharray":this.line_types[signal.linetype]}),y1=offsetY+SIGNAL_MARGIN,y2=y1+signal.height-SIGNAL_MARGIN;line=this.draw_line(aX,y1,aX+SELF_SIGNAL_WIDTH,y1),line.attr(attr),line=this.draw_line(aX+SELF_SIGNAL_WIDTH,y1,aX+SELF_SIGNAL_WIDTH,y2),line.attr(attr),line=this.draw_line(aX+SELF_SIGNAL_WIDTH,y2,aX,y2),attr["arrow-end"]=this.arrow_types[signal.arrowtype]+"-wide-long",line.attr(attr)},draw_signal:function(signal,offsetY){var aX=getCenterX(signal.actorA),bX=getCenterX(signal.actorB),x=(bX-aX)/2+aX,y=offsetY+SIGNAL_MARGIN+2*SIGNAL_PADDING;this.draw_text(x,y,signal.message,this._font),y=offsetY+signal.height-SIGNAL_MARGIN-SIGNAL_PADDING;var line=this.draw_line(aX,y,bX,y);line.attr(LINE),line.attr({"arrow-end":this.arrow_types[signal.arrowtype]+"-wide-long","stroke-dasharray":this.line_types[signal.linetype]})},draw_note:function(note,offsetY){note.y=offsetY;var actorA=note.hasManyActors()?note.actor[0]:note.actor,aX=getCenterX(actorA);switch(note.placement){case PLACEMENT.RIGHTOF:note.x=aX+ACTOR_MARGIN;break;case PLACEMENT.LEFTOF:note.x=aX-ACTOR_MARGIN-note.width;break;case PLACEMENT.OVER:if(note.hasManyActors()){var bX=getCenterX(note.actor[1]),overlap=NOTE_OVERLAP+NOTE_PADDING;note.x=aX-overlap,note.width=bX+overlap-note.x}else note.x=aX-note.width/2;break;default:throw new Error("Unhandled note placement:"+note.placement)}this.draw_text_box(note,note.message,NOTE_MARGIN,NOTE_PADDING,this._font)},draw_text:function(x,y,text,font){var t,paper=this._paper,f=font||{};f._obj?t=paper.print_center(x,y,text,f._obj,f["font-size"]):(t=paper.text(x,y,text),t.attr(f));var bb=t.getBBox(),r=paper.rect(bb.x,bb.y,bb.width,bb.height);r.attr({fill:"#fff",stroke:"none"}),t.toFront()},draw_text_box:function(box,text,margin,padding,font){var x=box.x+margin,y=box.y+margin,w=box.width-2*margin,h=box.height-2*margin,rect=this.draw_rect(x,y,w,h);rect.attr(LINE),x=getCenterX(box),y=getCenterY(box),this.draw_text(x,y,text,font)}});var RaphaëlTheme=function(diagram){this.init(diagram)};_.extend(RaphaëlTheme.prototype,BaseTheme.prototype,{init_font:function(){this._font={"font-size":16,"font-family":"Andale Mono, monospace"}}});var HandRaphaëlTheme=function(diagram){this.init(diagram)};_.extend(HandRaphaëlTheme.prototype,BaseTheme.prototype,{init_font:function(){this._font={"font-size":16,"font-family":"daniel"},this._font._obj=this._paper.getFont("daniel")},draw_line:function(x1,y1,x2,y2){return this._paper.handLine(x1,y1,x2,y2)},draw_rect:function(x,y,w,h){return this._paper.handRect(x,y,w,h)}});var themes={simple:RaphaëlTheme,hand:HandRaphaëlTheme};Diagram.prototype.drawSVG=function(container,options){var default_options={theme:"hand"};if(options=_.defaults(options||{},default_options),!(options.theme in themes))throw new Error("Unsupported theme: "+options.theme);var drawing=new themes[options.theme](this);drawing.draw(container)}}(); \ No newline at end of file diff --git a/static/js/mdeditor/lib/underscore.min.js b/static/js/mdeditor/lib/underscore.min.js new file mode 100644 index 00000000..447e19b7 --- /dev/null +++ b/static/js/mdeditor/lib/underscore.min.js @@ -0,0 +1,5 @@ +// Underscore.js 1.8.2 +// http://underscorejs.org +// (c) 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors +// Underscore may be freely distributed under the MIT license. +(function(){function n(n){function t(t,r,e,u,i,o){for(;i>=0&&o>i;i+=n){var a=u?u[i]:i;e=r(e,t[a],a,t)}return e}return function(r,e,u,i){e=d(e,i,4);var o=!w(r)&&m.keys(r),a=(o||r).length,c=n>0?0:a-1;return arguments.length<3&&(u=r[o?o[c]:c],c+=n),t(r,e,u,o,c,a)}}function t(n){return function(t,r,e){r=b(r,e);for(var u=null!=t&&t.length,i=n>0?0:u-1;i>=0&&u>i;i+=n)if(r(t[i],i,t))return i;return-1}}function r(n,t){var r=S.length,e=n.constructor,u=m.isFunction(e)&&e.prototype||o,i="constructor";for(m.has(n,i)&&!m.contains(t,i)&&t.push(i);r--;)i=S[r],i in n&&n[i]!==u[i]&&!m.contains(t,i)&&t.push(i)}var e=this,u=e._,i=Array.prototype,o=Object.prototype,a=Function.prototype,c=i.push,l=i.slice,f=o.toString,s=o.hasOwnProperty,p=Array.isArray,h=Object.keys,v=a.bind,g=Object.create,y=function(){},m=function(n){return n instanceof m?n:this instanceof m?void(this._wrapped=n):new m(n)};"undefined"!=typeof exports?("undefined"!=typeof module&&module.exports&&(exports=module.exports=m),exports._=m):e._=m,m.VERSION="1.8.2";var d=function(n,t,r){if(t===void 0)return n;switch(null==r?3:r){case 1:return function(r){return n.call(t,r)};case 2:return function(r,e){return n.call(t,r,e)};case 3:return function(r,e,u){return n.call(t,r,e,u)};case 4:return function(r,e,u,i){return n.call(t,r,e,u,i)}}return function(){return n.apply(t,arguments)}},b=function(n,t,r){return null==n?m.identity:m.isFunction(n)?d(n,t,r):m.isObject(n)?m.matcher(n):m.property(n)};m.iteratee=function(n,t){return b(n,t,1/0)};var x=function(n,t){return function(r){var e=arguments.length;if(2>e||null==r)return r;for(var u=1;e>u;u++)for(var i=arguments[u],o=n(i),a=o.length,c=0;a>c;c++){var l=o[c];t&&r[l]!==void 0||(r[l]=i[l])}return r}},_=function(n){if(!m.isObject(n))return{};if(g)return g(n);y.prototype=n;var t=new y;return y.prototype=null,t},j=Math.pow(2,53)-1,w=function(n){var t=n&&n.length;return"number"==typeof t&&t>=0&&j>=t};m.each=m.forEach=function(n,t,r){t=d(t,r);var e,u;if(w(n))for(e=0,u=n.length;u>e;e++)t(n[e],e,n);else{var i=m.keys(n);for(e=0,u=i.length;u>e;e++)t(n[i[e]],i[e],n)}return n},m.map=m.collect=function(n,t,r){t=b(t,r);for(var e=!w(n)&&m.keys(n),u=(e||n).length,i=Array(u),o=0;u>o;o++){var a=e?e[o]:o;i[o]=t(n[a],a,n)}return i},m.reduce=m.foldl=m.inject=n(1),m.reduceRight=m.foldr=n(-1),m.find=m.detect=function(n,t,r){var e;return e=w(n)?m.findIndex(n,t,r):m.findKey(n,t,r),e!==void 0&&e!==-1?n[e]:void 0},m.filter=m.select=function(n,t,r){var e=[];return t=b(t,r),m.each(n,function(n,r,u){t(n,r,u)&&e.push(n)}),e},m.reject=function(n,t,r){return m.filter(n,m.negate(b(t)),r)},m.every=m.all=function(n,t,r){t=b(t,r);for(var e=!w(n)&&m.keys(n),u=(e||n).length,i=0;u>i;i++){var o=e?e[i]:i;if(!t(n[o],o,n))return!1}return!0},m.some=m.any=function(n,t,r){t=b(t,r);for(var e=!w(n)&&m.keys(n),u=(e||n).length,i=0;u>i;i++){var o=e?e[i]:i;if(t(n[o],o,n))return!0}return!1},m.contains=m.includes=m.include=function(n,t,r){return w(n)||(n=m.values(n)),m.indexOf(n,t,"number"==typeof r&&r)>=0},m.invoke=function(n,t){var r=l.call(arguments,2),e=m.isFunction(t);return m.map(n,function(n){var u=e?t:n[t];return null==u?u:u.apply(n,r)})},m.pluck=function(n,t){return m.map(n,m.property(t))},m.where=function(n,t){return m.filter(n,m.matcher(t))},m.findWhere=function(n,t){return m.find(n,m.matcher(t))},m.max=function(n,t,r){var e,u,i=-1/0,o=-1/0;if(null==t&&null!=n){n=w(n)?n:m.values(n);for(var a=0,c=n.length;c>a;a++)e=n[a],e>i&&(i=e)}else t=b(t,r),m.each(n,function(n,r,e){u=t(n,r,e),(u>o||u===-1/0&&i===-1/0)&&(i=n,o=u)});return i},m.min=function(n,t,r){var e,u,i=1/0,o=1/0;if(null==t&&null!=n){n=w(n)?n:m.values(n);for(var a=0,c=n.length;c>a;a++)e=n[a],i>e&&(i=e)}else t=b(t,r),m.each(n,function(n,r,e){u=t(n,r,e),(o>u||1/0===u&&1/0===i)&&(i=n,o=u)});return i},m.shuffle=function(n){for(var t,r=w(n)?n:m.values(n),e=r.length,u=Array(e),i=0;e>i;i++)t=m.random(0,i),t!==i&&(u[i]=u[t]),u[t]=r[i];return u},m.sample=function(n,t,r){return null==t||r?(w(n)||(n=m.values(n)),n[m.random(n.length-1)]):m.shuffle(n).slice(0,Math.max(0,t))},m.sortBy=function(n,t,r){return t=b(t,r),m.pluck(m.map(n,function(n,r,e){return{value:n,index:r,criteria:t(n,r,e)}}).sort(function(n,t){var r=n.criteria,e=t.criteria;if(r!==e){if(r>e||r===void 0)return 1;if(e>r||e===void 0)return-1}return n.index-t.index}),"value")};var A=function(n){return function(t,r,e){var u={};return r=b(r,e),m.each(t,function(e,i){var o=r(e,i,t);n(u,e,o)}),u}};m.groupBy=A(function(n,t,r){m.has(n,r)?n[r].push(t):n[r]=[t]}),m.indexBy=A(function(n,t,r){n[r]=t}),m.countBy=A(function(n,t,r){m.has(n,r)?n[r]++:n[r]=1}),m.toArray=function(n){return n?m.isArray(n)?l.call(n):w(n)?m.map(n,m.identity):m.values(n):[]},m.size=function(n){return null==n?0:w(n)?n.length:m.keys(n).length},m.partition=function(n,t,r){t=b(t,r);var e=[],u=[];return m.each(n,function(n,r,i){(t(n,r,i)?e:u).push(n)}),[e,u]},m.first=m.head=m.take=function(n,t,r){return null==n?void 0:null==t||r?n[0]:m.initial(n,n.length-t)},m.initial=function(n,t,r){return l.call(n,0,Math.max(0,n.length-(null==t||r?1:t)))},m.last=function(n,t,r){return null==n?void 0:null==t||r?n[n.length-1]:m.rest(n,Math.max(0,n.length-t))},m.rest=m.tail=m.drop=function(n,t,r){return l.call(n,null==t||r?1:t)},m.compact=function(n){return m.filter(n,m.identity)};var k=function(n,t,r,e){for(var u=[],i=0,o=e||0,a=n&&n.length;a>o;o++){var c=n[o];if(w(c)&&(m.isArray(c)||m.isArguments(c))){t||(c=k(c,t,r));var l=0,f=c.length;for(u.length+=f;f>l;)u[i++]=c[l++]}else r||(u[i++]=c)}return u};m.flatten=function(n,t){return k(n,t,!1)},m.without=function(n){return m.difference(n,l.call(arguments,1))},m.uniq=m.unique=function(n,t,r,e){if(null==n)return[];m.isBoolean(t)||(e=r,r=t,t=!1),null!=r&&(r=b(r,e));for(var u=[],i=[],o=0,a=n.length;a>o;o++){var c=n[o],l=r?r(c,o,n):c;t?(o&&i===l||u.push(c),i=l):r?m.contains(i,l)||(i.push(l),u.push(c)):m.contains(u,c)||u.push(c)}return u},m.union=function(){return m.uniq(k(arguments,!0,!0))},m.intersection=function(n){if(null==n)return[];for(var t=[],r=arguments.length,e=0,u=n.length;u>e;e++){var i=n[e];if(!m.contains(t,i)){for(var o=1;r>o&&m.contains(arguments[o],i);o++);o===r&&t.push(i)}}return t},m.difference=function(n){var t=k(arguments,!0,!0,1);return m.filter(n,function(n){return!m.contains(t,n)})},m.zip=function(){return m.unzip(arguments)},m.unzip=function(n){for(var t=n&&m.max(n,"length").length||0,r=Array(t),e=0;t>e;e++)r[e]=m.pluck(n,e);return r},m.object=function(n,t){for(var r={},e=0,u=n&&n.length;u>e;e++)t?r[n[e]]=t[e]:r[n[e][0]]=n[e][1];return r},m.indexOf=function(n,t,r){var e=0,u=n&&n.length;if("number"==typeof r)e=0>r?Math.max(0,u+r):r;else if(r&&u)return e=m.sortedIndex(n,t),n[e]===t?e:-1;if(t!==t)return m.findIndex(l.call(n,e),m.isNaN);for(;u>e;e++)if(n[e]===t)return e;return-1},m.lastIndexOf=function(n,t,r){var e=n?n.length:0;if("number"==typeof r&&(e=0>r?e+r+1:Math.min(e,r+1)),t!==t)return m.findLastIndex(l.call(n,0,e),m.isNaN);for(;--e>=0;)if(n[e]===t)return e;return-1},m.findIndex=t(1),m.findLastIndex=t(-1),m.sortedIndex=function(n,t,r,e){r=b(r,e,1);for(var u=r(t),i=0,o=n.length;o>i;){var a=Math.floor((i+o)/2);r(n[a])i;i++,n+=r)u[i]=n;return u};var O=function(n,t,r,e,u){if(!(e instanceof t))return n.apply(r,u);var i=_(n.prototype),o=n.apply(i,u);return m.isObject(o)?o:i};m.bind=function(n,t){if(v&&n.bind===v)return v.apply(n,l.call(arguments,1));if(!m.isFunction(n))throw new TypeError("Bind must be called on a function");var r=l.call(arguments,2),e=function(){return O(n,e,t,this,r.concat(l.call(arguments)))};return e},m.partial=function(n){var t=l.call(arguments,1),r=function(){for(var e=0,u=t.length,i=Array(u),o=0;u>o;o++)i[o]=t[o]===m?arguments[e++]:t[o];for(;e=e)throw new Error("bindAll must be passed function names");for(t=1;e>t;t++)r=arguments[t],n[r]=m.bind(n[r],n);return n},m.memoize=function(n,t){var r=function(e){var u=r.cache,i=""+(t?t.apply(this,arguments):e);return m.has(u,i)||(u[i]=n.apply(this,arguments)),u[i]};return r.cache={},r},m.delay=function(n,t){var r=l.call(arguments,2);return setTimeout(function(){return n.apply(null,r)},t)},m.defer=m.partial(m.delay,m,1),m.throttle=function(n,t,r){var e,u,i,o=null,a=0;r||(r={});var c=function(){a=r.leading===!1?0:m.now(),o=null,i=n.apply(e,u),o||(e=u=null)};return function(){var l=m.now();a||r.leading!==!1||(a=l);var f=t-(l-a);return e=this,u=arguments,0>=f||f>t?(o&&(clearTimeout(o),o=null),a=l,i=n.apply(e,u),o||(e=u=null)):o||r.trailing===!1||(o=setTimeout(c,f)),i}},m.debounce=function(n,t,r){var e,u,i,o,a,c=function(){var l=m.now()-o;t>l&&l>=0?e=setTimeout(c,t-l):(e=null,r||(a=n.apply(i,u),e||(i=u=null)))};return function(){i=this,u=arguments,o=m.now();var l=r&&!e;return e||(e=setTimeout(c,t)),l&&(a=n.apply(i,u),i=u=null),a}},m.wrap=function(n,t){return m.partial(t,n)},m.negate=function(n){return function(){return!n.apply(this,arguments)}},m.compose=function(){var n=arguments,t=n.length-1;return function(){for(var r=t,e=n[t].apply(this,arguments);r--;)e=n[r].call(this,e);return e}},m.after=function(n,t){return function(){return--n<1?t.apply(this,arguments):void 0}},m.before=function(n,t){var r;return function(){return--n>0&&(r=t.apply(this,arguments)),1>=n&&(t=null),r}},m.once=m.partial(m.before,2);var F=!{toString:null}.propertyIsEnumerable("toString"),S=["valueOf","isPrototypeOf","toString","propertyIsEnumerable","hasOwnProperty","toLocaleString"];m.keys=function(n){if(!m.isObject(n))return[];if(h)return h(n);var t=[];for(var e in n)m.has(n,e)&&t.push(e);return F&&r(n,t),t},m.allKeys=function(n){if(!m.isObject(n))return[];var t=[];for(var e in n)t.push(e);return F&&r(n,t),t},m.values=function(n){for(var t=m.keys(n),r=t.length,e=Array(r),u=0;r>u;u++)e[u]=n[t[u]];return e},m.mapObject=function(n,t,r){t=b(t,r);for(var e,u=m.keys(n),i=u.length,o={},a=0;i>a;a++)e=u[a],o[e]=t(n[e],e,n);return o},m.pairs=function(n){for(var t=m.keys(n),r=t.length,e=Array(r),u=0;r>u;u++)e[u]=[t[u],n[t[u]]];return e},m.invert=function(n){for(var t={},r=m.keys(n),e=0,u=r.length;u>e;e++)t[n[r[e]]]=r[e];return t},m.functions=m.methods=function(n){var t=[];for(var r in n)m.isFunction(n[r])&&t.push(r);return t.sort()},m.extend=x(m.allKeys),m.extendOwn=m.assign=x(m.keys),m.findKey=function(n,t,r){t=b(t,r);for(var e,u=m.keys(n),i=0,o=u.length;o>i;i++)if(e=u[i],t(n[e],e,n))return e},m.pick=function(n,t,r){var e,u,i={},o=n;if(null==o)return i;m.isFunction(t)?(u=m.allKeys(o),e=d(t,r)):(u=k(arguments,!1,!1,1),e=function(n,t,r){return t in r},o=Object(o));for(var a=0,c=u.length;c>a;a++){var l=u[a],f=o[l];e(f,l,o)&&(i[l]=f)}return i},m.omit=function(n,t,r){if(m.isFunction(t))t=m.negate(t);else{var e=m.map(k(arguments,!1,!1,1),String);t=function(n,t){return!m.contains(e,t)}}return m.pick(n,t,r)},m.defaults=x(m.allKeys,!0),m.clone=function(n){return m.isObject(n)?m.isArray(n)?n.slice():m.extend({},n):n},m.tap=function(n,t){return t(n),n},m.isMatch=function(n,t){var r=m.keys(t),e=r.length;if(null==n)return!e;for(var u=Object(n),i=0;e>i;i++){var o=r[i];if(t[o]!==u[o]||!(o in u))return!1}return!0};var E=function(n,t,r,e){if(n===t)return 0!==n||1/n===1/t;if(null==n||null==t)return n===t;n instanceof m&&(n=n._wrapped),t instanceof m&&(t=t._wrapped);var u=f.call(n);if(u!==f.call(t))return!1;switch(u){case"[object RegExp]":case"[object String]":return""+n==""+t;case"[object Number]":return+n!==+n?+t!==+t:0===+n?1/+n===1/t:+n===+t;case"[object Date]":case"[object Boolean]":return+n===+t}var i="[object Array]"===u;if(!i){if("object"!=typeof n||"object"!=typeof t)return!1;var o=n.constructor,a=t.constructor;if(o!==a&&!(m.isFunction(o)&&o instanceof o&&m.isFunction(a)&&a instanceof a)&&"constructor"in n&&"constructor"in t)return!1}r=r||[],e=e||[];for(var c=r.length;c--;)if(r[c]===n)return e[c]===t;if(r.push(n),e.push(t),i){if(c=n.length,c!==t.length)return!1;for(;c--;)if(!E(n[c],t[c],r,e))return!1}else{var l,s=m.keys(n);if(c=s.length,m.keys(t).length!==c)return!1;for(;c--;)if(l=s[c],!m.has(t,l)||!E(n[l],t[l],r,e))return!1}return r.pop(),e.pop(),!0};m.isEqual=function(n,t){return E(n,t)},m.isEmpty=function(n){return null==n?!0:w(n)&&(m.isArray(n)||m.isString(n)||m.isArguments(n))?0===n.length:0===m.keys(n).length},m.isElement=function(n){return!(!n||1!==n.nodeType)},m.isArray=p||function(n){return"[object Array]"===f.call(n)},m.isObject=function(n){var t=typeof n;return"function"===t||"object"===t&&!!n},m.each(["Arguments","Function","String","Number","Date","RegExp","Error"],function(n){m["is"+n]=function(t){return f.call(t)==="[object "+n+"]"}}),m.isArguments(arguments)||(m.isArguments=function(n){return m.has(n,"callee")}),"function"!=typeof/./&&"object"!=typeof Int8Array&&(m.isFunction=function(n){return"function"==typeof n||!1}),m.isFinite=function(n){return isFinite(n)&&!isNaN(parseFloat(n))},m.isNaN=function(n){return m.isNumber(n)&&n!==+n},m.isBoolean=function(n){return n===!0||n===!1||"[object Boolean]"===f.call(n)},m.isNull=function(n){return null===n},m.isUndefined=function(n){return n===void 0},m.has=function(n,t){return null!=n&&s.call(n,t)},m.noConflict=function(){return e._=u,this},m.identity=function(n){return n},m.constant=function(n){return function(){return n}},m.noop=function(){},m.property=function(n){return function(t){return null==t?void 0:t[n]}},m.propertyOf=function(n){return null==n?function(){}:function(t){return n[t]}},m.matcher=m.matches=function(n){return n=m.extendOwn({},n),function(t){return m.isMatch(t,n)}},m.times=function(n,t,r){var e=Array(Math.max(0,n));t=d(t,r,1);for(var u=0;n>u;u++)e[u]=t(u);return e},m.random=function(n,t){return null==t&&(t=n,n=0),n+Math.floor(Math.random()*(t-n+1))},m.now=Date.now||function(){return(new Date).getTime()};var M={"&":"&","<":"<",">":">",'"':""","'":"'","`":"`"},N=m.invert(M),I=function(n){var t=function(t){return n[t]},r="(?:"+m.keys(n).join("|")+")",e=RegExp(r),u=RegExp(r,"g");return function(n){return n=null==n?"":""+n,e.test(n)?n.replace(u,t):n}};m.escape=I(M),m.unescape=I(N),m.result=function(n,t,r){var e=null==n?void 0:n[t];return e===void 0&&(e=r),m.isFunction(e)?e.call(n):e};var B=0;m.uniqueId=function(n){var t=++B+"";return n?n+t:t},m.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var T=/(.)^/,R={"'":"'","\\":"\\","\r":"r","\n":"n","\u2028":"u2028","\u2029":"u2029"},q=/\\|'|\r|\n|\u2028|\u2029/g,K=function(n){return"\\"+R[n]};m.template=function(n,t,r){!t&&r&&(t=r),t=m.defaults({},t,m.templateSettings);var e=RegExp([(t.escape||T).source,(t.interpolate||T).source,(t.evaluate||T).source].join("|")+"|$","g"),u=0,i="__p+='";n.replace(e,function(t,r,e,o,a){return i+=n.slice(u,a).replace(q,K),u=a+t.length,r?i+="'+\n((__t=("+r+"))==null?'':_.escape(__t))+\n'":e?i+="'+\n((__t=("+e+"))==null?'':__t)+\n'":o&&(i+="';\n"+o+"\n__p+='"),t}),i+="';\n",t.variable||(i="with(obj||{}){\n"+i+"}\n"),i="var __t,__p='',__j=Array.prototype.join,"+"print=function(){__p+=__j.call(arguments,'');};\n"+i+"return __p;\n";try{var o=new Function(t.variable||"obj","_",i)}catch(a){throw a.source=i,a}var c=function(n){return o.call(this,n,m)},l=t.variable||"obj";return c.source="function("+l+"){\n"+i+"}",c},m.chain=function(n){var t=m(n);return t._chain=!0,t};var z=function(n,t){return n._chain?m(t).chain():t};m.mixin=function(n){m.each(m.functions(n),function(t){var r=m[t]=n[t];m.prototype[t]=function(){var n=[this._wrapped];return c.apply(n,arguments),z(this,r.apply(m,n))}})},m.mixin(m),m.each(["pop","push","reverse","shift","sort","splice","unshift"],function(n){var t=i[n];m.prototype[n]=function(){var r=this._wrapped;return t.apply(r,arguments),"shift"!==n&&"splice"!==n||0!==r.length||delete r[0],z(this,r)}}),m.each(["concat","join","slice"],function(n){var t=i[n];m.prototype[n]=function(){return z(this,t.apply(this._wrapped,arguments))}}),m.prototype.value=function(){return this._wrapped},m.prototype.valueOf=m.prototype.toJSON=m.prototype.value,m.prototype.toString=function(){return""+this._wrapped},"function"==typeof define&&define.amd&&define("underscore",[],function(){return m})}).call(this); \ No newline at end of file diff --git a/static/js/mdeditor/markdown-it.min.js b/static/js/mdeditor/markdown-it.min.js deleted file mode 100644 index 11118314..00000000 --- a/static/js/mdeditor/markdown-it.min.js +++ /dev/null @@ -1 +0,0 @@ -!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).markdownit=e()}}(function(){return function e(r,t,n){function s(i,a){if(!t[i]){if(!r[i]){var c="function"==typeof require&&require;if(!a&&c)return c(i,!0);if(o)return o(i,!0);var l=new Error("Cannot find module '"+i+"'");throw l.code="MODULE_NOT_FOUND",l}var u=t[i]={exports:{}};r[i][0].call(u.exports,function(e){var t=r[i][1][e];return s(t||e)},u,u.exports,e,r,t,n)}return t[i].exports}for(var o="function"==typeof require&&require,i=0;i`\\x00-\\x20]+|'[^']*'|\"[^\"]*\"))?)*\\s*\\/?>",s="<\\/[A-Za-z][A-Za-z0-9\\-]*\\s*>",o=new RegExp("^(?:"+n+"|"+s+"|\x3c!----\x3e|\x3c!--(?:-?[^>-])(?:-?[^-])*--\x3e|<[?].*?[?]>|]*>|)"),i=new RegExp("^(?:"+n+"|"+s+")");r.exports.HTML_TAG_RE=o,r.exports.HTML_OPEN_CLOSE_TAG_RE=i},{}],4:[function(e,r,t){"use strict";function n(e){return Object.prototype.toString.call(e)}function s(e,r){return l.call(e,r)}function o(e){return!(e>=55296&&e<=57343)&&(!(e>=64976&&e<=65007)&&(65535!=(65535&e)&&65534!=(65535&e)&&(!(e>=0&&e<=8)&&(11!==e&&(!(e>=14&&e<=31)&&(!(e>=127&&e<=159)&&!(e>1114111)))))))}function i(e){if(e>65535){var r=55296+((e-=65536)>>10),t=56320+(1023&e);return String.fromCharCode(r,t)}return String.fromCharCode(e)}function a(e,r){var t=0;return s(d,r)?d[r]:35===r.charCodeAt(0)&&f.test(r)&&(t="x"===r[1].toLowerCase()?parseInt(r.slice(2),16):parseInt(r.slice(1),10),o(t))?i(t):e}function c(e){return g[e]}var l=Object.prototype.hasOwnProperty,u=/\\([!"#$%&'()*+,\-.\/:;<=>?@[\\\]^_`{|}~])/g,p=/&([a-z#][a-z0-9]{1,31});/gi,h=new RegExp(u.source+"|"+p.source,"gi"),f=/^#((?:x[a-f0-9]{1,8}|[0-9]{1,8}))/i,d=e("./entities"),m=/[&<>"]/,_=/[&<>"]/g,g={"&":"&","<":"<",">":">",'"':"""},b=/[.?*+^$[\]\\(){}|-]/g,k=e("uc.micro/categories/P/regex");t.lib={},t.lib.mdurl=e("mdurl"),t.lib.ucmicro=e("uc.micro"),t.assign=function(e){return Array.prototype.slice.call(arguments,1).forEach(function(r){if(r){if("object"!=typeof r)throw new TypeError(r+"must be object");Object.keys(r).forEach(function(t){e[t]=r[t]})}}),e},t.isString=function(e){return"[object String]"===n(e)},t.has=s,t.unescapeMd=function(e){return e.indexOf("\\")<0?e:e.replace(u,"$1")},t.unescapeAll=function(e){return e.indexOf("\\")<0&&e.indexOf("&")<0?e:e.replace(h,function(e,r,t){return r||a(e,t)})},t.isValidEntityCode=o,t.fromCodePoint=i,t.escapeHtml=function(e){return m.test(e)?e.replace(_,c):e},t.arrayReplaceAt=function(e,r,t){return[].concat(e.slice(0,r),t,e.slice(r+1))},t.isSpace=function(e){switch(e){case 9:case 32:return!0}return!1},t.isWhiteSpace=function(e){if(e>=8192&&e<=8202)return!0;switch(e){case 9:case 10:case 11:case 12:case 13:case 32:case 160:case 5760:case 8239:case 8287:case 12288:return!0}return!1},t.isMdAsciiPunct=function(e){switch(e){case 33:case 34:case 35:case 36:case 37:case 38:case 39:case 40:case 41:case 42:case 43:case 44:case 45:case 46:case 47:case 58:case 59:case 60:case 61:case 62:case 63:case 64:case 91:case 92:case 93:case 94:case 95:case 96:case 123:case 124:case 125:case 126:return!0;default:return!1}},t.isPunctChar=function(e){return k.test(e)},t.escapeRE=function(e){return e.replace(b,"\\$&")},t.normalizeReference=function(e){return e.trim().replace(/\s+/g," ").toUpperCase()}},{"./entities":1,mdurl:58,"uc.micro":65,"uc.micro/categories/P/regex":63}],5:[function(e,r,t){"use strict";t.parseLinkLabel=e("./parse_link_label"),t.parseLinkDestination=e("./parse_link_destination"),t.parseLinkTitle=e("./parse_link_title")},{"./parse_link_destination":6,"./parse_link_label":7,"./parse_link_title":8}],6:[function(e,r,t){"use strict";var n=e("../common/utils").isSpace,s=e("../common/utils").unescapeAll;r.exports=function(e,r,t){var o,i,a=r,c={ok:!1,pos:0,lines:0,str:""};if(60===e.charCodeAt(r)){for(r++;r=t)return c;if(34!==(o=e.charCodeAt(r))&&39!==o&&40!==o)return c;for(r++,40===o&&(o=41);r=0))try{r.hostname=m.toASCII(r.hostname)}catch(e){}return d.encode(d.format(r))}function o(e){var r=d.parse(e,!0);if(r.hostname&&(!r.protocol||k.indexOf(r.protocol)>=0))try{r.hostname=m.toUnicode(r.hostname)}catch(e){}return d.decode(d.format(r))}function i(e,r){if(!(this instanceof i))return new i(e,r);r||a.isString(e)||(r=e||{},e="default"),this.inline=new h,this.block=new p,this.core=new u,this.renderer=new l,this.linkify=new f,this.validateLink=n,this.normalizeLink=s,this.normalizeLinkText=o,this.utils=a,this.helpers=a.assign({},c),this.options={},this.configure(e),r&&this.set(r)}var a=e("./common/utils"),c=e("./helpers"),l=e("./renderer"),u=e("./parser_core"),p=e("./parser_block"),h=e("./parser_inline"),f=e("linkify-it"),d=e("mdurl"),m=e("punycode"),_={default:e("./presets/default"),zero:e("./presets/zero"),commonmark:e("./presets/commonmark")},g=/^(vbscript|javascript|file|data):/,b=/^data:image\/(gif|png|jpeg|webp);/,k=["http:","https:","mailto:"];i.prototype.set=function(e){return a.assign(this.options,e),this},i.prototype.configure=function(e){var r,t=this;if(a.isString(e)&&(r=e,!(e=_[r])))throw new Error('Wrong `markdown-it` preset "'+r+'", check name');if(!e)throw new Error("Wrong `markdown-it` preset, can't be empty");return e.options&&t.set(e.options),e.components&&Object.keys(e.components).forEach(function(r){e.components[r].rules&&t[r].ruler.enableOnly(e.components[r].rules),e.components[r].rules2&&t[r].ruler2.enableOnly(e.components[r].rules2)}),this},i.prototype.enable=function(e,r){var t=[];Array.isArray(e)||(e=[e]),["core","block","inline"].forEach(function(r){t=t.concat(this[r].ruler.enable(e,!0))},this),t=t.concat(this.inline.ruler2.enable(e,!0));var n=e.filter(function(e){return t.indexOf(e)<0});if(n.length&&!r)throw new Error("MarkdownIt. Failed to enable unknown rule(s): "+n);return this},i.prototype.disable=function(e,r){var t=[];Array.isArray(e)||(e=[e]),["core","block","inline"].forEach(function(r){t=t.concat(this[r].ruler.disable(e,!0))},this),t=t.concat(this.inline.ruler2.disable(e,!0));var n=e.filter(function(e){return t.indexOf(e)<0});if(n.length&&!r)throw new Error("MarkdownIt. Failed to disable unknown rule(s): "+n);return this},i.prototype.use=function(e){var r=[this].concat(Array.prototype.slice.call(arguments,1));return e.apply(e,r),this},i.prototype.parse=function(e,r){if("string"!=typeof e)throw new Error("Input data should be a String");var t=new this.core.State(e,this,r);return this.core.process(t),t.tokens},i.prototype.render=function(e,r){return r=r||{},this.renderer.render(this.parse(e,r),this.options,r)},i.prototype.parseInline=function(e,r){var t=new this.core.State(e,this,r);return t.inlineMode=!0,this.core.process(t),t.tokens},i.prototype.renderInline=function(e,r){return r=r||{},this.renderer.render(this.parseInline(e,r),this.options,r)},r.exports=i},{"./common/utils":4,"./helpers":5,"./parser_block":10,"./parser_core":11,"./parser_inline":12,"./presets/commonmark":13,"./presets/default":14,"./presets/zero":15,"./renderer":16,"linkify-it":53,mdurl:58,punycode:60}],10:[function(e,r,t){"use strict";function n(){this.ruler=new s;for(var e=0;e=t))&&!(e.sCount[i]=c){e.line=t;break}for(n=0;n=o)break}else e.pending+=e.src[e.pos++]}e.pending&&e.pushPending()},n.prototype.parse=function(e,r,t,n){var s,o,i,a=new this.State(e,r,t,n);for(this.tokenize(a),i=(o=this.ruler2.getRules("")).length,s=0;s"+i(e[r].content)+""},a.code_block=function(e,r,t,n,s){var o=e[r];return""+i(e[r].content)+"\n"},a.fence=function(e,r,t,n,s){var a,c,l,u,p=e[r],h=p.info?o(p.info).trim():"",f="";return h&&(f=h.split(/\s+/g)[0]),0===(a=t.highlight?t.highlight(p.content,f)||i(p.content):i(p.content)).indexOf(""+a+"\n"):"
    "+a+"
    \n"},a.image=function(e,r,t,n,s){var o=e[r];return o.attrs[o.attrIndex("alt")][1]=s.renderInlineAsText(o.children,t,n),s.renderToken(e,r,t)},a.hardbreak=function(e,r,t){return t.xhtmlOut?"
    \n":"
    \n"},a.softbreak=function(e,r,t){return t.breaks?t.xhtmlOut?"
    \n":"
    \n":"\n"},a.text=function(e,r){return i(e[r].content)},a.html_block=function(e,r){return e[r].content},a.html_inline=function(e,r){return e[r].content},n.prototype.renderAttrs=function(e){var r,t,n;if(!e.attrs)return"";for(n="",r=0,t=e.attrs.length;r\n":">")},n.prototype.renderInline=function(e,r,t){for(var n,s="",o=this.rules,i=0,a=e.length;i=4)return!1;if(62!==e.src.charCodeAt(D++))return!1;if(s)return!0;for(c=f=e.sCount[r]+D-(e.bMarks[r]+e.tShift[r]),32===e.src.charCodeAt(D)?(D++,c++,f++,o=!1,v=!0):9===e.src.charCodeAt(D)?(v=!0,(e.bsCount[r]+f)%4==3?(D++,c++,f++,o=!1):o=!0):v=!1,d=[e.bMarks[r]],e.bMarks[r]=D;D=q,b=[e.sCount[r]],e.sCount[r]=f-c,k=[e.tShift[r]],e.tShift[r]=D-e.bMarks[r],y=e.md.block.ruler.getRules("blockquote"),g=e.parentType,e.parentType="blockquote",A=!1,h=r+1;h=q));h++)if(62!==e.src.charCodeAt(D++)||A){if(u)break;for(x=!1,a=0,l=y.length;a=q,m.push(e.bsCount[h]),e.bsCount[h]=e.sCount[h]+1+(v?1:0),b.push(e.sCount[h]),e.sCount[h]=f-c,k.push(e.tShift[h]),e.tShift[h]=D-e.bMarks[h]}for(_=e.blkIndent,e.blkIndent=0,(C=e.push("blockquote_open","blockquote",1)).markup=">",C.map=p=[r,0],e.md.block.tokenize(e,r,h),(C=e.push("blockquote_close","blockquote",-1)).markup=">",e.lineMax=w,e.parentType=g,p[1]=e.line,a=0;a=4))break;s=++n}return e.line=s,o=e.push("code_block","code",0),o.content=e.getLines(r,s,4+e.blkIndent,!0),o.map=[r,e.line],!0}},{}],20:[function(e,r,t){"use strict";r.exports=function(e,r,t,n){var s,o,i,a,c,l,u,p=!1,h=e.bMarks[r]+e.tShift[r],f=e.eMarks[r];if(e.sCount[r]-e.blkIndent>=4)return!1;if(h+3>f)return!1;if(126!==(s=e.src.charCodeAt(h))&&96!==s)return!1;if(c=h,h=e.skipChars(h,s),(o=h-c)<3)return!1;if(u=e.src.slice(c,h),(i=e.src.slice(h,f)).indexOf(String.fromCharCode(s))>=0)return!1;if(n)return!0;for(a=r;!(++a>=t)&&(h=c=e.bMarks[a]+e.tShift[a],f=e.eMarks[a],!(h=4||(h=e.skipChars(h,s))-c=4)return!1;if(35!==(o=e.src.charCodeAt(l))||l>=u)return!1;for(i=1,o=e.src.charCodeAt(++l);35===o&&l6||ll&&n(e.src.charCodeAt(a-1))&&(u=a),e.line=r+1,c=e.push("heading_open","h"+String(i),1),c.markup="########".slice(0,i),c.map=[r,e.line],c=e.push("inline","",0),c.content=e.src.slice(l,u).trim(),c.map=[r,e.line],c.children=[],c=e.push("heading_close","h"+String(i),-1),c.markup="########".slice(0,i),!0))}},{"../common/utils":4}],22:[function(e,r,t){"use strict";var n=e("../common/utils").isSpace;r.exports=function(e,r,t,s){var o,i,a,c,l=e.bMarks[r]+e.tShift[r],u=e.eMarks[r];if(e.sCount[r]-e.blkIndent>=4)return!1;if(42!==(o=e.src.charCodeAt(l++))&&45!==o&&95!==o)return!1;for(i=1;l|$))/i,/<\/(script|pre|style)>/i,!0],[/^/,!0],[/^<\?/,/\?>/,!0],[/^/,!0],[/^/,!0],[new RegExp("^|$))","i"),/^$/,!0],[new RegExp(s.source+"\\s*$"),/^$/,!1]];r.exports=function(e,r,t,n){var s,i,a,c,l=e.bMarks[r]+e.tShift[r],u=e.eMarks[r];if(e.sCount[r]-e.blkIndent>=4)return!1;if(!e.md.options.html)return!1;if(60!==e.src.charCodeAt(l))return!1;for(c=e.src.slice(l,u),s=0;s=4)return!1;for(h=e.parentType,e.parentType="paragraph";f3)){if(e.sCount[f]>=e.blkIndent&&(c=e.bMarks[f]+e.tShift[f],l=e.eMarks[f],c=l))){u=61===p?1:2;break}if(!(e.sCount[f]<0)){for(s=!1,o=0,i=d.length;o=o)return-1;if((t=e.src.charCodeAt(s++))<48||t>57)return-1;for(;;){if(s>=o)return-1;if(!((t=e.src.charCodeAt(s++))>=48&&t<=57)){if(41===t||46===t)break;return-1}if(s-n>=10)return-1}return s=4)return!1;if(i&&"paragraph"===e.parentType&&e.tShift[r]>=e.blkIndent&&(R=!0),(S=s(e,r))>=0){if(f=!0,L=e.bMarks[r]+e.tShift[r],k=Number(e.src.substr(L,S-L-1)),R&&1!==k)return!1}else{if(!((S=n(e,r))>=0))return!1;f=!1}if(R&&e.skipSpaces(S)>=e.eMarks[r])return!1;if(b=e.src.charCodeAt(S-1),i)return!0;for(g=e.tokens.length,f?(I=e.push("ordered_list_open","ol",1),1!==k&&(I.attrs=[["start",k]])):I=e.push("bullet_list_open","ul",1),I.map=_=[r,0],I.markup=String.fromCharCode(b),x=r,F=!1,T=e.md.block.ruler.getRules("list"),w=e.parentType,e.parentType="list";x=v?1:y-h)>4&&(p=1),u=h+p,I=e.push("list_item_open","li",1),I.markup=String.fromCharCode(b),I.map=d=[r,0],C=e.blkIndent,q=e.tight,D=e.tShift[r],A=e.sCount[r],e.blkIndent=u,e.tight=!0,e.tShift[r]=c-e.bMarks[r],e.sCount[r]=y,c>=v&&e.isEmpty(r+1)?e.line=Math.min(e.line+2,t):e.md.block.tokenize(e,r,t,!0),e.tight&&!F||(M=!1),F=e.line-r>1&&e.isEmpty(e.line-1),e.blkIndent=C,e.tShift[r]=D,e.sCount[r]=A,e.tight=q,I=e.push("list_item_close","li",-1),I.markup=String.fromCharCode(b),x=r=e.line,d[1]=x,c=e.bMarks[r],x>=t)break;if(e.sCount[x]3||e.sCount[c]<0)){for(n=!1,s=0,o=l.length;s=4)return!1;if(91!==e.src.charCodeAt(C))return!1;for(;++C3||e.sCount[w]<0)){for(k=!1,p=0,h=v.length;p0&&this.level++,this.tokens.push(n),n},n.prototype.isEmpty=function(e){return this.bMarks[e]+this.tShift[e]>=this.eMarks[e]},n.prototype.skipEmptyLines=function(e){for(var r=this.lineMax;er;)if(!o(this.src.charCodeAt(--e)))return e+1;return e},n.prototype.skipChars=function(e,r){for(var t=this.src.length;et;)if(r!==this.src.charCodeAt(--e))return e+1;return e},n.prototype.getLines=function(e,r,t,n){var s,i,a,c,l,u,p,h=e;if(e>=r)return"";for(u=new Array(r-e),s=0;ht?new Array(i-t+1).join(" ")+this.src.slice(c,l):this.src.slice(c,l)}return u.join("")},n.prototype.Token=s,r.exports=n},{"../common/utils":4,"../token":51}],29:[function(e,r,t){"use strict";function n(e,r){var t=e.bMarks[r]+e.blkIndent,n=e.eMarks[r];return e.src.substr(t,n-t)}function s(e){var r,t=[],n=0,s=e.length,o=0,i=0,a=!1,c=0;for(r=e.charCodeAt(n);nt)return!1;if(p=r+1,e.sCount[p]=4)return!1;if((l=e.bMarks[p]+e.tShift[p])>=e.eMarks[p])return!1;if(124!==(a=e.src.charCodeAt(l++))&&45!==a&&58!==a)return!1;for(;l=4)return!1;if(h=s(c.replace(/^\||\|$/g,"")),(f=h.length)>m.length)return!1;if(i)return!0;for((d=e.push("table_open","table",1)).map=g=[r,0],(d=e.push("thead_open","thead",1)).map=[r,r+1],(d=e.push("tr_open","tr",1)).map=[r,r+1],u=0;u=4);p++){for(h=s(c.replace(/^\||\|$/g,"")),d=e.push("tr_open","tr",1),u=0;u\s]/i.test(e)}function s(e){return/^<\/a\s*>/i.test(e)}var o=e("../common/utils").arrayReplaceAt;r.exports=function(e){var r,t,i,a,c,l,u,p,h,f,d,m,_,g,b,k,v,x=e.tokens;if(e.md.options.linkify)for(t=0,i=x.length;t=0;r--)if("link_close"!==(l=a[r]).type){if("html_inline"===l.type&&(n(l.content)&&_>0&&_--,s(l.content)&&_++),!(_>0)&&"text"===l.type&&e.md.linkify.test(l.content)){for(h=l.content,v=e.md.linkify.match(h),u=[],m=l.level,d=0,p=0;pd&&((c=new e.Token("text","",0)).content=h.slice(d,f),c.level=m,u.push(c)),(c=new e.Token("link_open","a",1)).attrs=[["href",b]],c.level=m++,c.markup="linkify",c.info="auto",u.push(c),(c=new e.Token("text","",0)).content=k,c.level=m,u.push(c),(c=new e.Token("link_close","a",-1)).level=--m,c.markup="linkify",c.info="auto",u.push(c),d=v[p].lastIndex);d=0;r--)"text"!==(t=e[r]).type||s||(t.content=t.content.replace(c,n)),"link_open"===t.type&&"auto"===t.info&&s--,"link_close"===t.type&&"auto"===t.info&&s++}function o(e){var r,t,n=0;for(r=e.length-1;r>=0;r--)"text"!==(t=e[r]).type||n||i.test(t.content)&&(t.content=t.content.replace(/\+-/g,"\xb1").replace(/\.{2,}/g,"\u2026").replace(/([?!])\u2026/g,"$1..").replace(/([?!]){4,}/g,"$1$1$1").replace(/,{2,}/g,",").replace(/(^|[^-])---([^-]|$)/gm,"$1\u2014$2").replace(/(^|\s)--(\s|$)/gm,"$1\u2013$2").replace(/(^|[^-\s])--([^-\s]|$)/gm,"$1\u2013$2")),"link_open"===t.type&&"auto"===t.info&&n--,"link_close"===t.type&&"auto"===t.info&&n++}var i=/\+-|\.\.|\?\?\?\?|!!!!|,,|--/,a=/\((c|tm|r|p)\)/i,c=/\((c|tm|r|p)\)/gi,l={c:"\xa9",r:"\xae",p:"\xa7",tm:"\u2122"};r.exports=function(e){var r;if(e.md.options.typographer)for(r=e.tokens.length-1;r>=0;r--)"inline"===e.tokens[r].type&&(a.test(e.tokens[r].content)&&s(e.tokens[r].children),i.test(e.tokens[r].content)&&o(e.tokens[r].children))}},{}],35:[function(e,r,t){"use strict";function n(e,r,t){return e.substr(0,r)+t+e.substr(r+1)}function s(e,r){var t,s,c,p,h,f,d,m,_,g,b,k,v,x,y,C,A,w,D,q,E;for(D=[],t=0;t=0&&!(D[A].level<=d);A--);if(D.length=A+1,"text"===s.type){h=0,f=(c=s.content).length;e:for(;h=0)_=c.charCodeAt(p.index-1);else for(A=t-1;A>=0;A--)if("text"===e[A].type){_=e[A].content.charCodeAt(e[A].content.length-1);break}if(g=32,h=48&&_<=57&&(C=y=!1),y&&C&&(y=!1,C=k),y||C){if(C)for(A=D.length-1;A>=0&&(m=D[A],!(D[A].level=0;r--)"inline"===e.tokens[r].type&&c.test(e.tokens[r].content)&&s(e.tokens[r].children,e)}},{"../common/utils":4}],36:[function(e,r,t){"use strict";function n(e,r,t){this.src=e,this.env=t,this.tokens=[],this.inlineMode=!1,this.md=r}var s=e("../token");n.prototype.Token=s,r.exports=n},{"../token":51}],37:[function(e,r,t){"use strict";var n=/^<([a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*)>/,s=/^<([a-zA-Z][a-zA-Z0-9+.\-]{1,31}):([^<>\x00-\x20]*)>/;r.exports=function(e,r){var t,o,i,a,c,l,u=e.pos;return 60===e.src.charCodeAt(u)&&!((t=e.src.slice(u)).indexOf(">")<0||(s.test(t)?(o=t.match(s),a=o[0].slice(1,-1),c=e.md.normalizeLink(a),!e.md.validateLink(c)||(r||((l=e.push("link_open","a",1)).attrs=[["href",c]],l.markup="autolink",l.info="auto",(l=e.push("text","",0)).content=e.md.normalizeLinkText(a),(l=e.push("link_close","a",-1)).markup="autolink",l.info="auto"),e.pos+=o[0].length,0)):!n.test(t)||(i=t.match(n),a=i[0].slice(1,-1),c=e.md.normalizeLink("mailto:"+a),!e.md.validateLink(c)||(r||((l=e.push("link_open","a",1)).attrs=[["href",c]],l.markup="autolink",l.info="auto",(l=e.push("text","",0)).content=e.md.normalizeLinkText(a),(l=e.push("link_close","a",-1)).markup="autolink",l.info="auto"),e.pos+=i[0].length,0))))}},{}],38:[function(e,r,t){"use strict";r.exports=function(e,r){var t,n,s,o,i,a,c=e.pos;if(96!==e.src.charCodeAt(c))return!1;for(t=c,c++,n=e.posMax;c=0;){if((s=o[t]).open&&s.marker===n.marker&&s.end<0&&s.level===n.level&&!((s.close||n.open)&&void 0!==s.length&&void 0!==n.length&&(s.length+n.length)%3==0)){n.jump=r-t,n.open=!1,s.end=r,s.jump=0;break}t-=s.jump+1}}},{}],40:[function(e,r,t){"use strict";r.exports.tokenize=function(e,r){var t,n,s=e.pos,o=e.src.charCodeAt(s);if(r)return!1;if(95!==o&&42!==o)return!1;for(n=e.scanDelims(e.pos,42===o),t=0;t=0;r--)95!==(t=a[r]).marker&&42!==t.marker||-1!==t.end&&(n=a[t.end],i=r>0&&a[r-1].end===t.end+1&&a[r-1].token===t.token-1&&a[t.end+1].token===n.token+1&&a[r-1].marker===t.marker,o=String.fromCharCode(t.marker),(s=e.tokens[t.token]).type=i?"strong_open":"em_open",s.tag=i?"strong":"em",s.nesting=1,s.markup=i?o+o:o,s.content="",(s=e.tokens[n.token]).type=i?"strong_close":"em_close",s.tag=i?"strong":"em",s.nesting=-1,s.markup=i?o+o:o,s.content="",i&&(e.tokens[a[r-1].token].content="",e.tokens[a[t.end+1].token].content="",r--))}},{}],41:[function(e,r,t){"use strict";var n=e("../common/entities"),s=e("../common/utils").has,o=e("../common/utils").isValidEntityCode,i=e("../common/utils").fromCodePoint,a=/^&#((?:x[a-f0-9]{1,8}|[0-9]{1,8}));/i,c=/^&([a-z][a-z0-9]{1,31});/i;r.exports=function(e,r){var t,l,u=e.pos,p=e.posMax;if(38!==e.src.charCodeAt(u))return!1;if(u+1?@[]^_`{|}~-".split("").forEach(function(e){s[e.charCodeAt(0)]=1}),r.exports=function(e,r){var t,o=e.pos,i=e.posMax;if(92!==e.src.charCodeAt(o))return!1;if(++o=97&&r<=122}var s=e("../common/html_re").HTML_TAG_RE;r.exports=function(e,r){var t,o,i,a=e.pos;return!!e.md.options.html&&(i=e.posMax,!(60!==e.src.charCodeAt(a)||a+2>=i)&&(!(33!==(t=e.src.charCodeAt(a+1))&&63!==t&&47!==t&&!n(t))&&(!!(o=e.src.slice(a).match(s))&&(r||(e.push("html_inline","",0).content=e.src.slice(a,a+o[0].length)),e.pos+=o[0].length,!0))))}},{"../common/html_re":3}],44:[function(e,r,t){"use strict";var n=e("../common/utils").normalizeReference,s=e("../common/utils").isSpace;r.exports=function(e,r){var t,o,i,a,c,l,u,p,h,f,d,m,_,g="",b=e.pos,k=e.posMax;if(33!==e.src.charCodeAt(e.pos))return!1;if(91!==e.src.charCodeAt(e.pos+1))return!1;if(l=e.pos+2,(c=e.md.helpers.parseLinkLabel(e,e.pos+1,!1))<0)return!1;if((u=c+1)=k)return!1;for(_=u,(h=e.md.helpers.parseLinkDestination(e.src,u,e.posMax)).ok&&(g=e.md.normalizeLink(h.str),e.md.validateLink(g)?u=h.pos:g=""),_=u;u=k||41!==e.src.charCodeAt(u))return e.pos=b,!1;u++}else{if(void 0===e.env.references)return!1;if(u=0?a=e.src.slice(_,u++):u=c+1):u=c+1,a||(a=e.src.slice(l,c)),!(p=e.env.references[n(a)]))return e.pos=b,!1;g=p.href,f=p.title}return r||(i=e.src.slice(l,c),e.md.inline.parse(i,e.md,e.env,m=[]),(d=e.push("image","img",0)).attrs=t=[["src",g],["alt",""]],d.children=m,d.content=i,f&&t.push(["title",f])),e.pos=u,e.posMax=k,!0}},{"../common/utils":4}],45:[function(e,r,t){"use strict";var n=e("../common/utils").normalizeReference,s=e("../common/utils").isSpace;r.exports=function(e,r){var t,o,i,a,c,l,u,p,h,f="",d=e.pos,m=e.posMax,_=e.pos,g=!0;if(91!==e.src.charCodeAt(e.pos))return!1;if(c=e.pos+1,(a=e.md.helpers.parseLinkLabel(e,e.pos,!0))<0)return!1;if((l=a+1)=m)return!1;for(_=l,(u=e.md.helpers.parseLinkDestination(e.src,l,e.posMax)).ok&&(f=e.md.normalizeLink(u.str),e.md.validateLink(f)?l=u.pos:f=""),_=l;l=m||41!==e.src.charCodeAt(l))&&(g=!0),l++}if(g){if(void 0===e.env.references)return!1;if(l=0?i=e.src.slice(_,l++):l=a+1):l=a+1,i||(i=e.src.slice(c,a)),!(p=e.env.references[n(i)]))return e.pos=d,!1;f=p.href,h=p.title}return r||(e.pos=c,e.posMax=a,e.push("link_open","a",1).attrs=t=[["href",f]],h&&t.push(["title",h]),e.md.inline.tokenize(e),e.push("link_close","a",-1)),e.pos=l,e.posMax=m,!0}},{"../common/utils":4}],46:[function(e,r,t){"use strict";var n=e("../common/utils").isSpace;r.exports=function(e,r){var t,s,o=e.pos;if(10!==e.src.charCodeAt(o))return!1;for(t=e.pending.length-1,s=e.posMax,r||(t>=0&&32===e.pending.charCodeAt(t)?t>=1&&32===e.pending.charCodeAt(t-1)?(e.pending=e.pending.replace(/ +$/,""),e.push("hardbreak","br",0)):(e.pending=e.pending.slice(0,-1),e.push("softbreak","br",0)):e.push("softbreak","br",0)),o++;o0&&this.level++,this.pendingLevel=this.level,this.tokens.push(n),n},n.prototype.scanDelims=function(e,r){var t,n,s,c,l,u,p,h,f,d=e,m=!0,_=!0,g=this.posMax,b=this.src.charCodeAt(e);for(t=e>0?this.src.charCodeAt(e-1):32;d=0&&(t=this.attrs[r][1]),t},n.prototype.attrJoin=function(e,r){var t=this.attrIndex(e);t<0?this.attrPush([e,r]):this.attrs[t][1]=this.attrs[t][1]+" "+r},r.exports=n},{}],52:[function(e,r,t){r.exports={Aacute:"\xc1",aacute:"\xe1",Abreve:"\u0102",abreve:"\u0103",ac:"\u223e",acd:"\u223f",acE:"\u223e\u0333",Acirc:"\xc2",acirc:"\xe2",acute:"\xb4",Acy:"\u0410",acy:"\u0430",AElig:"\xc6",aelig:"\xe6",af:"\u2061",Afr:"\ud835\udd04",afr:"\ud835\udd1e",Agrave:"\xc0",agrave:"\xe0",alefsym:"\u2135",aleph:"\u2135",Alpha:"\u0391",alpha:"\u03b1",Amacr:"\u0100",amacr:"\u0101",amalg:"\u2a3f",amp:"&",AMP:"&",andand:"\u2a55",And:"\u2a53",and:"\u2227",andd:"\u2a5c",andslope:"\u2a58",andv:"\u2a5a",ang:"\u2220",ange:"\u29a4",angle:"\u2220",angmsdaa:"\u29a8",angmsdab:"\u29a9",angmsdac:"\u29aa",angmsdad:"\u29ab",angmsdae:"\u29ac",angmsdaf:"\u29ad",angmsdag:"\u29ae",angmsdah:"\u29af",angmsd:"\u2221",angrt:"\u221f",angrtvb:"\u22be",angrtvbd:"\u299d",angsph:"\u2222",angst:"\xc5",angzarr:"\u237c",Aogon:"\u0104",aogon:"\u0105",Aopf:"\ud835\udd38",aopf:"\ud835\udd52",apacir:"\u2a6f",ap:"\u2248",apE:"\u2a70",ape:"\u224a",apid:"\u224b",apos:"'",ApplyFunction:"\u2061",approx:"\u2248",approxeq:"\u224a",Aring:"\xc5",aring:"\xe5",Ascr:"\ud835\udc9c",ascr:"\ud835\udcb6",Assign:"\u2254",ast:"*",asymp:"\u2248",asympeq:"\u224d",Atilde:"\xc3",atilde:"\xe3",Auml:"\xc4",auml:"\xe4",awconint:"\u2233",awint:"\u2a11",backcong:"\u224c",backepsilon:"\u03f6",backprime:"\u2035",backsim:"\u223d",backsimeq:"\u22cd",Backslash:"\u2216",Barv:"\u2ae7",barvee:"\u22bd",barwed:"\u2305",Barwed:"\u2306",barwedge:"\u2305",bbrk:"\u23b5",bbrktbrk:"\u23b6",bcong:"\u224c",Bcy:"\u0411",bcy:"\u0431",bdquo:"\u201e",becaus:"\u2235",because:"\u2235",Because:"\u2235",bemptyv:"\u29b0",bepsi:"\u03f6",bernou:"\u212c",Bernoullis:"\u212c",Beta:"\u0392",beta:"\u03b2",beth:"\u2136",between:"\u226c",Bfr:"\ud835\udd05",bfr:"\ud835\udd1f",bigcap:"\u22c2",bigcirc:"\u25ef",bigcup:"\u22c3",bigodot:"\u2a00",bigoplus:"\u2a01",bigotimes:"\u2a02",bigsqcup:"\u2a06",bigstar:"\u2605",bigtriangledown:"\u25bd",bigtriangleup:"\u25b3",biguplus:"\u2a04",bigvee:"\u22c1",bigwedge:"\u22c0",bkarow:"\u290d",blacklozenge:"\u29eb",blacksquare:"\u25aa",blacktriangle:"\u25b4",blacktriangledown:"\u25be",blacktriangleleft:"\u25c2",blacktriangleright:"\u25b8",blank:"\u2423",blk12:"\u2592",blk14:"\u2591",blk34:"\u2593",block:"\u2588",bne:"=\u20e5",bnequiv:"\u2261\u20e5",bNot:"\u2aed",bnot:"\u2310",Bopf:"\ud835\udd39",bopf:"\ud835\udd53",bot:"\u22a5",bottom:"\u22a5",bowtie:"\u22c8",boxbox:"\u29c9",boxdl:"\u2510",boxdL:"\u2555",boxDl:"\u2556",boxDL:"\u2557",boxdr:"\u250c",boxdR:"\u2552",boxDr:"\u2553",boxDR:"\u2554",boxh:"\u2500",boxH:"\u2550",boxhd:"\u252c",boxHd:"\u2564",boxhD:"\u2565",boxHD:"\u2566",boxhu:"\u2534",boxHu:"\u2567",boxhU:"\u2568",boxHU:"\u2569",boxminus:"\u229f",boxplus:"\u229e",boxtimes:"\u22a0",boxul:"\u2518",boxuL:"\u255b",boxUl:"\u255c",boxUL:"\u255d",boxur:"\u2514",boxuR:"\u2558",boxUr:"\u2559",boxUR:"\u255a",boxv:"\u2502",boxV:"\u2551",boxvh:"\u253c",boxvH:"\u256a",boxVh:"\u256b",boxVH:"\u256c",boxvl:"\u2524",boxvL:"\u2561",boxVl:"\u2562",boxVL:"\u2563",boxvr:"\u251c",boxvR:"\u255e",boxVr:"\u255f",boxVR:"\u2560",bprime:"\u2035",breve:"\u02d8",Breve:"\u02d8",brvbar:"\xa6",bscr:"\ud835\udcb7",Bscr:"\u212c",bsemi:"\u204f",bsim:"\u223d",bsime:"\u22cd",bsolb:"\u29c5",bsol:"\\",bsolhsub:"\u27c8",bull:"\u2022",bullet:"\u2022",bump:"\u224e",bumpE:"\u2aae",bumpe:"\u224f",Bumpeq:"\u224e",bumpeq:"\u224f",Cacute:"\u0106",cacute:"\u0107",capand:"\u2a44",capbrcup:"\u2a49",capcap:"\u2a4b",cap:"\u2229",Cap:"\u22d2",capcup:"\u2a47",capdot:"\u2a40",CapitalDifferentialD:"\u2145",caps:"\u2229\ufe00",caret:"\u2041",caron:"\u02c7",Cayleys:"\u212d",ccaps:"\u2a4d",Ccaron:"\u010c",ccaron:"\u010d",Ccedil:"\xc7",ccedil:"\xe7",Ccirc:"\u0108",ccirc:"\u0109",Cconint:"\u2230",ccups:"\u2a4c",ccupssm:"\u2a50",Cdot:"\u010a",cdot:"\u010b",cedil:"\xb8",Cedilla:"\xb8",cemptyv:"\u29b2",cent:"\xa2",centerdot:"\xb7",CenterDot:"\xb7",cfr:"\ud835\udd20",Cfr:"\u212d",CHcy:"\u0427",chcy:"\u0447",check:"\u2713",checkmark:"\u2713",Chi:"\u03a7",chi:"\u03c7",circ:"\u02c6",circeq:"\u2257",circlearrowleft:"\u21ba",circlearrowright:"\u21bb",circledast:"\u229b",circledcirc:"\u229a",circleddash:"\u229d",CircleDot:"\u2299",circledR:"\xae",circledS:"\u24c8",CircleMinus:"\u2296",CirclePlus:"\u2295",CircleTimes:"\u2297",cir:"\u25cb",cirE:"\u29c3",cire:"\u2257",cirfnint:"\u2a10",cirmid:"\u2aef",cirscir:"\u29c2",ClockwiseContourIntegral:"\u2232",CloseCurlyDoubleQuote:"\u201d",CloseCurlyQuote:"\u2019",clubs:"\u2663",clubsuit:"\u2663",colon:":",Colon:"\u2237",Colone:"\u2a74",colone:"\u2254",coloneq:"\u2254",comma:",",commat:"@",comp:"\u2201",compfn:"\u2218",complement:"\u2201",complexes:"\u2102",cong:"\u2245",congdot:"\u2a6d",Congruent:"\u2261",conint:"\u222e",Conint:"\u222f",ContourIntegral:"\u222e",copf:"\ud835\udd54",Copf:"\u2102",coprod:"\u2210",Coproduct:"\u2210",copy:"\xa9",COPY:"\xa9",copysr:"\u2117",CounterClockwiseContourIntegral:"\u2233",crarr:"\u21b5",cross:"\u2717",Cross:"\u2a2f",Cscr:"\ud835\udc9e",cscr:"\ud835\udcb8",csub:"\u2acf",csube:"\u2ad1",csup:"\u2ad0",csupe:"\u2ad2",ctdot:"\u22ef",cudarrl:"\u2938",cudarrr:"\u2935",cuepr:"\u22de",cuesc:"\u22df",cularr:"\u21b6",cularrp:"\u293d",cupbrcap:"\u2a48",cupcap:"\u2a46",CupCap:"\u224d",cup:"\u222a",Cup:"\u22d3",cupcup:"\u2a4a",cupdot:"\u228d",cupor:"\u2a45",cups:"\u222a\ufe00",curarr:"\u21b7",curarrm:"\u293c",curlyeqprec:"\u22de",curlyeqsucc:"\u22df",curlyvee:"\u22ce",curlywedge:"\u22cf",curren:"\xa4",curvearrowleft:"\u21b6",curvearrowright:"\u21b7",cuvee:"\u22ce",cuwed:"\u22cf",cwconint:"\u2232",cwint:"\u2231",cylcty:"\u232d",dagger:"\u2020",Dagger:"\u2021",daleth:"\u2138",darr:"\u2193",Darr:"\u21a1",dArr:"\u21d3",dash:"\u2010",Dashv:"\u2ae4",dashv:"\u22a3",dbkarow:"\u290f",dblac:"\u02dd",Dcaron:"\u010e",dcaron:"\u010f",Dcy:"\u0414",dcy:"\u0434",ddagger:"\u2021",ddarr:"\u21ca",DD:"\u2145",dd:"\u2146",DDotrahd:"\u2911",ddotseq:"\u2a77",deg:"\xb0",Del:"\u2207",Delta:"\u0394",delta:"\u03b4",demptyv:"\u29b1",dfisht:"\u297f",Dfr:"\ud835\udd07",dfr:"\ud835\udd21",dHar:"\u2965",dharl:"\u21c3",dharr:"\u21c2",DiacriticalAcute:"\xb4",DiacriticalDot:"\u02d9",DiacriticalDoubleAcute:"\u02dd",DiacriticalGrave:"`",DiacriticalTilde:"\u02dc",diam:"\u22c4",diamond:"\u22c4",Diamond:"\u22c4",diamondsuit:"\u2666",diams:"\u2666",die:"\xa8",DifferentialD:"\u2146",digamma:"\u03dd",disin:"\u22f2",div:"\xf7",divide:"\xf7",divideontimes:"\u22c7",divonx:"\u22c7",DJcy:"\u0402",djcy:"\u0452",dlcorn:"\u231e",dlcrop:"\u230d",dollar:"$",Dopf:"\ud835\udd3b",dopf:"\ud835\udd55",Dot:"\xa8",dot:"\u02d9",DotDot:"\u20dc",doteq:"\u2250",doteqdot:"\u2251",DotEqual:"\u2250",dotminus:"\u2238",dotplus:"\u2214",dotsquare:"\u22a1",doublebarwedge:"\u2306",DoubleContourIntegral:"\u222f",DoubleDot:"\xa8",DoubleDownArrow:"\u21d3",DoubleLeftArrow:"\u21d0",DoubleLeftRightArrow:"\u21d4",DoubleLeftTee:"\u2ae4",DoubleLongLeftArrow:"\u27f8",DoubleLongLeftRightArrow:"\u27fa",DoubleLongRightArrow:"\u27f9",DoubleRightArrow:"\u21d2",DoubleRightTee:"\u22a8",DoubleUpArrow:"\u21d1",DoubleUpDownArrow:"\u21d5",DoubleVerticalBar:"\u2225",DownArrowBar:"\u2913",downarrow:"\u2193",DownArrow:"\u2193",Downarrow:"\u21d3",DownArrowUpArrow:"\u21f5",DownBreve:"\u0311",downdownarrows:"\u21ca",downharpoonleft:"\u21c3",downharpoonright:"\u21c2",DownLeftRightVector:"\u2950",DownLeftTeeVector:"\u295e",DownLeftVectorBar:"\u2956",DownLeftVector:"\u21bd",DownRightTeeVector:"\u295f",DownRightVectorBar:"\u2957",DownRightVector:"\u21c1",DownTeeArrow:"\u21a7",DownTee:"\u22a4",drbkarow:"\u2910",drcorn:"\u231f",drcrop:"\u230c",Dscr:"\ud835\udc9f",dscr:"\ud835\udcb9",DScy:"\u0405",dscy:"\u0455",dsol:"\u29f6",Dstrok:"\u0110",dstrok:"\u0111",dtdot:"\u22f1",dtri:"\u25bf",dtrif:"\u25be",duarr:"\u21f5",duhar:"\u296f",dwangle:"\u29a6",DZcy:"\u040f",dzcy:"\u045f",dzigrarr:"\u27ff",Eacute:"\xc9",eacute:"\xe9",easter:"\u2a6e",Ecaron:"\u011a",ecaron:"\u011b",Ecirc:"\xca",ecirc:"\xea",ecir:"\u2256",ecolon:"\u2255",Ecy:"\u042d",ecy:"\u044d",eDDot:"\u2a77",Edot:"\u0116",edot:"\u0117",eDot:"\u2251",ee:"\u2147",efDot:"\u2252",Efr:"\ud835\udd08",efr:"\ud835\udd22",eg:"\u2a9a",Egrave:"\xc8",egrave:"\xe8",egs:"\u2a96",egsdot:"\u2a98",el:"\u2a99",Element:"\u2208",elinters:"\u23e7",ell:"\u2113",els:"\u2a95",elsdot:"\u2a97",Emacr:"\u0112",emacr:"\u0113",empty:"\u2205",emptyset:"\u2205",EmptySmallSquare:"\u25fb",emptyv:"\u2205",EmptyVerySmallSquare:"\u25ab",emsp13:"\u2004",emsp14:"\u2005",emsp:"\u2003",ENG:"\u014a",eng:"\u014b",ensp:"\u2002",Eogon:"\u0118",eogon:"\u0119",Eopf:"\ud835\udd3c",eopf:"\ud835\udd56",epar:"\u22d5",eparsl:"\u29e3",eplus:"\u2a71",epsi:"\u03b5",Epsilon:"\u0395",epsilon:"\u03b5",epsiv:"\u03f5",eqcirc:"\u2256",eqcolon:"\u2255",eqsim:"\u2242",eqslantgtr:"\u2a96",eqslantless:"\u2a95",Equal:"\u2a75",equals:"=",EqualTilde:"\u2242",equest:"\u225f",Equilibrium:"\u21cc",equiv:"\u2261",equivDD:"\u2a78",eqvparsl:"\u29e5",erarr:"\u2971",erDot:"\u2253",escr:"\u212f",Escr:"\u2130",esdot:"\u2250",Esim:"\u2a73",esim:"\u2242",Eta:"\u0397",eta:"\u03b7",ETH:"\xd0",eth:"\xf0",Euml:"\xcb",euml:"\xeb",euro:"\u20ac",excl:"!",exist:"\u2203",Exists:"\u2203",expectation:"\u2130",exponentiale:"\u2147",ExponentialE:"\u2147",fallingdotseq:"\u2252",Fcy:"\u0424",fcy:"\u0444",female:"\u2640",ffilig:"\ufb03",fflig:"\ufb00",ffllig:"\ufb04",Ffr:"\ud835\udd09",ffr:"\ud835\udd23",filig:"\ufb01",FilledSmallSquare:"\u25fc",FilledVerySmallSquare:"\u25aa",fjlig:"fj",flat:"\u266d",fllig:"\ufb02",fltns:"\u25b1",fnof:"\u0192",Fopf:"\ud835\udd3d",fopf:"\ud835\udd57",forall:"\u2200",ForAll:"\u2200",fork:"\u22d4",forkv:"\u2ad9",Fouriertrf:"\u2131",fpartint:"\u2a0d",frac12:"\xbd",frac13:"\u2153",frac14:"\xbc",frac15:"\u2155",frac16:"\u2159",frac18:"\u215b",frac23:"\u2154",frac25:"\u2156",frac34:"\xbe",frac35:"\u2157",frac38:"\u215c",frac45:"\u2158",frac56:"\u215a",frac58:"\u215d",frac78:"\u215e",frasl:"\u2044",frown:"\u2322",fscr:"\ud835\udcbb",Fscr:"\u2131",gacute:"\u01f5",Gamma:"\u0393",gamma:"\u03b3",Gammad:"\u03dc",gammad:"\u03dd",gap:"\u2a86",Gbreve:"\u011e",gbreve:"\u011f",Gcedil:"\u0122",Gcirc:"\u011c",gcirc:"\u011d",Gcy:"\u0413",gcy:"\u0433",Gdot:"\u0120",gdot:"\u0121",ge:"\u2265",gE:"\u2267",gEl:"\u2a8c",gel:"\u22db",geq:"\u2265",geqq:"\u2267",geqslant:"\u2a7e",gescc:"\u2aa9",ges:"\u2a7e",gesdot:"\u2a80",gesdoto:"\u2a82",gesdotol:"\u2a84",gesl:"\u22db\ufe00",gesles:"\u2a94",Gfr:"\ud835\udd0a",gfr:"\ud835\udd24",gg:"\u226b",Gg:"\u22d9",ggg:"\u22d9",gimel:"\u2137",GJcy:"\u0403",gjcy:"\u0453",gla:"\u2aa5",gl:"\u2277",glE:"\u2a92",glj:"\u2aa4",gnap:"\u2a8a",gnapprox:"\u2a8a",gne:"\u2a88",gnE:"\u2269",gneq:"\u2a88",gneqq:"\u2269",gnsim:"\u22e7",Gopf:"\ud835\udd3e",gopf:"\ud835\udd58",grave:"`",GreaterEqual:"\u2265",GreaterEqualLess:"\u22db",GreaterFullEqual:"\u2267",GreaterGreater:"\u2aa2",GreaterLess:"\u2277",GreaterSlantEqual:"\u2a7e",GreaterTilde:"\u2273",Gscr:"\ud835\udca2",gscr:"\u210a",gsim:"\u2273",gsime:"\u2a8e",gsiml:"\u2a90",gtcc:"\u2aa7",gtcir:"\u2a7a",gt:">",GT:">",Gt:"\u226b",gtdot:"\u22d7",gtlPar:"\u2995",gtquest:"\u2a7c",gtrapprox:"\u2a86",gtrarr:"\u2978",gtrdot:"\u22d7",gtreqless:"\u22db",gtreqqless:"\u2a8c",gtrless:"\u2277",gtrsim:"\u2273",gvertneqq:"\u2269\ufe00",gvnE:"\u2269\ufe00",Hacek:"\u02c7",hairsp:"\u200a",half:"\xbd",hamilt:"\u210b",HARDcy:"\u042a",hardcy:"\u044a",harrcir:"\u2948",harr:"\u2194",hArr:"\u21d4",harrw:"\u21ad",Hat:"^",hbar:"\u210f",Hcirc:"\u0124",hcirc:"\u0125",hearts:"\u2665",heartsuit:"\u2665",hellip:"\u2026",hercon:"\u22b9",hfr:"\ud835\udd25",Hfr:"\u210c",HilbertSpace:"\u210b",hksearow:"\u2925",hkswarow:"\u2926",hoarr:"\u21ff",homtht:"\u223b",hookleftarrow:"\u21a9",hookrightarrow:"\u21aa",hopf:"\ud835\udd59",Hopf:"\u210d",horbar:"\u2015",HorizontalLine:"\u2500",hscr:"\ud835\udcbd",Hscr:"\u210b",hslash:"\u210f",Hstrok:"\u0126",hstrok:"\u0127",HumpDownHump:"\u224e",HumpEqual:"\u224f",hybull:"\u2043",hyphen:"\u2010",Iacute:"\xcd",iacute:"\xed",ic:"\u2063",Icirc:"\xce",icirc:"\xee",Icy:"\u0418",icy:"\u0438",Idot:"\u0130",IEcy:"\u0415",iecy:"\u0435",iexcl:"\xa1",iff:"\u21d4",ifr:"\ud835\udd26",Ifr:"\u2111",Igrave:"\xcc",igrave:"\xec",ii:"\u2148",iiiint:"\u2a0c",iiint:"\u222d",iinfin:"\u29dc",iiota:"\u2129",IJlig:"\u0132",ijlig:"\u0133",Imacr:"\u012a",imacr:"\u012b",image:"\u2111",ImaginaryI:"\u2148",imagline:"\u2110",imagpart:"\u2111",imath:"\u0131",Im:"\u2111",imof:"\u22b7",imped:"\u01b5",Implies:"\u21d2",incare:"\u2105",in:"\u2208",infin:"\u221e",infintie:"\u29dd",inodot:"\u0131",intcal:"\u22ba",int:"\u222b",Int:"\u222c",integers:"\u2124",Integral:"\u222b",intercal:"\u22ba",Intersection:"\u22c2",intlarhk:"\u2a17",intprod:"\u2a3c",InvisibleComma:"\u2063",InvisibleTimes:"\u2062",IOcy:"\u0401",iocy:"\u0451",Iogon:"\u012e",iogon:"\u012f",Iopf:"\ud835\udd40",iopf:"\ud835\udd5a",Iota:"\u0399",iota:"\u03b9",iprod:"\u2a3c",iquest:"\xbf",iscr:"\ud835\udcbe",Iscr:"\u2110",isin:"\u2208",isindot:"\u22f5",isinE:"\u22f9",isins:"\u22f4",isinsv:"\u22f3",isinv:"\u2208",it:"\u2062",Itilde:"\u0128",itilde:"\u0129",Iukcy:"\u0406",iukcy:"\u0456",Iuml:"\xcf",iuml:"\xef",Jcirc:"\u0134",jcirc:"\u0135",Jcy:"\u0419",jcy:"\u0439",Jfr:"\ud835\udd0d",jfr:"\ud835\udd27",jmath:"\u0237",Jopf:"\ud835\udd41",jopf:"\ud835\udd5b",Jscr:"\ud835\udca5",jscr:"\ud835\udcbf",Jsercy:"\u0408",jsercy:"\u0458",Jukcy:"\u0404",jukcy:"\u0454",Kappa:"\u039a",kappa:"\u03ba",kappav:"\u03f0",Kcedil:"\u0136",kcedil:"\u0137",Kcy:"\u041a",kcy:"\u043a",Kfr:"\ud835\udd0e",kfr:"\ud835\udd28",kgreen:"\u0138",KHcy:"\u0425",khcy:"\u0445",KJcy:"\u040c",kjcy:"\u045c",Kopf:"\ud835\udd42",kopf:"\ud835\udd5c",Kscr:"\ud835\udca6",kscr:"\ud835\udcc0",lAarr:"\u21da",Lacute:"\u0139",lacute:"\u013a",laemptyv:"\u29b4",lagran:"\u2112",Lambda:"\u039b",lambda:"\u03bb",lang:"\u27e8",Lang:"\u27ea",langd:"\u2991",langle:"\u27e8",lap:"\u2a85",Laplacetrf:"\u2112",laquo:"\xab",larrb:"\u21e4",larrbfs:"\u291f",larr:"\u2190",Larr:"\u219e",lArr:"\u21d0",larrfs:"\u291d",larrhk:"\u21a9",larrlp:"\u21ab",larrpl:"\u2939",larrsim:"\u2973",larrtl:"\u21a2",latail:"\u2919",lAtail:"\u291b",lat:"\u2aab",late:"\u2aad",lates:"\u2aad\ufe00",lbarr:"\u290c",lBarr:"\u290e",lbbrk:"\u2772",lbrace:"{",lbrack:"[",lbrke:"\u298b",lbrksld:"\u298f",lbrkslu:"\u298d",Lcaron:"\u013d",lcaron:"\u013e",Lcedil:"\u013b",lcedil:"\u013c",lceil:"\u2308",lcub:"{",Lcy:"\u041b",lcy:"\u043b",ldca:"\u2936",ldquo:"\u201c",ldquor:"\u201e",ldrdhar:"\u2967",ldrushar:"\u294b",ldsh:"\u21b2",le:"\u2264",lE:"\u2266",LeftAngleBracket:"\u27e8",LeftArrowBar:"\u21e4",leftarrow:"\u2190",LeftArrow:"\u2190",Leftarrow:"\u21d0",LeftArrowRightArrow:"\u21c6",leftarrowtail:"\u21a2",LeftCeiling:"\u2308",LeftDoubleBracket:"\u27e6",LeftDownTeeVector:"\u2961",LeftDownVectorBar:"\u2959",LeftDownVector:"\u21c3",LeftFloor:"\u230a",leftharpoondown:"\u21bd",leftharpoonup:"\u21bc",leftleftarrows:"\u21c7",leftrightarrow:"\u2194",LeftRightArrow:"\u2194",Leftrightarrow:"\u21d4",leftrightarrows:"\u21c6",leftrightharpoons:"\u21cb",leftrightsquigarrow:"\u21ad",LeftRightVector:"\u294e",LeftTeeArrow:"\u21a4",LeftTee:"\u22a3",LeftTeeVector:"\u295a",leftthreetimes:"\u22cb",LeftTriangleBar:"\u29cf",LeftTriangle:"\u22b2",LeftTriangleEqual:"\u22b4",LeftUpDownVector:"\u2951",LeftUpTeeVector:"\u2960",LeftUpVectorBar:"\u2958",LeftUpVector:"\u21bf",LeftVectorBar:"\u2952",LeftVector:"\u21bc",lEg:"\u2a8b",leg:"\u22da",leq:"\u2264",leqq:"\u2266",leqslant:"\u2a7d",lescc:"\u2aa8",les:"\u2a7d",lesdot:"\u2a7f",lesdoto:"\u2a81",lesdotor:"\u2a83",lesg:"\u22da\ufe00",lesges:"\u2a93",lessapprox:"\u2a85",lessdot:"\u22d6",lesseqgtr:"\u22da",lesseqqgtr:"\u2a8b",LessEqualGreater:"\u22da",LessFullEqual:"\u2266",LessGreater:"\u2276",lessgtr:"\u2276",LessLess:"\u2aa1",lesssim:"\u2272",LessSlantEqual:"\u2a7d",LessTilde:"\u2272",lfisht:"\u297c",lfloor:"\u230a",Lfr:"\ud835\udd0f",lfr:"\ud835\udd29",lg:"\u2276",lgE:"\u2a91",lHar:"\u2962",lhard:"\u21bd",lharu:"\u21bc",lharul:"\u296a",lhblk:"\u2584",LJcy:"\u0409",ljcy:"\u0459",llarr:"\u21c7",ll:"\u226a",Ll:"\u22d8",llcorner:"\u231e",Lleftarrow:"\u21da",llhard:"\u296b",lltri:"\u25fa",Lmidot:"\u013f",lmidot:"\u0140",lmoustache:"\u23b0",lmoust:"\u23b0",lnap:"\u2a89",lnapprox:"\u2a89",lne:"\u2a87",lnE:"\u2268",lneq:"\u2a87",lneqq:"\u2268",lnsim:"\u22e6",loang:"\u27ec",loarr:"\u21fd",lobrk:"\u27e6",longleftarrow:"\u27f5",LongLeftArrow:"\u27f5",Longleftarrow:"\u27f8",longleftrightarrow:"\u27f7",LongLeftRightArrow:"\u27f7",Longleftrightarrow:"\u27fa",longmapsto:"\u27fc",longrightarrow:"\u27f6",LongRightArrow:"\u27f6",Longrightarrow:"\u27f9",looparrowleft:"\u21ab",looparrowright:"\u21ac",lopar:"\u2985",Lopf:"\ud835\udd43",lopf:"\ud835\udd5d",loplus:"\u2a2d",lotimes:"\u2a34",lowast:"\u2217",lowbar:"_",LowerLeftArrow:"\u2199",LowerRightArrow:"\u2198",loz:"\u25ca",lozenge:"\u25ca",lozf:"\u29eb",lpar:"(",lparlt:"\u2993",lrarr:"\u21c6",lrcorner:"\u231f",lrhar:"\u21cb",lrhard:"\u296d",lrm:"\u200e",lrtri:"\u22bf",lsaquo:"\u2039",lscr:"\ud835\udcc1",Lscr:"\u2112",lsh:"\u21b0",Lsh:"\u21b0",lsim:"\u2272",lsime:"\u2a8d",lsimg:"\u2a8f",lsqb:"[",lsquo:"\u2018",lsquor:"\u201a",Lstrok:"\u0141",lstrok:"\u0142",ltcc:"\u2aa6",ltcir:"\u2a79",lt:"<",LT:"<",Lt:"\u226a",ltdot:"\u22d6",lthree:"\u22cb",ltimes:"\u22c9",ltlarr:"\u2976",ltquest:"\u2a7b",ltri:"\u25c3",ltrie:"\u22b4",ltrif:"\u25c2",ltrPar:"\u2996",lurdshar:"\u294a",luruhar:"\u2966",lvertneqq:"\u2268\ufe00",lvnE:"\u2268\ufe00",macr:"\xaf",male:"\u2642",malt:"\u2720",maltese:"\u2720",Map:"\u2905",map:"\u21a6",mapsto:"\u21a6",mapstodown:"\u21a7",mapstoleft:"\u21a4",mapstoup:"\u21a5",marker:"\u25ae",mcomma:"\u2a29",Mcy:"\u041c",mcy:"\u043c",mdash:"\u2014",mDDot:"\u223a",measuredangle:"\u2221",MediumSpace:"\u205f",Mellintrf:"\u2133",Mfr:"\ud835\udd10",mfr:"\ud835\udd2a",mho:"\u2127",micro:"\xb5",midast:"*",midcir:"\u2af0",mid:"\u2223",middot:"\xb7",minusb:"\u229f",minus:"\u2212",minusd:"\u2238",minusdu:"\u2a2a",MinusPlus:"\u2213",mlcp:"\u2adb",mldr:"\u2026",mnplus:"\u2213",models:"\u22a7",Mopf:"\ud835\udd44",mopf:"\ud835\udd5e",mp:"\u2213",mscr:"\ud835\udcc2",Mscr:"\u2133",mstpos:"\u223e",Mu:"\u039c",mu:"\u03bc",multimap:"\u22b8",mumap:"\u22b8",nabla:"\u2207",Nacute:"\u0143",nacute:"\u0144",nang:"\u2220\u20d2",nap:"\u2249",napE:"\u2a70\u0338",napid:"\u224b\u0338",napos:"\u0149",napprox:"\u2249",natural:"\u266e",naturals:"\u2115",natur:"\u266e",nbsp:"\xa0",nbump:"\u224e\u0338",nbumpe:"\u224f\u0338",ncap:"\u2a43",Ncaron:"\u0147",ncaron:"\u0148",Ncedil:"\u0145",ncedil:"\u0146",ncong:"\u2247",ncongdot:"\u2a6d\u0338",ncup:"\u2a42",Ncy:"\u041d",ncy:"\u043d",ndash:"\u2013",nearhk:"\u2924",nearr:"\u2197",neArr:"\u21d7",nearrow:"\u2197",ne:"\u2260",nedot:"\u2250\u0338",NegativeMediumSpace:"\u200b",NegativeThickSpace:"\u200b",NegativeThinSpace:"\u200b",NegativeVeryThinSpace:"\u200b",nequiv:"\u2262",nesear:"\u2928",nesim:"\u2242\u0338",NestedGreaterGreater:"\u226b",NestedLessLess:"\u226a",NewLine:"\n",nexist:"\u2204",nexists:"\u2204",Nfr:"\ud835\udd11",nfr:"\ud835\udd2b",ngE:"\u2267\u0338",nge:"\u2271",ngeq:"\u2271",ngeqq:"\u2267\u0338",ngeqslant:"\u2a7e\u0338",nges:"\u2a7e\u0338",nGg:"\u22d9\u0338",ngsim:"\u2275",nGt:"\u226b\u20d2",ngt:"\u226f",ngtr:"\u226f",nGtv:"\u226b\u0338",nharr:"\u21ae",nhArr:"\u21ce",nhpar:"\u2af2",ni:"\u220b",nis:"\u22fc",nisd:"\u22fa",niv:"\u220b",NJcy:"\u040a",njcy:"\u045a",nlarr:"\u219a",nlArr:"\u21cd",nldr:"\u2025",nlE:"\u2266\u0338",nle:"\u2270",nleftarrow:"\u219a",nLeftarrow:"\u21cd",nleftrightarrow:"\u21ae",nLeftrightarrow:"\u21ce",nleq:"\u2270",nleqq:"\u2266\u0338",nleqslant:"\u2a7d\u0338",nles:"\u2a7d\u0338",nless:"\u226e",nLl:"\u22d8\u0338",nlsim:"\u2274",nLt:"\u226a\u20d2",nlt:"\u226e",nltri:"\u22ea",nltrie:"\u22ec",nLtv:"\u226a\u0338",nmid:"\u2224",NoBreak:"\u2060",NonBreakingSpace:"\xa0",nopf:"\ud835\udd5f",Nopf:"\u2115",Not:"\u2aec",not:"\xac",NotCongruent:"\u2262",NotCupCap:"\u226d",NotDoubleVerticalBar:"\u2226",NotElement:"\u2209",NotEqual:"\u2260",NotEqualTilde:"\u2242\u0338",NotExists:"\u2204",NotGreater:"\u226f",NotGreaterEqual:"\u2271",NotGreaterFullEqual:"\u2267\u0338",NotGreaterGreater:"\u226b\u0338",NotGreaterLess:"\u2279",NotGreaterSlantEqual:"\u2a7e\u0338",NotGreaterTilde:"\u2275",NotHumpDownHump:"\u224e\u0338",NotHumpEqual:"\u224f\u0338",notin:"\u2209",notindot:"\u22f5\u0338",notinE:"\u22f9\u0338",notinva:"\u2209",notinvb:"\u22f7",notinvc:"\u22f6",NotLeftTriangleBar:"\u29cf\u0338",NotLeftTriangle:"\u22ea",NotLeftTriangleEqual:"\u22ec",NotLess:"\u226e",NotLessEqual:"\u2270",NotLessGreater:"\u2278",NotLessLess:"\u226a\u0338",NotLessSlantEqual:"\u2a7d\u0338",NotLessTilde:"\u2274",NotNestedGreaterGreater:"\u2aa2\u0338",NotNestedLessLess:"\u2aa1\u0338",notni:"\u220c",notniva:"\u220c",notnivb:"\u22fe",notnivc:"\u22fd",NotPrecedes:"\u2280",NotPrecedesEqual:"\u2aaf\u0338",NotPrecedesSlantEqual:"\u22e0",NotReverseElement:"\u220c",NotRightTriangleBar:"\u29d0\u0338",NotRightTriangle:"\u22eb",NotRightTriangleEqual:"\u22ed",NotSquareSubset:"\u228f\u0338",NotSquareSubsetEqual:"\u22e2",NotSquareSuperset:"\u2290\u0338",NotSquareSupersetEqual:"\u22e3",NotSubset:"\u2282\u20d2",NotSubsetEqual:"\u2288",NotSucceeds:"\u2281",NotSucceedsEqual:"\u2ab0\u0338",NotSucceedsSlantEqual:"\u22e1",NotSucceedsTilde:"\u227f\u0338",NotSuperset:"\u2283\u20d2",NotSupersetEqual:"\u2289",NotTilde:"\u2241",NotTildeEqual:"\u2244",NotTildeFullEqual:"\u2247",NotTildeTilde:"\u2249",NotVerticalBar:"\u2224",nparallel:"\u2226",npar:"\u2226",nparsl:"\u2afd\u20e5",npart:"\u2202\u0338",npolint:"\u2a14",npr:"\u2280",nprcue:"\u22e0",nprec:"\u2280",npreceq:"\u2aaf\u0338",npre:"\u2aaf\u0338",nrarrc:"\u2933\u0338",nrarr:"\u219b",nrArr:"\u21cf",nrarrw:"\u219d\u0338",nrightarrow:"\u219b",nRightarrow:"\u21cf",nrtri:"\u22eb",nrtrie:"\u22ed",nsc:"\u2281",nsccue:"\u22e1",nsce:"\u2ab0\u0338",Nscr:"\ud835\udca9",nscr:"\ud835\udcc3",nshortmid:"\u2224",nshortparallel:"\u2226",nsim:"\u2241",nsime:"\u2244",nsimeq:"\u2244",nsmid:"\u2224",nspar:"\u2226",nsqsube:"\u22e2",nsqsupe:"\u22e3",nsub:"\u2284",nsubE:"\u2ac5\u0338",nsube:"\u2288",nsubset:"\u2282\u20d2",nsubseteq:"\u2288",nsubseteqq:"\u2ac5\u0338",nsucc:"\u2281",nsucceq:"\u2ab0\u0338",nsup:"\u2285",nsupE:"\u2ac6\u0338",nsupe:"\u2289",nsupset:"\u2283\u20d2",nsupseteq:"\u2289",nsupseteqq:"\u2ac6\u0338",ntgl:"\u2279",Ntilde:"\xd1",ntilde:"\xf1",ntlg:"\u2278",ntriangleleft:"\u22ea",ntrianglelefteq:"\u22ec",ntriangleright:"\u22eb",ntrianglerighteq:"\u22ed",Nu:"\u039d",nu:"\u03bd",num:"#",numero:"\u2116",numsp:"\u2007",nvap:"\u224d\u20d2",nvdash:"\u22ac",nvDash:"\u22ad",nVdash:"\u22ae",nVDash:"\u22af",nvge:"\u2265\u20d2",nvgt:">\u20d2",nvHarr:"\u2904",nvinfin:"\u29de",nvlArr:"\u2902",nvle:"\u2264\u20d2",nvlt:"<\u20d2",nvltrie:"\u22b4\u20d2",nvrArr:"\u2903",nvrtrie:"\u22b5\u20d2",nvsim:"\u223c\u20d2",nwarhk:"\u2923",nwarr:"\u2196",nwArr:"\u21d6",nwarrow:"\u2196",nwnear:"\u2927",Oacute:"\xd3",oacute:"\xf3",oast:"\u229b",Ocirc:"\xd4",ocirc:"\xf4",ocir:"\u229a",Ocy:"\u041e",ocy:"\u043e",odash:"\u229d",Odblac:"\u0150",odblac:"\u0151",odiv:"\u2a38",odot:"\u2299",odsold:"\u29bc",OElig:"\u0152",oelig:"\u0153",ofcir:"\u29bf",Ofr:"\ud835\udd12",ofr:"\ud835\udd2c",ogon:"\u02db",Ograve:"\xd2",ograve:"\xf2",ogt:"\u29c1",ohbar:"\u29b5",ohm:"\u03a9",oint:"\u222e",olarr:"\u21ba",olcir:"\u29be",olcross:"\u29bb",oline:"\u203e",olt:"\u29c0",Omacr:"\u014c",omacr:"\u014d",Omega:"\u03a9",omega:"\u03c9",Omicron:"\u039f",omicron:"\u03bf",omid:"\u29b6",ominus:"\u2296",Oopf:"\ud835\udd46",oopf:"\ud835\udd60",opar:"\u29b7",OpenCurlyDoubleQuote:"\u201c",OpenCurlyQuote:"\u2018",operp:"\u29b9",oplus:"\u2295",orarr:"\u21bb",Or:"\u2a54",or:"\u2228",ord:"\u2a5d",order:"\u2134",orderof:"\u2134",ordf:"\xaa",ordm:"\xba",origof:"\u22b6",oror:"\u2a56",orslope:"\u2a57",orv:"\u2a5b",oS:"\u24c8",Oscr:"\ud835\udcaa",oscr:"\u2134",Oslash:"\xd8",oslash:"\xf8",osol:"\u2298",Otilde:"\xd5",otilde:"\xf5",otimesas:"\u2a36",Otimes:"\u2a37",otimes:"\u2297",Ouml:"\xd6",ouml:"\xf6",ovbar:"\u233d",OverBar:"\u203e",OverBrace:"\u23de",OverBracket:"\u23b4",OverParenthesis:"\u23dc",para:"\xb6",parallel:"\u2225",par:"\u2225",parsim:"\u2af3",parsl:"\u2afd",part:"\u2202",PartialD:"\u2202",Pcy:"\u041f",pcy:"\u043f",percnt:"%",period:".",permil:"\u2030",perp:"\u22a5",pertenk:"\u2031",Pfr:"\ud835\udd13",pfr:"\ud835\udd2d",Phi:"\u03a6",phi:"\u03c6",phiv:"\u03d5",phmmat:"\u2133",phone:"\u260e",Pi:"\u03a0",pi:"\u03c0",pitchfork:"\u22d4",piv:"\u03d6",planck:"\u210f",planckh:"\u210e",plankv:"\u210f",plusacir:"\u2a23",plusb:"\u229e",pluscir:"\u2a22",plus:"+",plusdo:"\u2214",plusdu:"\u2a25",pluse:"\u2a72",PlusMinus:"\xb1",plusmn:"\xb1",plussim:"\u2a26",plustwo:"\u2a27",pm:"\xb1",Poincareplane:"\u210c",pointint:"\u2a15",popf:"\ud835\udd61",Popf:"\u2119",pound:"\xa3",prap:"\u2ab7",Pr:"\u2abb",pr:"\u227a",prcue:"\u227c",precapprox:"\u2ab7",prec:"\u227a",preccurlyeq:"\u227c",Precedes:"\u227a",PrecedesEqual:"\u2aaf",PrecedesSlantEqual:"\u227c",PrecedesTilde:"\u227e",preceq:"\u2aaf",precnapprox:"\u2ab9",precneqq:"\u2ab5",precnsim:"\u22e8",pre:"\u2aaf",prE:"\u2ab3",precsim:"\u227e",prime:"\u2032",Prime:"\u2033",primes:"\u2119",prnap:"\u2ab9",prnE:"\u2ab5",prnsim:"\u22e8",prod:"\u220f",Product:"\u220f",profalar:"\u232e",profline:"\u2312",profsurf:"\u2313",prop:"\u221d",Proportional:"\u221d",Proportion:"\u2237",propto:"\u221d",prsim:"\u227e",prurel:"\u22b0",Pscr:"\ud835\udcab",pscr:"\ud835\udcc5",Psi:"\u03a8",psi:"\u03c8",puncsp:"\u2008",Qfr:"\ud835\udd14",qfr:"\ud835\udd2e",qint:"\u2a0c",qopf:"\ud835\udd62",Qopf:"\u211a",qprime:"\u2057",Qscr:"\ud835\udcac",qscr:"\ud835\udcc6",quaternions:"\u210d",quatint:"\u2a16",quest:"?",questeq:"\u225f",quot:'"',QUOT:'"',rAarr:"\u21db",race:"\u223d\u0331",Racute:"\u0154",racute:"\u0155",radic:"\u221a",raemptyv:"\u29b3",rang:"\u27e9",Rang:"\u27eb",rangd:"\u2992",range:"\u29a5",rangle:"\u27e9",raquo:"\xbb",rarrap:"\u2975",rarrb:"\u21e5",rarrbfs:"\u2920",rarrc:"\u2933",rarr:"\u2192",Rarr:"\u21a0",rArr:"\u21d2",rarrfs:"\u291e",rarrhk:"\u21aa",rarrlp:"\u21ac",rarrpl:"\u2945",rarrsim:"\u2974",Rarrtl:"\u2916",rarrtl:"\u21a3",rarrw:"\u219d",ratail:"\u291a",rAtail:"\u291c",ratio:"\u2236",rationals:"\u211a",rbarr:"\u290d",rBarr:"\u290f",RBarr:"\u2910",rbbrk:"\u2773",rbrace:"}",rbrack:"]",rbrke:"\u298c",rbrksld:"\u298e",rbrkslu:"\u2990",Rcaron:"\u0158",rcaron:"\u0159",Rcedil:"\u0156",rcedil:"\u0157",rceil:"\u2309",rcub:"}",Rcy:"\u0420",rcy:"\u0440",rdca:"\u2937",rdldhar:"\u2969",rdquo:"\u201d",rdquor:"\u201d",rdsh:"\u21b3",real:"\u211c",realine:"\u211b",realpart:"\u211c",reals:"\u211d",Re:"\u211c",rect:"\u25ad",reg:"\xae",REG:"\xae",ReverseElement:"\u220b",ReverseEquilibrium:"\u21cb",ReverseUpEquilibrium:"\u296f",rfisht:"\u297d",rfloor:"\u230b",rfr:"\ud835\udd2f",Rfr:"\u211c",rHar:"\u2964",rhard:"\u21c1",rharu:"\u21c0",rharul:"\u296c",Rho:"\u03a1",rho:"\u03c1",rhov:"\u03f1",RightAngleBracket:"\u27e9",RightArrowBar:"\u21e5",rightarrow:"\u2192",RightArrow:"\u2192",Rightarrow:"\u21d2",RightArrowLeftArrow:"\u21c4",rightarrowtail:"\u21a3",RightCeiling:"\u2309",RightDoubleBracket:"\u27e7",RightDownTeeVector:"\u295d",RightDownVectorBar:"\u2955",RightDownVector:"\u21c2",RightFloor:"\u230b",rightharpoondown:"\u21c1",rightharpoonup:"\u21c0",rightleftarrows:"\u21c4",rightleftharpoons:"\u21cc",rightrightarrows:"\u21c9",rightsquigarrow:"\u219d",RightTeeArrow:"\u21a6",RightTee:"\u22a2",RightTeeVector:"\u295b",rightthreetimes:"\u22cc",RightTriangleBar:"\u29d0",RightTriangle:"\u22b3",RightTriangleEqual:"\u22b5",RightUpDownVector:"\u294f",RightUpTeeVector:"\u295c",RightUpVectorBar:"\u2954",RightUpVector:"\u21be",RightVectorBar:"\u2953",RightVector:"\u21c0",ring:"\u02da",risingdotseq:"\u2253",rlarr:"\u21c4",rlhar:"\u21cc",rlm:"\u200f",rmoustache:"\u23b1",rmoust:"\u23b1",rnmid:"\u2aee",roang:"\u27ed",roarr:"\u21fe",robrk:"\u27e7",ropar:"\u2986",ropf:"\ud835\udd63",Ropf:"\u211d",roplus:"\u2a2e",rotimes:"\u2a35",RoundImplies:"\u2970",rpar:")",rpargt:"\u2994",rppolint:"\u2a12",rrarr:"\u21c9",Rrightarrow:"\u21db",rsaquo:"\u203a",rscr:"\ud835\udcc7",Rscr:"\u211b",rsh:"\u21b1",Rsh:"\u21b1",rsqb:"]",rsquo:"\u2019",rsquor:"\u2019",rthree:"\u22cc",rtimes:"\u22ca",rtri:"\u25b9",rtrie:"\u22b5",rtrif:"\u25b8",rtriltri:"\u29ce",RuleDelayed:"\u29f4",ruluhar:"\u2968",rx:"\u211e",Sacute:"\u015a",sacute:"\u015b",sbquo:"\u201a",scap:"\u2ab8",Scaron:"\u0160",scaron:"\u0161",Sc:"\u2abc",sc:"\u227b",sccue:"\u227d",sce:"\u2ab0",scE:"\u2ab4",Scedil:"\u015e",scedil:"\u015f",Scirc:"\u015c",scirc:"\u015d",scnap:"\u2aba",scnE:"\u2ab6",scnsim:"\u22e9",scpolint:"\u2a13",scsim:"\u227f",Scy:"\u0421",scy:"\u0441",sdotb:"\u22a1",sdot:"\u22c5",sdote:"\u2a66",searhk:"\u2925",searr:"\u2198",seArr:"\u21d8",searrow:"\u2198",sect:"\xa7",semi:";",seswar:"\u2929",setminus:"\u2216",setmn:"\u2216",sext:"\u2736",Sfr:"\ud835\udd16",sfr:"\ud835\udd30",sfrown:"\u2322",sharp:"\u266f",SHCHcy:"\u0429",shchcy:"\u0449",SHcy:"\u0428",shcy:"\u0448",ShortDownArrow:"\u2193",ShortLeftArrow:"\u2190",shortmid:"\u2223",shortparallel:"\u2225",ShortRightArrow:"\u2192",ShortUpArrow:"\u2191",shy:"\xad",Sigma:"\u03a3",sigma:"\u03c3",sigmaf:"\u03c2",sigmav:"\u03c2",sim:"\u223c",simdot:"\u2a6a",sime:"\u2243",simeq:"\u2243",simg:"\u2a9e",simgE:"\u2aa0",siml:"\u2a9d",simlE:"\u2a9f",simne:"\u2246",simplus:"\u2a24",simrarr:"\u2972",slarr:"\u2190",SmallCircle:"\u2218",smallsetminus:"\u2216",smashp:"\u2a33",smeparsl:"\u29e4",smid:"\u2223",smile:"\u2323",smt:"\u2aaa",smte:"\u2aac",smtes:"\u2aac\ufe00",SOFTcy:"\u042c",softcy:"\u044c",solbar:"\u233f",solb:"\u29c4",sol:"/",Sopf:"\ud835\udd4a",sopf:"\ud835\udd64",spades:"\u2660",spadesuit:"\u2660",spar:"\u2225",sqcap:"\u2293",sqcaps:"\u2293\ufe00",sqcup:"\u2294",sqcups:"\u2294\ufe00",Sqrt:"\u221a",sqsub:"\u228f",sqsube:"\u2291",sqsubset:"\u228f",sqsubseteq:"\u2291",sqsup:"\u2290",sqsupe:"\u2292",sqsupset:"\u2290",sqsupseteq:"\u2292",square:"\u25a1",Square:"\u25a1",SquareIntersection:"\u2293",SquareSubset:"\u228f",SquareSubsetEqual:"\u2291",SquareSuperset:"\u2290",SquareSupersetEqual:"\u2292",SquareUnion:"\u2294",squarf:"\u25aa",squ:"\u25a1",squf:"\u25aa",srarr:"\u2192",Sscr:"\ud835\udcae",sscr:"\ud835\udcc8",ssetmn:"\u2216",ssmile:"\u2323",sstarf:"\u22c6",Star:"\u22c6",star:"\u2606",starf:"\u2605",straightepsilon:"\u03f5",straightphi:"\u03d5",strns:"\xaf",sub:"\u2282",Sub:"\u22d0",subdot:"\u2abd",subE:"\u2ac5",sube:"\u2286",subedot:"\u2ac3",submult:"\u2ac1",subnE:"\u2acb",subne:"\u228a",subplus:"\u2abf",subrarr:"\u2979",subset:"\u2282",Subset:"\u22d0",subseteq:"\u2286",subseteqq:"\u2ac5",SubsetEqual:"\u2286",subsetneq:"\u228a",subsetneqq:"\u2acb",subsim:"\u2ac7",subsub:"\u2ad5",subsup:"\u2ad3",succapprox:"\u2ab8",succ:"\u227b",succcurlyeq:"\u227d",Succeeds:"\u227b",SucceedsEqual:"\u2ab0",SucceedsSlantEqual:"\u227d",SucceedsTilde:"\u227f",succeq:"\u2ab0",succnapprox:"\u2aba",succneqq:"\u2ab6",succnsim:"\u22e9",succsim:"\u227f",SuchThat:"\u220b",sum:"\u2211",Sum:"\u2211",sung:"\u266a",sup1:"\xb9",sup2:"\xb2",sup3:"\xb3",sup:"\u2283",Sup:"\u22d1",supdot:"\u2abe",supdsub:"\u2ad8",supE:"\u2ac6",supe:"\u2287",supedot:"\u2ac4",Superset:"\u2283",SupersetEqual:"\u2287",suphsol:"\u27c9",suphsub:"\u2ad7",suplarr:"\u297b",supmult:"\u2ac2",supnE:"\u2acc",supne:"\u228b",supplus:"\u2ac0",supset:"\u2283",Supset:"\u22d1",supseteq:"\u2287",supseteqq:"\u2ac6",supsetneq:"\u228b",supsetneqq:"\u2acc",supsim:"\u2ac8",supsub:"\u2ad4",supsup:"\u2ad6",swarhk:"\u2926",swarr:"\u2199",swArr:"\u21d9",swarrow:"\u2199",swnwar:"\u292a",szlig:"\xdf",Tab:"\t",target:"\u2316",Tau:"\u03a4",tau:"\u03c4",tbrk:"\u23b4",Tcaron:"\u0164",tcaron:"\u0165",Tcedil:"\u0162",tcedil:"\u0163",Tcy:"\u0422",tcy:"\u0442",tdot:"\u20db",telrec:"\u2315",Tfr:"\ud835\udd17",tfr:"\ud835\udd31",there4:"\u2234",therefore:"\u2234",Therefore:"\u2234",Theta:"\u0398",theta:"\u03b8",thetasym:"\u03d1",thetav:"\u03d1",thickapprox:"\u2248",thicksim:"\u223c",ThickSpace:"\u205f\u200a",ThinSpace:"\u2009",thinsp:"\u2009",thkap:"\u2248",thksim:"\u223c",THORN:"\xde",thorn:"\xfe",tilde:"\u02dc",Tilde:"\u223c",TildeEqual:"\u2243",TildeFullEqual:"\u2245",TildeTilde:"\u2248",timesbar:"\u2a31",timesb:"\u22a0",times:"\xd7",timesd:"\u2a30",tint:"\u222d",toea:"\u2928",topbot:"\u2336",topcir:"\u2af1",top:"\u22a4",Topf:"\ud835\udd4b",topf:"\ud835\udd65",topfork:"\u2ada",tosa:"\u2929",tprime:"\u2034",trade:"\u2122",TRADE:"\u2122",triangle:"\u25b5",triangledown:"\u25bf",triangleleft:"\u25c3",trianglelefteq:"\u22b4",triangleq:"\u225c",triangleright:"\u25b9",trianglerighteq:"\u22b5",tridot:"\u25ec",trie:"\u225c",triminus:"\u2a3a",TripleDot:"\u20db",triplus:"\u2a39",trisb:"\u29cd",tritime:"\u2a3b",trpezium:"\u23e2",Tscr:"\ud835\udcaf",tscr:"\ud835\udcc9",TScy:"\u0426",tscy:"\u0446",TSHcy:"\u040b",tshcy:"\u045b",Tstrok:"\u0166",tstrok:"\u0167",twixt:"\u226c",twoheadleftarrow:"\u219e",twoheadrightarrow:"\u21a0",Uacute:"\xda",uacute:"\xfa",uarr:"\u2191",Uarr:"\u219f",uArr:"\u21d1",Uarrocir:"\u2949",Ubrcy:"\u040e",ubrcy:"\u045e",Ubreve:"\u016c",ubreve:"\u016d",Ucirc:"\xdb",ucirc:"\xfb",Ucy:"\u0423",ucy:"\u0443",udarr:"\u21c5",Udblac:"\u0170",udblac:"\u0171",udhar:"\u296e",ufisht:"\u297e",Ufr:"\ud835\udd18",ufr:"\ud835\udd32",Ugrave:"\xd9",ugrave:"\xf9",uHar:"\u2963",uharl:"\u21bf",uharr:"\u21be",uhblk:"\u2580",ulcorn:"\u231c",ulcorner:"\u231c",ulcrop:"\u230f",ultri:"\u25f8",Umacr:"\u016a",umacr:"\u016b",uml:"\xa8",UnderBar:"_",UnderBrace:"\u23df",UnderBracket:"\u23b5",UnderParenthesis:"\u23dd",Union:"\u22c3",UnionPlus:"\u228e",Uogon:"\u0172",uogon:"\u0173",Uopf:"\ud835\udd4c",uopf:"\ud835\udd66",UpArrowBar:"\u2912",uparrow:"\u2191",UpArrow:"\u2191",Uparrow:"\u21d1",UpArrowDownArrow:"\u21c5",updownarrow:"\u2195",UpDownArrow:"\u2195",Updownarrow:"\u21d5",UpEquilibrium:"\u296e",upharpoonleft:"\u21bf",upharpoonright:"\u21be",uplus:"\u228e",UpperLeftArrow:"\u2196",UpperRightArrow:"\u2197",upsi:"\u03c5",Upsi:"\u03d2",upsih:"\u03d2",Upsilon:"\u03a5",upsilon:"\u03c5",UpTeeArrow:"\u21a5",UpTee:"\u22a5",upuparrows:"\u21c8",urcorn:"\u231d",urcorner:"\u231d",urcrop:"\u230e",Uring:"\u016e",uring:"\u016f",urtri:"\u25f9",Uscr:"\ud835\udcb0",uscr:"\ud835\udcca",utdot:"\u22f0",Utilde:"\u0168",utilde:"\u0169",utri:"\u25b5",utrif:"\u25b4",uuarr:"\u21c8",Uuml:"\xdc",uuml:"\xfc",uwangle:"\u29a7",vangrt:"\u299c",varepsilon:"\u03f5",varkappa:"\u03f0",varnothing:"\u2205",varphi:"\u03d5",varpi:"\u03d6",varpropto:"\u221d",varr:"\u2195",vArr:"\u21d5",varrho:"\u03f1",varsigma:"\u03c2",varsubsetneq:"\u228a\ufe00",varsubsetneqq:"\u2acb\ufe00",varsupsetneq:"\u228b\ufe00",varsupsetneqq:"\u2acc\ufe00",vartheta:"\u03d1",vartriangleleft:"\u22b2",vartriangleright:"\u22b3",vBar:"\u2ae8",Vbar:"\u2aeb",vBarv:"\u2ae9",Vcy:"\u0412",vcy:"\u0432",vdash:"\u22a2",vDash:"\u22a8",Vdash:"\u22a9",VDash:"\u22ab",Vdashl:"\u2ae6",veebar:"\u22bb",vee:"\u2228",Vee:"\u22c1",veeeq:"\u225a",vellip:"\u22ee",verbar:"|",Verbar:"\u2016",vert:"|",Vert:"\u2016",VerticalBar:"\u2223",VerticalLine:"|",VerticalSeparator:"\u2758",VerticalTilde:"\u2240",VeryThinSpace:"\u200a",Vfr:"\ud835\udd19",vfr:"\ud835\udd33",vltri:"\u22b2",vnsub:"\u2282\u20d2",vnsup:"\u2283\u20d2",Vopf:"\ud835\udd4d",vopf:"\ud835\udd67",vprop:"\u221d",vrtri:"\u22b3",Vscr:"\ud835\udcb1",vscr:"\ud835\udccb",vsubnE:"\u2acb\ufe00",vsubne:"\u228a\ufe00",vsupnE:"\u2acc\ufe00",vsupne:"\u228b\ufe00",Vvdash:"\u22aa",vzigzag:"\u299a",Wcirc:"\u0174",wcirc:"\u0175",wedbar:"\u2a5f",wedge:"\u2227",Wedge:"\u22c0",wedgeq:"\u2259",weierp:"\u2118",Wfr:"\ud835\udd1a",wfr:"\ud835\udd34",Wopf:"\ud835\udd4e",wopf:"\ud835\udd68",wp:"\u2118",wr:"\u2240",wreath:"\u2240",Wscr:"\ud835\udcb2",wscr:"\ud835\udccc",xcap:"\u22c2",xcirc:"\u25ef",xcup:"\u22c3",xdtri:"\u25bd",Xfr:"\ud835\udd1b",xfr:"\ud835\udd35",xharr:"\u27f7",xhArr:"\u27fa",Xi:"\u039e",xi:"\u03be",xlarr:"\u27f5",xlArr:"\u27f8",xmap:"\u27fc",xnis:"\u22fb",xodot:"\u2a00",Xopf:"\ud835\udd4f",xopf:"\ud835\udd69",xoplus:"\u2a01",xotime:"\u2a02",xrarr:"\u27f6",xrArr:"\u27f9",Xscr:"\ud835\udcb3",xscr:"\ud835\udccd",xsqcup:"\u2a06",xuplus:"\u2a04",xutri:"\u25b3",xvee:"\u22c1",xwedge:"\u22c0",Yacute:"\xdd",yacute:"\xfd",YAcy:"\u042f",yacy:"\u044f",Ycirc:"\u0176",ycirc:"\u0177",Ycy:"\u042b",ycy:"\u044b",yen:"\xa5",Yfr:"\ud835\udd1c",yfr:"\ud835\udd36",YIcy:"\u0407",yicy:"\u0457",Yopf:"\ud835\udd50",yopf:"\ud835\udd6a",Yscr:"\ud835\udcb4",yscr:"\ud835\udcce",YUcy:"\u042e",yucy:"\u044e",yuml:"\xff",Yuml:"\u0178",Zacute:"\u0179",zacute:"\u017a",Zcaron:"\u017d",zcaron:"\u017e",Zcy:"\u0417",zcy:"\u0437",Zdot:"\u017b",zdot:"\u017c",zeetrf:"\u2128",ZeroWidthSpace:"\u200b",Zeta:"\u0396",zeta:"\u03b6",zfr:"\ud835\udd37",Zfr:"\u2128",ZHcy:"\u0416",zhcy:"\u0436",zigrarr:"\u21dd",zopf:"\ud835\udd6b",Zopf:"\u2124",Zscr:"\ud835\udcb5",zscr:"\ud835\udccf",zwj:"\u200d",zwnj:"\u200c"}},{}],53:[function(e,r,t){"use strict";function n(e){return Array.prototype.slice.call(arguments,1).forEach(function(r){r&&Object.keys(r).forEach(function(t){e[t]=r[t]})}),e}function s(e){return Object.prototype.toString.call(e)}function o(e){return"[object String]"===s(e)}function i(e){return"[object Object]"===s(e)}function a(e){return"[object RegExp]"===s(e)}function c(e){return"[object Function]"===s(e)}function l(e){return e.replace(/[.?*+^$[\]\\(){}|-]/g,"\\$&")}function u(e){return Object.keys(e||{}).reduce(function(e,r){return e||b.hasOwnProperty(r)},!1)}function p(e){e.__index__=-1,e.__text_cache__=""}function h(e){return function(r,t){var n=r.slice(t);return e.test(n)?n.match(e)[0].length:0}}function f(){return function(e,r){r.normalize(e)}}function d(r){function t(e){return e.replace("%TLDS%",s.src_tlds)}function n(e,r){throw new Error('(LinkifyIt) Invalid schema "'+e+'": '+r)}var s=r.re=e("./lib/re")(r.__opts__),u=r.__tlds__.slice();r.onCompile(),r.__tlds_replaced__||u.push(v),u.push(s.src_xn),s.src_tlds=u.join("|"),s.email_fuzzy=RegExp(t(s.tpl_email_fuzzy),"i"),s.link_fuzzy=RegExp(t(s.tpl_link_fuzzy),"i"),s.link_no_ip_fuzzy=RegExp(t(s.tpl_link_no_ip_fuzzy),"i"),s.host_fuzzy_test=RegExp(t(s.tpl_host_fuzzy_test),"i");var d=[];r.__compiled__={},Object.keys(r.__schemas__).forEach(function(e){var t=r.__schemas__[e];if(null!==t){var s={validate:null,link:null};if(r.__compiled__[e]=s,i(t))return a(t.validate)?s.validate=h(t.validate):c(t.validate)?s.validate=t.validate:n(e,t),void(c(t.normalize)?s.normalize=t.normalize:t.normalize?n(e,t):s.normalize=f());o(t)?d.push(e):n(e,t)}}),d.forEach(function(e){r.__compiled__[r.__schemas__[e]]&&(r.__compiled__[e].validate=r.__compiled__[r.__schemas__[e]].validate,r.__compiled__[e].normalize=r.__compiled__[r.__schemas__[e]].normalize)}),r.__compiled__[""]={validate:null,normalize:f()};var m=Object.keys(r.__compiled__).filter(function(e){return e.length>0&&r.__compiled__[e]}).map(l).join("|");r.re.schema_test=RegExp("(^|(?!_)(?:[><\uff5c]|"+s.src_ZPCc+"))("+m+")","i"),r.re.schema_search=RegExp("(^|(?!_)(?:[><\uff5c]|"+s.src_ZPCc+"))("+m+")","ig"),r.re.pretest=RegExp("("+r.re.schema_test.source+")|("+r.re.host_fuzzy_test.source+")|@","i"),p(r)}function m(e,r){var t=e.__index__,n=e.__last_index__,s=e.__text_cache__.slice(t,n);this.schema=e.__schema__.toLowerCase(),this.index=t+r,this.lastIndex=n+r,this.raw=s,this.text=s,this.url=s}function _(e,r){var t=new m(e,r);return e.__compiled__[t.schema].normalize(t,e),t}function g(e,r){if(!(this instanceof g))return new g(e,r);r||u(e)&&(r=e,e={}),this.__opts__=n({},b,r),this.__index__=-1,this.__last_index__=-1,this.__schema__="",this.__text_cache__="",this.__schemas__=n({},k,e),this.__compiled__={},this.__tlds__=x,this.__tlds_replaced__=!1,this.re={},d(this)}var b={fuzzyLink:!0,fuzzyEmail:!0,fuzzyIP:!1},k={"http:":{validate:function(e,r,t){var n=e.slice(r);return t.re.http||(t.re.http=new RegExp("^\\/\\/"+t.re.src_auth+t.re.src_host_port_strict+t.re.src_path,"i")),t.re.http.test(n)?n.match(t.re.http)[0].length:0}},"https:":"http:","ftp:":"http:","//":{validate:function(e,r,t){var n=e.slice(r);return t.re.no_http||(t.re.no_http=new RegExp("^"+t.re.src_auth+"(?:localhost|(?:(?:"+t.re.src_domain+")\\.)+"+t.re.src_domain_root+")"+t.re.src_port+t.re.src_host_terminator+t.re.src_path,"i")),t.re.no_http.test(n)?r>=3&&":"===e[r-3]?0:r>=3&&"/"===e[r-3]?0:n.match(t.re.no_http)[0].length:0}},"mailto:":{validate:function(e,r,t){var n=e.slice(r);return t.re.mailto||(t.re.mailto=new RegExp("^"+t.re.src_email_name+"@"+t.re.src_host_strict,"i")),t.re.mailto.test(n)?n.match(t.re.mailto)[0].length:0}}},v="a[cdefgilmnoqrstuwxz]|b[abdefghijmnorstvwyz]|c[acdfghiklmnoruvwxyz]|d[ejkmoz]|e[cegrstu]|f[ijkmor]|g[abdefghilmnpqrstuwy]|h[kmnrtu]|i[delmnoqrst]|j[emop]|k[eghimnprwyz]|l[abcikrstuvy]|m[acdeghklmnopqrstuvwxyz]|n[acefgilopruz]|om|p[aefghklmnrstwy]|qa|r[eosuw]|s[abcdeghijklmnortuvxyz]|t[cdfghjklmnortvwz]|u[agksyz]|v[aceginu]|w[fs]|y[et]|z[amw]",x="biz|com|edu|gov|net|org|pro|web|xxx|aero|asia|coop|info|museum|name|shop|\u0440\u0444".split("|");g.prototype.add=function(e,r){return this.__schemas__[e]=r,d(this),this},g.prototype.set=function(e){return this.__opts__=n(this.__opts__,e),this},g.prototype.test=function(e){if(this.__text_cache__=e,this.__index__=-1,!e.length)return!1;var r,t,n,s,o,i,a,c;if(this.re.schema_test.test(e))for((a=this.re.schema_search).lastIndex=0;null!==(r=a.exec(e));)if(s=this.testSchemaAt(e,r[2],a.lastIndex)){this.__schema__=r[2],this.__index__=r.index+r[1].length,this.__last_index__=r.index+r[0].length+s;break}return this.__opts__.fuzzyLink&&this.__compiled__["http:"]&&(c=e.search(this.re.host_fuzzy_test))>=0&&(this.__index__<0||c=0&&null!==(n=e.match(this.re.email_fuzzy))&&(o=n.index+n[1].length,i=n.index+n[0].length,(this.__index__<0||othis.__last_index__)&&(this.__schema__="mailto:",this.__index__=o,this.__last_index__=i)),this.__index__>=0},g.prototype.pretest=function(e){return this.re.pretest.test(e)},g.prototype.testSchemaAt=function(e,r,t){return this.__compiled__[r.toLowerCase()]?this.__compiled__[r.toLowerCase()].validate(e,t,this):0},g.prototype.match=function(e){var r=0,t=[];this.__index__>=0&&this.__text_cache__===e&&(t.push(_(this,r)),r=this.__last_index__);for(var n=r?e.slice(r):e;this.test(n);)t.push(_(this,r)),n=n.slice(this.__last_index__),r+=this.__last_index__;return t.length?t:null},g.prototype.tlds=function(e,r){return e=Array.isArray(e)?e:[e],r?(this.__tlds__=this.__tlds__.concat(e).sort().filter(function(e,r,t){return e!==t[r-1]}).reverse(),d(this),this):(this.__tlds__=e.slice(),this.__tlds_replaced__=!0,d(this),this)},g.prototype.normalize=function(e){e.schema||(e.url="http://"+e.url),"mailto:"!==e.schema||/^mailto:/i.test(e.url)||(e.url="mailto:"+e.url)},g.prototype.onCompile=function(){},r.exports=g},{"./lib/re":54}],54:[function(e,r,t){"use strict";r.exports=function(r){var t={};t.src_Any=e("uc.micro/properties/Any/regex").source,t.src_Cc=e("uc.micro/categories/Cc/regex").source,t.src_Z=e("uc.micro/categories/Z/regex").source,t.src_P=e("uc.micro/categories/P/regex").source,t.src_ZPCc=[t.src_Z,t.src_P,t.src_Cc].join("|"),t.src_ZCc=[t.src_Z,t.src_Cc].join("|");return t.src_pseudo_letter="(?:(?![><\uff5c]|"+t.src_ZPCc+")"+t.src_Any+")",t.src_ip4="(?:(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)",t.src_auth="(?:(?:(?!"+t.src_ZCc+"|[@/\\[\\]()]).)+@)?",t.src_port="(?::(?:6(?:[0-4]\\d{3}|5(?:[0-4]\\d{2}|5(?:[0-2]\\d|3[0-5])))|[1-5]?\\d{1,4}))?",t.src_host_terminator="(?=$|[><\uff5c]|"+t.src_ZPCc+")(?!-|_|:\\d|\\.-|\\.(?!$|"+t.src_ZPCc+"))",t.src_path="(?:[/?#](?:(?!"+t.src_ZCc+"|[><\uff5c]|[()[\\]{}.,\"'?!\\-]).|\\[(?:(?!"+t.src_ZCc+"|\\]).)*\\]|\\((?:(?!"+t.src_ZCc+"|[)]).)*\\)|\\{(?:(?!"+t.src_ZCc+'|[}]).)*\\}|\\"(?:(?!'+t.src_ZCc+'|["]).)+\\"|\\\'(?:(?!'+t.src_ZCc+"|[']).)+\\'|\\'(?="+t.src_pseudo_letter+"|[-]).|\\.{2,3}[a-zA-Z0-9%/]|\\.(?!"+t.src_ZCc+"|[.]).|"+(r&&r["---"]?"\\-(?!--(?:[^-]|$))(?:-*)|":"\\-+|")+"\\,(?!"+t.src_ZCc+").|\\!(?!"+t.src_ZCc+"|[!]).|\\?(?!"+t.src_ZCc+"|[?]).)+|\\/)?",t.src_email_name='[\\-;:&=\\+\\$,\\"\\.a-zA-Z0-9_]+',t.src_xn="xn--[a-z0-9\\-]{1,59}",t.src_domain_root="(?:"+t.src_xn+"|"+t.src_pseudo_letter+"{1,63})",t.src_domain="(?:"+t.src_xn+"|(?:"+t.src_pseudo_letter+")|(?:"+t.src_pseudo_letter+"(?:-(?!-)|"+t.src_pseudo_letter+"){0,61}"+t.src_pseudo_letter+"))",t.src_host="(?:(?:(?:(?:"+t.src_domain+")\\.)*"+t.src_domain+"))",t.tpl_host_fuzzy="(?:"+t.src_ip4+"|(?:(?:(?:"+t.src_domain+")\\.)+(?:%TLDS%)))",t.tpl_host_no_ip_fuzzy="(?:(?:(?:"+t.src_domain+")\\.)+(?:%TLDS%))",t.src_host_strict=t.src_host+t.src_host_terminator,t.tpl_host_fuzzy_strict=t.tpl_host_fuzzy+t.src_host_terminator,t.src_host_port_strict=t.src_host+t.src_port+t.src_host_terminator,t.tpl_host_port_fuzzy_strict=t.tpl_host_fuzzy+t.src_port+t.src_host_terminator,t.tpl_host_port_no_ip_fuzzy_strict=t.tpl_host_no_ip_fuzzy+t.src_port+t.src_host_terminator,t.tpl_host_fuzzy_test="localhost|www\\.|\\.\\d{1,3}\\.|(?:\\.(?:%TLDS%)(?:"+t.src_ZPCc+"|>|$))",t.tpl_email_fuzzy="(^|[><\uff5c]|\\(|"+t.src_ZCc+")("+t.src_email_name+"@"+t.tpl_host_fuzzy_strict+")",t.tpl_link_fuzzy="(^|(?![.:/\\-_@])(?:[$+<=>^`|\uff5c]|"+t.src_ZPCc+"))((?![$+<=>^`|\uff5c])"+t.tpl_host_port_fuzzy_strict+t.src_path+")",t.tpl_link_no_ip_fuzzy="(^|(?![.:/\\-_@])(?:[$+<=>^`|\uff5c]|"+t.src_ZPCc+"))((?![$+<=>^`|\uff5c])"+t.tpl_host_port_no_ip_fuzzy_strict+t.src_path+")",t}},{"uc.micro/categories/Cc/regex":61,"uc.micro/categories/P/regex":63,"uc.micro/categories/Z/regex":64,"uc.micro/properties/Any/regex":66}],55:[function(e,r,t){"use strict";function n(e){var r,t,n=o[e];if(n)return n;for(n=o[e]=[],r=0;r<128;r++)t=String.fromCharCode(r),n.push(t);for(r=0;r=55296&&c<=57343?"\ufffd\ufffd\ufffd":String.fromCharCode(c),r+=6):240==(248&s)&&r+91114111?l+="\ufffd\ufffd\ufffd\ufffd":(c-=65536,l+=String.fromCharCode(55296+(c>>10),56320+(1023&c))),r+=9):l+="\ufffd";return l})}var o={};s.defaultChars=";/?:@&=+$,#",s.componentChars="",r.exports=s},{}],56:[function(e,r,t){"use strict";function n(e){var r,t,n=o[e];if(n)return n;for(n=o[e]=[],r=0;r<128;r++)t=String.fromCharCode(r),/^[0-9a-z]$/i.test(t)?n.push(t):n.push("%"+("0"+r.toString(16).toUpperCase()).slice(-2));for(r=0;r=55296&&a<=57343){if(a>=55296&&a<=56319&&o+1=56320&&c<=57343){u+=encodeURIComponent(e[o]+e[o+1]),o++;continue}u+="%EF%BF%BD"}else u+=encodeURIComponent(e[o]);return u}var o={};s.defaultChars=";/?:@&=+$,-_.!~*'()#",s.componentChars="-_.!~*'()",r.exports=s},{}],57:[function(e,r,t){"use strict";r.exports=function(e){var r="";return r+=e.protocol||"",r+=e.slashes?"//":"",r+=e.auth?e.auth+"@":"",e.hostname&&-1!==e.hostname.indexOf(":")?r+="["+e.hostname+"]":r+=e.hostname||"",r+=e.port?":"+e.port:"",r+=e.pathname||"",r+=e.search||"",r+=e.hash||""}},{}],58:[function(e,r,t){"use strict";r.exports.encode=e("./encode"),r.exports.decode=e("./decode"),r.exports.format=e("./format"),r.exports.parse=e("./parse")},{"./decode":55,"./encode":56,"./format":57,"./parse":59}],59:[function(e,r,t){"use strict";function n(){this.protocol=null,this.slashes=null,this.auth=null,this.port=null,this.hostname=null,this.hash=null,this.search=null,this.pathname=null}var s=/^([a-z0-9.+-]+:)/i,o=/:[0-9]*$/,i=/^(\/\/?(?!\/)[^\?\s]*)(\?[^\s]*)?$/,a=["<",">",'"',"`"," ","\r","\n","\t"],c=["{","}","|","\\","^","`"].concat(a),l=["'"].concat(c),u=["%","/","?",";","#"].concat(l),p=["/","?","#"],h=/^[+a-z0-9A-Z_-]{0,63}$/,f=/^([+a-z0-9A-Z_-]{0,63})(.*)$/,d={javascript:!0,"javascript:":!0},m={http:!0,https:!0,ftp:!0,gopher:!0,file:!0,"http:":!0,"https:":!0,"ftp:":!0,"gopher:":!0,"file:":!0};n.prototype.parse=function(e,r){var t,n,o,a,c,l=e;if(l=l.trim(),!r&&1===e.split("#").length){var _=i.exec(l);if(_)return this.pathname=_[1],_[2]&&(this.search=_[2]),this}var g=s.exec(l);if(g&&(o=(g=g[0]).toLowerCase(),this.protocol=g,l=l.substr(g.length)),(r||g||l.match(/^\/\/[^@\/]+@[^@\/]+/))&&(!(c="//"===l.substr(0,2))||g&&d[g]||(l=l.substr(2),this.slashes=!0)),!d[g]&&(c||g&&!m[g])){var b=-1;for(t=0;t127?w+="x":w+=A[D];if(!w.match(h)){var E=C.slice(0,t),S=C.slice(t+1),F=A.match(f);F&&(E.push(F[1]),S.unshift(F[2])),S.length&&(l=S.join(".")+l),this.hostname=E.join(".");break}}}}this.hostname.length>255&&(this.hostname=""),y&&(this.hostname=this.hostname.substr(1,this.hostname.length-2))}var L=l.indexOf("#");-1!==L&&(this.hash=l.substr(L),l=l.slice(0,L));var z=l.indexOf("?");return-1!==z&&(this.search=l.substr(z),l=l.slice(0,z)),l&&(this.pathname=l),m[o]&&this.hostname&&!this.pathname&&(this.pathname=""),this},n.prototype.parseHost=function(e){var r=o.exec(e);r&&(":"!==(r=r[0])&&(this.port=r.substr(1)),e=e.substr(0,e.length-r.length)),e&&(this.hostname=e)},r.exports=function(e,r){if(e&&e instanceof n)return e;var t=new n;return t.parse(e,r),t}},{}],60:[function(e,r,t){(function(e){!function(n){function s(e){throw new RangeError(L[e])}function o(e,r){for(var t=e.length,n=[];t--;)n[t]=r(e[t]);return n}function i(e,r){var t=e.split("@"),n="";return t.length>1&&(n=t[0]+"@",e=t[1]),n+o((e=e.replace(F,".")).split("."),r).join(".")}function a(e){for(var r,t,n=[],s=0,o=e.length;s=55296&&r<=56319&&s65535&&(r+=I((e-=65536)>>>10&1023|55296),e=56320|1023&e),r+=I(e)}).join("")}function l(e){return e-48<10?e-22:e-65<26?e-65:e-97<26?e-97:v}function u(e,r){return e+22+75*(e<26)-((0!=r)<<5)}function p(e,r,t){var n=0;for(e=t?T(e/A):e>>1,e+=T(e/r);e>z*y>>1;n+=v)e=T(e/z);return T(n+(z+1)*e/(e+C))}function h(e){var r,t,n,o,i,a,u,h,f,d,m=[],_=e.length,g=0,b=D,C=w;for((t=e.lastIndexOf(q))<0&&(t=0),n=0;n=128&&s("not-basic"),m.push(e.charCodeAt(n));for(o=t>0?t+1:0;o<_;){for(i=g,a=1,u=v;o>=_&&s("invalid-input"),((h=l(e.charCodeAt(o++)))>=v||h>T((k-g)/a))&&s("overflow"),g+=h*a,f=u<=C?x:u>=C+y?y:u-C,!(hT(k/(d=v-f))&&s("overflow"),a*=d;C=p(g-i,r=m.length+1,0==i),T(g/r)>k-b&&s("overflow"),b+=T(g/r),g%=r,m.splice(g++,0,b)}return c(m)}function f(e){var r,t,n,o,i,c,l,h,f,d,m,_,g,b,C,A=[];for(_=(e=a(e)).length,r=D,t=0,i=w,c=0;c<_;++c)(m=e[c])<128&&A.push(I(m));for(n=o=A.length,o&&A.push(q);n<_;){for(l=k,c=0;c<_;++c)(m=e[c])>=r&&mT((k-t)/(g=n+1))&&s("overflow"),t+=(l-r)*g,r=l,c=0;c<_;++c)if((m=e[c])k&&s("overflow"),m==r){for(h=t,f=v;d=f<=i?x:f>=i+y?y:f-i,!(h= 0x80 (not a basic code point)","invalid-input":"Invalid input"},z=v-x,T=Math.floor,I=String.fromCharCode;if(g={version:"1.4.1",ucs2:{decode:a,encode:c},decode:h,encode:f,toASCII:function(e){return i(e,function(e){return S.test(e)?"xn--"+f(e):e})},toUnicode:function(e){return i(e,function(e){return E.test(e)?h(e.slice(4).toLowerCase()):e})}},d&&m)if(r.exports==d)m.exports=g;else for(b in g)g.hasOwnProperty(b)&&(d[b]=g[b]);else n.punycode=g}(this)}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}],61:[function(e,r,t){r.exports=/[\0-\x1F\x7F-\x9F]/},{}],62:[function(e,r,t){r.exports=/[\xAD\u0600-\u0605\u061C\u06DD\u070F\u08E2\u180E\u200B-\u200F\u202A-\u202E\u2060-\u2064\u2066-\u206F\uFEFF\uFFF9-\uFFFB]|\uD804\uDCBD|\uD82F[\uDCA0-\uDCA3]|\uD834[\uDD73-\uDD7A]|\uDB40[\uDC01\uDC20-\uDC7F]/},{}],63:[function(e,r,t){r.exports=/[!-#%-\*,-/:;\?@\[-\]_\{\}\xA1\xA7\xAB\xB6\xB7\xBB\xBF\u037E\u0387\u055A-\u055F\u0589\u058A\u05BE\u05C0\u05C3\u05C6\u05F3\u05F4\u0609\u060A\u060C\u060D\u061B\u061E\u061F\u066A-\u066D\u06D4\u0700-\u070D\u07F7-\u07F9\u0830-\u083E\u085E\u0964\u0965\u0970\u0AF0\u0DF4\u0E4F\u0E5A\u0E5B\u0F04-\u0F12\u0F14\u0F3A-\u0F3D\u0F85\u0FD0-\u0FD4\u0FD9\u0FDA\u104A-\u104F\u10FB\u1360-\u1368\u1400\u166D\u166E\u169B\u169C\u16EB-\u16ED\u1735\u1736\u17D4-\u17D6\u17D8-\u17DA\u1800-\u180A\u1944\u1945\u1A1E\u1A1F\u1AA0-\u1AA6\u1AA8-\u1AAD\u1B5A-\u1B60\u1BFC-\u1BFF\u1C3B-\u1C3F\u1C7E\u1C7F\u1CC0-\u1CC7\u1CD3\u2010-\u2027\u2030-\u2043\u2045-\u2051\u2053-\u205E\u207D\u207E\u208D\u208E\u2308-\u230B\u2329\u232A\u2768-\u2775\u27C5\u27C6\u27E6-\u27EF\u2983-\u2998\u29D8-\u29DB\u29FC\u29FD\u2CF9-\u2CFC\u2CFE\u2CFF\u2D70\u2E00-\u2E2E\u2E30-\u2E44\u3001-\u3003\u3008-\u3011\u3014-\u301F\u3030\u303D\u30A0\u30FB\uA4FE\uA4FF\uA60D-\uA60F\uA673\uA67E\uA6F2-\uA6F7\uA874-\uA877\uA8CE\uA8CF\uA8F8-\uA8FA\uA8FC\uA92E\uA92F\uA95F\uA9C1-\uA9CD\uA9DE\uA9DF\uAA5C-\uAA5F\uAADE\uAADF\uAAF0\uAAF1\uABEB\uFD3E\uFD3F\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE61\uFE63\uFE68\uFE6A\uFE6B\uFF01-\uFF03\uFF05-\uFF0A\uFF0C-\uFF0F\uFF1A\uFF1B\uFF1F\uFF20\uFF3B-\uFF3D\uFF3F\uFF5B\uFF5D\uFF5F-\uFF65]|\uD800[\uDD00-\uDD02\uDF9F\uDFD0]|\uD801\uDD6F|\uD802[\uDC57\uDD1F\uDD3F\uDE50-\uDE58\uDE7F\uDEF0-\uDEF6\uDF39-\uDF3F\uDF99-\uDF9C]|\uD804[\uDC47-\uDC4D\uDCBB\uDCBC\uDCBE-\uDCC1\uDD40-\uDD43\uDD74\uDD75\uDDC5-\uDDC9\uDDCD\uDDDB\uDDDD-\uDDDF\uDE38-\uDE3D\uDEA9]|\uD805[\uDC4B-\uDC4F\uDC5B\uDC5D\uDCC6\uDDC1-\uDDD7\uDE41-\uDE43\uDE60-\uDE6C\uDF3C-\uDF3E]|\uD807[\uDC41-\uDC45\uDC70\uDC71]|\uD809[\uDC70-\uDC74]|\uD81A[\uDE6E\uDE6F\uDEF5\uDF37-\uDF3B\uDF44]|\uD82F\uDC9F|\uD836[\uDE87-\uDE8B]|\uD83A[\uDD5E\uDD5F]/},{}],64:[function(e,r,t){r.exports=/[ \xA0\u1680\u2000-\u200A\u202F\u205F\u3000]/},{}],65:[function(e,r,t){"use strict";t.Any=e("./properties/Any/regex"),t.Cc=e("./categories/Cc/regex"),t.Cf=e("./categories/Cf/regex"),t.P=e("./categories/P/regex"),t.Z=e("./categories/Z/regex")},{"./categories/Cc/regex":61,"./categories/Cf/regex":62,"./categories/P/regex":63,"./categories/Z/regex":64,"./properties/Any/regex":66}],66:[function(e,r,t){r.exports=/[\0-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/},{}],67:[function(e,r,t){"use strict";r.exports=e("./lib/")},{"./lib/":9}]},{},[67])(67)}); diff --git a/static/js/mdeditor/plugins/code-block-dialog/code-block-dialog.js b/static/js/mdeditor/plugins/code-block-dialog/code-block-dialog.js new file mode 100644 index 00000000..b4b0d8cb --- /dev/null +++ b/static/js/mdeditor/plugins/code-block-dialog/code-block-dialog.js @@ -0,0 +1,237 @@ +/*! + * Code block dialog plugin for Editor.md + * + * @file code-block-dialog.js + * @author pandao + * @version 1.2.0 + * @updateTime 2015-03-07 + * {@link https://github.com/pandao/editor.md} + * @license MIT + */ + +(function() { + + var factory = function (exports) { + var cmEditor; + var pluginName = "code-block-dialog"; + + // for CodeBlock dialog select + var codeLanguages = exports.codeLanguages = { + asp : ["ASP", "vbscript"], + actionscript : ["ActionScript(3.0)/Flash/Flex", "clike"], + bash : ["Bash/Bat", "shell"], + css : ["CSS", "css"], + c : ["C", "clike"], + cpp : ["C++", "clike"], + csharp : ["C#", "clike"], + coffeescript : ["CoffeeScript", "coffeescript"], + d : ["D", "d"], + dart : ["Dart", "dart"], + delphi : ["Delphi/Pascal", "pascal"], + erlang : ["Erlang", "erlang"], + go : ["Golang", "go"], + groovy : ["Groovy", "groovy"], + html : ["HTML", "text/html"], + java : ["Java", "clike"], + json : ["JSON", "text/json"], + javascript : ["Javascript", "javascript"], + lua : ["Lua", "lua"], + less : ["LESS", "css"], + markdown : ["Markdown", "gfm"], + "objective-c" : ["Objective-C", "clike"], + php : ["PHP", "php"], + perl : ["Perl", "perl"], + python : ["Python", "python"], + r : ["R", "r"], + rst : ["reStructedText", "rst"], + ruby : ["Ruby", "ruby"], + sql : ["SQL", "sql"], + sass : ["SASS/SCSS", "sass"], + shell : ["Shell", "shell"], + scala : ["Scala", "clike"], + swift : ["Swift", "clike"], + vb : ["VB/VBScript", "vb"], + xml : ["XML", "text/xml"], + yaml : ["YAML", "yaml"] + }; + + exports.fn.codeBlockDialog = function() { + + var _this = this; + var cm = this.cm; + var lang = this.lang; + var editor = this.editor; + var settings = this.settings; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + var classPrefix = this.classPrefix; + var dialogName = classPrefix + pluginName, dialog; + var dialogLang = lang.dialog.codeBlock; + + cm.focus(); + + if (editor.find("." + dialogName).length > 0) + { + dialog = editor.find("." + dialogName); + dialog.find("option:first").attr("selected", "selected"); + dialog.find("textarea").val(selection); + + this.dialogShowMask(dialog); + this.dialogLockScreen(); + dialog.show(); + } + else + { + var dialogHTML = "
    " + + dialogLang.selectLabel + "" + + "
    " + + ""; + + dialog = this.createDialog({ + name : dialogName, + title : dialogLang.title, + width : 780, + height : 565, + mask : settings.dialogShowMask, + drag : settings.dialogDraggable, + content : dialogHTML, + lockScreen : settings.dialogLockScreen, + maskStyle : { + opacity : settings.dialogMaskOpacity, + backgroundColor : settings.dialogMaskBgColor + }, + buttons : { + enter : [lang.buttons.enter, function() { + var codeTexts = this.find("textarea").val(); + var langName = this.find("select").val(); + + if (langName === "") + { + alert(lang.dialog.codeBlock.unselectedLanguageAlert); + return false; + } + + if (codeTexts === "") + { + alert(lang.dialog.codeBlock.codeEmptyAlert); + return false; + } + + langName = (langName === "other") ? "" : langName; + + cm.replaceSelection(["```" + langName, codeTexts, "```"].join("\n")); + + if (langName === "") { + cm.setCursor(cursor.line, cursor.ch + 3); + } + + this.hide().lockScreen(false).hideMask(); + + return false; + }], + cancel : [lang.buttons.cancel, function() { + this.hide().lockScreen(false).hideMask(); + + return false; + }] + } + }); + } + + var langSelect = dialog.find("select"); + + if (langSelect.find("option").length === 1) + { + for (var key in codeLanguages) + { + var codeLang = codeLanguages[key]; + langSelect.append(""); + } + + langSelect.append(""); + } + + var mode = langSelect.find("option:selected").attr("mode"); + + var cmConfig = { + mode : (mode) ? mode : "text/html", + theme : settings.theme, + tabSize : 4, + autofocus : true, + autoCloseTags : true, + indentUnit : 4, + lineNumbers : true, + lineWrapping : true, + extraKeys : {"Ctrl-Q": function(cm){ cm.foldCode(cm.getCursor()); }}, + foldGutter : true, + gutters : ["CodeMirror-linenumbers", "CodeMirror-foldgutter"], + matchBrackets : true, + indentWithTabs : true, + styleActiveLine : true, + styleSelectedText : true, + autoCloseBrackets : true, + showTrailingSpace : true, + highlightSelectionMatches : true + }; + + var textarea = dialog.find("textarea"); + var cmObj = dialog.find(".CodeMirror"); + + if (dialog.find(".CodeMirror").length < 1) + { + cmEditor = exports.$CodeMirror.fromTextArea(textarea[0], cmConfig); + cmObj = dialog.find(".CodeMirror"); + + cmObj.css({ + "float" : "none", + margin : "8px 0", + border : "1px solid #ddd", + fontSize : settings.fontSize, + width : "100%", + height : "390px" + }); + + cmEditor.on("change", function(cm) { + textarea.val(cm.getValue()); + }); + } + else + { + + cmEditor.setValue(cm.getSelection()); + } + + langSelect.change(function(){ + var _mode = $(this).find("option:selected").attr("mode"); + cmEditor.setOption("mode", _mode); + }); + }; + + }; + + // CommonJS/Node.js + if (typeof require === "function" && typeof exports === "object" && typeof module === "object") + { + module.exports = factory; + } + else if (typeof define === "function") // AMD/CMD/Sea.js + { + if (define.amd) { // for Require.js + + define(["editormd"], function(editormd) { + factory(editormd); + }); + + } else { // for Sea.js + define(function(require) { + var editormd = require("./../../editormd"); + factory(editormd); + }); + } + } + else + { + factory(window.editormd); + } + +})(); diff --git a/static/js/mdeditor/plugins/goto-line-dialog/goto-line-dialog.js b/static/js/mdeditor/plugins/goto-line-dialog/goto-line-dialog.js new file mode 100644 index 00000000..f8757437 --- /dev/null +++ b/static/js/mdeditor/plugins/goto-line-dialog/goto-line-dialog.js @@ -0,0 +1,157 @@ +/*! + * Goto line dialog plugin for Editor.md + * + * @file goto-line-dialog.js + * @author pandao + * @version 1.2.1 + * @updateTime 2015-06-09 + * {@link https://github.com/pandao/editor.md} + * @license MIT + */ + +(function() { + + var factory = function (exports) { + + var $ = jQuery; + var pluginName = "goto-line-dialog"; + + var langs = { + "zh-cn" : { + toolbar : { + "goto-line" : "跳转到行" + }, + dialog : { + "goto-line" : { + title : "跳转到行", + label : "请输入行号", + error : "错误:" + } + } + }, + "zh-tw" : { + toolbar : { + "goto-line" : "跳轉到行" + }, + dialog : { + "goto-line" : { + title : "跳轉到行", + label : "請輸入行號", + error : "錯誤:" + } + } + }, + "en" : { + toolbar : { + "goto-line" : "Goto line" + }, + dialog : { + "goto-line" : { + title : "Goto line", + label : "Enter a line number, range ", + error : "Error: " + } + } + } + }; + + exports.fn.gotoLineDialog = function() { + var _this = this; + var cm = this.cm; + var editor = this.editor; + var settings = this.settings; + var path = settings.pluginPath + pluginName +"/"; + var classPrefix = this.classPrefix; + var dialogName = classPrefix + pluginName, dialog; + + $.extend(true, this.lang, langs[this.lang.name]); + this.setToolbar(); + + var lang = this.lang; + var dialogLang = lang.dialog["goto-line"]; + var lineCount = cm.lineCount(); + + dialogLang.error += dialogLang.label + " 1-" + lineCount; + + if (editor.find("." + dialogName).length < 1) + { + var dialogContent = [ + "
    ", + "

    " + dialogLang.label + " 1-" + lineCount +"   

    ", + "
    " + ].join("\n"); + + dialog = this.createDialog({ + name : dialogName, + title : dialogLang.title, + width : 400, + height : 180, + mask : settings.dialogShowMask, + drag : settings.dialogDraggable, + content : dialogContent, + lockScreen : settings.dialogLockScreen, + maskStyle : { + opacity : settings.dialogMaskOpacity, + backgroundColor : settings.dialogMaskBgColor + }, + buttons : { + enter : [lang.buttons.enter, function() { + var line = parseInt(this.find("[data-line-number]").val()); + + if (line < 1 || line > lineCount) { + alert(dialogLang.error); + + return false; + } + + _this.gotoLine(line); + + this.hide().lockScreen(false).hideMask(); + + return false; + }], + + cancel : [lang.buttons.cancel, function() { + this.hide().lockScreen(false).hideMask(); + + return false; + }] + } + }); + } + + dialog = editor.find("." + dialogName); + + this.dialogShowMask(dialog); + this.dialogLockScreen(); + dialog.show(); + }; + + }; + + // CommonJS/Node.js + if (typeof require === "function" && typeof exports === "object" && typeof module === "object") + { + module.exports = factory; + } + else if (typeof define === "function") // AMD/CMD/Sea.js + { + if (define.amd) { // for Require.js + + define(["editormd"], function(editormd) { + factory(editormd); + }); + + } else { // for Sea.js + define(function(require) { + var editormd = require("./../../editormd"); + factory(editormd); + }); + } + } + else + { + factory(window.editormd); + } + +})(); diff --git a/static/js/mdeditor/plugins/help-dialog/help-dialog.js b/static/js/mdeditor/plugins/help-dialog/help-dialog.js new file mode 100644 index 00000000..339b3c0e --- /dev/null +++ b/static/js/mdeditor/plugins/help-dialog/help-dialog.js @@ -0,0 +1,102 @@ +/*! + * Help dialog plugin for Editor.md + * + * @file help-dialog.js + * @author pandao + * @version 1.2.0 + * @updateTime 2015-03-08 + * {@link https://github.com/pandao/editor.md} + * @license MIT + */ + +(function() { + + var factory = function (exports) { + + var $ = jQuery; + var pluginName = "help-dialog"; + + exports.fn.helpDialog = function() { + var _this = this; + var lang = this.lang; + var editor = this.editor; + var settings = this.settings; + var path = settings.pluginPath + pluginName + "/"; + var classPrefix = this.classPrefix; + var dialogName = classPrefix + pluginName, dialog; + var dialogLang = lang.dialog.help; + + if (editor.find("." + dialogName).length < 1) + { + var dialogContent = "
    "; + + dialog = this.createDialog({ + name : dialogName, + title : dialogLang.title, + width : 840, + height : 540, + mask : settings.dialogShowMask, + drag : settings.dialogDraggable, + content : dialogContent, + lockScreen : settings.dialogLockScreen, + maskStyle : { + opacity : settings.dialogMaskOpacity, + backgroundColor : settings.dialogMaskBgColor + }, + buttons : { + close : [lang.buttons.close, function() { + this.hide().lockScreen(false).hideMask(); + + return false; + }] + } + }); + } + + dialog = editor.find("." + dialogName); + + this.dialogShowMask(dialog); + this.dialogLockScreen(); + dialog.show(); + + var helpContent = dialog.find(".markdown-body"); + + if (helpContent.html() === "") + { + $.get(path + "help.md", function(text) { + var md = exports.$marked(text); + helpContent.html(md); + + helpContent.find("a").attr("target", "_blank"); + }); + } + }; + + }; + + // CommonJS/Node.js + if (typeof require === "function" && typeof exports === "object" && typeof module === "object") + { + module.exports = factory; + } + else if (typeof define === "function") // AMD/CMD/Sea.js + { + if (define.amd) { // for Require.js + + define(["editormd"], function(editormd) { + factory(editormd); + }); + + } else { // for Sea.js + define(function(require) { + var editormd = require("./../../editormd"); + factory(editormd); + }); + } + } + else + { + factory(window.editormd); + } + +})(); diff --git a/static/js/mdeditor/plugins/help-dialog/help.md b/static/js/mdeditor/plugins/help-dialog/help.md new file mode 100644 index 00000000..9a030f2f --- /dev/null +++ b/static/js/mdeditor/plugins/help-dialog/help.md @@ -0,0 +1,77 @@ +##### Markdown语法教程 (Markdown syntax tutorial) + +- [Markdown Syntax](http://daringfireball.net/projects/markdown/syntax/ "Markdown Syntax") +- [Mastering Markdown](https://guides.github.com/features/mastering-markdown/ "Mastering Markdown") +- [Markdown Basics](https://help.github.com/articles/markdown-basics/ "Markdown Basics") +- [GitHub Flavored Markdown](https://help.github.com/articles/github-flavored-markdown/ "GitHub Flavored Markdown") +- [Markdown 语法说明(简体中文)](http://www.markdown.cn/ "Markdown 语法说明(简体中文)") +- [Markdown 語法說明(繁體中文)](http://markdown.tw/ "Markdown 語法說明(繁體中文)") + +##### 键盘快捷键 (Keyboard shortcuts) + +> If Editor.md code editor is on focus, you can use keyboard shortcuts. + +| Keyboard shortcuts (键盘快捷键) | 说明 | Description | +| :---------------------------------------------- |:--------------------------------- | :------------------------------------------------- | +| F9 | 切换实时预览 | Switch watch/unwatch | +| F10 | 全屏HTML预览(按 Shift + ESC 退出) | Full preview HTML (Press Shift + ESC exit) | +| F11 | 切换全屏状态 | Switch fullscreen (Press ESC exit) | +| Ctrl + 1~6 / Command + 1~6 | 插入标题1~6 | Insert heading 1~6 | +| Ctrl + A / Command + A | 全选 | Select all | +| Ctrl + B / Command + B | 插入粗体 | Insert bold | +| Ctrl + D / Command + D | 插入日期时间 | Insert datetime | +| Ctrl + E / Command + E | 插入Emoji符号 | Insert :emoji: | +| Ctrl + F / Command + F | 查找/搜索 | Start searching | +| Ctrl + G / Command + G | 切换到下一个搜索结果项 | Find next search results | +| Ctrl + H / Command + H | 插入水平线 | Insert horizontal rule | +| Ctrl + I / Command + I | 插入斜体 | Insert italic | +| Ctrl + K / Command + K | 插入行内代码 | Insert inline code | +| Ctrl + L / Command + L | 插入链接 | Insert link | +| Ctrl + U / Command + U | 插入无序列表 | Insert unordered list | +| Ctrl + Q | 代码折叠切换 | Switch code fold | +| Ctrl + Z / Command + Z | 撤销 | Undo | +| Ctrl + Y / Command + Y | 重做 | Redo | +| Ctrl + Shift + A | 插入@链接 | Insert @link | +| Ctrl + Shift + C | 插入行内代码 | Insert inline code | +| Ctrl + Shift + E | 打开插入Emoji表情对话框 | Open emoji dialog | +| Ctrl + Shift + F / Command + Option + F | 替换 | Replace | +| Ctrl + Shift + G / Shift + Command + G | 切换到上一个搜索结果项 | Find previous search results | +| Ctrl + Shift + H | 打开HTML实体字符对话框 | Open HTML Entities dialog | +| Ctrl + Shift + I | 插入图片 | Insert image ![]() | +| Ctrl + Shift + K | 插入TeX(KaTeX)公式符号 | Insert TeX(KaTeX) symbol $$TeX$$ | +| Ctrl + Shift + L | 打开插入链接对话框 | Open link dialog | +| Ctrl + Shift + O | 插入有序列表 | Insert ordered list | +| Ctrl + Shift + P | 打开插入PRE对话框 | Open Preformatted text dialog | +| Ctrl + Shift + Q | 插入引用 | Insert blockquotes | +| Ctrl + Shift + R / Shift + Command + Option + F | 全部替换 | Replace all | +| Ctrl + Shift + S | 插入删除线 | Insert strikethrough | +| Ctrl + Shift + T | 打开插入表格对话框 | Open table dialog | +| Ctrl + Shift + U | 将所选文字转成大写 | Selection text convert to uppercase | +| Shift + Alt + C | 插入```代码 | Insert code blocks (```) | +| Shift + Alt + H | 打开使用帮助对话框 | Open help dialog | +| Shift + Alt + L | 将所选文本转成小写 | Selection text convert to lowercase | +| Shift + Alt + P | 插入分页符 | Insert page break | +| Alt + L | 将所选文本转成小写 | Selection text convert to lowercase | +| Shift + Alt + U | 将所选的每个单词的首字母转成大写 | Selection words first letter convert to Uppercase | +| Ctrl + Shift + Alt + C | 打开插入代码块对话框层 | Open code blocks dialog | +| Ctrl + Shift + Alt + I | 打开插入图片对话框层 | Open image dialog | +| Ctrl + Shift + Alt + U | 将所选文本的第一个首字母转成大写 | Selection text first letter convert to uppercase | +| Ctrl + Alt + G | 跳转到指定的行 | Goto line | + +##### Emoji表情参考 (Emoji reference) + +- [Github emoji](http://www.emoji-cheat-sheet.com/ "Github emoji") +- [Twitter Emoji \(Twemoji\)](http://twitter.github.io/twemoji/preview.html "Twitter Emoji \(Twemoji\)") +- [FontAwesome icons emoji](http://fortawesome.github.io/Font-Awesome/icons/ "FontAwesome icons emoji") + +##### 流程图参考 (Flowchart reference) + +[http://adrai.github.io/flowchart.js/](http://adrai.github.io/flowchart.js/) + +##### 时序图参考 (SequenceDiagram reference) + +[http://bramp.github.io/js-sequence-diagrams/](http://bramp.github.io/js-sequence-diagrams/) + +##### TeX/LaTeX reference + +[http://meta.wikimedia.org/wiki/Help:Formula](http://meta.wikimedia.org/wiki/Help:Formula) diff --git a/static/js/mdeditor/plugins/html-entities-dialog/html-entities-dialog.js b/static/js/mdeditor/plugins/html-entities-dialog/html-entities-dialog.js new file mode 100644 index 00000000..6c770535 --- /dev/null +++ b/static/js/mdeditor/plugins/html-entities-dialog/html-entities-dialog.js @@ -0,0 +1,173 @@ +/*! + * HTML entities dialog plugin for Editor.md + * + * @file html-entities-dialog.js + * @author pandao + * @version 1.2.0 + * @updateTime 2015-03-08 + * {@link https://github.com/pandao/editor.md} + * @license MIT + */ + +(function() { + + var factory = function (exports) { + + var $ = jQuery; + var pluginName = "html-entities-dialog"; + var selecteds = []; + var entitiesData = []; + + exports.fn.htmlEntitiesDialog = function() { + var _this = this; + var cm = this.cm; + var lang = _this.lang; + var settings = _this.settings; + var path = settings.pluginPath + pluginName + "/"; + var editor = this.editor; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + var classPrefix = _this.classPrefix; + + var dialogName = classPrefix + "dialog-" + pluginName, dialog; + var dialogLang = lang.dialog.htmlEntities; + + var dialogContent = [ + '
    ', + '
    ', + '
    ', + '
    ', + ].join("\r\n"); + + cm.focus(); + + if (editor.find("." + dialogName).length > 0) + { + dialog = editor.find("." + dialogName); + + selecteds = []; + dialog.find("a").removeClass("selected"); + + this.dialogShowMask(dialog); + this.dialogLockScreen(); + dialog.show(); + } + else + { + dialog = this.createDialog({ + name : dialogName, + title : dialogLang.title, + width : 800, + height : 475, + mask : settings.dialogShowMask, + drag : settings.dialogDraggable, + content : dialogContent, + lockScreen : settings.dialogLockScreen, + maskStyle : { + opacity : settings.dialogMaskOpacity, + backgroundColor : settings.dialogMaskBgColor + }, + buttons : { + enter : [lang.buttons.enter, function() { + cm.replaceSelection(selecteds.join(" ")); + this.hide().lockScreen(false).hideMask(); + + return false; + }], + cancel : [lang.buttons.cancel, function() { + this.hide().lockScreen(false).hideMask(); + + return false; + }] + } + }); + } + + var table = dialog.find("." + classPrefix + "grid-table"); + + var drawTable = function() { + + if (entitiesData.length < 1) return ; + + var rowNumber = 20; + var pageTotal = Math.ceil(entitiesData.length / rowNumber); + + table.html(""); + + for (var i = 0; i < pageTotal; i++) + { + var row = "
    "; + + table.append(row); + } + + dialog.find("." + classPrefix + "html-entity-btn").bind(exports.mouseOrTouch("click", "touchend"), function() { + $(this).toggleClass("selected"); + + if ($(this).hasClass("selected")) + { + selecteds.push($(this).attr("value")); + } + }); + }; + + if (entitiesData.length < 1) + { + if (typeof (dialog.loading) == "function") dialog.loading(true); + + $.getJSON(path + pluginName.replace("-dialog", "") + ".json", function(json) { + + if (typeof (dialog.loading) == "function") dialog.loading(false); + + entitiesData = json; + drawTable(); + }); + } + else + { + drawTable(); + } + }; + + }; + + // CommonJS/Node.js + if (typeof require === "function" && typeof exports === "object" && typeof module === "object") + { + module.exports = factory; + } + else if (typeof define === "function") // AMD/CMD/Sea.js + { + if (define.amd) { // for Require.js + + define(["editormd"], function(editormd) { + factory(editormd); + }); + + } else { // for Sea.js + define(function(require) { + var editormd = require("./../../editormd"); + factory(editormd); + }); + } + } + else + { + factory(window.editormd); + } + +})(); diff --git a/static/js/mdeditor/plugins/html-entities-dialog/html-entities.json b/static/js/mdeditor/plugins/html-entities-dialog/html-entities.json new file mode 100644 index 00000000..e9e8229c --- /dev/null +++ b/static/js/mdeditor/plugins/html-entities-dialog/html-entities.json @@ -0,0 +1,936 @@ +[ + { + "name" : "&#64;", + "description":"at symbol" + }, + { + "name":"&copy;", + "description":"copyright symbol" + }, + { + "name":"&reg;", + "description":"registered symbol" + }, + { + "name":"&trade;", + "description":"trademark symbol" + }, + { + "name":"&hearts;", + "description":"heart" + }, + { + "name":"&nbsp;", + "description":"Inserts a non-breaking blank space" + }, + { + "name":"&amp;", + "description":"Ampersand" + }, + { + "name":"&#36;", + "description":"dollar symbol" + }, + { + "name":"&cent;", + "description":"Cent symbol" + }, + { + "name":"&pound;", + "description":"Pound" + }, + { + "name":"&yen;", + "description":"Yen" + }, + { + "name":"&euro;", + "description":"Euro symbol" + }, + { + "name":"&quot;", + "description":"quotation mark" + }, + { + "name":"&ldquo;", + "description":"Opening Double Quotes " + }, + { + "name":"&rdquo;", + "description":"Closing Double Quotes " + }, + { + "name":"&lsquo;", + "description":"Opening Single Quote Mark " + }, + { + "name":"&rsquo;", + "description":"Closing Single Quote Mark " + }, + { + "name":"&laquo;", + "description":"angle quotation mark (left)" + }, + { + "name":"&raquo;", + "description":"angle quotation mark (right)" + }, + { + "name":"&lsaquo;", + "description":"single left angle quotation" + }, + { + "name":"&rsaquo;", + "description":"single right angle quotation" + }, + { + "name":"&sect;", + "description":"Section Symbol" + }, + { + "name":"&micro;", + "description":"micro sign" + }, + { + "name":"&para;", + "description":"Paragraph symbol" + }, + { + "name":"&bull;", + "description":"Big List Dot" + }, + { + "name":"&middot;", + "description":"Medium List Dot" + }, + { + "name":"&hellip;", + "description":"horizontal ellipsis" + }, + { + "name":"&#124;", + "description":"vertical bar" + }, + { + "name":"&brvbar;", + "description":"broken vertical bar" + }, + { + "name":"&ndash;", + "description":"en-dash" + }, + { + "name":"&mdash;", + "description":"em-dash" + }, + { + "name":"&curren;", + "description":"Generic currency symbol" + }, + { + "name":"&#33;", + "description":"exclamation point" + }, + { + "name":"&#35;", + "description":"number sign" + }, + { + "name":"&#39;", + "description":"single quote" + }, + { + "name":"&#40;", + "description":"" + }, + { + "name":"&#41;", + "description":"" + }, + { + "name":"&#42;", + "description":"asterisk" + }, + { + "name":"&#43;", + "description":"plus sign" + }, + { + "name":"&#44;", + "description":"comma" + }, + { + "name":"&#45;", + "description":"minus sign - hyphen" + }, + { + "name":"&#46;", + "description":"period" + }, + { + "name":"&#47;", + "description":"slash" + }, + { + "name":"&#48;", + "description":"0" + }, + { + "name":"&#49;", + "description":"1" + }, + { + "name":"&#50;", + "description":"2" + }, + { + "name":"&#51;", + "description":"3" + }, + { + "name":"&#52;", + "description":"4" + }, + { + "name":"&#53;", + "description":"5" + }, + { + "name":"&#54;", + "description":"6" + }, + { + "name":"&#55;", + "description":"7" + }, + { + "name":"&#56;", + "description":"8" + }, + { + "name":"&#57;", + "description":"9" + }, + { + "name":"&#58;", + "description":"colon" + }, + { + "name":"&#59;", + "description":"semicolon" + }, + { + "name":"&#61;", + "description":"equal sign" + }, + { + "name":"&#63;", + "description":"question mark" + }, + { + "name":"&lt;", + "description":"Less than" + }, + { + "name":"&gt;", + "description":"Greater than" + }, + { + "name":"&le;", + "description":"Less than or Equal to" + }, + { + "name":"&ge;", + "description":"Greater than or Equal to" + }, + { + "name":"&times;", + "description":"Multiplication symbol" + }, + { + "name":"&divide;", + "description":"Division symbol" + }, + { + "name":"&minus;", + "description":"Minus symbol" + }, + { + "name":"&plusmn;", + "description":"Plus/minus symbol" + }, + { + "name":"&ne;", + "description":"Not Equal" + }, + { + "name":"&sup1;", + "description":"Superscript 1" + }, + { + "name":"&sup2;", + "description":"Superscript 2" + }, + { + "name":"&sup3;", + "description":"Superscript 3" + }, + { + "name":"&frac12;", + "description":"Fraction ½" + }, + { + "name":"&frac14;", + "description":"Fraction ¼" + }, + { + "name":"&frac34;", + "description":"Fraction ¾" + }, + { + "name":"&permil;", + "description":"per mille" + }, + { + "name":"&deg;", + "description":"Degree symbol" + }, + { + "name":"&radic;", + "description":"square root" + }, + { + "name":"&infin;", + "description":"Infinity" + }, + { + "name":"&larr;", + "description":"left arrow" + }, + { + "name":"&uarr;", + "description":"up arrow" + }, + { + "name":"&rarr;", + "description":"right arrow" + }, + { + "name":"&darr;", + "description":"down arrow" + }, + { + "name":"&harr;", + "description":"left right arrow" + }, + { + "name":"&crarr;", + "description":"carriage return arrow" + }, + { + "name":"&lceil;", + "description":"left ceiling" + }, + { + "name":"&rceil;", + "description":"right ceiling" + }, + { + "name":"&lfloor;", + "description":"left floor" + }, + { + "name":"&rfloor;", + "description":"right floor" + }, + { + "name":"&spades;", + "description":"spade" + }, + { + "name":"&clubs;", + "description":"club" + }, + { + "name":"&hearts;", + "description":"heart" + }, + { + "name":"&diams;", + "description":"diamond" + }, + { + "name":"&loz;", + "description":"lozenge" + }, + { + "name":"&dagger;", + "description":"dagger" + }, + { + "name":"&Dagger;", + "description":"double dagger" + }, + { + "name":"&iexcl;", + "description":"inverted exclamation mark" + }, + { + "name":"&iquest;", + "description":"inverted question mark" + }, + { + "name":"&#338;", + "description":"latin capital letter OE" + }, + { + "name":"&#339;", + "description":"latin small letter oe" + }, + { + "name":"&#352;", + "description":"latin capital letter S with caron" + }, + { + "name":"&#353;", + "description":"latin small letter s with caron" + }, + { + "name":"&#376;", + "description":"latin capital letter Y with diaeresis" + }, + { + "name":"&#402;", + "description":"latin small f with hook - function" + }, + { + "name":"&not;", + "description":"not sign" + }, + { + "name":"&ordf;", + "description":"feminine ordinal indicator" + }, + { + "name":"&uml;", + "description":"spacing diaeresis - umlaut" + }, + { + "name":"&macr;", + "description":"spacing macron - overline" + }, + { + "name":"&acute;", + "description":"acute accent - spacing acute" + }, + { + "name":"&Agrave;", + "description":"latin capital letter A with grave" + }, + { + "name":"&Aacute;", + "description":"latin capital letter A with acute" + }, + { + "name":"&Acirc;", + "description":"latin capital letter A with circumflex" + }, + { + "name":"&Atilde;", + "description":"latin capital letter A with tilde" + }, + { + "name":"&Auml;", + "description":"latin capital letter A with diaeresis" + }, + { + "name":"&Aring;", + "description":"latin capital letter A with ring above" + }, + { + "name":"&AElig;", + "description":"latin capital letter AE" + }, + { + "name":"&Ccedil;", + "description":"latin capital letter C with cedilla" + }, + { + "name":"&Egrave;", + "description":"latin capital letter E with grave" + }, + { + "name":"&Eacute;", + "description":"latin capital letter E with acute" + }, + { + "name":"&Ecirc;", + "description":"latin capital letter E with circumflex" + }, + { + "name":"&Euml;", + "description":"latin capital letter E with diaeresis" + }, + { + "name":"&Igrave;", + "description":"latin capital letter I with grave" + }, + { + "name":"&Iacute;", + "description":"latin capital letter I with acute" + }, + { + "name":"&Icirc;", + "description":"latin capital letter I with circumflex" + }, + { + "name":"&Iuml;", + "description":"latin capital letter I with diaeresis" + }, + + { + "name":"&ETH;", + "description":"latin capital letter ETH" + }, + { + "name":"&Ntilde;", + "description":"latin capital letter N with tilde" + }, + { + "name":"&Ograve;", + "description":"latin capital letter O with grave" + }, + { + "name":"&Oacute;", + "description":"latin capital letter O with acute" + }, + { + "name":"&Ocirc;", + "description":"latin capital letter O with circumflex" + }, + { + "name":"&Otilde;", + "description":"latin capital letter O with tilde" + }, + { + "name":"&Ouml;", + "description":"latin capital letter O with diaeresis" + }, + { + "name":"&times;", + "description":"multiplication sign" + }, + { + "name":"&Oslash;", + "description":"latin capital letter O with slash" + }, + { + "name":"&Ugrave;", + "description":"latin capital letter U with grave" + }, + { + "name":"&Uacute;", + "description":"latin capital letter U with acute" + }, + { + "name":"&Ucirc;", + "description":"latin capital letter U with circumflex" + }, + { + "name":"&Uuml;", + "description":"latin capital letter U with diaeresis" + }, + { + "name":"&Yacute;", + "description":"latin capital letter Y with acute" + }, + { + "name":"&THORN;", + "description":"latin capital letter THORN" + }, + { + "name":"&szlig;", + "description":"latin small letter sharp s - ess-zed" + }, + + + { + "name":"&eth;", + "description":"latin capital letter eth" + }, + { + "name":"&ntilde;", + "description":"latin capital letter n with tilde" + }, + { + "name":"&ograve;", + "description":"latin capital letter o with grave" + }, + { + "name":"&oacute;", + "description":"latin capital letter o with acute" + }, + { + "name":"&ocirc;", + "description":"latin capital letter o with circumflex" + }, + { + "name":"&otilde;", + "description":"latin capital letter o with tilde" + }, + { + "name":"&ouml;", + "description":"latin capital letter o with diaeresis" + }, + { + "name":"&times;", + "description":"multiplication sign" + }, + { + "name":"&oslash;", + "description":"latin capital letter o with slash" + }, + { + "name":"&ugrave;", + "description":"latin capital letter u with grave" + }, + { + "name":"&uacute;", + "description":"latin capital letter u with acute" + }, + { + "name":"&ucirc;", + "description":"latin capital letter u with circumflex" + }, + { + "name":"&uuml;", + "description":"latin capital letter u with diaeresis" + }, + { + "name":"&yacute;", + "description":"latin capital letter y with acute" + }, + { + "name":"&thorn;", + "description":"latin capital letter thorn" + }, + { + "name":"&yuml;", + "description":"latin small letter y with diaeresis" + }, + + { + "name":"&agrave;", + "description":"latin capital letter a with grave" + }, + { + "name":"&aacute;", + "description":"latin capital letter a with acute" + }, + { + "name":"&acirc;", + "description":"latin capital letter a with circumflex" + }, + { + "name":"&atilde;", + "description":"latin capital letter a with tilde" + }, + { + "name":"&auml;", + "description":"latin capital letter a with diaeresis" + }, + { + "name":"&aring;", + "description":"latin capital letter a with ring above" + }, + { + "name":"&aelig;", + "description":"latin capital letter ae" + }, + { + "name":"&ccedil;", + "description":"latin capital letter c with cedilla" + }, + { + "name":"&egrave;", + "description":"latin capital letter e with grave" + }, + { + "name":"&eacute;", + "description":"latin capital letter e with acute" + }, + { + "name":"&ecirc;", + "description":"latin capital letter e with circumflex" + }, + { + "name":"&euml;", + "description":"latin capital letter e with diaeresis" + }, + { + "name":"&igrave;", + "description":"latin capital letter i with grave" + }, + { + "name":"&Iacute;", + "description":"latin capital letter i with acute" + }, + { + "name":"&icirc;", + "description":"latin capital letter i with circumflex" + }, + { + "name":"&iuml;", + "description":"latin capital letter i with diaeresis" + }, + + { + "name":"&#65;", + "description":"A" + }, + { + "name":"&#66;", + "description":"B" + }, + { + "name":"&#67;", + "description":"C" + }, + { + "name":"&#68;", + "description":"D" + }, + { + "name":"&#69;", + "description":"E" + }, + { + "name":"&#70;", + "description":"F" + }, + { + "name":"&#71;", + "description":"G" + }, + { + "name":"&#72;", + "description":"H" + }, + { + "name":"&#73;", + "description":"I" + }, + { + "name":"&#74;", + "description":"J" + }, + { + "name":"&#75;", + "description":"K" + }, + { + "name":"&#76;", + "description":"L" + }, + { + "name":"&#77;", + "description":"M" + }, + { + "name":"&#78;", + "description":"N" + }, + { + "name":"&#79;", + "description":"O" + }, + { + "name":"&#80;", + "description":"P" + }, + { + "name":"&#81;", + "description":"Q" + }, + { + "name":"&#82;", + "description":"R" + }, + { + "name":"&#83;", + "description":"S" + }, + { + "name":"&#84;", + "description":"T" + }, + { + "name":"&#85;", + "description":"U" + }, + { + "name":"&#86;", + "description":"V" + }, + { + "name":"&#87;", + "description":"W" + }, + { + "name":"&#88;", + "description":"X" + }, + { + "name":"&#89;", + "description":"Y" + }, + { + "name":"&#90;", + "description":"Z" + }, + { + "name":"&#91;", + "description":"opening bracket" + }, + { + "name":"&#92;", + "description":"backslash" + }, + { + "name":"&#93;", + "description":"closing bracket" + }, + { + "name":"&#94;", + "description":"caret - circumflex" + }, + { + "name":"&#95;", + "description":"underscore" + }, + + { + "name":"&#96;", + "description":"grave accent" + }, + { + "name":"&#97;", + "description":"a" + }, + { + "name":"&#98;", + "description":"b" + }, + { + "name":"&#99;", + "description":"c" + }, + { + "name":"&#100;", + "description":"d" + }, + { + "name":"&#101;", + "description":"e" + }, + { + "name":"&#102;", + "description":"f" + }, + { + "name":"&#103;", + "description":"g" + }, + { + "name":"&#104;", + "description":"h" + }, + { + "name":"&#105;", + "description":"i" + }, + { + "name":"&#106;", + "description":"j" + }, + { + "name":"&#107;", + "description":"k" + }, + { + "name":"&#108;", + "description":"l" + }, + { + "name":"&#109;", + "description":"m" + }, + { + "name":"&#110;", + "description":"n" + }, + { + "name":"&#111;", + "description":"o" + }, + { + "name":"&#112;", + "description":"p" + }, + { + "name":"&#113;", + "description":"q" + }, + { + "name":"&#114;", + "description":"r" + }, + { + "name":"&#115;", + "description":"s" + }, + { + "name":"&#116;", + "description":"t" + }, + { + "name":"&#117;", + "description":"u" + }, + { + "name":"&#118;", + "description":"v" + }, + { + "name":"&#119;", + "description":"w" + }, + { + "name":"&#120;", + "description":"x" + }, + { + "name":"&#121;", + "description":"y" + }, + { + "name":"&#122;", + "description":"z" + }, + { + "name":"&#123;", + "description":"opening brace" + }, + { + "name":"&#124;", + "description":"vertical bar" + }, + { + "name":"&#125;", + "description":"closing brace" + }, + { + "name":"&#126;", + "description":"equivalency sign - tilde" + } +] \ No newline at end of file diff --git a/static/js/mdeditor/plugins/image-dialog/image-dialog.js b/static/js/mdeditor/plugins/image-dialog/image-dialog.js new file mode 100644 index 00000000..58c5d25f --- /dev/null +++ b/static/js/mdeditor/plugins/image-dialog/image-dialog.js @@ -0,0 +1,221 @@ +/*! + * Image (upload) dialog plugin for Editor.md + * + * @file image-dialog.js + * @author pandao + * @version 1.3.4 + * @updateTime 2015-06-09 + * {@link https://github.com/pandao/editor.md} + * @license MIT + */ + +(function() { + + var factory = function (exports) { + + var pluginName = "image-dialog"; + + exports.fn.imageDialog = function() { + + var _this = this; + var cm = this.cm; + var lang = this.lang; + var editor = this.editor; + var settings = this.settings; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + var imageLang = lang.dialog.image; + var classPrefix = this.classPrefix; + var iframeName = classPrefix + "image-iframe"; + var dialogName = classPrefix + pluginName, dialog; + + cm.focus(); + + var loading = function(show) { + var _loading = dialog.find("." + classPrefix + "dialog-mask"); + _loading[(show) ? "show" : "hide"](); + }; + + if (editor.find("." + dialogName).length < 1) + { + var guid = (new Date).getTime(); + var action = settings.imageUploadURL + (settings.imageUploadURL.indexOf("?") >= 0 ? "&" : "?") + "guid=" + guid; + + if (settings.crossDomainUpload) + { + action += "&callback=" + settings.uploadCallbackURL + "&dialog_id=editormd-image-dialog-" + guid; + } + + var dialogContent = ( (settings.imageUpload) ? "
    " : "
    " ) + + ( (settings.imageUpload) ? "" : "" ) + + "" + + "" + (function(){ + return (settings.imageUpload) ? "
    " + + "" + + "" + + "
    " : ""; + })() + + "
    " + + "" + + "" + + "
    " + + "" + + "" + + "
    " + + ( (settings.imageUpload) ? "" : "
    "); + + //var imageFooterHTML = ""; + + dialog = this.createDialog({ + title : imageLang.title, + width : (settings.imageUpload) ? 465 : 380, + height : 254, + name : dialogName, + content : dialogContent, + mask : settings.dialogShowMask, + drag : settings.dialogDraggable, + lockScreen : settings.dialogLockScreen, + maskStyle : { + opacity : settings.dialogMaskOpacity, + backgroundColor : settings.dialogMaskBgColor + }, + buttons : { + enter : [lang.buttons.enter, function() { + var url = this.find("[data-url]").val(); + var alt = this.find("[data-alt]").val(); + var link = this.find("[data-link]").val(); + + if (url === "") + { + alert(imageLang.imageURLEmpty); + return false; + } + + var altAttr = (alt !== "") ? " \"" + alt + "\"" : ""; + + if (link === "" || link === "http://") + { + cm.replaceSelection("![" + alt + "](" + url + altAttr + ")"); + } + else + { + cm.replaceSelection("[![" + alt + "](" + url + altAttr + ")](" + link + altAttr + ")"); + } + + if (alt === "") { + cm.setCursor(cursor.line, cursor.ch + 2); + } + + this.hide().lockScreen(false).hideMask(); + + return false; + }], + + cancel : [lang.buttons.cancel, function() { + this.hide().lockScreen(false).hideMask(); + + return false; + }] + } + }); + + dialog.attr("id", classPrefix + "image-dialog-" + guid); + + if (!settings.imageUpload) { + return ; + } + + var fileInput = dialog.find("[name=\"" + classPrefix + "image-file\"]"); + + fileInput.bind("change", function() { + var fileName = fileInput.val(); + var isImage = new RegExp("(\\.(" + settings.imageFormats.join("|") + "))$"); // /(\.(webp|jpg|jpeg|gif|bmp|png))$/ + + if (fileName === "") + { + alert(imageLang.uploadFileEmpty); + + return false; + } + + if (!isImage.test(fileName)) + { + alert(imageLang.formatNotAllowed + settings.imageFormats.join(", ")); + + return false; + } + + loading(true); + + var submitHandler = function() { + + var uploadIframe = document.getElementById(iframeName); + + uploadIframe.onload = function() { + + loading(false); + + var body = (uploadIframe.contentWindow ? uploadIframe.contentWindow : uploadIframe.contentDocument).document.body; + var json = (body.innerText) ? body.innerText : ( (body.textContent) ? body.textContent : null); + + json = (typeof JSON.parse !== "undefined") ? JSON.parse(json) : eval("(" + json + ")"); + + if(!settings.crossDomainUpload) + { + if (json.success === 1) + { + dialog.find("[data-url]").val(json.url); + } + else + { + alert(json.message); + } + } + + return false; + }; + }; + + dialog.find("[type=\"submit\"]").bind("click", submitHandler).trigger("click"); + }); + } + + dialog = editor.find("." + dialogName); + dialog.find("[type=\"text\"]").val(""); + dialog.find("[type=\"file\"]").val(""); + dialog.find("[data-link]").val("http://"); + + this.dialogShowMask(dialog); + this.dialogLockScreen(); + dialog.show(); + + }; + + }; + + // CommonJS/Node.js + if (typeof require === "function" && typeof exports === "object" && typeof module === "object") + { + module.exports = factory; + } + else if (typeof define === "function") // AMD/CMD/Sea.js + { + if (define.amd) { // for Require.js + + define(["editormd"], function(editormd) { + factory(editormd); + }); + + } else { // for Sea.js + define(function(require) { + var editormd = require("./../../editormd"); + factory(editormd); + }); + } + } + else + { + factory(window.editormd); + } + +})(); diff --git a/static/js/mdeditor/plugins/link-dialog/link-dialog.js b/static/js/mdeditor/plugins/link-dialog/link-dialog.js new file mode 100644 index 00000000..3e1d0bf0 --- /dev/null +++ b/static/js/mdeditor/plugins/link-dialog/link-dialog.js @@ -0,0 +1,133 @@ +/*! + * Link dialog plugin for Editor.md + * + * @file link-dialog.js + * @author pandao + * @version 1.2.1 + * @updateTime 2015-06-09 + * {@link https://github.com/pandao/editor.md} + * @license MIT + */ + +(function() { + + var factory = function (exports) { + + var pluginName = "link-dialog"; + + exports.fn.linkDialog = function() { + + var _this = this; + var cm = this.cm; + var editor = this.editor; + var settings = this.settings; + var selection = cm.getSelection(); + var lang = this.lang; + var linkLang = lang.dialog.link; + var classPrefix = this.classPrefix; + var dialogName = classPrefix + pluginName, dialog; + + cm.focus(); + + if (editor.find("." + dialogName).length > 0) + { + dialog = editor.find("." + dialogName); + dialog.find("[data-url]").val("http://"); + dialog.find("[data-title]").val(selection); + + this.dialogShowMask(dialog); + this.dialogLockScreen(); + dialog.show(); + } + else + { + var dialogHTML = "
    " + + "" + + "" + + "
    " + + "" + + "" + + "
    " + + "
    "; + + dialog = this.createDialog({ + title : linkLang.title, + width : 380, + height : 211, + content : dialogHTML, + mask : settings.dialogShowMask, + drag : settings.dialogDraggable, + lockScreen : settings.dialogLockScreen, + maskStyle : { + opacity : settings.dialogMaskOpacity, + backgroundColor : settings.dialogMaskBgColor + }, + buttons : { + enter : [lang.buttons.enter, function() { + var url = this.find("[data-url]").val(); + var title = this.find("[data-title]").val(); + + if (url === "http://" || url === "") + { + alert(linkLang.urlEmpty); + return false; + } + + /*if (title === "") + { + alert(linkLang.titleEmpty); + return false; + }*/ + + var str = "[" + title + "](" + url + " \"" + title + "\")"; + + if (title == "") + { + str = "[" + url + "](" + url + ")"; + } + + cm.replaceSelection(str); + + this.hide().lockScreen(false).hideMask(); + + return false; + }], + + cancel : [lang.buttons.cancel, function() { + this.hide().lockScreen(false).hideMask(); + + return false; + }] + } + }); + } + }; + + }; + + // CommonJS/Node.js + if (typeof require === "function" && typeof exports === "object" && typeof module === "object") + { + module.exports = factory; + } + else if (typeof define === "function") // AMD/CMD/Sea.js + { + if (define.amd) { // for Require.js + + define(["editormd"], function(editormd) { + factory(editormd); + }); + + } else { // for Sea.js + define(function(require) { + var editormd = require("./../../editormd"); + factory(editormd); + }); + } + } + else + { + factory(window.editormd); + } + +})(); diff --git a/static/js/mdeditor/plugins/plugin-template.js b/static/js/mdeditor/plugins/plugin-template.js new file mode 100644 index 00000000..8e301697 --- /dev/null +++ b/static/js/mdeditor/plugins/plugin-template.js @@ -0,0 +1,111 @@ +/*! + * Link dialog plugin for Editor.md + * + * @file link-dialog.js + * @author pandao + * @version 1.2.0 + * @updateTime 2015-03-07 + * {@link https://github.com/pandao/editor.md} + * @license MIT + */ + +(function() { + + var factory = function (exports) { + + var $ = jQuery; // if using module loader(Require.js/Sea.js). + + var langs = { + "zh-cn" : { + toolbar : { + table : "表格" + }, + dialog : { + table : { + title : "添加表格", + cellsLabel : "单元格数", + alignLabel : "对齐方式", + rows : "行数", + cols : "列数", + aligns : ["默认", "左对齐", "居中对齐", "右对齐"] + } + } + }, + "zh-tw" : { + toolbar : { + table : "添加表格" + }, + dialog : { + table : { + title : "添加表格", + cellsLabel : "單元格數", + alignLabel : "對齊方式", + rows : "行數", + cols : "列數", + aligns : ["默認", "左對齊", "居中對齊", "右對齊"] + } + } + }, + "en" : { + toolbar : { + table : "Tables" + }, + dialog : { + table : { + title : "Tables", + cellsLabel : "Cells", + alignLabel : "Align", + rows : "Rows", + cols : "Cols", + aligns : ["Default", "Left align", "Center align", "Right align"] + } + } + } + }; + + exports.fn.htmlEntities = function() { + /* + var _this = this; // this == the current instance object of Editor.md + var lang = _this.lang; + var settings = _this.settings; + var editor = this.editor; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + var classPrefix = this.classPrefix; + + $.extend(true, this.lang, langs[this.lang.name]); // l18n + this.setToolbar(); + + cm.focus(); + */ + //.... + }; + + }; + + // CommonJS/Node.js + if (typeof require === "function" && typeof exports === "object" && typeof module === "object") + { + module.exports = factory; + } + else if (typeof define === "function") // AMD/CMD/Sea.js + { + if (define.amd) { // for Require.js + + define(["editormd"], function(editormd) { + factory(editormd); + }); + + } else { // for Sea.js + define(function(require) { + var editormd = require("./../../editormd"); + factory(editormd); + }); + } + } + else + { + factory(window.editormd); + } + +})(); diff --git a/static/js/mdeditor/plugins/preformatted-text-dialog/preformatted-text-dialog.js b/static/js/mdeditor/plugins/preformatted-text-dialog/preformatted-text-dialog.js new file mode 100644 index 00000000..c890adc6 --- /dev/null +++ b/static/js/mdeditor/plugins/preformatted-text-dialog/preformatted-text-dialog.js @@ -0,0 +1,172 @@ +/*! + * Preformatted text dialog plugin for Editor.md + * + * @file preformatted-text-dialog.js + * @author pandao + * @version 1.2.0 + * @updateTime 2015-03-07 + * {@link https://github.com/pandao/editor.md} + * @license MIT + */ + +(function() { + + var factory = function (exports) { + var cmEditor; + var pluginName = "preformatted-text-dialog"; + + exports.fn.preformattedTextDialog = function() { + + var _this = this; + var cm = this.cm; + var lang = this.lang; + var editor = this.editor; + var settings = this.settings; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + var classPrefix = this.classPrefix; + var dialogLang = lang.dialog.preformattedText; + var dialogName = classPrefix + pluginName, dialog; + + cm.focus(); + + if (editor.find("." + dialogName).length > 0) + { + dialog = editor.find("." + dialogName); + dialog.find("textarea").val(selection); + + this.dialogShowMask(dialog); + this.dialogLockScreen(); + dialog.show(); + } + else + { + var dialogContent = ""; + + dialog = this.createDialog({ + name : dialogName, + title : dialogLang.title, + width : 780, + height : 540, + mask : settings.dialogShowMask, + drag : settings.dialogDraggable, + content : dialogContent, + lockScreen : settings.dialogLockScreen, + maskStyle : { + opacity : settings.dialogMaskOpacity, + backgroundColor : settings.dialogMaskBgColor + }, + buttons : { + enter : [lang.buttons.enter, function() { + var codeTexts = this.find("textarea").val(); + + if (codeTexts === "") + { + alert(dialogLang.emptyAlert); + return false; + } + + codeTexts = codeTexts.split("\n"); + + for (var i in codeTexts) + { + codeTexts[i] = " " + codeTexts[i]; + } + + codeTexts = codeTexts.join("\n"); + + if (cursor.ch !== 0) { + codeTexts = "\r\n\r\n" + codeTexts; + } + + cm.replaceSelection(codeTexts); + + this.hide().lockScreen(false).hideMask(); + + return false; + }], + cancel : [lang.buttons.cancel, function() { + this.hide().lockScreen(false).hideMask(); + + return false; + }] + } + }); + } + + var cmConfig = { + mode : "text/html", + theme : settings.theme, + tabSize : 4, + autofocus : true, + autoCloseTags : true, + indentUnit : 4, + lineNumbers : true, + lineWrapping : true, + extraKeys : {"Ctrl-Q": function(cm){ cm.foldCode(cm.getCursor()); }}, + foldGutter : true, + gutters : ["CodeMirror-linenumbers", "CodeMirror-foldgutter"], + matchBrackets : true, + indentWithTabs : true, + styleActiveLine : true, + styleSelectedText : true, + autoCloseBrackets : true, + showTrailingSpace : true, + highlightSelectionMatches : true + }; + + var textarea = dialog.find("textarea"); + var cmObj = dialog.find(".CodeMirror"); + + if (dialog.find(".CodeMirror").length < 1) + { + cmEditor = exports.$CodeMirror.fromTextArea(textarea[0], cmConfig); + cmObj = dialog.find(".CodeMirror"); + + cmObj.css({ + "float" : "none", + margin : "0 0 5px", + border : "1px solid #ddd", + fontSize : settings.fontSize, + width : "100%", + height : "410px" + }); + + cmEditor.on("change", function(cm) { + textarea.val(cm.getValue()); + }); + } + else + { + cmEditor.setValue(cm.getSelection()); + } + }; + + }; + + // CommonJS/Node.js + if (typeof require === "function" && typeof exports === "object" && typeof module === "object") + { + module.exports = factory; + } + else if (typeof define === "function") // AMD/CMD/Sea.js + { + if (define.amd) { // for Require.js + + define(["editormd"], function(editormd) { + factory(editormd); + }); + + } else { // for Sea.js + define(function(require) { + var editormd = require("./../../editormd"); + factory(editormd); + }); + } + } + else + { + factory(window.editormd); + } + +})(); diff --git a/static/js/mdeditor/plugins/reference-link-dialog/reference-link-dialog.js b/static/js/mdeditor/plugins/reference-link-dialog/reference-link-dialog.js new file mode 100644 index 00000000..f1ad086b --- /dev/null +++ b/static/js/mdeditor/plugins/reference-link-dialog/reference-link-dialog.js @@ -0,0 +1,153 @@ +/*! + * Reference link dialog plugin for Editor.md + * + * @file reference-link-dialog.js + * @author pandao + * @version 1.2.1 + * @updateTime 2015-06-09 + * {@link https://github.com/pandao/editor.md} + * @license MIT + */ + +(function() { + + var factory = function (exports) { + + var pluginName = "reference-link-dialog"; + var ReLinkId = 1; + + exports.fn.referenceLinkDialog = function() { + + var _this = this; + var cm = this.cm; + var lang = this.lang; + var editor = this.editor; + var settings = this.settings; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + var dialogLang = lang.dialog.referenceLink; + var classPrefix = this.classPrefix; + var dialogName = classPrefix + pluginName, dialog; + + cm.focus(); + + if (editor.find("." + dialogName).length < 1) + { + var dialogHTML = "
    " + + "" + + "" + + "
    " + + "" + + "" + + "
    " + + "" + + "" + + "
    " + + "" + + "" + + "
    " + + "
    "; + + dialog = this.createDialog({ + name : dialogName, + title : dialogLang.title, + width : 380, + height : 296, + content : dialogHTML, + mask : settings.dialogShowMask, + drag : settings.dialogDraggable, + lockScreen : settings.dialogLockScreen, + maskStyle : { + opacity : settings.dialogMaskOpacity, + backgroundColor : settings.dialogMaskBgColor + }, + buttons : { + enter : [lang.buttons.enter, function() { + var name = this.find("[data-name]").val(); + var url = this.find("[data-url]").val(); + var rid = this.find("[data-url-id]").val(); + var title = this.find("[data-title]").val(); + + if (name === "") + { + alert(dialogLang.nameEmpty); + return false; + } + + if (rid === "") + { + alert(dialogLang.idEmpty); + return false; + } + + if (url === "http://" || url === "") + { + alert(dialogLang.urlEmpty); + return false; + } + + //cm.replaceSelection("[" + title + "][" + name + "]\n[" + name + "]: " + url + ""); + cm.replaceSelection("[" + name + "][" + rid + "]"); + + if (selection === "") { + cm.setCursor(cursor.line, cursor.ch + 1); + } + + title = (title === "") ? "" : " \"" + title + "\""; + + cm.setValue(cm.getValue() + "\n[" + rid + "]: " + url + title + ""); + + this.hide().lockScreen(false).hideMask(); + + return false; + }], + cancel : [lang.buttons.cancel, function() { + this.hide().lockScreen(false).hideMask(); + + return false; + }] + } + }); + } + + dialog = editor.find("." + dialogName); + dialog.find("[data-name]").val("[" + ReLinkId + "]"); + dialog.find("[data-url-id]").val(""); + dialog.find("[data-url]").val("http://"); + dialog.find("[data-title]").val(selection); + + this.dialogShowMask(dialog); + this.dialogLockScreen(); + dialog.show(); + + ReLinkId++; + }; + + }; + + // CommonJS/Node.js + if (typeof require === "function" && typeof exports === "object" && typeof module === "object") + { + module.exports = factory; + } + else if (typeof define === "function") // AMD/CMD/Sea.js + { + if (define.amd) { // for Require.js + + define(["editormd"], function(editormd) { + factory(editormd); + }); + + } else { // for Sea.js + define(function(require) { + var editormd = require("./../../editormd"); + factory(editormd); + }); + } + } + else + { + factory(window.editormd); + } + +})(); diff --git a/static/js/mdeditor/plugins/table-dialog/table-dialog.js b/static/js/mdeditor/plugins/table-dialog/table-dialog.js new file mode 100644 index 00000000..578adf25 --- /dev/null +++ b/static/js/mdeditor/plugins/table-dialog/table-dialog.js @@ -0,0 +1,218 @@ +/*! + * Table dialog plugin for Editor.md + * + * @file table-dialog.js + * @author pandao + * @version 1.2.1 + * @updateTime 2015-06-09 + * {@link https://github.com/pandao/editor.md} + * @license MIT + */ + +(function() { + + var factory = function (exports) { + + var $ = jQuery; + var pluginName = "table-dialog"; + + var langs = { + "zh-cn" : { + toolbar : { + table : "表格" + }, + dialog : { + table : { + title : "添加表格", + cellsLabel : "单元格数", + alignLabel : "对齐方式", + rows : "行数", + cols : "列数", + aligns : ["默认", "左对齐", "居中对齐", "右对齐"] + } + } + }, + "zh-tw" : { + toolbar : { + table : "添加表格" + }, + dialog : { + table : { + title : "添加表格", + cellsLabel : "單元格數", + alignLabel : "對齊方式", + rows : "行數", + cols : "列數", + aligns : ["默認", "左對齊", "居中對齊", "右對齊"] + } + } + }, + "en" : { + toolbar : { + table : "Tables" + }, + dialog : { + table : { + title : "Tables", + cellsLabel : "Cells", + alignLabel : "Align", + rows : "Rows", + cols : "Cols", + aligns : ["Default", "Left align", "Center align", "Right align"] + } + } + } + }; + + exports.fn.tableDialog = function() { + var _this = this; + var cm = this.cm; + var editor = this.editor; + var settings = this.settings; + var path = settings.path + "../plugins/" + pluginName +"/"; + var classPrefix = this.classPrefix; + var dialogName = classPrefix + pluginName, dialog; + + $.extend(true, this.lang, langs[this.lang.name]); + this.setToolbar(); + + var lang = this.lang; + var dialogLang = lang.dialog.table; + + var dialogContent = [ + "
    ", + "", + dialogLang.rows + "   ", + dialogLang.cols + "
    ", + "", + "
    ", + "
    " + ].join("\n"); + + if (editor.find("." + dialogName).length > 0) + { + dialog = editor.find("." + dialogName); + + this.dialogShowMask(dialog); + this.dialogLockScreen(); + dialog.show(); + } + else + { + dialog = this.createDialog({ + name : dialogName, + title : dialogLang.title, + width : 360, + height : 226, + mask : settings.dialogShowMask, + drag : settings.dialogDraggable, + content : dialogContent, + lockScreen : settings.dialogLockScreen, + maskStyle : { + opacity : settings.dialogMaskOpacity, + backgroundColor : settings.dialogMaskBgColor + }, + buttons : { + enter : [lang.buttons.enter, function() { + var rows = parseInt(this.find("[data-rows]").val()); + var cols = parseInt(this.find("[data-cols]").val()); + var align = this.find("[name=\"table-align\"]:checked").val(); + var table = ""; + var hrLine = "------------"; + + var alignSign = { + _default : hrLine, + left : ":" + hrLine, + center : ":" + hrLine + ":", + right : hrLine + ":" + }; + + if ( rows > 1 && cols > 0) + { + for (var r = 0, len = rows; r < len; r++) + { + var row = []; + var head = []; + + for (var c = 0, len2 = cols; c < len2; c++) + { + if (r === 1) { + head.push(alignSign[align]); + } + + row.push(" "); + } + + if (r === 1) { + table += "| " + head.join(" | ") + " |" + "\n"; + } + + table += "| " + row.join( (cols === 1) ? "" : " | " ) + " |" + "\n"; + } + } + + cm.replaceSelection(table); + + this.hide().lockScreen(false).hideMask(); + + return false; + }], + + cancel : [lang.buttons.cancel, function() { + this.hide().lockScreen(false).hideMask(); + + return false; + }] + } + }); + } + + var faBtns = dialog.find(".fa-btns"); + + if (faBtns.html() === "") + { + var icons = ["align-justify", "align-left", "align-center", "align-right"]; + var _lang = dialogLang.aligns; + var values = ["_default", "left", "center", "right"]; + + for (var i = 0, len = icons.length; i < len; i++) + { + var checked = (i === 0) ? " checked=\"checked\"" : ""; + var btn = ""; + + faBtns.append(btn); + } + } + }; + + }; + + // CommonJS/Node.js + if (typeof require === "function" && typeof exports === "object" && typeof module === "object") + { + module.exports = factory; + } + else if (typeof define === "function") // AMD/CMD/Sea.js + { + if (define.amd) { // for Require.js + + define(["editormd"], function(editormd) { + factory(editormd); + }); + + } else { // for Sea.js + define(function(require) { + var editormd = require("./../../editormd"); + factory(editormd); + }); + } + } + else + { + factory(window.editormd); + } + +})(); diff --git a/static/js/mdeditor/plugins/test-plugin/test-plugin.js b/static/js/mdeditor/plugins/test-plugin/test-plugin.js new file mode 100644 index 00000000..bc4da31d --- /dev/null +++ b/static/js/mdeditor/plugins/test-plugin/test-plugin.js @@ -0,0 +1,66 @@ +/*! + * Test plugin for Editor.md + * + * @file test-plugin.js + * @author pandao + * @version 1.2.0 + * @updateTime 2015-03-07 + * {@link https://github.com/pandao/editor.md} + * @license MIT + */ + +(function() { + + var factory = function (exports) { + + var $ = jQuery; // if using module loader(Require.js/Sea.js). + + exports.testPlugin = function(){ + alert("testPlugin"); + }; + + exports.fn.testPluginMethodA = function() { + /* + var _this = this; // this == the current instance object of Editor.md + var lang = _this.lang; + var settings = _this.settings; + var editor = this.editor; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + var classPrefix = this.classPrefix; + + cm.focus(); + */ + //.... + + alert("testPluginMethodA"); + }; + + }; + + // CommonJS/Node.js + if (typeof require === "function" && typeof exports === "object" && typeof module === "object") + { + module.exports = factory; + } + else if (typeof define === "function") // AMD/CMD/Sea.js + { + if (define.amd) { // for Require.js + + define(["editormd"], function(editormd) { + factory(editormd); + }); + + } else { // for Sea.js + define(function(require) { + var editormd = require("./../../editormd"); + factory(editormd); + }); + } + } + else + { + factory(window.editormd); + } + +})(); diff --git a/static/js/mdeditor/squire-raw.js b/static/js/mdeditor/squire-raw.js deleted file mode 100644 index 7da03f8a..00000000 --- a/static/js/mdeditor/squire-raw.js +++ /dev/null @@ -1,4701 +0,0 @@ -/* Copyright © 2011-2015 by Neil Jenkins. MIT Licensed. */ - -( function ( doc, undefined ) { - -"use strict"; - -var DOCUMENT_POSITION_PRECEDING = 2; // Node.DOCUMENT_POSITION_PRECEDING -var ELEMENT_NODE = 1; // Node.ELEMENT_NODE; -var TEXT_NODE = 3; // Node.TEXT_NODE; -var DOCUMENT_NODE = 9; // Node.DOCUMENT_NODE; -var DOCUMENT_FRAGMENT_NODE = 11; // Node.DOCUMENT_FRAGMENT_NODE; -var SHOW_ELEMENT = 1; // NodeFilter.SHOW_ELEMENT; -var SHOW_TEXT = 4; // NodeFilter.SHOW_TEXT; - -var START_TO_START = 0; // Range.START_TO_START -var START_TO_END = 1; // Range.START_TO_END -var END_TO_END = 2; // Range.END_TO_END -var END_TO_START = 3; // Range.END_TO_START - -var HIGHLIGHT_CLASS = 'highlight'; -var COLOUR_CLASS = 'colour'; -var FONT_FAMILY_CLASS = 'font'; -var FONT_SIZE_CLASS = 'size'; - -var ZWS = '\u200B'; - -var win = doc.defaultView; - -var ua = navigator.userAgent; - -var isAndroid = /Android/.test( ua ); -var isIOS = /iP(?:ad|hone|od)/.test( ua ); -var isMac = /Mac OS X/.test( ua ); -var isWin = /Windows NT/.test( ua ); - -var isGecko = /Gecko\//.test( ua ); -var isIElt11 = /Trident\/[456]\./.test( ua ); -var isPresto = !!win.opera; -var isEdge = /Edge\//.test( ua ); -var isWebKit = !isEdge && /WebKit\//.test( ua ); -var isIE = /Trident\/[4567]\./.test( ua ); - -var ctrlKey = isMac ? 'meta-' : 'ctrl-'; - -var useTextFixer = isIElt11 || isPresto; -var cantFocusEmptyTextNodes = isIElt11 || isWebKit; -var losesSelectionOnBlur = isIElt11; - -var canObserveMutations = typeof MutationObserver !== 'undefined'; -var canWeakMap = typeof WeakMap !== 'undefined'; - -// Use [^ \t\r\n] instead of \S so that nbsp does not count as white-space -var notWS = /[^ \t\r\n]/; - -var indexOf = Array.prototype.indexOf; - -// Polyfill for FF3.5 -if ( !Object.create ) { - Object.create = function ( proto ) { - var F = function () {}; - F.prototype = proto; - return new F(); - }; -} - -/* - Native TreeWalker is buggy in IE and Opera: - * IE9/10 sometimes throw errors when calling TreeWalker#nextNode or - TreeWalker#previousNode. No way to feature detect this. - * Some versions of Opera have a bug in TreeWalker#previousNode which makes - it skip to the wrong node. - - Rather than risk further bugs, it's easiest just to implement our own - (subset) of the spec in all browsers. -*/ - -var typeToBitArray = { - // ELEMENT_NODE - 1: 1, - // ATTRIBUTE_NODE - 2: 2, - // TEXT_NODE - 3: 4, - // COMMENT_NODE - 8: 128, - // DOCUMENT_NODE - 9: 256, - // DOCUMENT_FRAGMENT_NODE - 11: 1024 -}; - -function TreeWalker ( root, nodeType, filter ) { - this.root = this.currentNode = root; - this.nodeType = nodeType; - this.filter = filter; -} - -TreeWalker.prototype.nextNode = function () { - var current = this.currentNode, - root = this.root, - nodeType = this.nodeType, - filter = this.filter, - node; - while ( true ) { - node = current.firstChild; - while ( !node && current ) { - if ( current === root ) { - break; - } - node = current.nextSibling; - if ( !node ) { current = current.parentNode; } - } - if ( !node ) { - return null; - } - if ( ( typeToBitArray[ node.nodeType ] & nodeType ) && - filter( node ) ) { - this.currentNode = node; - return node; - } - current = node; - } -}; - -TreeWalker.prototype.previousNode = function () { - var current = this.currentNode, - root = this.root, - nodeType = this.nodeType, - filter = this.filter, - node; - while ( true ) { - if ( current === root ) { - return null; - } - node = current.previousSibling; - if ( node ) { - while ( current = node.lastChild ) { - node = current; - } - } else { - node = current.parentNode; - } - if ( !node ) { - return null; - } - if ( ( typeToBitArray[ node.nodeType ] & nodeType ) && - filter( node ) ) { - this.currentNode = node; - return node; - } - current = node; - } -}; - -// Previous node in post-order. -TreeWalker.prototype.previousPONode = function () { - var current = this.currentNode, - root = this.root, - nodeType = this.nodeType, - filter = this.filter, - node; - while ( true ) { - node = current.lastChild; - while ( !node && current ) { - if ( current === root ) { - break; - } - node = current.previousSibling; - if ( !node ) { current = current.parentNode; } - } - if ( !node ) { - return null; - } - if ( ( typeToBitArray[ node.nodeType ] & nodeType ) && - filter( node ) ) { - this.currentNode = node; - return node; - } - current = node; - } -}; - -var inlineNodeNames = /^(?:#text|A(?:BBR|CRONYM)?|B(?:R|D[IO])?|C(?:ITE|ODE)|D(?:ATA|EL|FN)|EM|FONT|HR|I(?:FRAME|MG|NPUT|NS)?|KBD|Q|R(?:P|T|UBY)|S(?:AMP|MALL|PAN|TR(?:IKE|ONG)|U[BP])?|TIME|U|VAR|WBR)$/; - -var leafNodeNames = { - BR: 1, - HR: 1, - IFRAME: 1, - IMG: 1, - INPUT: 1 -}; - -function every ( nodeList, fn ) { - var l = nodeList.length; - while ( l-- ) { - if ( !fn( nodeList[l] ) ) { - return false; - } - } - return true; -} - -// --- - -var UNKNOWN = 0; -var INLINE = 1; -var BLOCK = 2; -var CONTAINER = 3; - -var nodeCategoryCache = canWeakMap ? new WeakMap() : null; - -function isLeaf ( node ) { - return node.nodeType === ELEMENT_NODE && !!leafNodeNames[ node.nodeName ]; -} -function getNodeCategory ( node ) { - switch ( node.nodeType ) { - case TEXT_NODE: - return INLINE; - case ELEMENT_NODE: - case DOCUMENT_FRAGMENT_NODE: - if ( canWeakMap && nodeCategoryCache.has( node ) ) { - return nodeCategoryCache.get( node ); - } - break; - default: - return UNKNOWN; - } - - var nodeCategory; - if ( !every( node.childNodes, isInline ) ) { - // Malformed HTML can have block tags inside inline tags. Need to treat - // these as containers rather than inline. See #239. - nodeCategory = CONTAINER; - } else if ( inlineNodeNames.test( node.nodeName ) ) { - nodeCategory = INLINE; - } else { - nodeCategory = BLOCK; - } - if ( canWeakMap ) { - nodeCategoryCache.set( node, nodeCategory ); - } - return nodeCategory; -} -function isInline ( node ) { - return getNodeCategory( node ) === INLINE; -} -function isBlock ( node ) { - return getNodeCategory( node ) === BLOCK; -} -function isContainer ( node ) { - return getNodeCategory( node ) === CONTAINER; -} - -function getBlockWalker ( node, root ) { - var walker = new TreeWalker( root, SHOW_ELEMENT, isBlock ); - walker.currentNode = node; - return walker; -} -function getPreviousBlock ( node, root ) { - node = getBlockWalker( node, root ).previousNode(); - return node !== root ? node : null; -} -function getNextBlock ( node, root ) { - node = getBlockWalker( node, root ).nextNode(); - return node !== root ? node : null; -} - -function isEmptyBlock ( block ) { - return !block.textContent && !block.querySelector( 'IMG' ); -} - -function areAlike ( node, node2 ) { - return !isLeaf( node ) && ( - node.nodeType === node2.nodeType && - node.nodeName === node2.nodeName && - node.nodeName !== 'A' && - node.className === node2.className && - ( ( !node.style && !node2.style ) || - node.style.cssText === node2.style.cssText ) - ); -} -function hasTagAttributes ( node, tag, attributes ) { - if ( node.nodeName !== tag ) { - return false; - } - for ( var attr in attributes ) { - if ( node.getAttribute( attr ) !== attributes[ attr ] ) { - return false; - } - } - return true; -} -function getNearest ( node, root, tag, attributes ) { - while ( node && node !== root ) { - if ( hasTagAttributes( node, tag, attributes ) ) { - return node; - } - node = node.parentNode; - } - return null; -} -function isOrContains ( parent, node ) { - while ( node ) { - if ( node === parent ) { - return true; - } - node = node.parentNode; - } - return false; -} - -function getPath ( node, root ) { - var path = ''; - var id, className, classNames, dir; - if ( node && node !== root ) { - path = getPath( node.parentNode, root ); - if ( node.nodeType === ELEMENT_NODE ) { - path += ( path ? '>' : '' ) + node.nodeName; - if ( id = node.id ) { - path += '#' + id; - } - if ( className = node.className.trim() ) { - classNames = className.split( /\s\s*/ ); - classNames.sort(); - path += '.'; - path += classNames.join( '.' ); - } - if ( dir = node.dir ) { - path += '[dir=' + dir + ']'; - } - if ( classNames ) { - if ( indexOf.call( classNames, HIGHLIGHT_CLASS ) > -1 ) { - path += '[backgroundColor=' + - node.style.backgroundColor.replace( / /g,'' ) + ']'; - } - if ( indexOf.call( classNames, COLOUR_CLASS ) > -1 ) { - path += '[color=' + - node.style.color.replace( / /g,'' ) + ']'; - } - if ( indexOf.call( classNames, FONT_FAMILY_CLASS ) > -1 ) { - path += '[fontFamily=' + - node.style.fontFamily.replace( / /g,'' ) + ']'; - } - if ( indexOf.call( classNames, FONT_SIZE_CLASS ) > -1 ) { - path += '[fontSize=' + node.style.fontSize + ']'; - } - } - } - } - return path; -} - -function getLength ( node ) { - var nodeType = node.nodeType; - return nodeType === ELEMENT_NODE || nodeType === DOCUMENT_FRAGMENT_NODE ? - node.childNodes.length : node.length || 0; -} - -function detach ( node ) { - var parent = node.parentNode; - if ( parent ) { - parent.removeChild( node ); - } - return node; -} -function replaceWith ( node, node2 ) { - var parent = node.parentNode; - if ( parent ) { - parent.replaceChild( node2, node ); - } -} -function empty ( node ) { - var frag = node.ownerDocument.createDocumentFragment(), - childNodes = node.childNodes, - l = childNodes ? childNodes.length : 0; - while ( l-- ) { - frag.appendChild( node.firstChild ); - } - return frag; -} - -function createElement ( doc, tag, props, children ) { - var el = doc.createElement( tag ), - attr, value, i, l; - if ( props instanceof Array ) { - children = props; - props = null; - } - if ( props ) { - for ( attr in props ) { - value = props[ attr ]; - if ( value !== undefined ) { - el.setAttribute( attr, props[ attr ] ); - } - } - } - if ( children ) { - for ( i = 0, l = children.length; i < l; i += 1 ) { - el.appendChild( children[i] ); - } - } - return el; -} - -function fixCursor ( node, root ) { - // In Webkit and Gecko, block level elements are collapsed and - // unfocussable if they have no content. To remedy this, a
    must be - // inserted. In Opera and IE, we just need a textnode in order for the - // cursor to appear. - var self = root.__squire__; - var doc = node.ownerDocument; - var originalNode = node; - var fixer, child; - - if ( node === root ) { - if ( !( child = node.firstChild ) || child.nodeName === 'BR' ) { - fixer = self.createDefaultBlock(); - if ( child ) { - node.replaceChild( fixer, child ); - } - else { - node.appendChild( fixer ); - } - node = fixer; - fixer = null; - } - } - - if ( node.nodeType === TEXT_NODE ) { - return originalNode; - } - - if ( isInline( node ) ) { - child = node.firstChild; - while ( cantFocusEmptyTextNodes && child && - child.nodeType === TEXT_NODE && !child.data ) { - node.removeChild( child ); - child = node.firstChild; - } - if ( !child ) { - if ( cantFocusEmptyTextNodes ) { - fixer = doc.createTextNode( ZWS ); - self._didAddZWS(); - } else { - fixer = doc.createTextNode( '' ); - } - } - } else { - if ( useTextFixer ) { - while ( node.nodeType !== TEXT_NODE && !isLeaf( node ) ) { - child = node.firstChild; - if ( !child ) { - fixer = doc.createTextNode( '' ); - break; - } - node = child; - } - if ( node.nodeType === TEXT_NODE ) { - // Opera will collapse the block element if it contains - // just spaces (but not if it contains no data at all). - if ( /^ +$/.test( node.data ) ) { - node.data = ''; - } - } else if ( isLeaf( node ) ) { - node.parentNode.insertBefore( doc.createTextNode( '' ), node ); - } - } - else if ( !node.querySelector( 'BR' ) ) { - fixer = createElement( doc, 'BR' ); - while ( ( child = node.lastElementChild ) && !isInline( child ) ) { - node = child; - } - } - } - if ( fixer ) { - try { - node.appendChild( fixer ); - } catch ( error ) { - self.didError({ - name: 'Squire: fixCursor – ' + error, - message: 'Parent: ' + node.nodeName + '/' + node.innerHTML + - ' appendChild: ' + fixer.nodeName - }); - } - } - - return originalNode; -} - -// Recursively examine container nodes and wrap any inline children. -function fixContainer ( container, root ) { - var children = container.childNodes; - var doc = container.ownerDocument; - var wrapper = null; - var i, l, child, isBR; - var config = root.__squire__._config; - - for ( i = 0, l = children.length; i < l; i += 1 ) { - child = children[i]; - isBR = child.nodeName === 'BR'; - if ( !isBR && isInline( child ) ) { - if ( !wrapper ) { - wrapper = createElement( doc, - config.blockTag, config.blockAttributes ); - } - wrapper.appendChild( child ); - i -= 1; - l -= 1; - } else if ( isBR || wrapper ) { - if ( !wrapper ) { - wrapper = createElement( doc, - config.blockTag, config.blockAttributes ); - } - fixCursor( wrapper, root ); - if ( isBR ) { - container.replaceChild( wrapper, child ); - } else { - container.insertBefore( wrapper, child ); - i += 1; - l += 1; - } - wrapper = null; - } - if ( isContainer( child ) ) { - fixContainer( child, root ); - } - } - if ( wrapper ) { - container.appendChild( fixCursor( wrapper, root ) ); - } - return container; -} - -function split ( node, offset, stopNode, root ) { - var nodeType = node.nodeType, - parent, clone, next; - if ( nodeType === TEXT_NODE && node !== stopNode ) { - return split( - node.parentNode, node.splitText( offset ), stopNode, root ); - } - if ( nodeType === ELEMENT_NODE ) { - if ( typeof( offset ) === 'number' ) { - offset = offset < node.childNodes.length ? - node.childNodes[ offset ] : null; - } - if ( node === stopNode ) { - return offset; - } - - // Clone node without children - parent = node.parentNode; - clone = node.cloneNode( false ); - - // Add right-hand siblings to the clone - while ( offset ) { - next = offset.nextSibling; - clone.appendChild( offset ); - offset = next; - } - - // Maintain li numbering if inside a quote. - if ( node.nodeName === 'OL' && - getNearest( node, root, 'BLOCKQUOTE' ) ) { - clone.start = ( +node.start || 1 ) + node.childNodes.length - 1; - } - - // DO NOT NORMALISE. This may undo the fixCursor() call - // of a node lower down the tree! - - // We need something in the element in order for the cursor to appear. - fixCursor( node, root ); - fixCursor( clone, root ); - - // Inject clone after original node - if ( next = node.nextSibling ) { - parent.insertBefore( clone, next ); - } else { - parent.appendChild( clone ); - } - - // Keep on splitting up the tree - return split( parent, clone, stopNode, root ); - } - return offset; -} - -function _mergeInlines ( node, fakeRange ) { - var children = node.childNodes, - l = children.length, - frags = [], - child, prev, len; - while ( l-- ) { - child = children[l]; - prev = l && children[ l - 1 ]; - if ( l && isInline( child ) && areAlike( child, prev ) && - !leafNodeNames[ child.nodeName ] ) { - if ( fakeRange.startContainer === child ) { - fakeRange.startContainer = prev; - fakeRange.startOffset += getLength( prev ); - } - if ( fakeRange.endContainer === child ) { - fakeRange.endContainer = prev; - fakeRange.endOffset += getLength( prev ); - } - if ( fakeRange.startContainer === node ) { - if ( fakeRange.startOffset > l ) { - fakeRange.startOffset -= 1; - } - else if ( fakeRange.startOffset === l ) { - fakeRange.startContainer = prev; - fakeRange.startOffset = getLength( prev ); - } - } - if ( fakeRange.endContainer === node ) { - if ( fakeRange.endOffset > l ) { - fakeRange.endOffset -= 1; - } - else if ( fakeRange.endOffset === l ) { - fakeRange.endContainer = prev; - fakeRange.endOffset = getLength( prev ); - } - } - detach( child ); - if ( child.nodeType === TEXT_NODE ) { - prev.appendData( child.data ); - } - else { - frags.push( empty( child ) ); - } - } - else if ( child.nodeType === ELEMENT_NODE ) { - len = frags.length; - while ( len-- ) { - child.appendChild( frags.pop() ); - } - _mergeInlines( child, fakeRange ); - } - } -} - -function mergeInlines ( node, range ) { - if ( node.nodeType === TEXT_NODE ) { - node = node.parentNode; - } - if ( node.nodeType === ELEMENT_NODE ) { - var fakeRange = { - startContainer: range.startContainer, - startOffset: range.startOffset, - endContainer: range.endContainer, - endOffset: range.endOffset - }; - _mergeInlines( node, fakeRange ); - range.setStart( fakeRange.startContainer, fakeRange.startOffset ); - range.setEnd( fakeRange.endContainer, fakeRange.endOffset ); - } -} - -function mergeWithBlock ( block, next, range, root ) { - var container = next; - var parent, last, offset; - while ( ( parent = container.parentNode ) && - parent !== root && - parent.nodeType === ELEMENT_NODE && - parent.childNodes.length === 1 ) { - container = parent; - } - detach( container ); - - offset = block.childNodes.length; - - // Remove extra
    fixer if present. - last = block.lastChild; - if ( last && last.nodeName === 'BR' ) { - block.removeChild( last ); - offset -= 1; - } - - block.appendChild( empty( next ) ); - - range.setStart( block, offset ); - range.collapse( true ); - mergeInlines( block, range ); - - // Opera inserts a BR if you delete the last piece of text - // in a block-level element. Unfortunately, it then gets - // confused when setting the selection subsequently and - // refuses to accept the range that finishes just before the - // BR. Removing the BR fixes the bug. - // Steps to reproduce bug: Type "a-b-c" (where - is return) - // then backspace twice. The cursor goes to the top instead - // of after "b". - if ( isPresto && ( last = block.lastChild ) && last.nodeName === 'BR' ) { - block.removeChild( last ); - } -} - -function mergeContainers ( node, root ) { - var prev = node.previousSibling, - first = node.firstChild, - doc = node.ownerDocument, - isListItem = ( node.nodeName === 'LI' ), - needsFix, block; - - // Do not merge LIs, unless it only contains a UL - if ( isListItem && ( !first || !/^[OU]L$/.test( first.nodeName ) ) ) { - return; - } - - if ( prev && areAlike( prev, node ) ) { - if ( !isContainer( prev ) ) { - if ( isListItem ) { - block = createElement( doc, 'DIV' ); - block.appendChild( empty( prev ) ); - prev.appendChild( block ); - } else { - return; - } - } - detach( node ); - needsFix = !isContainer( node ); - prev.appendChild( empty( node ) ); - if ( needsFix ) { - fixContainer( prev, root ); - } - if ( first ) { - mergeContainers( first, root ); - } - } else if ( isListItem ) { - prev = createElement( doc, 'DIV' ); - node.insertBefore( prev, first ); - fixCursor( prev, root ); - } -} - -var getNodeBefore = function ( node, offset ) { - var children = node.childNodes; - while ( offset && node.nodeType === ELEMENT_NODE ) { - node = children[ offset - 1 ]; - children = node.childNodes; - offset = children.length; - } - return node; -}; - -var getNodeAfter = function ( node, offset ) { - if ( node.nodeType === ELEMENT_NODE ) { - var children = node.childNodes; - if ( offset < children.length ) { - node = children[ offset ]; - } else { - while ( node && !node.nextSibling ) { - node = node.parentNode; - } - if ( node ) { node = node.nextSibling; } - } - } - return node; -}; - -// --- - -var insertNodeInRange = function ( range, node ) { - // Insert at start. - var startContainer = range.startContainer, - startOffset = range.startOffset, - endContainer = range.endContainer, - endOffset = range.endOffset, - parent, children, childCount, afterSplit; - - // If part way through a text node, split it. - if ( startContainer.nodeType === TEXT_NODE ) { - parent = startContainer.parentNode; - children = parent.childNodes; - if ( startOffset === startContainer.length ) { - startOffset = indexOf.call( children, startContainer ) + 1; - if ( range.collapsed ) { - endContainer = parent; - endOffset = startOffset; - } - } else { - if ( startOffset ) { - afterSplit = startContainer.splitText( startOffset ); - if ( endContainer === startContainer ) { - endOffset -= startOffset; - endContainer = afterSplit; - } - else if ( endContainer === parent ) { - endOffset += 1; - } - startContainer = afterSplit; - } - startOffset = indexOf.call( children, startContainer ); - } - startContainer = parent; - } else { - children = startContainer.childNodes; - } - - childCount = children.length; - - if ( startOffset === childCount ) { - startContainer.appendChild( node ); - } else { - startContainer.insertBefore( node, children[ startOffset ] ); - } - - if ( startContainer === endContainer ) { - endOffset += children.length - childCount; - } - - range.setStart( startContainer, startOffset ); - range.setEnd( endContainer, endOffset ); -}; - -var extractContentsOfRange = function ( range, common, root ) { - var startContainer = range.startContainer, - startOffset = range.startOffset, - endContainer = range.endContainer, - endOffset = range.endOffset; - - if ( !common ) { - common = range.commonAncestorContainer; - } - - if ( common.nodeType === TEXT_NODE ) { - common = common.parentNode; - } - - var endNode = split( endContainer, endOffset, common, root ), - startNode = split( startContainer, startOffset, common, root ), - frag = common.ownerDocument.createDocumentFragment(), - next, before, after; - - // End node will be null if at end of child nodes list. - while ( startNode !== endNode ) { - next = startNode.nextSibling; - frag.appendChild( startNode ); - startNode = next; - } - - startContainer = common; - startOffset = endNode ? - indexOf.call( common.childNodes, endNode ) : - common.childNodes.length; - - // Merge text nodes if adjacent. IE10 in particular will not focus - // between two text nodes - after = common.childNodes[ startOffset ]; - before = after && after.previousSibling; - if ( before && - before.nodeType === TEXT_NODE && - after.nodeType === TEXT_NODE ) { - startContainer = before; - startOffset = before.length; - before.appendData( after.data ); - detach( after ); - } - - range.setStart( startContainer, startOffset ); - range.collapse( true ); - - fixCursor( common, root ); - - return frag; -}; - -var deleteContentsOfRange = function ( range, root ) { - var startBlock = getStartBlockOfRange( range, root ); - var endBlock = getEndBlockOfRange( range, root ); - var needsMerge = ( startBlock !== endBlock ); - var frag, child; - - // Move boundaries up as much as possible without exiting block, - // to reduce need to split. - moveRangeBoundariesDownTree( range ); - moveRangeBoundariesUpTree( range, startBlock, endBlock, root ); - - // Remove selected range - frag = extractContentsOfRange( range, null, root ); - - // Move boundaries back down tree as far as possible. - moveRangeBoundariesDownTree( range ); - - // If we split into two different blocks, merge the blocks. - if ( needsMerge ) { - // endBlock will have been split, so need to refetch - endBlock = getEndBlockOfRange( range, root ); - if ( startBlock && endBlock && startBlock !== endBlock ) { - mergeWithBlock( startBlock, endBlock, range, root ); - } - } - - // Ensure block has necessary children - if ( startBlock ) { - fixCursor( startBlock, root ); - } - - // Ensure root has a block-level element in it. - child = root.firstChild; - if ( !child || child.nodeName === 'BR' ) { - fixCursor( root, root ); - range.selectNodeContents( root.firstChild ); - } else { - range.collapse( true ); - } - return frag; -}; - -// --- - -// Contents of range will be deleted. -// After method, range will be around inserted content -var insertTreeFragmentIntoRange = function ( range, frag, root ) { - var node, block, blockContentsAfterSplit, stopPoint, container, offset; - var firstBlockInFrag, nodeAfterSplit, nodeBeforeSplit, tempRange; - - // Fixup content: ensure no top-level inline, and add cursor fix elements. - fixContainer( frag, root ); - node = frag; - while ( ( node = getNextBlock( node, root ) ) ) { - fixCursor( node, root ); - } - - // Delete any selected content. - if ( !range.collapsed ) { - deleteContentsOfRange( range, root ); - } - - // Move range down into text nodes. - moveRangeBoundariesDownTree( range ); - range.collapse( false ); // collapse to end - - // Where will we split up to? First blockquote parent, otherwise root. - stopPoint = getNearest( range.endContainer, root, 'BLOCKQUOTE' ) || root; - - // Merge the contents of the first block in the frag with the focused block. - // If there are contents in the block after the focus point, collect this - // up to insert in the last block later - block = getStartBlockOfRange( range, root ); - firstBlockInFrag = getNextBlock( frag, frag ); - if ( block && firstBlockInFrag && - // Don't merge table cells or PRE elements into block - !getNearest( firstBlockInFrag, frag, 'PRE' ) && - !getNearest( firstBlockInFrag, frag, 'TABLE' ) ) { - moveRangeBoundariesUpTree( range, block, block, root ); - range.collapse( true ); // collapse to start - container = range.endContainer; - offset = range.endOffset; - // Remove trailing
    – we don't want this considered content to be - // inserted again later - cleanupBRs( block, root, false ); - if ( isInline( container ) ) { - // Split up to block parent. - nodeAfterSplit = split( - container, offset, getPreviousBlock( container, root ), root ); - container = nodeAfterSplit.parentNode; - offset = indexOf.call( container.childNodes, nodeAfterSplit ); - } - if ( /*isBlock( container ) && */offset !== getLength( container ) ) { - // Collect any inline contents of the block after the range point - blockContentsAfterSplit = - root.ownerDocument.createDocumentFragment(); - while ( ( node = container.childNodes[ offset ] ) ) { - blockContentsAfterSplit.appendChild( node ); - } - } - // And merge the first block in. - mergeWithBlock( container, firstBlockInFrag, range, root ); - - // And where we will insert - offset = indexOf.call( container.parentNode.childNodes, container ) + 1; - container = container.parentNode; - range.setEnd( container, offset ); - } - - // Is there still any content in the fragment? - if ( getLength( frag ) ) { - moveRangeBoundariesUpTree( range, stopPoint, stopPoint, root ); - // Now split after block up to blockquote (if a parent) or root - nodeAfterSplit = split( - range.endContainer, range.endOffset, stopPoint, root ); - nodeBeforeSplit = nodeAfterSplit ? - nodeAfterSplit.previousSibling : - stopPoint.lastChild; - stopPoint.insertBefore( frag, nodeAfterSplit ); - if ( nodeAfterSplit ) { - range.setEndBefore( nodeAfterSplit ); - } else { - range.setEnd( stopPoint, getLength( stopPoint ) ); - } - block = getEndBlockOfRange( range, root ); - - // Get a reference that won't be invalidated if we merge containers. - moveRangeBoundariesDownTree( range ); - container = range.endContainer; - offset = range.endOffset; - - // Merge inserted containers with edges of split - if ( nodeAfterSplit && isContainer( nodeAfterSplit ) ) { - mergeContainers( nodeAfterSplit, root ); - } - nodeAfterSplit = nodeBeforeSplit && nodeBeforeSplit.nextSibling; - if ( nodeAfterSplit && isContainer( nodeAfterSplit ) ) { - mergeContainers( nodeAfterSplit, root ); - } - range.setEnd( container, offset ); - } - - // Insert inline content saved from before. - if ( blockContentsAfterSplit ) { - tempRange = range.cloneRange(); - mergeWithBlock( block, blockContentsAfterSplit, tempRange, root ); - range.setEnd( tempRange.endContainer, tempRange.endOffset ); - } - moveRangeBoundariesDownTree( range ); -}; - -// --- - -var isNodeContainedInRange = function ( range, node, partial ) { - var nodeRange = node.ownerDocument.createRange(); - - nodeRange.selectNode( node ); - - if ( partial ) { - // Node must not finish before range starts or start after range - // finishes. - var nodeEndBeforeStart = ( range.compareBoundaryPoints( - END_TO_START, nodeRange ) > -1 ), - nodeStartAfterEnd = ( range.compareBoundaryPoints( - START_TO_END, nodeRange ) < 1 ); - return ( !nodeEndBeforeStart && !nodeStartAfterEnd ); - } - else { - // Node must start after range starts and finish before range - // finishes - var nodeStartAfterStart = ( range.compareBoundaryPoints( - START_TO_START, nodeRange ) < 1 ), - nodeEndBeforeEnd = ( range.compareBoundaryPoints( - END_TO_END, nodeRange ) > -1 ); - return ( nodeStartAfterStart && nodeEndBeforeEnd ); - } -}; - -var moveRangeBoundariesDownTree = function ( range ) { - var startContainer = range.startContainer, - startOffset = range.startOffset, - endContainer = range.endContainer, - endOffset = range.endOffset, - maySkipBR = true, - child; - - while ( startContainer.nodeType !== TEXT_NODE ) { - child = startContainer.childNodes[ startOffset ]; - if ( !child || isLeaf( child ) ) { - break; - } - startContainer = child; - startOffset = 0; - } - if ( endOffset ) { - while ( endContainer.nodeType !== TEXT_NODE ) { - child = endContainer.childNodes[ endOffset - 1 ]; - if ( !child || isLeaf( child ) ) { - if ( maySkipBR && child && child.nodeName === 'BR' ) { - endOffset -= 1; - maySkipBR = false; - continue; - } - break; - } - endContainer = child; - endOffset = getLength( endContainer ); - } - } else { - while ( endContainer.nodeType !== TEXT_NODE ) { - child = endContainer.firstChild; - if ( !child || isLeaf( child ) ) { - break; - } - endContainer = child; - } - } - - // If collapsed, this algorithm finds the nearest text node positions - // *outside* the range rather than inside, but also it flips which is - // assigned to which. - if ( range.collapsed ) { - range.setStart( endContainer, endOffset ); - range.setEnd( startContainer, startOffset ); - } else { - range.setStart( startContainer, startOffset ); - range.setEnd( endContainer, endOffset ); - } -}; - -var moveRangeBoundariesUpTree = function ( range, startMax, endMax, root ) { - var startContainer = range.startContainer; - var startOffset = range.startOffset; - var endContainer = range.endContainer; - var endOffset = range.endOffset; - var maySkipBR = true; - var parent; - - if ( !startMax ) { - startMax = range.commonAncestorContainer; - } - if ( !endMax ) { - endMax = startMax; - } - - while ( !startOffset && - startContainer !== startMax && - startContainer !== root ) { - parent = startContainer.parentNode; - startOffset = indexOf.call( parent.childNodes, startContainer ); - startContainer = parent; - } - - while ( true ) { - if ( maySkipBR && - endContainer.nodeType !== TEXT_NODE && - endContainer.childNodes[ endOffset ] && - endContainer.childNodes[ endOffset ].nodeName === 'BR' ) { - endOffset += 1; - maySkipBR = false; - } - if ( endContainer === endMax || - endContainer === root || - endOffset !== getLength( endContainer ) ) { - break; - } - parent = endContainer.parentNode; - endOffset = indexOf.call( parent.childNodes, endContainer ) + 1; - endContainer = parent; - } - - range.setStart( startContainer, startOffset ); - range.setEnd( endContainer, endOffset ); -}; - -// Returns the first block at least partially contained by the range, -// or null if no block is contained by the range. -var getStartBlockOfRange = function ( range, root ) { - var container = range.startContainer, - block; - - // If inline, get the containing block. - if ( isInline( container ) ) { - block = getPreviousBlock( container, root ); - } else if ( container !== root && isBlock( container ) ) { - block = container; - } else { - block = getNodeBefore( container, range.startOffset ); - block = getNextBlock( block, root ); - } - // Check the block actually intersects the range - return block && isNodeContainedInRange( range, block, true ) ? block : null; -}; - -// Returns the last block at least partially contained by the range, -// or null if no block is contained by the range. -var getEndBlockOfRange = function ( range, root ) { - var container = range.endContainer, - block, child; - - // If inline, get the containing block. - if ( isInline( container ) ) { - block = getPreviousBlock( container, root ); - } else if ( container !== root && isBlock( container ) ) { - block = container; - } else { - block = getNodeAfter( container, range.endOffset ); - if ( !block || !isOrContains( root, block ) ) { - block = root; - while ( child = block.lastChild ) { - block = child; - } - } - block = getPreviousBlock( block, root ); - } - // Check the block actually intersects the range - return block && isNodeContainedInRange( range, block, true ) ? block : null; -}; - -var contentWalker = new TreeWalker( null, - SHOW_TEXT|SHOW_ELEMENT, - function ( node ) { - return node.nodeType === TEXT_NODE ? - notWS.test( node.data ) : - node.nodeName === 'IMG'; - } -); - -var rangeDoesStartAtBlockBoundary = function ( range, root ) { - var startContainer = range.startContainer; - var startOffset = range.startOffset; - var nodeAfterCursor; - - // If in the middle or end of a text node, we're not at the boundary. - contentWalker.root = null; - if ( startContainer.nodeType === TEXT_NODE ) { - if ( startOffset ) { - return false; - } - nodeAfterCursor = startContainer; - } else { - nodeAfterCursor = getNodeAfter( startContainer, startOffset ); - if ( nodeAfterCursor && !isOrContains( root, nodeAfterCursor ) ) { - nodeAfterCursor = null; - } - // The cursor was right at the end of the document - if ( !nodeAfterCursor ) { - nodeAfterCursor = getNodeBefore( startContainer, startOffset ); - if ( nodeAfterCursor.nodeType === TEXT_NODE && - nodeAfterCursor.length ) { - return false; - } - } - } - - // Otherwise, look for any previous content in the same block. - contentWalker.currentNode = nodeAfterCursor; - contentWalker.root = getStartBlockOfRange( range, root ); - - return !contentWalker.previousNode(); -}; - -var rangeDoesEndAtBlockBoundary = function ( range, root ) { - var endContainer = range.endContainer, - endOffset = range.endOffset, - length; - - // If in a text node with content, and not at the end, we're not - // at the boundary - contentWalker.root = null; - if ( endContainer.nodeType === TEXT_NODE ) { - length = endContainer.data.length; - if ( length && endOffset < length ) { - return false; - } - contentWalker.currentNode = endContainer; - } else { - contentWalker.currentNode = getNodeBefore( endContainer, endOffset ); - } - - // Otherwise, look for any further content in the same block. - contentWalker.root = getEndBlockOfRange( range, root ); - - return !contentWalker.nextNode(); -}; - -var expandRangeToBlockBoundaries = function ( range, root ) { - var start = getStartBlockOfRange( range, root ), - end = getEndBlockOfRange( range, root ), - parent; - - if ( start && end ) { - parent = start.parentNode; - range.setStart( parent, indexOf.call( parent.childNodes, start ) ); - parent = end.parentNode; - range.setEnd( parent, indexOf.call( parent.childNodes, end ) + 1 ); - } -}; - -var keys = { - 8: 'backspace', - 9: 'tab', - 13: 'enter', - 32: 'space', - 33: 'pageup', - 34: 'pagedown', - 37: 'left', - 39: 'right', - 46: 'delete', - 219: '[', - 221: ']' -}; - -// Ref: http://unixpapa.com/js/key.html -var onKey = function ( event ) { - var code = event.keyCode, - key = keys[ code ], - modifiers = '', - range = this.getSelection(); - - if ( event.defaultPrevented ) { - return; - } - - if ( !key ) { - key = String.fromCharCode( code ).toLowerCase(); - // Only reliable for letters and numbers - if ( !/^[A-Za-z0-9]$/.test( key ) ) { - key = ''; - } - } - - // On keypress, delete and '.' both have event.keyCode 46 - // Must check event.which to differentiate. - if ( isPresto && event.which === 46 ) { - key = '.'; - } - - // Function keys - if ( 111 < code && code < 124 ) { - key = 'f' + ( code - 111 ); - } - - // We need to apply the backspace/delete handlers regardless of - // control key modifiers. - if ( key !== 'backspace' && key !== 'delete' ) { - if ( event.altKey ) { modifiers += 'alt-'; } - if ( event.ctrlKey ) { modifiers += 'ctrl-'; } - if ( event.metaKey ) { modifiers += 'meta-'; } - } - // However, on Windows, shift-delete is apparently "cut" (WTF right?), so - // we want to let the browser handle shift-delete. - if ( event.shiftKey ) { modifiers += 'shift-'; } - - key = modifiers + key; - - if ( this._keyHandlers[ key ] ) { - this._keyHandlers[ key ]( this, event, range ); - } else if ( key.length === 1 && !range.collapsed ) { - // Record undo checkpoint. - this.saveUndoState( range ); - // Delete the selection - deleteContentsOfRange( range, this._root ); - this._ensureBottomLine(); - this.setSelection( range ); - this._updatePath( range, true ); - } -}; - -var mapKeyTo = function ( method ) { - return function ( self, event ) { - event.preventDefault(); - self[ method ](); - }; -}; - -var mapKeyToFormat = function ( tag, remove ) { - remove = remove || null; - return function ( self, event ) { - event.preventDefault(); - var range = self.getSelection(); - if ( self.hasFormat( tag, null, range ) ) { - self.changeFormat( null, { tag: tag }, range ); - } else { - self.changeFormat( { tag: tag }, remove, range ); - } - }; -}; - -// If you delete the content inside a span with a font styling, Webkit will -// replace it with a tag (!). If you delete all the text inside a -// link in Opera, it won't delete the link. Let's make things consistent. If -// you delete all text inside an inline tag, remove the inline tag. -var afterDelete = function ( self, range ) { - try { - if ( !range ) { range = self.getSelection(); } - var node = range.startContainer, - parent; - // Climb the tree from the focus point while we are inside an empty - // inline element - if ( node.nodeType === TEXT_NODE ) { - node = node.parentNode; - } - parent = node; - while ( isInline( parent ) && - ( !parent.textContent || parent.textContent === ZWS ) ) { - node = parent; - parent = node.parentNode; - } - // If focused in empty inline element - if ( node !== parent ) { - // Move focus to just before empty inline(s) - range.setStart( parent, - indexOf.call( parent.childNodes, node ) ); - range.collapse( true ); - // Remove empty inline(s) - parent.removeChild( node ); - // Fix cursor in block - if ( !isBlock( parent ) ) { - parent = getPreviousBlock( parent, self._root ); - } - fixCursor( parent, self._root ); - // Move cursor into text node - moveRangeBoundariesDownTree( range ); - } - // If you delete the last character in the sole
    in Chrome, - // it removes the div and replaces it with just a
    inside the - // root. Detach the
    ; the _ensureBottomLine call will insert a new - // block. - if ( node === self._root && - ( node = node.firstChild ) && node.nodeName === 'BR' ) { - detach( node ); - } - self._ensureBottomLine(); - self.setSelection( range ); - self._updatePath( range, true ); - } catch ( error ) { - self.didError( error ); - } -}; - -var keyHandlers = { - enter: function ( self, event, range ) { - var root = self._root; - var block, parent, nodeAfterSplit; - - // We handle this ourselves - event.preventDefault(); - - // Save undo checkpoint and add any links in the preceding section. - // Remove any zws so we don't think there's content in an empty - // block. - self._recordUndoState( range ); - addLinks( range.startContainer, root, self ); - self._removeZWS(); - self._getRangeAndRemoveBookmark( range ); - - // Selected text is overwritten, therefore delete the contents - // to collapse selection. - if ( !range.collapsed ) { - deleteContentsOfRange( range, root ); - } - - block = getStartBlockOfRange( range, root ); - - // If this is a malformed bit of document or in a table; - // just play it safe and insert a
    . - if ( !block || /^T[HD]$/.test( block.nodeName ) ) { - // If inside an , move focus out - parent = getNearest( range.endContainer, root, 'A' ); - if ( parent ) { - parent = parent.parentNode; - moveRangeBoundariesUpTree( range, parent, parent, root ); - range.collapse( false ); - } - insertNodeInRange( range, self.createElement( 'BR' ) ); - range.collapse( false ); - self.setSelection( range ); - self._updatePath( range, true ); - return; - } - - // If in a list, we'll split the LI instead. - if ( parent = getNearest( block, root, 'LI' ) ) { - block = parent; - } - - if ( isEmptyBlock( block ) ) { - // Break list - if ( getNearest( block, root, 'UL' ) || - getNearest( block, root, 'OL' ) ) { - return self.decreaseListLevel( range ); - } - // Break blockquote - else if ( getNearest( block, root, 'BLOCKQUOTE' ) ) { - return self.modifyBlocks( removeBlockQuote, range ); - } - } - - // Otherwise, split at cursor point. - nodeAfterSplit = splitBlock( self, block, - range.startContainer, range.startOffset ); - - // Clean up any empty inlines if we hit enter at the beginning of the - // block - removeZWS( block ); - removeEmptyInlines( block ); - fixCursor( block, root ); - - // Focus cursor - // If there's a / etc. at the beginning of the split - // make sure we focus inside it. - while ( nodeAfterSplit.nodeType === ELEMENT_NODE ) { - var child = nodeAfterSplit.firstChild, - next; - - // Don't continue links over a block break; unlikely to be the - // desired outcome. - if ( nodeAfterSplit.nodeName === 'A' && - ( !nodeAfterSplit.textContent || - nodeAfterSplit.textContent === ZWS ) ) { - child = self._doc.createTextNode( '' ); - replaceWith( nodeAfterSplit, child ); - nodeAfterSplit = child; - break; - } - - while ( child && child.nodeType === TEXT_NODE && !child.data ) { - next = child.nextSibling; - if ( !next || next.nodeName === 'BR' ) { - break; - } - detach( child ); - child = next; - } - - // 'BR's essentially don't count; they're a browser hack. - // If you try to select the contents of a 'BR', FF will not let - // you type anything! - if ( !child || child.nodeName === 'BR' || - ( child.nodeType === TEXT_NODE && !isPresto ) ) { - break; - } - nodeAfterSplit = child; - } - range = self._createRange( nodeAfterSplit, 0 ); - self.setSelection( range ); - self._updatePath( range, true ); - }, - backspace: function ( self, event, range ) { - var root = self._root; - self._removeZWS(); - // Record undo checkpoint. - self.saveUndoState( range ); - // If not collapsed, delete contents - if ( !range.collapsed ) { - event.preventDefault(); - deleteContentsOfRange( range, root ); - afterDelete( self, range ); - } - // If at beginning of block, merge with previous - else if ( rangeDoesStartAtBlockBoundary( range, root ) ) { - event.preventDefault(); - var current = getStartBlockOfRange( range, root ); - var previous; - if ( !current ) { - return; - } - // In case inline data has somehow got between blocks. - fixContainer( current.parentNode, root ); - // Now get previous block - previous = getPreviousBlock( current, root ); - // Must not be at the very beginning of the text area. - if ( previous ) { - // If not editable, just delete whole block. - if ( !previous.isContentEditable ) { - detach( previous ); - return; - } - // Otherwise merge. - mergeWithBlock( previous, current, range, root ); - // If deleted line between containers, merge newly adjacent - // containers. - current = previous.parentNode; - while ( current !== root && !current.nextSibling ) { - current = current.parentNode; - } - if ( current !== root && ( current = current.nextSibling ) ) { - mergeContainers( current, root ); - } - self.setSelection( range ); - } - // If at very beginning of text area, allow backspace - // to break lists/blockquote. - else if ( current ) { - // Break list - if ( getNearest( current, root, 'UL' ) || - getNearest( current, root, 'OL' ) ) { - return self.decreaseListLevel( range ); - } - // Break blockquote - else if ( getNearest( current, root, 'BLOCKQUOTE' ) ) { - return self.modifyBlocks( decreaseBlockQuoteLevel, range ); - } - self.setSelection( range ); - self._updatePath( range, true ); - } - } - // Otherwise, leave to browser but check afterwards whether it has - // left behind an empty inline tag. - else { - self.setSelection( range ); - setTimeout( function () { afterDelete( self ); }, 0 ); - } - }, - 'delete': function ( self, event, range ) { - var root = self._root; - var current, next, originalRange, - cursorContainer, cursorOffset, nodeAfterCursor; - self._removeZWS(); - // Record undo checkpoint. - self.saveUndoState( range ); - // If not collapsed, delete contents - if ( !range.collapsed ) { - event.preventDefault(); - deleteContentsOfRange( range, root ); - afterDelete( self, range ); - } - // If at end of block, merge next into this block - else if ( rangeDoesEndAtBlockBoundary( range, root ) ) { - event.preventDefault(); - current = getStartBlockOfRange( range, root ); - if ( !current ) { - return; - } - // In case inline data has somehow got between blocks. - fixContainer( current.parentNode, root ); - // Now get next block - next = getNextBlock( current, root ); - // Must not be at the very end of the text area. - if ( next ) { - // If not editable, just delete whole block. - if ( !next.isContentEditable ) { - detach( next ); - return; - } - // Otherwise merge. - mergeWithBlock( current, next, range, root ); - // If deleted line between containers, merge newly adjacent - // containers. - next = current.parentNode; - while ( next !== root && !next.nextSibling ) { - next = next.parentNode; - } - if ( next !== root && ( next = next.nextSibling ) ) { - mergeContainers( next, root ); - } - self.setSelection( range ); - self._updatePath( range, true ); - } - } - // Otherwise, leave to browser but check afterwards whether it has - // left behind an empty inline tag. - else { - // But first check if the cursor is just before an IMG tag. If so, - // delete it ourselves, because the browser won't if it is not - // inline. - originalRange = range.cloneRange(); - moveRangeBoundariesUpTree( range, root, root, root ); - cursorContainer = range.endContainer; - cursorOffset = range.endOffset; - if ( cursorContainer.nodeType === ELEMENT_NODE ) { - nodeAfterCursor = cursorContainer.childNodes[ cursorOffset ]; - if ( nodeAfterCursor && nodeAfterCursor.nodeName === 'IMG' ) { - event.preventDefault(); - detach( nodeAfterCursor ); - moveRangeBoundariesDownTree( range ); - afterDelete( self, range ); - return; - } - } - self.setSelection( originalRange ); - setTimeout( function () { afterDelete( self ); }, 0 ); - } - }, - tab: function ( self, event, range ) { - var root = self._root; - var node, parent; - self._removeZWS(); - // If no selection and at start of block - if ( range.collapsed && rangeDoesStartAtBlockBoundary( range, root ) ) { - node = getStartBlockOfRange( range, root ); - // Iterate through the block's parents - while ( ( parent = node.parentNode ) ) { - // If we find a UL or OL (so are in a list, node must be an LI) - if ( parent.nodeName === 'UL' || parent.nodeName === 'OL' ) { - // Then increase the list level - event.preventDefault(); - self.increaseListLevel( range ); - break; - } - node = parent; - } - } - }, - 'shift-tab': function ( self, event, range ) { - var root = self._root; - var node; - self._removeZWS(); - // If no selection and at start of block - if ( range.collapsed && rangeDoesStartAtBlockBoundary( range, root ) ) { - // Break list - node = range.startContainer; - if ( getNearest( node, root, 'UL' ) || - getNearest( node, root, 'OL' ) ) { - event.preventDefault(); - self.decreaseListLevel( range ); - } - } - }, - space: function ( self, _, range ) { - var node, parent; - self._recordUndoState( range ); - addLinks( range.startContainer, self._root, self ); - self._getRangeAndRemoveBookmark( range ); - - // If the cursor is at the end of a link (foo|) then move it - // outside of the link (foo|) so that the space is not part of - // the link text. - node = range.endContainer; - parent = node.parentNode; - if ( range.collapsed && parent.nodeName === 'A' && - !node.nextSibling && range.endOffset === getLength( node ) ) { - range.setStartAfter( parent ); - } - // Delete the selection if not collapsed - else if ( !range.collapsed ) { - deleteContentsOfRange( range, self._root ); - self._ensureBottomLine(); - self.setSelection( range ); - self._updatePath( range, true ); - } - - self.setSelection( range ); - }, - left: function ( self ) { - self._removeZWS(); - }, - right: function ( self ) { - self._removeZWS(); - } -}; - -// Firefox pre v29 incorrectly handles Cmd-left/Cmd-right on Mac: -// it goes back/forward in history! Override to do the right -// thing. -// https://bugzilla.mozilla.org/show_bug.cgi?id=289384 -if ( isMac && isGecko ) { - keyHandlers[ 'meta-left' ] = function ( self, event ) { - event.preventDefault(); - var sel = getWindowSelection( self ); - if ( sel && sel.modify ) { - sel.modify( 'move', 'backward', 'lineboundary' ); - } - }; - keyHandlers[ 'meta-right' ] = function ( self, event ) { - event.preventDefault(); - var sel = getWindowSelection( self ); - if ( sel && sel.modify ) { - sel.modify( 'move', 'forward', 'lineboundary' ); - } - }; -} - -// System standard for page up/down on Mac is to just scroll, not move the -// cursor. On Linux/Windows, it should move the cursor, but some browsers don't -// implement this natively. Override to support it. -if ( !isMac ) { - keyHandlers.pageup = function ( self ) { - self.moveCursorToStart(); - }; - keyHandlers.pagedown = function ( self ) { - self.moveCursorToEnd(); - }; -} - -keyHandlers[ ctrlKey + 'b' ] = mapKeyToFormat( 'B' ); -keyHandlers[ ctrlKey + 'i' ] = mapKeyToFormat( 'I' ); -keyHandlers[ ctrlKey + 'u' ] = mapKeyToFormat( 'U' ); -keyHandlers[ ctrlKey + 'shift-7' ] = mapKeyToFormat( 'S' ); -keyHandlers[ ctrlKey + 'shift-5' ] = mapKeyToFormat( 'SUB', { tag: 'SUP' } ); -keyHandlers[ ctrlKey + 'shift-6' ] = mapKeyToFormat( 'SUP', { tag: 'SUB' } ); -keyHandlers[ ctrlKey + 'shift-8' ] = mapKeyTo( 'makeUnorderedList' ); -keyHandlers[ ctrlKey + 'shift-9' ] = mapKeyTo( 'makeOrderedList' ); -keyHandlers[ ctrlKey + '[' ] = mapKeyTo( 'decreaseQuoteLevel' ); -keyHandlers[ ctrlKey + ']' ] = mapKeyTo( 'increaseQuoteLevel' ); -keyHandlers[ ctrlKey + 'y' ] = mapKeyTo( 'redo' ); -keyHandlers[ ctrlKey + 'z' ] = mapKeyTo( 'undo' ); -keyHandlers[ ctrlKey + 'shift-z' ] = mapKeyTo( 'redo' ); - -var fontSizes = { - 1: 10, - 2: 13, - 3: 16, - 4: 18, - 5: 24, - 6: 32, - 7: 48 -}; - -var styleToSemantic = { - backgroundColor: { - regexp: notWS, - replace: function ( doc, colour ) { - return createElement( doc, 'SPAN', { - 'class': HIGHLIGHT_CLASS, - style: 'background-color:' + colour - }); - } - }, - color: { - regexp: notWS, - replace: function ( doc, colour ) { - return createElement( doc, 'SPAN', { - 'class': COLOUR_CLASS, - style: 'color:' + colour - }); - } - }, - fontWeight: { - regexp: /^bold|^700/i, - replace: function ( doc ) { - return createElement( doc, 'B' ); - } - }, - fontStyle: { - regexp: /^italic/i, - replace: function ( doc ) { - return createElement( doc, 'I' ); - } - }, - fontFamily: { - regexp: notWS, - replace: function ( doc, family ) { - return createElement( doc, 'SPAN', { - 'class': FONT_FAMILY_CLASS, - style: 'font-family:' + family - }); - } - }, - fontSize: { - regexp: notWS, - replace: function ( doc, size ) { - return createElement( doc, 'SPAN', { - 'class': FONT_SIZE_CLASS, - style: 'font-size:' + size - }); - } - }, - textDecoration: { - regexp: /^underline/i, - replace: function ( doc ) { - return createElement( doc, 'U' ); - } - } -}; - -var replaceWithTag = function ( tag ) { - return function ( node, parent ) { - var el = createElement( node.ownerDocument, tag ); - parent.replaceChild( el, node ); - el.appendChild( empty( node ) ); - return el; - }; -}; - -var replaceStyles = function ( node, parent ) { - var style = node.style; - var doc = node.ownerDocument; - var attr, converter, css, newTreeBottom, newTreeTop, el; - - for ( attr in styleToSemantic ) { - converter = styleToSemantic[ attr ]; - css = style[ attr ]; - if ( css && converter.regexp.test( css ) ) { - el = converter.replace( doc, css ); - if ( !newTreeTop ) { - newTreeTop = el; - } - if ( newTreeBottom ) { - newTreeBottom.appendChild( el ); - } - newTreeBottom = el; - node.style[ attr ] = ''; - } - } - - if ( newTreeTop ) { - newTreeBottom.appendChild( empty( node ) ); - if ( node.nodeName === 'SPAN' ) { - parent.replaceChild( newTreeTop, node ); - } else { - node.appendChild( newTreeTop ); - } - } - - return newTreeBottom || node; -}; - -var stylesRewriters = { - P: replaceStyles, - SPAN: replaceStyles, - STRONG: replaceWithTag( 'B' ), - EM: replaceWithTag( 'I' ), - INS: replaceWithTag( 'U' ), - STRIKE: replaceWithTag( 'S' ), - FONT: function ( node, parent ) { - var face = node.face, - size = node.size, - colour = node.color, - doc = node.ownerDocument, - fontSpan, sizeSpan, colourSpan, - newTreeBottom, newTreeTop; - if ( face ) { - fontSpan = createElement( doc, 'SPAN', { - 'class': FONT_FAMILY_CLASS, - style: 'font-family:' + face - }); - newTreeTop = fontSpan; - newTreeBottom = fontSpan; - } - if ( size ) { - sizeSpan = createElement( doc, 'SPAN', { - 'class': FONT_SIZE_CLASS, - style: 'font-size:' + fontSizes[ size ] + 'px' - }); - if ( !newTreeTop ) { - newTreeTop = sizeSpan; - } - if ( newTreeBottom ) { - newTreeBottom.appendChild( sizeSpan ); - } - newTreeBottom = sizeSpan; - } - if ( colour && /^#?([\dA-F]{3}){1,2}$/i.test( colour ) ) { - if ( colour.charAt( 0 ) !== '#' ) { - colour = '#' + colour; - } - colourSpan = createElement( doc, 'SPAN', { - 'class': COLOUR_CLASS, - style: 'color:' + colour - }); - if ( !newTreeTop ) { - newTreeTop = colourSpan; - } - if ( newTreeBottom ) { - newTreeBottom.appendChild( colourSpan ); - } - newTreeBottom = colourSpan; - } - if ( !newTreeTop ) { - newTreeTop = newTreeBottom = createElement( doc, 'SPAN' ); - } - parent.replaceChild( newTreeTop, node ); - newTreeBottom.appendChild( empty( node ) ); - return newTreeBottom; - }, - TT: function ( node, parent ) { - var el = createElement( node.ownerDocument, 'SPAN', { - 'class': FONT_FAMILY_CLASS, - style: 'font-family:menlo,consolas,"courier new",monospace' - }); - parent.replaceChild( el, node ); - el.appendChild( empty( node ) ); - return el; - } -}; - -var allowedBlock = /^(?:A(?:DDRESS|RTICLE|SIDE|UDIO)|BLOCKQUOTE|CAPTION|D(?:[DLT]|IV)|F(?:IGURE|IGCAPTION|OOTER)|H[1-6]|HEADER|L(?:ABEL|EGEND|I)|O(?:L|UTPUT)|P(?:RE)?|SECTION|T(?:ABLE|BODY|D|FOOT|H|HEAD|R)|COL(?:GROUP)?|UL)$/; - -var blacklist = /^(?:HEAD|META|STYLE)/; - -var walker = new TreeWalker( null, SHOW_TEXT|SHOW_ELEMENT, function () { - return true; -}); - -/* - Two purposes: - - 1. Remove nodes we don't want, such as weird tags, comment nodes - and whitespace nodes. - 2. Convert inline tags into our preferred format. -*/ -var cleanTree = function cleanTree ( node, preserveWS ) { - var children = node.childNodes, - nonInlineParent, i, l, child, nodeName, nodeType, rewriter, childLength, - startsWithWS, endsWithWS, data, sibling; - - nonInlineParent = node; - while ( isInline( nonInlineParent ) ) { - nonInlineParent = nonInlineParent.parentNode; - } - walker.root = nonInlineParent; - - for ( i = 0, l = children.length; i < l; i += 1 ) { - child = children[i]; - nodeName = child.nodeName; - nodeType = child.nodeType; - rewriter = stylesRewriters[ nodeName ]; - if ( nodeType === ELEMENT_NODE ) { - childLength = child.childNodes.length; - if ( rewriter ) { - child = rewriter( child, node ); - } else if ( blacklist.test( nodeName ) ) { - node.removeChild( child ); - i -= 1; - l -= 1; - continue; - } else if ( !allowedBlock.test( nodeName ) && !isInline( child ) ) { - i -= 1; - l += childLength - 1; - node.replaceChild( empty( child ), child ); - continue; - } - if ( childLength ) { - cleanTree( child, preserveWS || ( nodeName === 'PRE' ) ); - } - } else { - if ( nodeType === TEXT_NODE ) { - data = child.data; - startsWithWS = !notWS.test( data.charAt( 0 ) ); - endsWithWS = !notWS.test( data.charAt( data.length - 1 ) ); - if ( preserveWS || ( !startsWithWS && !endsWithWS ) ) { - continue; - } - // Iterate through the nodes; if we hit some other content - // before the start of a new block we don't trim - if ( startsWithWS ) { - walker.currentNode = child; - while ( sibling = walker.previousPONode() ) { - nodeName = sibling.nodeName; - if ( nodeName === 'IMG' || - ( nodeName === '#text' && - notWS.test( sibling.data ) ) ) { - break; - } - if ( !isInline( sibling ) ) { - sibling = null; - break; - } - } - data = data.replace( /^[ \t\r\n]+/g, sibling ? ' ' : '' ); - } - if ( endsWithWS ) { - walker.currentNode = child; - while ( sibling = walker.nextNode() ) { - if ( nodeName === 'IMG' || - ( nodeName === '#text' && - notWS.test( sibling.data ) ) ) { - break; - } - if ( !isInline( sibling ) ) { - sibling = null; - break; - } - } - data = data.replace( /[ \t\r\n]+$/g, sibling ? ' ' : '' ); - } - if ( data ) { - child.data = data; - continue; - } - } - node.removeChild( child ); - i -= 1; - l -= 1; - } - } - return node; -}; - -// --- - -var removeEmptyInlines = function removeEmptyInlines ( node ) { - var children = node.childNodes, - l = children.length, - child; - while ( l-- ) { - child = children[l]; - if ( child.nodeType === ELEMENT_NODE && !isLeaf( child ) ) { - removeEmptyInlines( child ); - if ( isInline( child ) && !child.firstChild ) { - node.removeChild( child ); - } - } else if ( child.nodeType === TEXT_NODE && !child.data ) { - node.removeChild( child ); - } - } -}; - -// --- - -var notWSTextNode = function ( node ) { - return node.nodeType === ELEMENT_NODE ? - node.nodeName === 'BR' : - notWS.test( node.data ); -}; -var isLineBreak = function ( br, isLBIfEmptyBlock ) { - var block = br.parentNode; - var walker; - while ( isInline( block ) ) { - block = block.parentNode; - } - walker = new TreeWalker( - block, SHOW_ELEMENT|SHOW_TEXT, notWSTextNode ); - walker.currentNode = br; - return !!walker.nextNode() || - ( isLBIfEmptyBlock && !walker.previousNode() ); -}; - -//
    elements are treated specially, and differently depending on the -// browser, when in rich text editor mode. When adding HTML from external -// sources, we must remove them, replacing the ones that actually affect -// line breaks by wrapping the inline text in a
    . Browsers that want
    -// elements at the end of each block will then have them added back in a later -// fixCursor method call. -var cleanupBRs = function ( node, root, keepForBlankLine ) { - var brs = node.querySelectorAll( 'BR' ); - var brBreaksLine = []; - var l = brs.length; - var i, br, parent; - - // Must calculate whether the
    breaks a line first, because if we - // have two
    s next to each other, after the first one is converted - // to a block split, the second will be at the end of a block and - // therefore seem to not be a line break. But in its original context it - // was, so we should also convert it to a block split. - for ( i = 0; i < l; i += 1 ) { - brBreaksLine[i] = isLineBreak( brs[i], keepForBlankLine ); - } - while ( l-- ) { - br = brs[l]; - // Cleanup may have removed it - parent = br.parentNode; - if ( !parent ) { continue; } - // If it doesn't break a line, just remove it; it's not doing - // anything useful. We'll add it back later if required by the - // browser. If it breaks a line, wrap the content in div tags - // and replace the brs. - if ( !brBreaksLine[l] ) { - detach( br ); - } else if ( !isInline( parent ) ) { - fixContainer( parent, root ); - } - } -}; - -// The (non-standard but supported enough) innerText property is based on the -// render tree in Firefox and possibly other browsers, so we must insert the -// DOM node into the document to ensure the text part is correct. -var setClipboardData = function ( clipboardData, node, root ) { - var body = node.ownerDocument.body; - var html, text; - - // Firefox will add an extra new line for BRs at the end of block when - // calculating innerText, even though they don't actually affect display. - // So we need to remove them first. - cleanupBRs( node, root, true ); - - node.setAttribute( 'style', - 'position:fixed;overflow:hidden;bottom:100%;right:100%;' ); - body.appendChild( node ); - html = node.innerHTML; - text = node.innerText || node.textContent; - - // Firefox (and others?) returns unix line endings (\n) even on Windows. - // If on Windows, normalise to \r\n, since Notepad and some other crappy - // apps do not understand just \n. - if ( isWin ) { - text = text.replace( /\r?\n/g, '\r\n' ); - } - - clipboardData.setData( 'text/html', html ); - clipboardData.setData( 'text/plain', text ); - - body.removeChild( node ); -}; - -var onCut = function ( event ) { - var clipboardData = event.clipboardData; - var range = this.getSelection(); - var root = this._root; - var self = this; - var startBlock, endBlock, copyRoot, contents, parent, newContents, node; - - // Nothing to do - if ( range.collapsed ) { - event.preventDefault(); - return; - } - - // Save undo checkpoint - this.saveUndoState( range ); - - // Edge only seems to support setting plain text as of 2016-03-11. - // Mobile Safari flat out doesn't work: - // https://bugs.webkit.org/show_bug.cgi?id=143776 - if ( !isEdge && !isIOS && clipboardData ) { - // Clipboard content should include all parents within block, or all - // parents up to root if selection across blocks - startBlock = getStartBlockOfRange( range, root ); - endBlock = getEndBlockOfRange( range, root ); - copyRoot = ( ( startBlock === endBlock ) && startBlock ) || root; - // Extract the contents - contents = deleteContentsOfRange( range, root ); - // Add any other parents not in extracted content, up to copy root - parent = range.commonAncestorContainer; - if ( parent.nodeType === TEXT_NODE ) { - parent = parent.parentNode; - } - while ( parent && parent !== copyRoot ) { - newContents = parent.cloneNode( false ); - newContents.appendChild( contents ); - contents = newContents; - parent = parent.parentNode; - } - // Set clipboard data - node = this.createElement( 'div' ); - node.appendChild( contents ); - setClipboardData( clipboardData, node, root ); - event.preventDefault(); - } else { - setTimeout( function () { - try { - // If all content removed, ensure div at start of root. - self._ensureBottomLine(); - } catch ( error ) { - self.didError( error ); - } - }, 0 ); - } - - this.setSelection( range ); -}; - -var onCopy = function ( event ) { - var clipboardData = event.clipboardData; - var range = this.getSelection(); - var root = this._root; - var startBlock, endBlock, copyRoot, contents, parent, newContents, node; - - // Edge only seems to support setting plain text as of 2016-03-11. - // Mobile Safari flat out doesn't work: - // https://bugs.webkit.org/show_bug.cgi?id=143776 - if ( !isEdge && !isIOS && clipboardData ) { - // Clipboard content should include all parents within block, or all - // parents up to root if selection across blocks - startBlock = getStartBlockOfRange( range, root ); - endBlock = getEndBlockOfRange( range, root ); - copyRoot = ( ( startBlock === endBlock ) && startBlock ) || root; - // Clone range to mutate, then move up as high as possible without - // passing the copy root node. - range = range.cloneRange(); - moveRangeBoundariesDownTree( range ); - moveRangeBoundariesUpTree( range, copyRoot, copyRoot, root ); - // Extract the contents - contents = range.cloneContents(); - // Add any other parents not in extracted content, up to copy root - parent = range.commonAncestorContainer; - if ( parent.nodeType === TEXT_NODE ) { - parent = parent.parentNode; - } - while ( parent && parent !== copyRoot ) { - newContents = parent.cloneNode( false ); - newContents.appendChild( contents ); - contents = newContents; - parent = parent.parentNode; - } - // Set clipboard data - node = this.createElement( 'div' ); - node.appendChild( contents ); - setClipboardData( clipboardData, node, root ); - event.preventDefault(); - } -}; - -// Need to monitor for shift key like this, as event.shiftKey is not available -// in paste event. -function monitorShiftKey ( event ) { - this.isShiftDown = event.shiftKey; -} - -var onPaste = function ( event ) { - var clipboardData = event.clipboardData; - var items = clipboardData && clipboardData.items; - var choosePlain = this.isShiftDown; - var fireDrop = false; - var hasImage = false; - var plainItem = null; - var self = this; - var l, item, type, types, data; - - // Current HTML5 Clipboard interface - // --------------------------------- - // https://html.spec.whatwg.org/multipage/interaction.html - - // Edge only provides access to plain text as of 2016-03-11. - if ( !isEdge && items ) { - event.preventDefault(); - l = items.length; - while ( l-- ) { - item = items[l]; - type = item.type; - if ( !choosePlain && type === 'text/html' ) { - /*jshint loopfunc: true */ - item.getAsString( function ( html ) { - self.insertHTML( html, true ); - }); - /*jshint loopfunc: false */ - return; - } - if ( type === 'text/plain' ) { - plainItem = item; - } - if ( !choosePlain && /^image\/.*/.test( type ) ) { - hasImage = true; - } - } - // Treat image paste as a drop of an image file. - if ( hasImage ) { - this.fireEvent( 'dragover', { - dataTransfer: clipboardData, - /*jshint loopfunc: true */ - preventDefault: function () { - fireDrop = true; - } - /*jshint loopfunc: false */ - }); - if ( fireDrop ) { - this.fireEvent( 'drop', { - dataTransfer: clipboardData - }); - } - } else if ( plainItem ) { - plainItem.getAsString( function ( text ) { - self.insertPlainText( text, true ); - }); - } - return; - } - - // Old interface - // ------------- - - // Safari (and indeed many other OS X apps) copies stuff as text/rtf - // rather than text/html; even from a webpage in Safari. The only way - // to get an HTML version is to fallback to letting the browser insert - // the content. Same for getting image data. *Sigh*. - // - // Firefox is even worse: it doesn't even let you know that there might be - // an RTF version on the clipboard, but it will also convert to HTML if you - // let the browser insert the content. I've filed - // https://bugzilla.mozilla.org/show_bug.cgi?id=1254028 - types = clipboardData && clipboardData.types; - if ( !isEdge && types && ( - indexOf.call( types, 'text/html' ) > -1 || ( - !isGecko && - indexOf.call( types, 'text/plain' ) > -1 && - indexOf.call( types, 'text/rtf' ) < 0 ) - )) { - event.preventDefault(); - // Abiword on Linux copies a plain text and html version, but the HTML - // version is the empty string! So always try to get HTML, but if none, - // insert plain text instead. On iOS, Facebook (and possibly other - // apps?) copy links as type text/uri-list, but also insert a **blank** - // text/plain item onto the clipboard. Why? Who knows. - if ( !choosePlain && ( data = clipboardData.getData( 'text/html' ) ) ) { - this.insertHTML( data, true ); - } else if ( - ( data = clipboardData.getData( 'text/plain' ) ) || - ( data = clipboardData.getData( 'text/uri-list' ) ) ) { - this.insertPlainText( data, true ); - } - return; - } - - // No interface. Includes all versions of IE :( - // -------------------------------------------- - - this._awaitingPaste = true; - - var body = this._doc.body, - range = this.getSelection(), - startContainer = range.startContainer, - startOffset = range.startOffset, - endContainer = range.endContainer, - endOffset = range.endOffset; - - // We need to position the pasteArea in the visible portion of the screen - // to stop the browser auto-scrolling. - var pasteArea = this.createElement( 'DIV', { - contenteditable: 'true', - style: 'position:fixed; overflow:hidden; top:0; right:100%; width:1px; height:1px;' - }); - body.appendChild( pasteArea ); - range.selectNodeContents( pasteArea ); - this.setSelection( range ); - - // A setTimeout of 0 means this is added to the back of the - // single javascript thread, so it will be executed after the - // paste event. - setTimeout( function () { - try { - // IE sometimes fires the beforepaste event twice; make sure it is - // not run again before our after paste function is called. - self._awaitingPaste = false; - - // Get the pasted content and clean - var html = '', - next = pasteArea, - first, range; - - // #88: Chrome can apparently split the paste area if certain - // content is inserted; gather them all up. - while ( pasteArea = next ) { - next = pasteArea.nextSibling; - detach( pasteArea ); - // Safari and IE like putting extra divs around things. - first = pasteArea.firstChild; - if ( first && first === pasteArea.lastChild && - first.nodeName === 'DIV' ) { - pasteArea = first; - } - html += pasteArea.innerHTML; - } - - range = self._createRange( - startContainer, startOffset, endContainer, endOffset ); - self.setSelection( range ); - - if ( html ) { - self.insertHTML( html, true ); - } - } catch ( error ) { - self.didError( error ); - } - }, 0 ); -}; - -// On Windows you can drag an drop text. We can't handle this ourselves, because -// as far as I can see, there's no way to get the drop insertion point. So just -// save an undo state and hope for the best. -var onDrop = function ( event ) { - var types = event.dataTransfer.types; - var l = types.length; - var hasPlain = false; - var hasHTML = false; - while ( l-- ) { - switch ( types[l] ) { - case 'text/plain': - hasPlain = true; - break; - case 'text/html': - hasHTML = true; - break; - default: - return; - } - } - if ( hasHTML || hasPlain ) { - this.saveUndoState(); - } -}; - -function mergeObjects ( base, extras, mayOverride ) { - var prop, value; - if ( !base ) { - base = {}; - } - if ( extras ) { - for ( prop in extras ) { - if ( mayOverride || !( prop in base ) ) { - value = extras[ prop ]; - base[ prop ] = ( value && value.constructor === Object ) ? - mergeObjects( base[ prop ], value, mayOverride ) : - value; - } - } - } - return base; -} - -function Squire ( root, config ) { - if ( root.nodeType === DOCUMENT_NODE ) { - root = root.body; - } - var doc = root.ownerDocument; - var win = doc.defaultView; - var mutation; - - this._win = win; - this._doc = doc; - this._root = root; - - this._events = {}; - - this._isFocused = false; - this._lastSelection = null; - - // IE loses selection state of iframe on blur, so make sure we - // cache it just before it loses focus. - if ( losesSelectionOnBlur ) { - this.addEventListener( 'beforedeactivate', this.getSelection ); - } - - this._hasZWS = false; - - this._lastAnchorNode = null; - this._lastFocusNode = null; - this._path = ''; - this._willUpdatePath = false; - - if ( 'onselectionchange' in doc ) { - this.addEventListener( 'selectionchange', this._updatePathOnEvent ); - } else { - this.addEventListener( 'keyup', this._updatePathOnEvent ); - this.addEventListener( 'mouseup', this._updatePathOnEvent ); - } - - this._undoIndex = -1; - this._undoStack = []; - this._undoStackLength = 0; - this._isInUndoState = false; - this._ignoreChange = false; - this._ignoreAllChanges = false; - - if ( canObserveMutations ) { - mutation = new MutationObserver( this._docWasChanged.bind( this ) ); - mutation.observe( root, { - childList: true, - attributes: true, - characterData: true, - subtree: true - }); - this._mutation = mutation; - } else { - this.addEventListener( 'keyup', this._keyUpDetectChange ); - } - - // On blur, restore focus except if the user taps or clicks to focus a - // specific point. Can't actually use click event because focus happens - // before click, so use mousedown/touchstart - this._restoreSelection = false; - this.addEventListener( 'blur', enableRestoreSelection ); - this.addEventListener( 'mousedown', disableRestoreSelection ); - this.addEventListener( 'touchstart', disableRestoreSelection ); - this.addEventListener( 'focus', restoreSelection ); - - // IE sometimes fires the beforepaste event twice; make sure it is not run - // again before our after paste function is called. - this._awaitingPaste = false; - this.addEventListener( isIElt11 ? 'beforecut' : 'cut', onCut ); - this.addEventListener( 'copy', onCopy ); - this.addEventListener( 'keydown', monitorShiftKey ); - this.addEventListener( 'keyup', monitorShiftKey ); - this.addEventListener( isIElt11 ? 'beforepaste' : 'paste', onPaste ); - this.addEventListener( 'drop', onDrop ); - - // Opera does not fire keydown repeatedly. - this.addEventListener( isPresto ? 'keypress' : 'keydown', onKey ); - - // Add key handlers - this._keyHandlers = Object.create( keyHandlers ); - - // Override default properties - this.setConfig( config ); - - // Fix IE<10's buggy implementation of Text#splitText. - // If the split is at the end of the node, it doesn't insert the newly split - // node into the document, and sets its value to undefined rather than ''. - // And even if the split is not at the end, the original node is removed - // from the document and replaced by another, rather than just having its - // data shortened. - // We used to feature test for this, but then found the feature test would - // sometimes pass, but later on the buggy behaviour would still appear. - // I think IE10 does not have the same bug, but it doesn't hurt to replace - // its native fn too and then we don't need yet another UA category. - if ( isIElt11 ) { - win.Text.prototype.splitText = function ( offset ) { - var afterSplit = this.ownerDocument.createTextNode( - this.data.slice( offset ) ), - next = this.nextSibling, - parent = this.parentNode, - toDelete = this.length - offset; - if ( next ) { - parent.insertBefore( afterSplit, next ); - } else { - parent.appendChild( afterSplit ); - } - if ( toDelete ) { - this.deleteData( offset, toDelete ); - } - return afterSplit; - }; - } - - root.setAttribute( 'contenteditable', 'true' ); - - // Remove Firefox's built-in controls - try { - doc.execCommand( 'enableObjectResizing', false, 'false' ); - doc.execCommand( 'enableInlineTableEditing', false, 'false' ); - } catch ( error ) {} - - root.__squire__ = this; - - // Need to register instance before calling setHTML, so that the fixCursor - // function can lookup any default block tag options set. - this.setHTML( '' ); -} - -var proto = Squire.prototype; - -var sanitizeToDOMFragment = function ( html, isPaste, self ) { - var doc = self._doc; - var frag = html ? DOMPurify.sanitize( html, { - ALLOW_UNKNOWN_PROTOCOLS: true, - WHOLE_DOCUMENT: false, - RETURN_DOM: true, - RETURN_DOM_FRAGMENT: true - }) : null; - return frag ? doc.importNode( frag, true ) : doc.createDocumentFragment(); -}; - -proto.setConfig = function ( config ) { - config = mergeObjects({ - blockTag: 'DIV', - blockAttributes: null, - tagAttributes: { - blockquote: null, - ul: null, - ol: null, - li: null, - a: null - }, - leafNodeNames: leafNodeNames, - undo: { - documentSizeThreshold: -1, // -1 means no threshold - undoLimit: -1 // -1 means no limit - }, - isInsertedHTMLSanitized: true, - isSetHTMLSanitized: true, - sanitizeToDOMFragment: - typeof DOMPurify !== 'undefined' && DOMPurify.isSupported ? - sanitizeToDOMFragment : null - - }, config, true ); - - // Users may specify block tag in lower case - config.blockTag = config.blockTag.toUpperCase(); - - this._config = config; - - return this; -}; - -proto.createElement = function ( tag, props, children ) { - return createElement( this._doc, tag, props, children ); -}; - -proto.createDefaultBlock = function ( children ) { - var config = this._config; - return fixCursor( - this.createElement( config.blockTag, config.blockAttributes, children ), - this._root - ); -}; - -proto.didError = function ( error ) { - console.log( error ); -}; - -proto.getDocument = function () { - return this._doc; -}; -proto.getRoot = function () { - return this._root; -}; - -proto.modifyDocument = function ( modificationCallback ) { - var mutation = this._mutation; - if ( mutation ) { - if ( mutation.takeRecords().length ) { - this._docWasChanged(); - } - mutation.disconnect(); - } - - this._ignoreAllChanges = true; - modificationCallback(); - this._ignoreAllChanges = false; - - if ( mutation ) { - mutation.observe( this._root, { - childList: true, - attributes: true, - characterData: true, - subtree: true - }); - this._ignoreChange = false; - } -}; - -// --- Events --- - -// Subscribing to these events won't automatically add a listener to the -// document node, since these events are fired in a custom manner by the -// editor code. -var customEvents = { - pathChange: 1, select: 1, input: 1, undoStateChange: 1 -}; - -proto.fireEvent = function ( type, event ) { - var handlers = this._events[ type ]; - var isFocused, l, obj; - // UI code, especially modal views, may be monitoring for focus events and - // immediately removing focus. In certain conditions, this can cause the - // focus event to fire after the blur event, which can cause an infinite - // loop. So we detect whether we're actually focused/blurred before firing. - if ( /^(?:focus|blur)/.test( type ) ) { - isFocused = this._root === this._doc.activeElement; - if ( type === 'focus' ) { - if ( !isFocused || this._isFocused ) { - return this; - } - this._isFocused = true; - } else { - if ( isFocused || !this._isFocused ) { - return this; - } - this._isFocused = false; - } - } - if ( handlers ) { - if ( !event ) { - event = {}; - } - if ( event.type !== type ) { - event.type = type; - } - // Clone handlers array, so any handlers added/removed do not affect it. - handlers = handlers.slice(); - l = handlers.length; - while ( l-- ) { - obj = handlers[l]; - try { - if ( obj.handleEvent ) { - obj.handleEvent( event ); - } else { - obj.call( this, event ); - } - } catch ( error ) { - error.details = 'Squire: fireEvent error. Event type: ' + type; - this.didError( error ); - } - } - } - return this; -}; - -proto.destroy = function () { - var events = this._events; - var type; - - for ( type in events ) { - this.removeEventListener( type ); - } - if ( this._mutation ) { - this._mutation.disconnect(); - } - delete this._root.__squire__; - - // Destroy undo stack - this._undoIndex = -1; - this._undoStack = []; - this._undoStackLength = 0; -}; - -proto.handleEvent = function ( event ) { - this.fireEvent( event.type, event ); -}; - -proto.addEventListener = function ( type, fn ) { - var handlers = this._events[ type ]; - var target = this._root; - if ( !fn ) { - this.didError({ - name: 'Squire: addEventListener with null or undefined fn', - message: 'Event type: ' + type - }); - return this; - } - if ( !handlers ) { - handlers = this._events[ type ] = []; - if ( !customEvents[ type ] ) { - if ( type === 'selectionchange' ) { - target = this._doc; - } - target.addEventListener( type, this, true ); - } - } - handlers.push( fn ); - return this; -}; - -proto.removeEventListener = function ( type, fn ) { - var handlers = this._events[ type ]; - var target = this._root; - var l; - if ( handlers ) { - if ( fn ) { - l = handlers.length; - while ( l-- ) { - if ( handlers[l] === fn ) { - handlers.splice( l, 1 ); - } - } - } else { - handlers.length = 0; - } - if ( !handlers.length ) { - delete this._events[ type ]; - if ( !customEvents[ type ] ) { - if ( type === 'selectionchange' ) { - target = this._doc; - } - target.removeEventListener( type, this, true ); - } - } - } - return this; -}; - -// --- Selection and Path --- - -proto._createRange = - function ( range, startOffset, endContainer, endOffset ) { - if ( range instanceof this._win.Range ) { - return range.cloneRange(); - } - var domRange = this._doc.createRange(); - domRange.setStart( range, startOffset ); - if ( endContainer ) { - domRange.setEnd( endContainer, endOffset ); - } else { - domRange.setEnd( range, startOffset ); - } - return domRange; -}; - -proto.getCursorPosition = function ( range ) { - if ( ( !range && !( range = this.getSelection() ) ) || - !range.getBoundingClientRect ) { - return null; - } - // Get the bounding rect - var rect = range.getBoundingClientRect(); - var node, parent; - if ( rect && !rect.top ) { - this._ignoreChange = true; - node = this._doc.createElement( 'SPAN' ); - node.textContent = ZWS; - insertNodeInRange( range, node ); - rect = node.getBoundingClientRect(); - parent = node.parentNode; - parent.removeChild( node ); - mergeInlines( parent, range ); - } - return rect; -}; - -proto._moveCursorTo = function ( toStart ) { - var root = this._root, - range = this._createRange( root, toStart ? 0 : root.childNodes.length ); - moveRangeBoundariesDownTree( range ); - this.setSelection( range ); - return this; -}; -proto.moveCursorToStart = function () { - return this._moveCursorTo( true ); -}; -proto.moveCursorToEnd = function () { - return this._moveCursorTo( false ); -}; - -var getWindowSelection = function ( self ) { - return self._win.getSelection() || null; -}; - -proto.setSelection = function ( range ) { - if ( range ) { - this._lastSelection = range; - // If we're setting selection, that automatically, and synchronously, // triggers a focus event. So just store the selection and mark it as - // needing restore on focus. - if ( !this._isFocused ) { - enableRestoreSelection.call( this ); - } else if ( isAndroid && !this._restoreSelection ) { - // Android closes the keyboard on removeAllRanges() and doesn't - // open it again when addRange() is called, sigh. - // Since Android doesn't trigger a focus event in setSelection(), - // use a blur/focus dance to work around this by letting the - // selection be restored on focus. - // Need to check for !this._restoreSelection to avoid infinite loop - enableRestoreSelection.call( this ); - this.blur(); - this.focus(); - } else { - // iOS bug: if you don't focus the iframe before setting the - // selection, you can end up in a state where you type but the input - // doesn't get directed into the contenteditable area but is instead - // lost in a black hole. Very strange. - if ( isIOS ) { - this._win.focus(); - } - var sel = getWindowSelection( this ); - if ( sel ) { - sel.removeAllRanges(); - sel.addRange( range ); - } - } - } - return this; -}; - -proto.getSelection = function () { - var sel = getWindowSelection( this ); - var root = this._root; - var selection, startContainer, endContainer, node; - // If not focused, always rely on cached selection; another function may - // have set it but the DOM is not modified until focus again - if ( this._isFocused && sel && sel.rangeCount ) { - selection = sel.getRangeAt( 0 ).cloneRange(); - startContainer = selection.startContainer; - endContainer = selection.endContainer; - // FF can return the selection as being inside an . WTF? - if ( startContainer && isLeaf( startContainer ) ) { - selection.setStartBefore( startContainer ); - } - if ( endContainer && isLeaf( endContainer ) ) { - selection.setEndBefore( endContainer ); - } - } - if ( selection && - isOrContains( root, selection.commonAncestorContainer ) ) { - this._lastSelection = selection; - } else { - selection = this._lastSelection; - node = selection.commonAncestorContainer; - // Check the editor is in the live document; if not, the range has - // probably been rewritten by the browser and is bogus - if ( !isOrContains( node.ownerDocument, node ) ) { - selection = null; - } - } - if ( !selection ) { - selection = this._createRange( root.firstChild, 0 ); - } - return selection; -}; - -function enableRestoreSelection () { - this._restoreSelection = true; -} -function disableRestoreSelection () { - this._restoreSelection = false; -} -function restoreSelection () { - if ( this._restoreSelection ) { - this.setSelection( this._lastSelection ); - } -} - -proto.getSelectedText = function () { - var range = this.getSelection(); - if ( !range || range.collapsed ) { - return ''; - } - var walker = new TreeWalker( - range.commonAncestorContainer, - SHOW_TEXT|SHOW_ELEMENT, - function ( node ) { - return isNodeContainedInRange( range, node, true ); - } - ); - var startContainer = range.startContainer; - var endContainer = range.endContainer; - var node = walker.currentNode = startContainer; - var textContent = ''; - var addedTextInBlock = false; - var value; - - if ( !walker.filter( node ) ) { - node = walker.nextNode(); - } - - while ( node ) { - if ( node.nodeType === TEXT_NODE ) { - value = node.data; - if ( value && ( /\S/.test( value ) ) ) { - if ( node === endContainer ) { - value = value.slice( 0, range.endOffset ); - } - if ( node === startContainer ) { - value = value.slice( range.startOffset ); - } - textContent += value; - addedTextInBlock = true; - } - } else if ( node.nodeName === 'BR' || - addedTextInBlock && !isInline( node ) ) { - textContent += '\n'; - addedTextInBlock = false; - } - node = walker.nextNode(); - } - - return textContent; -}; - -proto.getPath = function () { - return this._path; -}; - -// --- Workaround for browsers that can't focus empty text nodes --- - -// WebKit bug: https://bugs.webkit.org/show_bug.cgi?id=15256 - -// Walk down the tree starting at the root and remove any ZWS. If the node only -// contained ZWS space then remove it too. We may want to keep one ZWS node at -// the bottom of the tree so the block can be selected. Define that node as the -// keepNode. -var removeZWS = function ( root, keepNode ) { - var walker = new TreeWalker( root, SHOW_TEXT, function () { - return true; - }, false ), - parent, node, index; - while ( node = walker.nextNode() ) { - while ( ( index = node.data.indexOf( ZWS ) ) > -1 && - ( !keepNode || node.parentNode !== keepNode ) ) { - if ( node.length === 1 ) { - do { - parent = node.parentNode; - parent.removeChild( node ); - node = parent; - walker.currentNode = parent; - } while ( isInline( node ) && !getLength( node ) ); - break; - } else { - node.deleteData( index, 1 ); - } - } - } -}; - -proto._didAddZWS = function () { - this._hasZWS = true; -}; -proto._removeZWS = function () { - if ( !this._hasZWS ) { - return; - } - removeZWS( this._root ); - this._hasZWS = false; -}; - -// --- Path change events --- - -proto._updatePath = function ( range, force ) { - if ( !range ) { - return; - } - var anchor = range.startContainer, - focus = range.endContainer, - newPath; - if ( force || anchor !== this._lastAnchorNode || - focus !== this._lastFocusNode ) { - this._lastAnchorNode = anchor; - this._lastFocusNode = focus; - newPath = ( anchor && focus ) ? ( anchor === focus ) ? - getPath( focus, this._root ) : '(selection)' : ''; - if ( this._path !== newPath ) { - this._path = newPath; - this.fireEvent( 'pathChange', { path: newPath } ); - } - } - this.fireEvent( range.collapsed ? 'cursor' : 'select', { - range: range - }); -}; - -// selectionchange is fired synchronously in IE when removing current selection -// and when setting new selection; keyup/mouseup may have processing we want -// to do first. Either way, send to next event loop. -proto._updatePathOnEvent = function ( event ) { - var self = this; - if ( self._isFocused && !self._willUpdatePath ) { - self._willUpdatePath = true; - setTimeout( function () { - self._willUpdatePath = false; - self._updatePath( self.getSelection() ); - }, 0 ); - } -}; - -// --- Focus --- - -proto.focus = function () { - this._root.focus(); - - if ( isIE ) { - this.fireEvent( 'focus' ); - } - - return this; -}; - -proto.blur = function () { - this._root.blur(); - - if ( isIE ) { - this.fireEvent( 'blur' ); - } - - return this; -}; - -// --- Bookmarking --- - -var startSelectionId = 'squire-selection-start'; -var endSelectionId = 'squire-selection-end'; - -proto._saveRangeToBookmark = function ( range ) { - var startNode = this.createElement( 'INPUT', { - id: startSelectionId, - type: 'hidden' - }), - endNode = this.createElement( 'INPUT', { - id: endSelectionId, - type: 'hidden' - }), - temp; - - insertNodeInRange( range, startNode ); - range.collapse( false ); - insertNodeInRange( range, endNode ); - - // In a collapsed range, the start is sometimes inserted after the end! - if ( startNode.compareDocumentPosition( endNode ) & - DOCUMENT_POSITION_PRECEDING ) { - startNode.id = endSelectionId; - endNode.id = startSelectionId; - temp = startNode; - startNode = endNode; - endNode = temp; - } - - range.setStartAfter( startNode ); - range.setEndBefore( endNode ); -}; - -proto._getRangeAndRemoveBookmark = function ( range ) { - var root = this._root, - start = root.querySelector( '#' + startSelectionId ), - end = root.querySelector( '#' + endSelectionId ); - - if ( start && end ) { - var startContainer = start.parentNode, - endContainer = end.parentNode, - startOffset = indexOf.call( startContainer.childNodes, start ), - endOffset = indexOf.call( endContainer.childNodes, end ); - - if ( startContainer === endContainer ) { - endOffset -= 1; - } - - detach( start ); - detach( end ); - - if ( !range ) { - range = this._doc.createRange(); - } - range.setStart( startContainer, startOffset ); - range.setEnd( endContainer, endOffset ); - - // Merge any text nodes we split - mergeInlines( startContainer, range ); - if ( startContainer !== endContainer ) { - mergeInlines( endContainer, range ); - } - - // If we didn't split a text node, we should move into any adjacent - // text node to current selection point - if ( range.collapsed ) { - startContainer = range.startContainer; - if ( startContainer.nodeType === TEXT_NODE ) { - endContainer = startContainer.childNodes[ range.startOffset ]; - if ( !endContainer || endContainer.nodeType !== TEXT_NODE ) { - endContainer = - startContainer.childNodes[ range.startOffset - 1 ]; - } - if ( endContainer && endContainer.nodeType === TEXT_NODE ) { - range.setStart( endContainer, 0 ); - range.collapse( true ); - } - } - } - } - return range || null; -}; - -// --- Undo --- - -proto._keyUpDetectChange = function ( event ) { - var code = event.keyCode; - // Presume document was changed if: - // 1. A modifier key (other than shift) wasn't held down - // 2. The key pressed is not in range 16<=x<=20 (control keys) - // 3. The key pressed is not in range 33<=x<=45 (navigation keys) - if ( !event.ctrlKey && !event.metaKey && !event.altKey && - ( code < 16 || code > 20 ) && - ( code < 33 || code > 45 ) ) { - this._docWasChanged(); - } -}; - -proto._docWasChanged = function () { - if ( canWeakMap ) { - nodeCategoryCache = new WeakMap(); - } - if ( this._ignoreAllChanges ) { - return; - } - - if ( canObserveMutations && this._ignoreChange ) { - this._ignoreChange = false; - return; - } - if ( this._isInUndoState ) { - this._isInUndoState = false; - this.fireEvent( 'undoStateChange', { - canUndo: true, - canRedo: false - }); - } - this.fireEvent( 'input' ); -}; - -// Leaves bookmark -proto._recordUndoState = function ( range, replace ) { - // Don't record if we're already in an undo state - if ( !this._isInUndoState|| replace ) { - // Advance pointer to new position - var undoIndex = this._undoIndex; - var undoStack = this._undoStack; - var undoConfig = this._config.undo; - var undoThreshold = undoConfig.documentSizeThreshold; - var undoLimit = undoConfig.undoLimit; - var html; - - if ( !replace ) { - undoIndex += 1; - } - - // Truncate stack if longer (i.e. if has been previously undone) - if ( undoIndex < this._undoStackLength ) { - undoStack.length = this._undoStackLength = undoIndex; - } - - // Get data - if ( range ) { - this._saveRangeToBookmark( range ); - } - html = this._getHTML(); - - // If this document is above the configured size threshold, - // limit the number of saved undo states. - // Threshold is in bytes, JS uses 2 bytes per character - if ( undoThreshold > -1 && html.length * 2 > undoThreshold ) { - if ( undoLimit > -1 && undoIndex > undoLimit ) { - undoStack.splice( 0, undoIndex - undoLimit ); - undoIndex = undoLimit; - this._undoStackLength = undoLimit; - } - } - - // Save data - undoStack[ undoIndex ] = html; - this._undoIndex = undoIndex; - this._undoStackLength += 1; - this._isInUndoState = true; - } -}; - -proto.saveUndoState = function ( range ) { - if ( range === undefined ) { - range = this.getSelection(); - } - this._recordUndoState( range, this._isInUndoState ); - this._getRangeAndRemoveBookmark( range ); - - return this; -}; - -proto.undo = function () { - // Sanity check: must not be at beginning of the history stack - if ( this._undoIndex !== 0 || !this._isInUndoState ) { - // Make sure any changes since last checkpoint are saved. - this._recordUndoState( this.getSelection(), false ); - - this._undoIndex -= 1; - this._setHTML( this._undoStack[ this._undoIndex ] ); - var range = this._getRangeAndRemoveBookmark(); - if ( range ) { - this.setSelection( range ); - } - this._isInUndoState = true; - this.fireEvent( 'undoStateChange', { - canUndo: this._undoIndex !== 0, - canRedo: true - }); - this.fireEvent( 'input' ); - } - return this; -}; - -proto.redo = function () { - // Sanity check: must not be at end of stack and must be in an undo - // state. - var undoIndex = this._undoIndex, - undoStackLength = this._undoStackLength; - if ( undoIndex + 1 < undoStackLength && this._isInUndoState ) { - this._undoIndex += 1; - this._setHTML( this._undoStack[ this._undoIndex ] ); - var range = this._getRangeAndRemoveBookmark(); - if ( range ) { - this.setSelection( range ); - } - this.fireEvent( 'undoStateChange', { - canUndo: true, - canRedo: undoIndex + 2 < undoStackLength - }); - this.fireEvent( 'input' ); - } - return this; -}; - -// --- Inline formatting --- - -// Looks for matching tag and attributes, so won't work -// if instead of etc. -proto.hasFormat = function ( tag, attributes, range ) { - // 1. Normalise the arguments and get selection - tag = tag.toUpperCase(); - if ( !attributes ) { attributes = {}; } - if ( !range && !( range = this.getSelection() ) ) { - return false; - } - - // Sanitize range to prevent weird IE artifacts - if ( !range.collapsed && - range.startContainer.nodeType === TEXT_NODE && - range.startOffset === range.startContainer.length && - range.startContainer.nextSibling ) { - range.setStartBefore( range.startContainer.nextSibling ); - } - if ( !range.collapsed && - range.endContainer.nodeType === TEXT_NODE && - range.endOffset === 0 && - range.endContainer.previousSibling ) { - range.setEndAfter( range.endContainer.previousSibling ); - } - - // If the common ancestor is inside the tag we require, we definitely - // have the format. - var root = this._root; - var common = range.commonAncestorContainer; - var walker, node; - if ( getNearest( common, root, tag, attributes ) ) { - return true; - } - - // If common ancestor is a text node and doesn't have the format, we - // definitely don't have it. - if ( common.nodeType === TEXT_NODE ) { - return false; - } - - // Otherwise, check each text node at least partially contained within - // the selection and make sure all of them have the format we want. - walker = new TreeWalker( common, SHOW_TEXT, function ( node ) { - return isNodeContainedInRange( range, node, true ); - }, false ); - - var seenNode = false; - while ( node = walker.nextNode() ) { - if ( !getNearest( node, root, tag, attributes ) ) { - return false; - } - seenNode = true; - } - - return seenNode; -}; - -// Extracts the font-family and font-size (if any) of the element -// holding the cursor. If there's a selection, returns an empty object. -proto.getFontInfo = function ( range ) { - var fontInfo = { - color: undefined, - backgroundColor: undefined, - family: undefined, - size: undefined - }; - var seenAttributes = 0; - var element, style, attr; - - if ( !range && !( range = this.getSelection() ) ) { - return fontInfo; - } - - element = range.commonAncestorContainer; - if ( range.collapsed || element.nodeType === TEXT_NODE ) { - if ( element.nodeType === TEXT_NODE ) { - element = element.parentNode; - } - while ( seenAttributes < 4 && element ) { - if ( style = element.style ) { - if ( !fontInfo.color && ( attr = style.color ) ) { - fontInfo.color = attr; - seenAttributes += 1; - } - if ( !fontInfo.backgroundColor && - ( attr = style.backgroundColor ) ) { - fontInfo.backgroundColor = attr; - seenAttributes += 1; - } - if ( !fontInfo.family && ( attr = style.fontFamily ) ) { - fontInfo.family = attr; - seenAttributes += 1; - } - if ( !fontInfo.size && ( attr = style.fontSize ) ) { - fontInfo.size = attr; - seenAttributes += 1; - } - } - element = element.parentNode; - } - } - return fontInfo; -}; - -proto._addFormat = function ( tag, attributes, range ) { - // If the range is collapsed we simply insert the node by wrapping - // it round the range and focus it. - var root = this._root; - var el, walker, startContainer, endContainer, startOffset, endOffset, - node, needsFormat, block; - - if ( range.collapsed ) { - el = fixCursor( this.createElement( tag, attributes ), root ); - insertNodeInRange( range, el ); - range.setStart( el.firstChild, el.firstChild.length ); - range.collapse( true ); - - // Clean up any previous formats that may have been set on this block - // that are unused. - block = el; - while ( isInline( block ) ) { - block = block.parentNode; - } - removeZWS( block, el ); - } - // Otherwise we find all the textnodes in the range (splitting - // partially selected nodes) and if they're not already formatted - // correctly we wrap them in the appropriate tag. - else { - // Create an iterator to walk over all the text nodes under this - // ancestor which are in the range and not already formatted - // correctly. - // - // In Blink/WebKit, empty blocks may have no text nodes, just a
    . - // Therefore we wrap this in the tag as well, as this will then cause it - // to apply when the user types something in the block, which is - // presumably what was intended. - // - // IMG tags are included because we may want to create a link around - // them, and adding other styles is harmless. - walker = new TreeWalker( - range.commonAncestorContainer, - SHOW_TEXT|SHOW_ELEMENT, - function ( node ) { - return ( node.nodeType === TEXT_NODE || - node.nodeName === 'BR' || - node.nodeName === 'IMG' - ) && isNodeContainedInRange( range, node, true ); - }, - false - ); - - // Start at the beginning node of the range and iterate through - // all the nodes in the range that need formatting. - startContainer = range.startContainer; - startOffset = range.startOffset; - endContainer = range.endContainer; - endOffset = range.endOffset; - - // Make sure we start with a valid node. - walker.currentNode = startContainer; - if ( !walker.filter( startContainer ) ) { - startContainer = walker.nextNode(); - startOffset = 0; - } - - // If there are no interesting nodes in the selection, abort - if ( !startContainer ) { - return range; - } - - do { - node = walker.currentNode; - needsFormat = !getNearest( node, root, tag, attributes ); - if ( needsFormat ) { - //
    can never be a container node, so must have a text node - // if node == (end|start)Container - if ( node === endContainer && node.length > endOffset ) { - node.splitText( endOffset ); - } - if ( node === startContainer && startOffset ) { - node = node.splitText( startOffset ); - if ( endContainer === startContainer ) { - endContainer = node; - endOffset -= startOffset; - } - startContainer = node; - startOffset = 0; - } - el = this.createElement( tag, attributes ); - replaceWith( node, el ); - el.appendChild( node ); - } - } while ( walker.nextNode() ); - - // If we don't finish inside a text node, offset may have changed. - if ( endContainer.nodeType !== TEXT_NODE ) { - if ( node.nodeType === TEXT_NODE ) { - endContainer = node; - endOffset = node.length; - } else { - // If
    , we must have just wrapped it, so it must have only - // one child - endContainer = node.parentNode; - endOffset = 1; - } - } - - // Now set the selection to as it was before - range = this._createRange( - startContainer, startOffset, endContainer, endOffset ); - } - return range; -}; - -proto._removeFormat = function ( tag, attributes, range, partial ) { - // Add bookmark - this._saveRangeToBookmark( range ); - - // We need a node in the selection to break the surrounding - // formatted text. - var doc = this._doc, - fixer; - if ( range.collapsed ) { - if ( cantFocusEmptyTextNodes ) { - fixer = doc.createTextNode( ZWS ); - this._didAddZWS(); - } else { - fixer = doc.createTextNode( '' ); - } - insertNodeInRange( range, fixer ); - } - - // Find block-level ancestor of selection - var root = range.commonAncestorContainer; - while ( isInline( root ) ) { - root = root.parentNode; - } - - // Find text nodes inside formatTags that are not in selection and - // add an extra tag with the same formatting. - var startContainer = range.startContainer, - startOffset = range.startOffset, - endContainer = range.endContainer, - endOffset = range.endOffset, - toWrap = [], - examineNode = function ( node, exemplar ) { - // If the node is completely contained by the range then - // we're going to remove all formatting so ignore it. - if ( isNodeContainedInRange( range, node, false ) ) { - return; - } - - var isText = ( node.nodeType === TEXT_NODE ), - child, next; - - // If not at least partially contained, wrap entire contents - // in a clone of the tag we're removing and we're done. - if ( !isNodeContainedInRange( range, node, true ) ) { - // Ignore bookmarks and empty text nodes - if ( node.nodeName !== 'INPUT' && - ( !isText || node.data ) ) { - toWrap.push([ exemplar, node ]); - } - return; - } - - // Split any partially selected text nodes. - if ( isText ) { - if ( node === endContainer && endOffset !== node.length ) { - toWrap.push([ exemplar, node.splitText( endOffset ) ]); - } - if ( node === startContainer && startOffset ) { - node.splitText( startOffset ); - toWrap.push([ exemplar, node ]); - } - } - // If not a text node, recurse onto all children. - // Beware, the tree may be rewritten with each call - // to examineNode, hence find the next sibling first. - else { - for ( child = node.firstChild; child; child = next ) { - next = child.nextSibling; - examineNode( child, exemplar ); - } - } - }, - formatTags = Array.prototype.filter.call( - root.getElementsByTagName( tag ), function ( el ) { - return isNodeContainedInRange( range, el, true ) && - hasTagAttributes( el, tag, attributes ); - } - ); - - if ( !partial ) { - formatTags.forEach( function ( node ) { - examineNode( node, node ); - }); - } - - // Now wrap unselected nodes in the tag - toWrap.forEach( function ( item ) { - // [ exemplar, node ] tuple - var el = item[0].cloneNode( false ), - node = item[1]; - replaceWith( node, el ); - el.appendChild( node ); - }); - // and remove old formatting tags. - formatTags.forEach( function ( el ) { - replaceWith( el, empty( el ) ); - }); - - // Merge adjacent inlines: - this._getRangeAndRemoveBookmark( range ); - if ( fixer ) { - range.collapse( false ); - } - mergeInlines( root, range ); - - return range; -}; - -proto.changeFormat = function ( add, remove, range, partial ) { - // Normalise the arguments and get selection - if ( !range && !( range = this.getSelection() ) ) { - return this; - } - - // Save undo checkpoint - this.saveUndoState( range ); - - if ( remove ) { - range = this._removeFormat( remove.tag.toUpperCase(), - remove.attributes || {}, range, partial ); - } - if ( add ) { - range = this._addFormat( add.tag.toUpperCase(), - add.attributes || {}, range ); - } - - this.setSelection( range ); - this._updatePath( range, true ); - - // We're not still in an undo state - if ( !canObserveMutations ) { - this._docWasChanged(); - } - - return this; -}; - -// --- Block formatting --- - -var tagAfterSplit = { - DT: 'DD', - DD: 'DT', - LI: 'LI', - PRE: 'PRE' -}; - -var splitBlock = function ( self, block, node, offset ) { - var splitTag = tagAfterSplit[ block.nodeName ], - splitProperties = null, - nodeAfterSplit = split( node, offset, block.parentNode, self._root ), - config = self._config; - - if ( !splitTag ) { - splitTag = config.blockTag; - splitProperties = config.blockAttributes; - } - - // Make sure the new node is the correct type. - if ( !hasTagAttributes( nodeAfterSplit, splitTag, splitProperties ) ) { - block = createElement( nodeAfterSplit.ownerDocument, - splitTag, splitProperties ); - if ( nodeAfterSplit.dir ) { - block.dir = nodeAfterSplit.dir; - } - replaceWith( nodeAfterSplit, block ); - block.appendChild( empty( nodeAfterSplit ) ); - nodeAfterSplit = block; - } - return nodeAfterSplit; -}; - -proto.forEachBlock = function ( fn, mutates, range ) { - if ( !range && !( range = this.getSelection() ) ) { - return this; - } - - // Save undo checkpoint - if ( mutates ) { - this.saveUndoState( range ); - } - - var root = this._root; - var start = getStartBlockOfRange( range, root ); - var end = getEndBlockOfRange( range, root ); - if ( start && end ) { - do { - if ( fn( start ) || start === end ) { break; } - } while ( start = getNextBlock( start, root ) ); - } - - if ( mutates ) { - this.setSelection( range ); - - // Path may have changed - this._updatePath( range, true ); - - // We're not still in an undo state - if ( !canObserveMutations ) { - this._docWasChanged(); - } - } - return this; -}; - -proto.modifyBlocks = function ( modify, range ) { - if ( !range && !( range = this.getSelection() ) ) { - return this; - } - - // 1. Save undo checkpoint and bookmark selection - this._recordUndoState( range, this._isInUndoState ); - - var root = this._root; - var frag; - - // 2. Expand range to block boundaries - expandRangeToBlockBoundaries( range, root ); - - // 3. Remove range. - moveRangeBoundariesUpTree( range, root, root, root ); - frag = extractContentsOfRange( range, root, root ); - - // 4. Modify tree of fragment and reinsert. - insertNodeInRange( range, modify.call( this, frag ) ); - - // 5. Merge containers at edges - if ( range.endOffset < range.endContainer.childNodes.length ) { - mergeContainers( range.endContainer.childNodes[ range.endOffset ], root ); - } - mergeContainers( range.startContainer.childNodes[ range.startOffset ], root ); - - // 6. Restore selection - this._getRangeAndRemoveBookmark( range ); - this.setSelection( range ); - this._updatePath( range, true ); - - // 7. We're not still in an undo state - if ( !canObserveMutations ) { - this._docWasChanged(); - } - - return this; -}; - -var increaseBlockQuoteLevel = function ( frag ) { - return this.createElement( 'BLOCKQUOTE', - this._config.tagAttributes.blockquote, [ - frag - ]); -}; - -var decreaseBlockQuoteLevel = function ( frag ) { - var root = this._root; - var blockquotes = frag.querySelectorAll( 'blockquote' ); - Array.prototype.filter.call( blockquotes, function ( el ) { - return !getNearest( el.parentNode, root, 'BLOCKQUOTE' ); - }).forEach( function ( el ) { - replaceWith( el, empty( el ) ); - }); - return frag; -}; - -var removeBlockQuote = function (/* frag */) { - return this.createDefaultBlock([ - this.createElement( 'INPUT', { - id: startSelectionId, - type: 'hidden' - }), - this.createElement( 'INPUT', { - id: endSelectionId, - type: 'hidden' - }) - ]); -}; - -var makeList = function ( self, frag, type ) { - var walker = getBlockWalker( frag, self._root ), - node, tag, prev, newLi, - tagAttributes = self._config.tagAttributes, - listAttrs = tagAttributes[ type.toLowerCase() ], - listItemAttrs = tagAttributes.li; - - while ( node = walker.nextNode() ) { - if ( node.parentNode.nodeName === 'LI' ) { - node = node.parentNode; - walker.currentNode = node.lastChild; - } - if ( node.nodeName !== 'LI' ) { - newLi = self.createElement( 'LI', listItemAttrs ); - if ( node.dir ) { - newLi.dir = node.dir; - } - - // Have we replaced the previous block with a new
      /
        ? - if ( ( prev = node.previousSibling ) && prev.nodeName === type ) { - prev.appendChild( newLi ); - detach( node ); - } - // Otherwise, replace this block with the
          /
            - else { - replaceWith( - node, - self.createElement( type, listAttrs, [ - newLi - ]) - ); - } - newLi.appendChild( empty( node ) ); - walker.currentNode = newLi; - } else { - node = node.parentNode; - tag = node.nodeName; - if ( tag !== type && ( /^[OU]L$/.test( tag ) ) ) { - replaceWith( node, - self.createElement( type, listAttrs, [ empty( node ) ] ) - ); - } - } - } -}; - -var makeUnorderedList = function ( frag ) { - makeList( this, frag, 'UL' ); - return frag; -}; - -var makeOrderedList = function ( frag ) { - makeList( this, frag, 'OL' ); - return frag; -}; - -var removeList = function ( frag ) { - var lists = frag.querySelectorAll( 'UL, OL' ), - items = frag.querySelectorAll( 'LI' ), - root = this._root, - i, l, list, listFrag, item; - for ( i = 0, l = lists.length; i < l; i += 1 ) { - list = lists[i]; - listFrag = empty( list ); - fixContainer( listFrag, root ); - replaceWith( list, listFrag ); - } - - for ( i = 0, l = items.length; i < l; i += 1 ) { - item = items[i]; - if ( isBlock( item ) ) { - replaceWith( item, - this.createDefaultBlock([ empty( item ) ]) - ); - } else { - fixContainer( item, root ); - replaceWith( item, empty( item ) ); - } - } - return frag; -}; - -var getListSelection = function ( range, root ) { - // Get start+end li in single common ancestor - var list = range.commonAncestorContainer; - var startLi = range.startContainer; - var endLi = range.endContainer; - while ( list && list !== root && !/^[OU]L$/.test( list.nodeName ) ) { - list = list.parentNode; - } - if ( !list || list === root ) { - return null; - } - if ( startLi === list ) { - startLi = startLi.childNodes[ range.startOffset ]; - } - if ( endLi === list ) { - endLi = endLi.childNodes[ range.endOffset ]; - } - while ( startLi && startLi.parentNode !== list ) { - startLi = startLi.parentNode; - } - while ( endLi && endLi.parentNode !== list ) { - endLi = endLi.parentNode; - } - return [ list, startLi, endLi ]; -}; - -proto.increaseListLevel = function ( range ) { - if ( !range && !( range = this.getSelection() ) ) { - return this.focus(); - } - - var root = this._root; - var listSelection = getListSelection( range, root ); - if ( !listSelection ) { - return this.focus(); - } - - var list = listSelection[0]; - var startLi = listSelection[1]; - var endLi = listSelection[2]; - if ( !startLi || startLi === list.firstChild ) { - return this.focus(); - } - - // Save undo checkpoint and bookmark selection - this._recordUndoState( range, this._isInUndoState ); - - // Increase list depth - var type = list.nodeName; - var newParent = startLi.previousSibling; - var listAttrs, next; - if ( newParent.nodeName !== type ) { - listAttrs = this._config.tagAttributes[ type.toLowerCase() ]; - newParent = this.createElement( type, listAttrs ); - list.insertBefore( newParent, startLi ); - } - do { - next = startLi === endLi ? null : startLi.nextSibling; - newParent.appendChild( startLi ); - } while ( ( startLi = next ) ); - next = newParent.nextSibling; - if ( next ) { - mergeContainers( next, root ); - } - - // Restore selection - this._getRangeAndRemoveBookmark( range ); - this.setSelection( range ); - this._updatePath( range, true ); - - // We're not still in an undo state - if ( !canObserveMutations ) { - this._docWasChanged(); - } - - return this.focus(); -}; - -proto.decreaseListLevel = function ( range ) { - if ( !range && !( range = this.getSelection() ) ) { - return this.focus(); - } - - var root = this._root; - var listSelection = getListSelection( range, root ); - if ( !listSelection ) { - return this.focus(); - } - - var list = listSelection[0]; - var startLi = listSelection[1]; - var endLi = listSelection[2]; - if ( !startLi ) { - startLi = list.firstChild; - } - if ( !endLi ) { - endLi = list.lastChild; - } - - // Save undo checkpoint and bookmark selection - this._recordUndoState( range, this._isInUndoState ); - - // Find the new parent list node - var newParent = list.parentNode; - var next; - - // Split list if necesary - var insertBefore = !endLi.nextSibling ? - list.nextSibling : - split( list, endLi.nextSibling, newParent, root ); - - if ( newParent !== root && newParent.nodeName === 'LI' ) { - newParent = newParent.parentNode; - while ( insertBefore ) { - next = insertBefore.nextSibling; - endLi.appendChild( insertBefore ); - insertBefore = next; - } - insertBefore = list.parentNode.nextSibling; - } - - var makeNotList = !/^[OU]L$/.test( newParent.nodeName ); - do { - next = startLi === endLi ? null : startLi.nextSibling; - list.removeChild( startLi ); - if ( makeNotList && startLi.nodeName === 'LI' ) { - startLi = this.createDefaultBlock([ empty( startLi ) ]); - } - newParent.insertBefore( startLi, insertBefore ); - } while ( ( startLi = next ) ); - - if ( !list.firstChild ) { - detach( list ); - } - - if ( insertBefore ) { - mergeContainers( insertBefore, root ); - } - - // Restore selection - this._getRangeAndRemoveBookmark( range ); - this.setSelection( range ); - this._updatePath( range, true ); - - // We're not still in an undo state - if ( !canObserveMutations ) { - this._docWasChanged(); - } - - return this.focus(); -}; - -proto._ensureBottomLine = function () { - var root = this._root; - var last = root.lastElementChild; - if ( !last || - last.nodeName !== this._config.blockTag || !isBlock( last ) ) { - root.appendChild( this.createDefaultBlock() ); - } -}; - -// --- Keyboard interaction --- - -proto.setKeyHandler = function ( key, fn ) { - this._keyHandlers[ key ] = fn; - return this; -}; - -// --- Get/Set data --- - -proto._getHTML = function () { - return this._root.innerHTML; -}; - -proto._setHTML = function ( html ) { - var root = this._root; - var node = root; - node.innerHTML = html; - do { - fixCursor( node, root ); - } while ( node = getNextBlock( node, root ) ); - this._ignoreChange = true; -}; - -proto.getHTML = function ( withBookMark ) { - var brs = [], - root, node, fixer, html, l, range; - if ( withBookMark && ( range = this.getSelection() ) ) { - this._saveRangeToBookmark( range ); - } - if ( useTextFixer ) { - root = this._root; - node = root; - while ( node = getNextBlock( node, root ) ) { - if ( !node.textContent && !node.querySelector( 'BR' ) ) { - fixer = this.createElement( 'BR' ); - node.appendChild( fixer ); - brs.push( fixer ); - } - } - } - html = this._getHTML().replace( /\u200B/g, '' ); - if ( useTextFixer ) { - l = brs.length; - while ( l-- ) { - detach( brs[l] ); - } - } - if ( range ) { - this._getRangeAndRemoveBookmark( range ); - } - return html; -}; - -proto.setHTML = function ( html ) { - var config = this._config; - var sanitizeToDOMFragment = config.isSetHTMLSanitized ? - config.sanitizeToDOMFragment : null; - var root = this._root; - var div, frag, child; - - // Parse HTML into DOM tree - if ( typeof sanitizeToDOMFragment === 'function' ) { - frag = sanitizeToDOMFragment( html, false, this ); - } else { - div = this.createElement( 'DIV' ); - div.innerHTML = html; - frag = this._doc.createDocumentFragment(); - frag.appendChild( empty( div ) ); - } - - cleanTree( frag ); - cleanupBRs( frag, root, false ); - - fixContainer( frag, root ); - - // Fix cursor - var node = frag; - while ( node = getNextBlock( node, root ) ) { - fixCursor( node, root ); - } - - // Don't fire an input event - this._ignoreChange = true; - - // Remove existing root children - while ( child = root.lastChild ) { - root.removeChild( child ); - } - - // And insert new content - root.appendChild( frag ); - fixCursor( root, root ); - - // Reset the undo stack - this._undoIndex = -1; - this._undoStack.length = 0; - this._undoStackLength = 0; - this._isInUndoState = false; - - // Record undo state - var range = this._getRangeAndRemoveBookmark() || - this._createRange( root.firstChild, 0 ); - this.saveUndoState( range ); - // IE will also set focus when selecting text so don't use - // setSelection. Instead, just store it in lastSelection, so if - // anything calls getSelection before first focus, we have a range - // to return. - this._lastSelection = range; - enableRestoreSelection.call( this ); - this._updatePath( range, true ); - - return this; -}; - -proto.insertElement = function ( el, range ) { - if ( !range ) { - range = this.getSelection(); - } - range.collapse( true ); - if ( isInline( el ) ) { - insertNodeInRange( range, el ); - range.setStartAfter( el ); - } else { - // Get containing block node. - var root = this._root; - var splitNode = getStartBlockOfRange( range, root ) || root; - var parent, nodeAfterSplit; - // While at end of container node, move up DOM tree. - while ( splitNode !== root && !splitNode.nextSibling ) { - splitNode = splitNode.parentNode; - } - // If in the middle of a container node, split up to root. - if ( splitNode !== root ) { - parent = splitNode.parentNode; - nodeAfterSplit = split( parent, splitNode.nextSibling, root, root ); - } - if ( nodeAfterSplit ) { - root.insertBefore( el, nodeAfterSplit ); - } else { - root.appendChild( el ); - // Insert blank line below block. - nodeAfterSplit = this.createDefaultBlock(); - root.appendChild( nodeAfterSplit ); - } - range.setStart( nodeAfterSplit, 0 ); - range.setEnd( nodeAfterSplit, 0 ); - moveRangeBoundariesDownTree( range ); - } - this.focus(); - this.setSelection( range ); - this._updatePath( range ); - - if ( !canObserveMutations ) { - this._docWasChanged(); - } - - return this; -}; - -proto.insertImage = function ( src, attributes ) { - var img = this.createElement( 'IMG', mergeObjects({ - src: src - }, attributes, true )); - this.insertElement( img ); - return img; -}; - -var linkRegExp = /\b((?:(?:ht|f)tps?:\/\/|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,}\/)(?:[^\s()<>]+|\([^\s()<>]+\))+(?:\((?:[^\s()<>]+|(?:\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))|([\w\-.%+]+@(?:[\w\-]+\.)+[A-Z]{2,}\b)/i; - -var addLinks = function ( frag, root, self ) { - var doc = frag.ownerDocument, - walker = new TreeWalker( frag, SHOW_TEXT, - function ( node ) { - return !getNearest( node, root, 'A' ); - }, false ), - defaultAttributes = self._config.tagAttributes.a, - node, data, parent, match, index, endIndex, child; - while ( node = walker.nextNode() ) { - data = node.data; - parent = node.parentNode; - while ( match = linkRegExp.exec( data ) ) { - index = match.index; - endIndex = index + match[0].length; - if ( index ) { - child = doc.createTextNode( data.slice( 0, index ) ); - parent.insertBefore( child, node ); - } - child = self.createElement( 'A', mergeObjects({ - href: match[1] ? - /^(?:ht|f)tps?:/.test( match[1] ) ? - match[1] : - 'http://' + match[1] : - 'mailto:' + match[2] - }, defaultAttributes, false )); - child.textContent = data.slice( index, endIndex ); - parent.insertBefore( child, node ); - node.data = data = data.slice( endIndex ); - } - } -}; - -// Insert HTML at the cursor location. If the selection is not collapsed -// insertTreeFragmentIntoRange will delete the selection so that it is replaced -// by the html being inserted. -proto.insertHTML = function ( html, isPaste ) { - var config = this._config; - var sanitizeToDOMFragment = config.isInsertedHTMLSanitized ? - config.sanitizeToDOMFragment : null; - var range = this.getSelection(); - var doc = this._doc; - var startFragmentIndex, endFragmentIndex; - var div, frag, root, node, event; - - // Edge doesn't just copy the fragment, but includes the surrounding guff - // including the full of the page. Need to strip this out. If - // available use DOMPurify to parse and sanitise. - if ( typeof sanitizeToDOMFragment === 'function' ) { - frag = sanitizeToDOMFragment( html, isPaste, this ); - } else { - if ( isPaste ) { - startFragmentIndex = html.indexOf( '' ); - endFragmentIndex = html.lastIndexOf( '' ); - if ( startFragmentIndex > -1 && endFragmentIndex > -1 ) { - html = html.slice( startFragmentIndex + 20, endFragmentIndex ); - } - } - // Wrap with if html contains dangling tags - if ( /<\/td>((?!<\/tr>)[\s\S])*$/i.test( html ) ) { - html = '' + html + ''; - } - // Wrap with if html contains dangling tags - if ( /<\/tr>((?!<\/table>)[\s\S])*$/i.test( html ) ) { - html = '
            ' + html + '
            '; - } - // Parse HTML into DOM tree - div = this.createElement( 'DIV' ); - div.innerHTML = html; - frag = doc.createDocumentFragment(); - frag.appendChild( empty( div ) ); - } - - // Record undo checkpoint - this.saveUndoState( range ); - - try { - root = this._root; - node = frag; - event = { - fragment: frag, - preventDefault: function () { - this.defaultPrevented = true; - }, - defaultPrevented: false - }; - - addLinks( frag, frag, this ); - cleanTree( frag ); - cleanupBRs( frag, root, false ); - removeEmptyInlines( frag ); - frag.normalize(); - - while ( node = getNextBlock( node, frag ) ) { - fixCursor( node, root ); - } - - if ( isPaste ) { - this.fireEvent( 'willPaste', event ); - } - - if ( !event.defaultPrevented ) { - insertTreeFragmentIntoRange( range, event.fragment, root ); - if ( !canObserveMutations ) { - this._docWasChanged(); - } - range.collapse( false ); - this._ensureBottomLine(); - } - - this.setSelection( range ); - this._updatePath( range, true ); - // Safari sometimes loses focus after paste. Weird. - if ( isPaste ) { - this.focus(); - } - } catch ( error ) { - this.didError( error ); - } - return this; -}; - -var escapeHTMLFragement = function ( text ) { - return text.split( '&' ).join( '&' ) - .split( '<' ).join( '<' ) - .split( '>' ).join( '>' ) - .split( '"' ).join( '"' ); -}; - -proto.insertPlainText = function ( plainText, isPaste ) { - var lines = plainText.split( '\n' ); - var config = this._config; - var tag = config.blockTag; - var attributes = config.blockAttributes; - var closeBlock = ''; - var openBlock = '<' + tag; - var attr, i, l, line; - - for ( attr in attributes ) { - openBlock += ' ' + attr + '="' + - escapeHTMLFragement( attributes[ attr ] ) + - '"'; - } - openBlock += '>'; - - for ( i = 0, l = lines.length; i < l; i += 1 ) { - line = lines[i]; - line = escapeHTMLFragement( line ).replace( / (?= )/g, ' ' ); - // Wrap each line in
            - lines[i] = openBlock + ( line || '
            ' ) + closeBlock; - } - return this.insertHTML( lines.join( '' ), isPaste ); -}; - -// --- Formatting --- - -var command = function ( method, arg, arg2 ) { - return function () { - this[ method ]( arg, arg2 ); - return this.focus(); - }; -}; - -proto.addStyles = function ( styles ) { - if ( styles ) { - var head = this._doc.documentElement.firstChild, - style = this.createElement( 'STYLE', { - type: 'text/css' - }); - style.appendChild( this._doc.createTextNode( styles ) ); - head.appendChild( style ); - } - return this; -}; - -proto.bold = command( 'changeFormat', { tag: 'B' } ); -proto.italic = command( 'changeFormat', { tag: 'I' } ); -proto.underline = command( 'changeFormat', { tag: 'U' } ); -proto.strikethrough = command( 'changeFormat', { tag: 'S' } ); -proto.subscript = command( 'changeFormat', { tag: 'SUB' }, { tag: 'SUP' } ); -proto.superscript = command( 'changeFormat', { tag: 'SUP' }, { tag: 'SUB' } ); - -proto.removeBold = command( 'changeFormat', null, { tag: 'B' } ); -proto.removeItalic = command( 'changeFormat', null, { tag: 'I' } ); -proto.removeUnderline = command( 'changeFormat', null, { tag: 'U' } ); -proto.removeStrikethrough = command( 'changeFormat', null, { tag: 'S' } ); -proto.removeSubscript = command( 'changeFormat', null, { tag: 'SUB' } ); -proto.removeSuperscript = command( 'changeFormat', null, { tag: 'SUP' } ); - -proto.makeLink = function ( url, attributes ) { - var range = this.getSelection(); - if ( range.collapsed ) { - var protocolEnd = url.indexOf( ':' ) + 1; - if ( protocolEnd ) { - while ( url[ protocolEnd ] === '/' ) { protocolEnd += 1; } - } - insertNodeInRange( - range, - this._doc.createTextNode( url.slice( protocolEnd ) ) - ); - } - attributes = mergeObjects( - mergeObjects({ - href: url - }, attributes, true ), - this._config.tagAttributes.a, - false - ); - - this.changeFormat({ - tag: 'A', - attributes: attributes - }, { - tag: 'A' - }, range ); - return this.focus(); -}; -proto.removeLink = function () { - this.changeFormat( null, { - tag: 'A' - }, this.getSelection(), true ); - return this.focus(); -}; - -proto.setFontFace = function ( name ) { - this.changeFormat( name ? { - tag: 'SPAN', - attributes: { - 'class': FONT_FAMILY_CLASS, - style: 'font-family: ' + name + ', sans-serif;' - } - } : null, { - tag: 'SPAN', - attributes: { 'class': FONT_FAMILY_CLASS } - }); - return this.focus(); -}; -proto.setFontSize = function ( size ) { - this.changeFormat( size ? { - tag: 'SPAN', - attributes: { - 'class': FONT_SIZE_CLASS, - style: 'font-size: ' + - ( typeof size === 'number' ? size + 'px' : size ) - } - } : null, { - tag: 'SPAN', - attributes: { 'class': FONT_SIZE_CLASS } - }); - return this.focus(); -}; - -proto.setTextColour = function ( colour ) { - this.changeFormat( colour ? { - tag: 'SPAN', - attributes: { - 'class': COLOUR_CLASS, - style: 'color:' + colour - } - } : null, { - tag: 'SPAN', - attributes: { 'class': COLOUR_CLASS } - }); - return this.focus(); -}; - -proto.setHighlightColour = function ( colour ) { - this.changeFormat( colour ? { - tag: 'SPAN', - attributes: { - 'class': HIGHLIGHT_CLASS, - style: 'background-color:' + colour - } - } : colour, { - tag: 'SPAN', - attributes: { 'class': HIGHLIGHT_CLASS } - }); - return this.focus(); -}; - -proto.setTextAlignment = function ( alignment ) { - this.forEachBlock( function ( block ) { - var className = block.className - .split( /\s+/ ) - .filter( function ( klass ) { - return !!klass && !/^align/.test( klass ); - }) - .join( ' ' ); - if ( alignment ) { - block.className = className + ' align-' + alignment; - block.style.textAlign = alignment; - } else { - block.className = className; - block.style.textAlign = ''; - } - }, true ); - return this.focus(); -}; - -proto.setTextDirection = function ( direction ) { - this.forEachBlock( function ( block ) { - if ( direction ) { - block.dir = direction; - } else { - block.removeAttribute( 'dir' ); - } - }, true ); - return this.focus(); -}; - -function removeFormatting ( self, root, clean ) { - var node, next; - for ( node = root.firstChild; node; node = next ) { - next = node.nextSibling; - if ( isInline( node ) ) { - if ( node.nodeType === TEXT_NODE || node.nodeName === 'BR' || node.nodeName === 'IMG' ) { - clean.appendChild( node ); - continue; - } - } else if ( isBlock( node ) ) { - clean.appendChild( self.createDefaultBlock([ - removeFormatting( - self, node, self._doc.createDocumentFragment() ) - ])); - continue; - } - removeFormatting( self, node, clean ); - } - return clean; -} - -proto.removeAllFormatting = function ( range ) { - if ( !range && !( range = this.getSelection() ) || range.collapsed ) { - return this; - } - - var root = this._root; - var stopNode = range.commonAncestorContainer; - while ( stopNode && !isBlock( stopNode ) ) { - stopNode = stopNode.parentNode; - } - if ( !stopNode ) { - expandRangeToBlockBoundaries( range, root ); - stopNode = root; - } - if ( stopNode.nodeType === TEXT_NODE ) { - return this; - } - - // Record undo point - this.saveUndoState( range ); - - // Avoid splitting where we're already at edges. - moveRangeBoundariesUpTree( range, stopNode, stopNode, root ); - - // Split the selection up to the block, or if whole selection in same - // block, expand range boundaries to ends of block and split up to root. - var doc = stopNode.ownerDocument; - var startContainer = range.startContainer; - var startOffset = range.startOffset; - var endContainer = range.endContainer; - var endOffset = range.endOffset; - - // Split end point first to avoid problems when end and start - // in same container. - var formattedNodes = doc.createDocumentFragment(); - var cleanNodes = doc.createDocumentFragment(); - var nodeAfterSplit = split( endContainer, endOffset, stopNode, root ); - var nodeInSplit = split( startContainer, startOffset, stopNode, root ); - var nextNode, childNodes; - - // Then replace contents in split with a cleaned version of the same: - // blocks become default blocks, text and leaf nodes survive, everything - // else is obliterated. - while ( nodeInSplit !== nodeAfterSplit ) { - nextNode = nodeInSplit.nextSibling; - formattedNodes.appendChild( nodeInSplit ); - nodeInSplit = nextNode; - } - removeFormatting( this, formattedNodes, cleanNodes ); - cleanNodes.normalize(); - nodeInSplit = cleanNodes.firstChild; - nextNode = cleanNodes.lastChild; - - // Restore selection - childNodes = stopNode.childNodes; - if ( nodeInSplit ) { - stopNode.insertBefore( cleanNodes, nodeAfterSplit ); - startOffset = indexOf.call( childNodes, nodeInSplit ); - endOffset = indexOf.call( childNodes, nextNode ) + 1; - } else { - startOffset = indexOf.call( childNodes, nodeAfterSplit ); - endOffset = startOffset; - } - - // Merge text nodes at edges, if possible - range.setStart( stopNode, startOffset ); - range.setEnd( stopNode, endOffset ); - mergeInlines( stopNode, range ); - - // And move back down the tree - moveRangeBoundariesDownTree( range ); - - this.setSelection( range ); - this._updatePath( range, true ); - - return this.focus(); -}; - -proto.increaseQuoteLevel = command( 'modifyBlocks', increaseBlockQuoteLevel ); -proto.decreaseQuoteLevel = command( 'modifyBlocks', decreaseBlockQuoteLevel ); - -proto.makeUnorderedList = command( 'modifyBlocks', makeUnorderedList ); -proto.makeOrderedList = command( 'modifyBlocks', makeOrderedList ); -proto.removeList = command( 'modifyBlocks', removeList ); - -// Node.js exports -Squire.isInline = isInline; -Squire.isBlock = isBlock; -Squire.isContainer = isContainer; -Squire.getBlockWalker = getBlockWalker; -Squire.getPreviousBlock = getPreviousBlock; -Squire.getNextBlock = getNextBlock; -Squire.areAlike = areAlike; -Squire.hasTagAttributes = hasTagAttributes; -Squire.getNearest = getNearest; -Squire.isOrContains = isOrContains; -Squire.detach = detach; -Squire.replaceWith = replaceWith; -Squire.empty = empty; - -// Range.js exports -Squire.getNodeBefore = getNodeBefore; -Squire.getNodeAfter = getNodeAfter; -Squire.insertNodeInRange = insertNodeInRange; -Squire.extractContentsOfRange = extractContentsOfRange; -Squire.deleteContentsOfRange = deleteContentsOfRange; -Squire.insertTreeFragmentIntoRange = insertTreeFragmentIntoRange; -Squire.isNodeContainedInRange = isNodeContainedInRange; -Squire.moveRangeBoundariesDownTree = moveRangeBoundariesDownTree; -Squire.moveRangeBoundariesUpTree = moveRangeBoundariesUpTree; -Squire.getStartBlockOfRange = getStartBlockOfRange; -Squire.getEndBlockOfRange = getEndBlockOfRange; -Squire.contentWalker = contentWalker; -Squire.rangeDoesStartAtBlockBoundary = rangeDoesStartAtBlockBoundary; -Squire.rangeDoesEndAtBlockBoundary = rangeDoesEndAtBlockBoundary; -Squire.expandRangeToBlockBoundaries = expandRangeToBlockBoundaries; - -// Clipboard.js exports -Squire.onPaste = onPaste; - -// Editor.js exports -Squire.addLinks = addLinks; -Squire.splitBlock = splitBlock; -Squire.startSelectionId = startSelectionId; -Squire.endSelectionId = endSelectionId; - -if ( typeof exports === 'object' ) { - module.exports = Squire; -} else if ( typeof define === 'function' && define.amd ) { - define( function () { - return Squire; - }); -} else { - win.Squire = Squire; - - if ( top !== win && - doc.documentElement.getAttribute( 'data-squireinit' ) === 'true' ) { - win.editor = new Squire( doc ); - if ( win.onEditorLoad ) { - win.onEditorLoad( win.editor ); - win.onEditorLoad = null; - } - } -} - -}( document ) ); diff --git a/static/js/mdeditor/toMark.min.js b/static/js/mdeditor/toMark.min.js deleted file mode 100644 index 3ba10868..00000000 --- a/static/js/mdeditor/toMark.min.js +++ /dev/null @@ -1 +0,0 @@ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.toMark=t():e.toMark=t()}(this,function(){return function(e){function t(r){if(n[r])return n[r].exports;var o=n[r]={exports:{},id:r,loaded:!1};return e[r].call(o.exports,o,o.exports,t),o.loaded=!0,o.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){"use strict";var r=n(1),o=n(5),i=n(4),u=n(6);r.Renderer=o,r.basicRenderer=i,r.gfmRenderer=u,e.exports=r},function(e,t,n){"use strict";function r(e,t){var n,r,u=!0;return e?(r=p,t&&(u=t.gfm,u===!1&&(r=s),r=t.renderer||r),n=new a(c(e)),i(o(n,r),u,r.lineFeedReplacement)):""}function o(e,t){for(var n="";e.next();)n+=u(e,t);return n}function i(e,t,n){return e=e.replace(l,"\n"),e=e.replace(d,"\n\n"),e=e.replace(h,function(e){var t=(e.match(/\n/g)||[]).length;return t>=3?"\n\n":e>=1?"\n":e}),e=e.replace(f,""),e=e.replace(new RegExp(n,"g"),"\n"),t&&(e=e.replace(g,"\n")),e}function u(e,t){var n,r,o,i="",a=e.getNode();for(n=0,r=a.childNodes.length;n<"),e=e.replace(u,"> <")}var o=/^[\s\r\n\t]+|[\s\r\n\t]+$/g,i=/>[\r\n\t]+[ ]+"+e.innerHTML+""},"UL, OL":function(e,t){return"\n\n"+t+"\n\n"},"LI OL, LI UL":function(e,t){var n,r;return r=t.replace(i,"\n"),r=r.replace(o,""),n=r.replace(c," "),"\n"+n},"UL LI":function(e,t){var n="";return t=t.replace(u," \n"),e.firstChild&&"P"===e.firstChild.tagName&&(n+="\n"),n+="* "+t+"\n"},"OL LI":function(e,t){for(var n="",r=1;e.previousSibling;)e=e.previousSibling,1===e.nodeType&&"LI"===e.tagName&&(r+=1);return t=t.replace(u," \n"),e.firstChild&&"P"===e.firstChild.tagName&&(n+="\n"),n+=r+". "+t+"\n"},HR:function(){return"\n\n- - -\n\n"},BLOCKQUOTE:function(e,t){var n,r;return t=t.replace(u,"\n\n"),r=this.trim(t),n=r.replace(c,"> "),"\n\n"+n+"\n\n"},"PRE CODE":function(e,t){var n,r;return r=t.replace(o,""),n=r.replace(c," "),"\n\n"+n+"\n\n"}});e.exports=s},function(e,t){"use strict";function n(e,t,n){var r;n=n||null;for(r in e)if(e.hasOwnProperty(r)&&t.call(n,e[r],r,e)===!1)break}function r(e){this.rules={},e&&this.addRules(e)}function o(e){var t=e.tagName;return"S"===t||"B"===t||"I"===t||"EM"===t||"STRONG"===t||"A"===t||"IMG"===t||"CODE"===t}function i(e,t){n(t,function(t,n){"converter"!==n?(e[n]||(e[n]={}),i(e[n],t)):e[n]=t})}var u=/^\u0020/,a=/.+\u0020$/,c=/[\n\s\t]+/g,s=/^[\u0020\r\n\t]+|[\u0020\r\n\t]+$/g,p=/[\u0020]+/g,l=/[~>()*{}\[\]_`+-.!#|]/g,f=3;r.prototype.lineFeedReplacement="​​",r.prototype.addRule=function(e,t){var n=e.split(", "),r=n.pop();for(t.fname=e;r;)this._setConverterWithSelector(r,t),r=n.pop()},r.prototype.addRules=function(e){n(e,function(e,t){this.addRule(t,e)},this)},r.prototype.getSpaceControlled=function(e,t){var n,r="",i="";return t.previousSibling&&(t.previousSibling.nodeType===f||o(t.previousSibling))&&(n=t.previousSibling.innerHTML||t.previousSibling.nodeValue,(a.test(n)||u.test(t.innerHTML||t.nodeValue))&&(r=" ")),t.nextSibling&&(t.nextSibling.nodeType===f||o(t.nextSibling))&&(n=t.nextSibling.innerHTML||t.nextSibling.nodeValue,(u.test(n)||a.test(t.innerHTML||t.nodeValue))&&(i=" ")),r+e+i},r.prototype.convert=function(e,t){var n,r=this._getConverter(e);return e&&e.nodeType===Node.ELEMENT_NODE&&e.hasAttribute("data-tomark-pass")?(e.removeAttribute("data-tomark-pass"),n=e.outerHTML):r?n=r.call(this,e,t):e&&(n=this.getSpaceControlled(this._getInlineHtml(e,t),e)),n||""},r.prototype._getInlineHtml=function(e,t){var n=e.outerHTML,r=e.tagName,o=t.replace(/\$/g,"$$$$");return n.replace(new RegExp("(<"+r+" ?.*?>).*()","i"),"$1"+o+"$2")},r.prototype._getConverter=function(e){for(var t,n=this.rules;e&&n;)n=this._getNextRule(n,this._getRuleNameFromNode(e)),e=this._getPrevNode(e),n&&n.converter&&(t=n.converter);return t},r.prototype._getNextRule=function(e,t){return e[t]},r.prototype._getRuleNameFromNode=function(e){return e.tagName||"TEXT_NODE"},r.prototype._getPrevNode=function(e){var t,n=e.parentNode;return n&&!n.__htmlRootByToMark&&(t=n),t},r.prototype._setConverterWithSelector=function(e,t){var n=this.rules;this._eachSelector(e,function(e){n[e]||(n[e]={}),n=n[e]}),n.converter=t},r.prototype._eachSelector=function(e,t){var n,r;for(n=e.split(" "),r=n.length-1;r>=0;)t(n[r]),r-=1},r.prototype.trim=function(e){return e.replace(s,"")},r.prototype.isEmptyText=function(e){return""===e.replace(c,"")},r.prototype.getSpaceCollapsedText=function(e){return e.replace(p," ")},r.prototype.escapeText=function(e){return e=e.replace(l,function(e){return"\\"+e})},r.prototype.escapeTextHtml=function(e){return e=e.replace(r.markdownTextToEscapeHtmlRx,function(e){return"\\"+e})},r.markdownTextToEscapeRx={codeblock:/(^ {4}[^\n]+\n*)+/,hr:/^ *((\* *){3,}|(- *){3,} *|(_ *){3,}) */,heading:/^(#{1,6}) +[\s\S]+/,lheading:/^([^\n]+)\n *(=|-){2,} */,blockquote:/^( *>[^\n]+.*)+/,list:/^ *(\*+|-+|\d+\.) [\s\S]+/,def:/^ *\[([^\]]+)\]: *]+)>?(?: +["(]([^\n]+)[")])? */,link:/!?\[.*\]\(.*\)/,reflink:/!?\[.*\]\s*\[([^\]]*)\]/,strong:/__(\S[\s\S]*\h)__|\*\*(\S[\s\S]*\S)\*\*/,em:/_(\S[\s\S]*\S)_|\*(\S[\s\S]*\S)\*/,strikeThrough:/~~(\S[\s\S]*\S)~~/,code:/(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,verticalBar:/\u007C/,codeblockGfm:/^(`{3,})/,codeblockTildes:/^(~{3,})/},r.markdownTextToEscapeHtmlRx=/<([a-zA-Z_][a-zA-Z0-9\-\._]*)(\s|[^\\\/>])*\/?>|<(\/)([a-zA-Z_][a-zA-Z0-9\-\._]*)\s*\/?>||<([a-zA-Z_][a-zA-Z0-9\-\.:\/]*)>/g,r.prototype._isNeedEscape=function(e){var t,n=!1,o=r.markdownTextToEscapeRx;for(t in o)if(o.hasOwnProperty(t)&&o[t].test(e)){n=!0;break}return n},r.prototype._isNeedEscapeHtml=function(e){return r.markdownTextToEscapeHtmlRx.test(e)},r.prototype.mix=function(e){i(this.rules,e.rules)},r.factory=function(e,t){var n=new r;return t?n.mix(e):t=e,n.addRules(t),n},e.exports=r},function(e,t,n){"use strict";function r(e,t){var n;return e.className.indexOf("task-list-item")!==-1&&(n=e.className.indexOf("checked")!==-1?"x":" ",t="["+n+"] "+t),t}function o(e){var t,n,r,o;return t=e.align,o=e.textContent?e.textContent.length:e.innerText.length,n="",r="",t&&("left"===t?(n=":",o-=1):"right"===t?(r=":",o-=1):"center"===t&&(r=":",n=":",o-=2)),n+u("-",o)+r}function i(e,t){var n,r=e.childNodes,o=r.length,i=[];for(n=0;n1;)n+=e,t-=1;return n}var a=n(5),c=n(4),s=a.factory(c,{"DEL, S":function(e,t){return"~~"+t+"~~"},"PRE CODE":function(e,t){var n="";return e.getAttribute("data-language")&&(n=" "+e.getAttribute("data-language")),t=t.replace(/(\r\n)|(\r)|(\n)/g,this.lineFeedReplacement),"\n\n```"+n+"\n"+t+"\n```\n\n"},PRE:function(e,t){return t},"UL LI":function(e,t){return c.convert(e,r(e,t))},"OL LI":function(e,t){return c.convert(e,r(e,t))},TABLE:function(e,t){return"\n\n"+t+"\n\n"},"TBODY, TFOOT":function(e,t){return t},"TR TD, TR TH":function(e,t){return" "+t+" |"},"TD BR, TH BR":function(){return"
            "},TR:function(e,t){return"|"+t+"\n"},THEAD:function(e,t){var n,r,u,a="";for(r=i(i(e,"TR")[0],"TH"),u=r.length,n=0;n - * @license MIT - */ -!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.util=e():(t.tui=t.tui||{},t.tui.util=e())}(this,function(){return function(t){function e(r){if(n[r])return n[r].exports;var o=n[r]={exports:{},id:r,loaded:!1};return t[r].call(o.exports,o,o.exports,e),o.loaded=!0,o.exports}var n={};return e.m=t,e.c=n,e.p="dist",e(0)}([function(t,e,n){"use strict";var r={},o=n(1),i=o.extend;i(r,o),i(r,n(3)),i(r,n(2)),i(r,n(4)),i(r,n(5)),i(r,n(6)),i(r,n(7)),i(r,n(8)),r.browser=n(9),r.popup=n(10),r.formatDate=n(11),r.defineClass=n(12),r.defineModule=n(13),r.defineNamespace=n(14),r.CustomEvents=n(15),r.Enum=n(16),r.ExMap=n(17),r.HashMap=n(19),r.Map=n(18),t.exports=r},function(t,e,n){"use strict";function r(t,e){var n,r,o,i,u=Object.prototype.hasOwnProperty;for(o=1,i=arguments.length;o-1||h.inArray(e,o)>-1)return!1;for(n in e){if(e.hasOwnProperty(n)!==t.hasOwnProperty(n))return!1;if(typeof e[n]!=typeof t[n])return!1}for(n in t){if(e.hasOwnProperty(n)!==t.hasOwnProperty(n))return!1;if(typeof e[n]!=typeof t[n])return!1;if("object"==typeof t[n]||"function"==typeof t[n]){if(r.push(t),o.push(e),!c(t[n],e[n]))return!1;r.pop(),o.pop()}else if(t[n]!==e[n])return!1}return!0}function p(t,e){for(var n=arguments,r=n[0],o=1,i=n.length;o=0&&r","'":"'"," ":" "};return t.replace(/&|<|>|"|'| /g,function(t){return e[t]?e[t]:t})}function o(t){var e={'"':"quot","&":"amp","<":"lt",">":"gt","'":"#39"};return t.replace(/[<>&"']/g,function(t){return e[t]?"&"+e[t]+";":t})}function i(t){return/[<>&"']/.test(t)}function u(t,e){for(var n,r,o=0,i=t.length,u={};o1}),u=a.keys(u).sort(),n=u.join("")}var s=n(4),a=n(1);t.exports={decodeHTMLEntity:r,encodeHTMLEntity:o,hasEncodableString:i,getDuplicatedChar:u}},function(t,e){"use strict";function n(t,e){function n(){o=u.call(arguments),window.clearTimeout(r),r=window.setTimeout(function(){t.apply(null,o)},e)}var r,o;return e=e||0,n}function r(){return Number(new Date)}function o(t,e){function n(){return c=u.call(arguments),p?(f(c),void(p=!1)):(a=i.timestamp(),o=o||a,s(c),void(a-o>=e&&f(c)))}function r(){p=!0,o=null}var o,s,a,c,p=!0,f=function(e){t.apply(null,e),o=null};return e=e||0,s=i.debounce(f,e),n.reset=r,n}var i={},u=Array.prototype.slice;i.timestamp=r,i.debounce=n,i.throttle=o,t.exports=i},function(t,e){"use strict";var n,r,o={chrome:!1,firefox:!1,safari:!1,msie:!1,edge:!1,others:!1,version:0},i=window.navigator,u=i.appName.replace(/\s/g,"_"),s=i.userAgent,a=/MSIE\s([0-9]+[.0-9]*)/,c=/Trident.*rv:11\./,p=/Edge\/(\d+)\./,f={firefox:/Firefox\/(\d+)\./,chrome:/Chrome\/(\d+)\./,safari:/Version\/([\d.]+).*Safari\/(\d+)/},h={Microsoft_Internet_Explorer:function(){var t=s.match(a);t?(o.msie=!0,o.version=parseFloat(t[1])):o.others=!0},Netscape:function(){var t=!1;if(c.exec(s))o.msie=!0,o.version=11,t=!0;else if(p.exec(s))o.edge=!0,o.version=s.match(p)[1],t=!0;else for(n in f)if(f.hasOwnProperty(n)&&(r=s.match(f[n]),r&&r.length>1)){o[n]=t=!0,o.version=parseFloat(r[1]||0);break}t||(o.others=!0)}},l=h[u];l&&h[u](),t.exports=o},function(t,e,n){"use strict";function r(){this.openedPopup={},this.closeWithParentPopup={},this.postBridgeUrl=""}var o=n(4),i=n(2),u=n(5),s=n(9),a=n(1),c=0;r.prototype.getPopupList=function(t){var e;return e=i.isExisty(t)?this.openedPopup[t]:this.openedPopup},r.prototype.openPopup=function(t,e){var n,r,o;if(e=a.extend({popupName:"popup_"+c+"_"+Number(new Date),popupOptionStr:"",useReload:!0,closeWithParent:!0,method:"get",param:{}},e||{}),e.method=e.method.toUpperCase(),this.postBridgeUrl=e.postBridgeUrl||this.postBridgeUrl,o="POST"===e.method&&e.param&&s.msie&&11===s.version,!i.isExisty(t))throw new Error("Popup#open() need popup url.");c+=1,e.param&&("GET"===e.method?t=t+(/\?/.test(t)?"&":"?")+this._parameterize(e.param):"POST"===e.method&&(o||(r=this.createForm(t,e.param,e.method,e.popupName),t="about:blank"))),n=this.openedPopup[e.popupName],i.isExisty(n)?n.closed?this.openedPopup[e.popupName]=n=this._open(o,e.param,t,e.popupName,e.popupOptionStr):(e.useReload&&n.location.replace(t),n.focus()):this.openedPopup[e.popupName]=n=this._open(o,e.param,t,e.popupName,e.popupOptionStr),this.closeWithParentPopup[e.popupName]=e.closeWithParent,(!n||n.closed||i.isUndefined(n.closed))&&alert("please enable popup windows for this website"),e.param&&"POST"===e.method&&!o&&(n&&r.submit(),r.parentNode&&r.parentNode.removeChild(r)),window.onunload=u.bind(this.closeAllPopup,this)},r.prototype.close=function(t,e){var n=e||window;t=!!i.isExisty(t)&&t,t&&(window.onunload=null),n.closed||(n.opener=window.location.href,n.close())},r.prototype.closeAllPopup=function(t){var e=i.isExisty(t);o.forEachOwnProperties(this.openedPopup,function(t,n){(e&&this.closeWithParentPopup[n]||!e)&&this.close(!1,t)},this)},r.prototype.focus=function(t){this.getPopupList(t).focus()},r.prototype.parseQuery=function(){var t,e,n={};return t=window.location.search.substr(1),o.forEachArray(t.split("&"),function(t){e=t.split("="),n[decodeURIComponent(e[0])]=decodeURIComponent(e[1])}),n},r.prototype.createForm=function(t,e,n,r,i){var u,s=document.createElement("form");return i=i||document.body,s.method=n||"POST",s.action=t||"",s.target=r||"",s.style.display="none",o.forEachOwnProperties(e,function(t,e){u=document.createElement("input"),u.name=e,u.type="hidden",u.value=t,s.appendChild(u)}),i.appendChild(s),s},r.prototype._parameterize=function(t){var e=[];return o.forEachOwnProperties(t,function(t,n){e.push(encodeURIComponent(n)+"="+encodeURIComponent(t))}),e.join("&")},r.prototype._open=function(t,e,n,r,o){var i;return t?(i=window.open(this.postBridgeUrl,r,o),setTimeout(function(){i.redirect(n,e)},100)):i=window.open(n,r,o),i},t.exports=new r},function(t,e,n){"use strict";function r(t,e,n){var r,o,i,u;return t=Number(t),e=Number(e),n=Number(n),r=t>-1&&t<100||t>1969&&t<2070,o=e>0&&e<13,!(!r||!o)&&(u=c[e],2===e&&t%4===0&&(t%100===0&&t%400!==0||(u=29)),i=n>0&&n<=u)}function o(t,e,n){var o,a,c,f=u.pick(n,"meridiemSet","AM")||"AM",h=u.pick(n,"meridiemSet","PM")||"PM";return a=i.isDate(e)?{year:e.getFullYear(),month:e.getMonth()+1,date:e.getDate(),hour:e.getHours(),minute:e.getMinutes()}:{year:e.year,month:e.month,date:e.date,hour:e.hour,minute:e.minute},!!r(a.year,a.month,a.date)&&(a.meridiem="",/([^\\]|^)[aA]\b/.test(t)&&(o=a.hour>11?h:f,a.hour>12&&(a.hour%=12),0===a.hour&&(a.hour=12),a.meridiem=o),c=t.replace(s,function(t){return t.indexOf("\\")>-1?t.replace(/\\/,""):p[t](a)||""}))}var i=n(2),u=n(1),s=/[\\]*YYYY|[\\]*YY|[\\]*MMMM|[\\]*MMM|[\\]*MM|[\\]*M|[\\]*DD|[\\]*D|[\\]*HH|[\\]*H|[\\]*A/gi,a=["Invalid month","January","February","March","April","May","June","July","August","September","October","November","December"],c=[0,31,28,31,30,31,30,31,31,30,31,30,31],p={M:function(t){return Number(t.month)},MM:function(t){var e=t.month;return Number(e)<10?"0"+e:e},MMM:function(t){return a[Number(t.month)].substr(0,3)},MMMM:function(t){return a[Number(t.month)]},D:function(t){return Number(t.date)},d:function(t){return p.D(t)},DD:function(t){var e=t.date;return Number(e)<10?"0"+e:e},dd:function(t){return p.DD(t)},YY:function(t){return Number(t.year)%100},yy:function(t){return p.YY(t)},YYYY:function(t){var e="20",n=t.year;return n>69&&n<100&&(e="19"),Number(n)<100?e+String(n):n},yyyy:function(t){return p.YYYY(t)},A:function(t){return t.meridiem},a:function(t){return t.meridiem},hh:function(t){var e=t.hour;return Number(e)<10?"0"+e:e},HH:function(t){return p.hh(t)},h:function(t){return String(Number(t.hour))},H:function(t){return p.h(t)},m:function(t){return String(Number(t.minute))},mm:function(t){var e=t.minute;return Number(e)<10?"0"+e:e}};t.exports=o},function(t,e,n){"use strict";function r(t,e){var n;return e||(e=t,t=null),n=e.init||function(){},t&&o(n,t),e.hasOwnProperty("static")&&(i(n,e["static"]),delete e["static"]),i(n.prototype,e),n}var o=n(6).inherit,i=n(1).extend;t.exports=r},function(t,e,n){"use strict";function r(t,e){var n=e||{};return i.isFunction(n[u])&&n[u](),o(t,n)}var o=n(14),i=n(2),u="initialize";t.exports=r},function(t,e,n){"use strict";function r(t,e,n){var r,u,s,a;return r=t.split("."),r.unshift(window),u=o.reduce(r,function(t,e){return t[e]=t[e]||{},t[e]}),n?(a=r.pop(),s=i.pick.apply(null,r),u=s[a]=e):i.extend(u,e),u}var o=n(4),i=n(1);t.exports=r},function(t,e,n){"use strict";function r(){this.events=null,this.contexts=null}var o=n(4),i=n(2),u=n(1),s=/\s+/g;r.mixin=function(t){u.extend(t.prototype,r.prototype)},r.prototype._getHandlerItem=function(t,e){var n={handler:t};return e&&(n.context=e),n},r.prototype._safeEvent=function(t){var e,n=this.events;return n||(n=this.events={}),t&&(e=n[t],e||(e=[],n[t]=e),n=e),n},r.prototype._safeContext=function(){var t=this.contexts;return t||(t=this.contexts=[]),t},r.prototype._indexOfContext=function(t){for(var e=this._safeContext(),n=0;e[n];){if(t===e[n][0])return n;n+=1}return-1},r.prototype._memorizeContext=function(t){var e,n;i.isExisty(t)&&(e=this._safeContext(),n=this._indexOfContext(t),n>-1?e[n][1]+=1:e.push([t,1]))},r.prototype._forgetContext=function(t){var e,n;i.isExisty(t)&&(e=this._safeContext(),n=this._indexOfContext(t),n>-1&&(e[n][1]-=1,e[n][1]<=0&&e.splice(n,1)))},r.prototype._bindEvent=function(t,e,n){var r=this._safeEvent(t);this._memorizeContext(n),r.push(this._getHandlerItem(e,n))},r.prototype.on=function(t,e,n){var r=this;i.isString(t)?(t=t.split(s),o.forEach(t,function(t){r._bindEvent(t,e,n)})):i.isObject(t)&&(n=e,o.forEach(t,function(t,e){r.on(e,t,n)}))},r.prototype.once=function(t,e,n){function r(){e.apply(n,arguments),u.off(t,r,n)}var u=this;return i.isObject(t)?(n=e,void o.forEach(t,function(t,e){u.once(e,t,n)})):void this.on(t,r,n)},r.prototype._spliceMatches=function(t,e){var n,r=0;if(i.isArray(t))for(n=t.length;r0},r.prototype.getListenerLength=function(t){var e=this._safeEvent(t);return e.length},t.exports=r},function(t,e,n){"use strict";function r(t){t&&this.set.apply(this,arguments)}var o=n(4),i=n(2),u=function(){try{return Object.defineProperty({},"x",{}),!0}catch(t){return!1}}(),s=0;r.prototype.set=function(t){var e=this;i.isArray(t)||(t=o.toArray(arguments)),o.forEach(t,function(t){e._addItem(t)})},r.prototype.getName=function(t){var e,n=this;return o.forEach(this,function(r,o){if(n._isEnumItem(o)&&t===r)return e=o,!1}),e},r.prototype._addItem=function(t){var e;this.hasOwnProperty(t)||(e=this._makeEnumValue(),u?Object.defineProperty(this,t,{enumerable:!0,configurable:!1,writable:!1,value:e}):this[t]=e)},r.prototype._makeEnumValue=function(){var t;return t=s,s+=1,t},r.prototype._isEnumItem=function(t){return i.isNumber(this[t])},t.exports=r},function(t,e,n){"use strict";function r(t){this._map=new i(t),this.size=this._map.size}var o=n(4),i=n(18),u=["get","has","forEach","keys","values","entries"],s=["delete","clear"];o.forEachArray(u,function(t){r.prototype[t]=function(){return this._map[t].apply(this._map,arguments)}}),o.forEachArray(s,function(t){r.prototype[t]=function(){var e=this._map[t].apply(this._map,arguments);return this.size=this._map.size,e}}),r.prototype.set=function(){return this._map.set.apply(this._map,arguments),this.size=this._map.size,this},r.prototype.setObject=function(t){o.forEachOwnProperties(t,function(t,e){this.set(e,t)},this)},r.prototype.deleteByKeys=function(t){o.forEachArray(t,function(t){this["delete"](t)},this)},r.prototype.merge=function(t){t.forEach(function(t,e){this.set(e,t)},this)},r.prototype.filter=function(t){var e=new r;return this.forEach(function(n,r){t(n,r)&&e.set(r,n)}),e},t.exports=r},function(t,e,n){"use strict";function r(t,e){this._keys=t,this._valueGetter=e,this._length=this._keys.length,this._index=-1,this._done=!1}function o(t){this._valuesForString={},this._valuesForIndex={},this._keys=[],t&&this._setInitData(t),this.size=0}var i=n(4),u=n(2),s=n(3),a=n(9),c=n(5),p={},f={};r.prototype.next=function(){var t={};do this._index+=1;while(u.isUndefined(this._keys[this._index])&&this._index=this._length?t.done=!0:(t.done=!1,t.value=this._valueGetter(this._keys[this._index],this._index)),t},o.prototype._setInitData=function(t){if(!u.isArray(t))throw new Error("Only Array is supported.");i.forEachArray(t,function(t){this.set(t[0],t[1])},this)},o.prototype._isNaN=function(t){return"number"==typeof t&&t!==t},o.prototype._getKeyIndex=function(t){var e,n=-1;return u.isString(t)?(e=this._valuesForString[t],e&&(n=e.keyIndex)):n=s.inArray(t,this._keys),n},o.prototype._getOriginKey=function(t){var e=t;return t===p?e=void 0:t===f&&(e=NaN),e},o.prototype._getUniqueKey=function(t){var e=t;return u.isUndefined(t)?e=p:this._isNaN(t)&&(e=f),e},o.prototype._getValueObject=function(t,e){return u.isString(t)?this._valuesForString[t]:(u.isUndefined(e)&&(e=this._getKeyIndex(t)),e>=0?this._valuesForIndex[e]:void 0)},o.prototype._getOriginValue=function(t,e){return this._getValueObject(t,e).origin},o.prototype._getKeyValuePair=function(t,e){return[this._getOriginKey(t),this._getOriginValue(t,e)]},o.prototype._createValueObject=function(t,e){return{keyIndex:e,origin:t}},o.prototype.set=function(t,e){var n,r=this._getUniqueKey(t),o=this._getKeyIndex(r);return o<0&&(o=this._keys.push(r)-1,this.size+=1),n=this._createValueObject(e,o),u.isString(t)?this._valuesForString[t]=n:this._valuesForIndex[o]=n,this},o.prototype.get=function(t){var e=this._getUniqueKey(t),n=this._getValueObject(e);return n&&n.origin},o.prototype.keys=function(){return new r(this._keys,c.bind(this._getOriginKey,this))},o.prototype.values=function(){return new r(this._keys,c.bind(this._getOriginValue,this))},o.prototype.entries=function(){return new r(this._keys,c.bind(this._getKeyValuePair,this))},o.prototype.has=function(t){return!!this._getValueObject(t)},o.prototype["delete"]=function(t){var e;u.isString(t)?this._valuesForString[t]&&(e=this._valuesForString[t].keyIndex,delete this._valuesForString[t]):(e=this._getKeyIndex(t),e>=0&&delete this._valuesForIndex[e]),e>=0&&(delete this._keys[e],this.size-=1)},o.prototype.forEach=function(t,e){e=e||this,i.forEachArray(this._keys,function(n){u.isUndefined(n)||t.call(e,this._getValueObject(n).origin,n,this)},this)},o.prototype.clear=function(){o.call(this)},function(){window.Map&&(a.firefox&&a.version>=37||a.chrome&&a.version>=42)&&(o=window.Map)}(),t.exports=o},function(t,e,n){"use strict";function r(t){this.length=0,t&&this.setObject(t)}var o=n(4),i=n(2),u="å";r.prototype.set=function(t,e){2===arguments.length?this.setKeyValue(t,e):this.setObject(t)},r.prototype.setKeyValue=function(t,e){this.has(t)||(this.length+=1),this[this.encodeKey(t)]=e},r.prototype.setObject=function(t){var e=this;o.forEachOwnProperties(t,function(t,n){e.setKeyValue(n,t)})},r.prototype.merge=function(t){var e=this;t.each(function(t,n){e.setKeyValue(n,t)})},r.prototype.encodeKey=function(t){return u+t},r.prototype.decodeKey=function(t){var e=t.split(u);return e[e.length-1]},r.prototype.get=function(t){return this[this.encodeKey(t)]},r.prototype.has=function(t){return this.hasOwnProperty(this.encodeKey(t))},r.prototype.remove=function(t){return arguments.length>1&&(t=o.toArray(arguments)),i.isArray(t)?this.removeByKeyArray(t):this.removeByKey(t)},r.prototype.removeByKey=function(t){var e=this.has(t)?this.get(t):null;return null!==e&&(delete this[this.encodeKey(t)],this.length-=1),e},r.prototype.removeByKeyArray=function(t){var e=[],n=this;return o.forEach(t,function(t){e.push(n.removeByKey(t))}),e},r.prototype.removeAll=function(){var t=this;this.each(function(e,n){t.remove(n)})},r.prototype.each=function(t){var e,n=this;o.forEachOwnProperties(this,function(r,o){if(o.charAt(0)===u&&(e=t(r,n.decodeKey(o))),e===!1)return e})},r.prototype.keys=function(){var t=[],e=this;return this.each(function(n,r){t.push(e.decodeKey(r))}),t},r.prototype.find=function(t){var e=[];return this.each(function(n,r){t(n,r)&&e.push(n)}),e},r.prototype.toArray=function(){var t=[];return this.each(function(e){t.push(e)}),t},t.exports=r}])}); \ No newline at end of file diff --git a/static/js/mdeditor/tui-editor-Editor-all.min.js b/static/js/mdeditor/tui-editor-Editor-all.min.js deleted file mode 100644 index f6de65e5..00000000 --- a/static/js/mdeditor/tui-editor-Editor-all.min.js +++ /dev/null @@ -1,13 +0,0 @@ -/*! - * tui-editor - * @version 1.0.1 - * @author NHN Ent. FE Development Lab (https://nhnent.github.io/tui.editor/) - * @license MIT - */ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("jquery"),require("tui-code-snippet"),require("codemirror"),require("toMark"),require("tui-chart"),require("squire-rte"),require("markdown-it"),require("highlight.js"),require("tui-color-picker"),require("plantuml-encoder")):"function"==typeof define&&define.amd?define(["jquery","tui-code-snippet","codemirror","toMark","tui-chart","squire-rte","markdown-it","highlight.js","tui-color-picker","plantuml-encoder"],t):"object"==typeof exports?exports.Editor=t(require("jquery"),require("tui-code-snippet"),require("codemirror"),require("toMark"),require("tui-chart"),require("squire-rte"),require("markdown-it"),require("highlight.js"),require("tui-color-picker"),require("plantuml-encoder")):(e.tui=e.tui||{},e.tui.Editor=t(e.$,e.tui&&e.tui.util,e.CodeMirror,e.toMark,e.tui&&e.tui.chart,e.Squire,e.markdownit,e.hljs,e.tui&&e.tui.colorPicker,e.plantumlEncoder))}("undefined"!=typeof self?self:this,function(e,t,n,r,i,o,a,l,s,u){return function(e){function t(r){if(n[r])return n[r].exports;var i=n[r]={i:r,l:!1,exports:{}};return e[r].call(i.exports,i,i.exports,t),i.l=!0,i.exports}var n={};return t.m=e,t.c=n,t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="dist/",t(t.s=49)}([function(t,n){t.exports=e},function(e,n){e.exports=t},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(t,"__esModule",{value:!0});var o=function(){function e(e,t){for(var n=0;n1&&void 0!==arguments[1]?arguments[1]:{};i(this,e),this._command=new u.default.Map,this._mdCommand=new u.default.Map,this._wwCommand=new u.default.Map,this._options=l.default.extend({useCommandShortcut:!0},n),this.base=t,this.keyMapCommand={},this._initEvent()}return o(e,[{key:"_addCommandBefore",value:function(e){var t={command:e};return this.base.eventManager.emit("addCommandBefore",t),t.command||e}},{key:"addCommand",value:function(t){for(var n=arguments.length,r=Array(n>1?n-1:0),i=1;i1?o-1:0),l=1;l=0&&(n=e.childNodes[t]),n},v=function(e,t,n){for(var r=e+"Sibling",i=void 0,o=void 0;t&&!t[r]&&(i=d(t.parentNode))!==n&&"BODY"!==i;)t=t.parentNode;return t[r]&&(o=t[r]),o},m=function(e,t,n){return t>0?g(e,t-1):v("previous",e,n)},y=function(e,t){for(var n=void 0;e.parentNode&&!t(e.parentNode);)e=e.parentNode;return t(e.parentNode)&&(n=e),n},_=function(e,t){return l.default.isString(t)?y(e,function(e){return t===d(e)}):y(e,function(e){return t===e})},b=function(e,t,n){var r=e+"Sibling",i=void 0;return t=_(t,n),t&&t[r]&&(i=t[r]),i},w=function(e,t){return b("previous",e,t)},k=function(e,t){return b("next",e,t)},E=function(e){return _(e,"BODY")},C=function(e){for(e=e.previousSibling||e.parentNode;!u(e)&&"BODY"!==d(e);)if(e.previousSibling)for(e=e.previousSibling;e.lastChild;)e=e.lastChild;else e=e.parentNode;return"BODY"===d(e)&&(e=null),e},T=function(e,t,n){var r=[],i="",o=0,a=void 0;if(!t.length)return r;for(var s=t.shift(),u=document.createTreeWalker(e,4,null,!1);u.nextNode();){for(i=u.currentNode.nodeValue||"",n&&(i=n(i)),a=o+i.length;a>=s;){if(r.push({container:u.currentNode,offsetInContainer:s-o,offset:s}),!t.length)return r;s=t.shift()}o=a}do{r.push({container:u.currentNode,offsetInContainer:i.length,offset:s}),s=t.shift()}while(!l.default.isUndefined(s));return r},M=function(e){var t={};t.tagName=e.nodeName,e.id&&(t.id=e.id);var n=e.className.trim();return n&&(t.className=n),t},S=function(e,t){for(var n=[];e&&e!==t;)c(e)&&n.unshift(M(e)),e=e.parentNode;return n},O=function(e,t){var n=!0;return l.default.isUndefined(t)||"next"!==t&&"previous"!==t?null:("previous"===t&&(n=!1),n?e.nextElementSibling:e.previousElementSibling)},x=function(e,t,n){var r=!0,i=null,a=void 0,s=void 0,u=void 0,c=void 0,f=void 0,h=void 0;return l.default.isUndefined(t)||"next"!==t&&"previous"!==t?null:("previous"===t&&(r=!1),e?(a=(0,o.default)(e),r?(u=a.parent().next(),c=a.parents("thead"),f=c[0]&&c.next(),h=f&&"TBODY"===d(f[0]),s=0):(u=a.parent().prev(),c=a.parents("tbody"),f=c[0]&&c.prev(),h=f&&"THEAD"===d(f[0]),s=e.parentNode.childNodes.length-1),!l.default.isUndefined(n)&&n||(s=p(e)),u[0]?i=u.children("td,th")[s]:c[0]&&h&&(i=f.find("td,th")[s]),i):null)};t.default={getNodeName:d,isTextNode:u,isElemNode:c,getTextLength:f,getOffsetLength:h,getPrevOffsetNodeUntil:m,getNodeOffsetOfParent:p,getChildNodeByOffset:g,getTopPrevNodeUnder:w,getTopNextNodeUnder:k,getParentUntil:_,getTopBlockNode:E,getPrevTextNode:C,findOffsetNode:T,getPath:S,getNodeInfo:M,getTableCellByDirection:O,getSiblingRowCellByDirection:x}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=void 0;try{r=n(25)}catch(e){}if(!r)try{r=n(!function(){var e=new Error('Cannot find module "../viewer"');throw e.code="MODULE_NOT_FOUND",e}())}catch(e){}t.default=r},function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(t,"__esModule",{value:!0}),t.I18n=void 0;var i=function(){function e(e,t){for(var n=0;n1,s=o>1;if(l||s){var u=n+o,c=r+i;k.default.range(n,u).forEach(function(t){e[t]=e[t]||[],k.default.range(r,c).forEach(function(i){var o={nodeName:a};t===n&&i===r||(l&&(o.colMergeWith=r),s&&(o.rowMergeWith=n),e[t][i]=o)})})}}function a(e){var t=[];return e.find("tr").each(function(e,n){var r=0;t[e]=t[e]||[],(0,b.default)(n).children().each(function(n,a){var l=i(a,e,n);if(l){for(var s=n+r;t[e][s];)s+=1,r+=1;t[e][s]=l,o(t,l,e,s)}})}),e[0].className&&(t.className=e[0].className),t}function l(e){var t=[];return e.forEach(function(e,n){var r=[];e.forEach(function(e,t){k.default.isUndefined(e.colMergeWith)&&k.default.isUndefined(e.rowMergeWith)&&r.push({rowIndex:n,colIndex:t})}),t.push(r)}),t}function s(e){var t=e[0];return t.map(function(e){return k.default.isExisty(e.colMergeWith)?t[e.colMergeWith].align:e.align})}function u(e,t){var n=s(e),r=t.map(function(t){return t.map(function(t){var r=t.rowIndex,i=t.colIndex;return k.default.extend({align:n[i]},e[r][i])})});return e.className&&(r.className=e.className),r}function c(e,t,n){return{nodeName:n||"TD",colspan:1,rowspan:1,content:E,elementIndex:{rowIndex:e,colIndex:t}}}function d(e){var t=e.closest("tr"),n=t.prevAll().length;return"TBODY"===t.parent()[0].nodeName&&(n+=1),n}function f(e){return e.closest("td, th").prevAll().length}function h(e,t){var n=d(t),r=f(t);return e[n][r]}function p(e,t,n){var r=e[t][n],i=t;return r.rowspan>1&&(i+=r.rowspan-1),i}function g(e,t,n){var r=e[t][n],i=n;return r.colspan>1&&(i+=r.colspan-1),i}function v(e,t,n){var r=e[t][n];return t=k.default.isExisty(r.rowMergeWith)?r.rowMergeWith:t,n=k.default.isExisty(r.colMergeWith)?r.colMergeWith:n,e[t][n].elementIndex}function m(e,t){e.forEach(function(e,n){var r=e.length,i=e[0].nodeName;k.default.range(r,t).forEach(function(t){e.push(c(n,t,i))})})}function y(e){var t=e[0],n=t.length,r=!0;if(!n&&e[1])k.default.range(0,e[1].length).forEach(function(e){t.push(c(0,e,"TH"))});else if("TH"!==e[0][0].nodeName){var i,o=k.default.range(0,n).map(function(e){return c(0,e,"TH")});(i=[]).concat.apply(i,e).forEach(function(e){e.elementIndex&&(e.elementIndex.rowIndex+=1)}),e.unshift(o)}else if(1===e.length){var a=k.default.range(0,n).map(function(e){return c(1,e,"TD")});e.push(a)}else r=!1;return r}Object.defineProperty(t,"__esModule",{value:!0}),t.createTableData=a,t.createCellIndexData=l;var _=n(0),b=r(_),w=n(1),k=r(w),E=k.default.browser.msie?"":"
            ";t.default={createTableData:a,createCellIndexData:l,createRenderData:u,findElementRowIndex:d,findElementColIndex:f,findCellIndex:h,createBasicCell:c,findRowMergedLastIndex:p,findColMergedLastIndex:g,findElementIndex:v,stuffCellsIntoIncompleteRow:m,addTbodyOrTheadIfNeed:y}},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e){var t=e.colspan>1?' colspan="'+e.colspan+'"':"";return t+=e.rowspan>1?' rowspan="'+e.rowspan+'"':"",t+=e.align?' align="'+e.align+'"':"","<"+e.nodeName+t+">"+e.content+""}function o(e,t){var n="";return e.length&&(n=e.map(function(e){return""+e.map(i).join("")+""}).join(""),n="<"+t+">"+n+""),n}function a(e){var t=[e[0]],n=e.slice(1),r=o(t,"THEAD"),i=o(n,"TBODY");return""+(r+i)+""}function l(e,t){var n=f.default.createCellIndexData(t),r=f.default.createRenderData(t,n),i=(0,c.default)(a(r));return e.replaceWith(i),i}function s(e,t,n){t.selectNodeContents(n),t.collapse(!0),e.setSelection(t)}Object.defineProperty(t,"__esModule",{value:!0});var u=n(0),c=r(u),d=n(6),f=r(d);t.default={createTableHtml:a,replaceTable:l,focusToCell:s}},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t,n){var r=g.default.createCellIndexData(e),i=g.default.findCellIndex(r,t),o=g.default.findCellIndex(r,n),a=void 0,l=void 0,s=void 0,u=void 0;return i.rowIndex>o.rowIndex?(a=o.rowIndex,l=i.rowIndex):(a=i.rowIndex,l=o.rowIndex),i.colIndex>o.colIndex?(s=o.colIndex,u=i.colIndex):(s=i.colIndex,u=o.colIndex),{start:{rowIndex:a,colIndex:s},end:{rowIndex:l,colIndex:u}}}function o(e,t,n){var r=t[n].rowIndex,i=e[r];h.default.range(t.start.colIndex,t.end.colIndex+1).forEach(function(n){var o=i[n],a=o.rowMergeWith,l=-1;h.default.isExisty(a)?(a1&&(l=r+o.rowspan-1),l>t.end.rowIndex&&(t.end.rowIndex=l)})}function a(e,t,n,r){var i=e[n],o=i[r],a=o.colMergeWith,l=-1;h.default.isExisty(a)?(a1&&(l=r+o.colspan-1),l>t.end.colIndex&&(t.end.colIndex=l)}function l(e,t){for(var n="";n!==JSON.stringify(t);)n=JSON.stringify(t),o(e,t,"start"),o(e,t,"end"),h.default.range(t.start.rowIndex,t.end.rowIndex+1).forEach(function(n){a(e,t,n,t.start.colIndex),a(e,t,n,t.end.colIndex)});return t}function s(e,t,n){return l(e,i(e,t,n))}function u(e,t,n){var r=g.default.createCellIndexData(e),i={};if(t.length){var o=g.default.findCellIndex(r,t.first()),a=h.default.extend({},o);t.each(function(t,n){var i=g.default.findCellIndex(r,(0,d.default)(n)),o=e[i.rowIndex][i.colIndex],l=i.rowIndex+o.rowspan-1,s=i.colIndex+o.colspan-1;a.rowIndex=Math.max(a.rowIndex,l),a.colIndex=Math.max(a.colIndex,s)}),i.start=o,i.end=a}else{var l=g.default.findCellIndex(r,n);i.start=l,i.end=h.default.extend({},l)}return i}Object.defineProperty(t,"__esModule",{value:!0});var c=n(0),d=r(c),f=n(1),h=r(f),p=n(6),g=r(p);t.default={findSelectionRange:s,getTableSelectionRange:u}},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(t,"__esModule",{value:!0});var l=function(){function e(e,t){for(var n=0;n\n \n
            \n \n
            \n
    \n
    ',v='
    \n
    \n \n
    \n \n
    \n
    \n
    \n
    ',m=function(e){function t(e){i(this,t),e=d.default.extend({header:!0,$target:(0,u.default)("body"),textContent:""},e);var n=o(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,{tagName:"div",className:e.modal?p+"modal-background":p+"wrapper",rootElement:e.$el}));return n._initInstance(e),n._initDOM(e),n._initDOMEvent(e),n._initEditorEvent(e),n}return a(t,e),l(t,[{key:"_initInstance",value:function(e){this._$target=e.$target,e.$el&&(this.$el=e.$el,this._isExternalHtmlUse=!0),e.content?this.$content=(0,u.default)(e.content):this.$content=e.textContent,this.options=e}},{key:"_initDOM",value:function(){this._initLayout(),this._isExternalHtmlUse||(d.default.isExisty(this.options.title)&&this.setTitle(this.options.title),this.setContent(this.$content));var e=this.options.headerButtons;if(e){this.$el.find("."+p+"close-button").remove();var t=this.$el.find("."+p+"header-buttons");t.empty(),t.append((0,u.default)(e))}this.options.css&&this.$el.css(this.options.css)}},{key:"_initDOMEvent",value:function(){var e=this,t=this.options,n=t.openerCssQuery,r=t.closerCssQuery;n&&(0,u.default)(n).on("click."+this._id,function(){return e.show()}),r&&(0,u.default)(r).on("click."+this._id,function(){return e.hide()}),this.on("click ."+p+"close-button",function(){return e.hide()})}},{key:"_initEditorEvent",value:function(){}},{key:"_initLayout",value:function(){var e=this.options;if(this._isExternalHtmlUse)this.hide(),this._$target.append(this.$el);else{var t=e.modal?v:g;this.$el.html(t),this.$el.addClass(e.className),this.hide(),this._$target.append(this.$el),this.$body=this.$el.find("."+p+"body"),e.header||this.$el.find("."+p+"header").remove()}}},{key:"setContent",value:function(e){this.$body.empty(),this.$body.append(e)}},{key:"setTitle",value:function(e){var t=this.$el.find("."+p+"title");t.empty(),t.append(e)}},{key:"getTitleElement",value:function(){return this.$el.find("."+p+"title").get(0)}},{key:"hide",value:function(){this.$el.css("display","none"),this._isShow=!1,this.trigger("hidden",this)}},{key:"show",value:function(){this.$el.css("display","block"),this._isShow=!0,this.trigger("shown",this)}},{key:"isShow",value:function(){return this._isShow}},{key:"remove",value:function(){var e=this.options,t=e.openerCssQuery,n=e.closerCssQuery;this.trigger("remove",this),this.off(),t&&(0,u.default)(t).off("."+this._id),n&&(0,u.default)(n).off("."+this._id),this.$el.remove()}},{key:"setFitToWindow",value:function(e){this.$el.toggleClass("fit-window",e)}},{key:"isFitToWindow",value:function(){return this.$el.hasClass("fit-window")}},{key:"toggleFitToWindow",value:function(){var e=!this.isFitToWindow();return this.setFitToWindow(e),e}}]),t}(h.default);t.default=m},function(e,t){e.exports=n},function(e,t,n){"use strict";function r(e){if(!(this instanceof r))return new r(e);u.call(this,e),c.call(this,e),e&&!1===e.readable&&(this.readable=!1),e&&!1===e.writable&&(this.writable=!1),this.allowHalfOpen=!0,e&&!1===e.allowHalfOpen&&(this.allowHalfOpen=!1),this.once("end",i)}function i(){this.allowHalfOpen||this._writableState.ended||a(o,this)}function o(e){e.end()}var a=n(17),l=Object.keys||function(e){var t=[];for(var n in e)t.push(n);return t};e.exports=r;var s=n(15);s.inherits=n(12);var u=n(42),c=n(24);s.inherits(r,u);for(var d=l(c.prototype),f=0;f0&&void 0!==arguments[0]?arguments[0]:{};i(this,e),t=c.default.extend({tagName:"div"},t),this.tagName=t.tagName,this.className=t.className,this._id=o(),this.$el=null,this._setRootElement(t.rootElement)}return a(e,[{key:"on",value:function(e,t){var n=this;c.default.isObject(e)?c.default.forEach(e,function(e,t){n._addEvent(t,e)}):this._addEvent(e,t)}},{key:"_addEvent",value:function(e,t){var n=this._parseEventType(e),r=n.event,i=n.selector;i?this.$el.on(r,i,t):this.$el.on(r,t)}},{key:"off",value:function(e,t){if(e){var n=this._parseEventType(e),r=n.event,i=n.selector;i?this.$el.off(r,i,t):this.$el.off(r,t)}else this.$el.off()}},{key:"_parseEventType",value:function(e){var t=e.split(" ");return{event:t.shift(),selector:t.join(" ")}}},{key:"_setRootElement",value:function(e){var t=this.tagName,n=this.className;e||(n=n||"uic"+this._id,e=(0,s.default)("<"+t+' class="'+n+'"/>')),this.$el=e}},{key:"trigger",value:function(){var e;(e=this.$el).trigger.apply(e,arguments)}},{key:"_getEventNameWithNamespace",value:function(e){var t=e.split(" ");return t[0]+=".uicEvent"+this._id,t.join(" ")}},{key:"remove",value:function(){this.$el.remove()}},{key:"destroy",value:function(){var e=this;this.remove(),c.default.forEachOwnProperties(this,function(t,n){e[n]=null})}}]),e}();t.default=f},function(e,t){var n;n=function(){return this}();try{n=n||Function("return this")()||(0,eval)("this")}catch(e){"object"==typeof window&&(n=window)}e.exports=n},function(e,t,n){(function(e){function n(e){return Array.isArray?Array.isArray(e):"[object Array]"===v(e)}function r(e){return"boolean"==typeof e}function i(e){return null===e}function o(e){return null==e}function a(e){return"number"==typeof e}function l(e){return"string"==typeof e}function s(e){return"symbol"==typeof e}function u(e){return void 0===e}function c(e){return"[object RegExp]"===v(e)}function d(e){return"object"==typeof e&&null!==e}function f(e){return"[object Date]"===v(e)}function h(e){return"[object Error]"===v(e)||e instanceof Error}function p(e){return"function"==typeof e}function g(e){return null===e||"boolean"==typeof e||"number"==typeof e||"string"==typeof e||"symbol"==typeof e||void 0===e}function v(e){return Object.prototype.toString.call(e)}t.isArray=n,t.isBoolean=r,t.isNull=i,t.isNullOrUndefined=o,t.isNumber=a,t.isString=l,t.isSymbol=s,t.isUndefined=u,t.isRegExp=c,t.isObject=d,t.isDate=f,t.isError=h,t.isFunction=p,t.isPrimitive=g,t.isBuffer=e.isBuffer}).call(t,n(45).Buffer)},function(e,t){function n(){throw new Error("setTimeout has not been defined")}function r(){throw new Error("clearTimeout has not been defined")}function i(e){if(c===setTimeout)return setTimeout(e,0);if((c===n||!c)&&setTimeout)return c=setTimeout,setTimeout(e,0);try{return c(e,0)}catch(t){try{return c.call(null,e,0)}catch(t){return c.call(this,e,0)}}}function o(e){if(d===clearTimeout)return clearTimeout(e);if((d===r||!d)&&clearTimeout)return d=clearTimeout,clearTimeout(e);try{return d(e)}catch(t){try{return d.call(null,e)}catch(t){return d.call(this,e)}}}function a(){g&&h&&(g=!1,h.length?p=h.concat(p):v=-1,p.length&&l())}function l(){if(!g){var e=i(a);g=!0;for(var t=p.length;t;){for(h=p,p=[];++v1)for(var n=1;n","?","AT","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","","","CONTEXT_MENU","","SLEEP","NUMPAD0","NUMPAD1","NUMPAD2","NUMPAD3","NUMPAD4","NUMPAD5","NUMPAD6","NUMPAD7","NUMPAD8","NUMPAD9","MULTIPLY","ADD","SEPARATOR","SUBTRACT","DECIMAL","DIVIDE","F1","F2","F3","F4","F5","F6","F7","F8","F9","F10","F11","F12","F13","F14","F15","F16","F17","F18","F19","F20","F21","F22","F23","F24","","","","","","","","","NUM_LOCK","SCROLL_LOCK","WIN_OEM_FJ_JISHO","WIN_OEM_FJ_MASSHOU","WIN_OEM_FJ_TOUROKU","WIN_OEM_FJ_LOYA","WIN_OEM_FJ_ROYA","","","","","","","","","","@","!",'"',"#","$","%","&","_","(",")","*","+","|","-","{","}","~","","","","","VOLUME_MUTE","VOLUME_DOWN","VOLUME_UP","","",";","=",",","-",".","/","`","","","","","","","","","","","","","","","","","","","","","","","","","","","[","\\","]","'","","META","ALTGR","","WIN_ICO_HELP","WIN_ICO_00","","WIN_ICO_CLEAR","","","WIN_OEM_RESET","WIN_OEM_JUMP","WIN_OEM_PA1","WIN_OEM_PA2","WIN_OEM_PA3","WIN_OEM_WSCTRL","WIN_OEM_CUSEL","WIN_OEM_ATTN","WIN_OEM_FINISH","WIN_OEM_COPY","WIN_OEM_AUTO","WIN_OEM_ENLW","WIN_OEM_BACKTAB","ATTN","CRSEL","EXSEL","EREOF","PLAY","ZOOM","","PA1","WIN_OEM_CLEAR",""],a=void 0,l=function(){function e(t){r(this,e),this._setSplitter(t)}return i(e,[{key:"_setSplitter",value:function(e){var t=e?e.splitter:"+";this._splitter=t}},{key:"convert",value:function(e){var t=[];e.shiftKey&&t.push("SHIFT"),e.ctrlKey&&t.push("CTRL"),e.metaKey&&t.push("META"),e.altKey&&t.push("ALT");var n=this._getKeyCodeChar(e.keyCode);return n&&t.push(n),t.join(this._splitter)}},{key:"_getKeyCodeChar",value:function(e){return o[e]}}],[{key:"getSharedInstance",value:function(){return a||(a=new e),a}},{key:"keyCode",value:function(e){return o.indexOf(e)}}]),e}();t.default=l},function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function i(e){for(var t=atob(e.split(",")[1]),n=e.split(",")[0].split(":")[1].split(";")[0],r=new ArrayBuffer(t.length),i=new Uint8Array(r),o=0;o/g,"%3E")}},{key:"escapeMarkdownCharacters",value:function(e){return e.replace(/\(/g,"\\(").replace(/\)/g,"\\)").replace(/\[/g,"\\[").replace(/\]/g,"\\]").replace(//g,"\\>")}}]),e}();t.default=u},function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function i(e,t){return e.replace(t?/&/g:/&(?!#?\w+;)/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")}Object.defineProperty(t,"__esModule",{value:!0}),t.CodeBlockManager=void 0;var o=function(){function e(e,t){for(var n=0;n0&&this._events[e].length>i&&(this._events[e].warned=!0,console.error("(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.",this._events[e].length),"function"==typeof console.trace&&console.trace()),this},n.prototype.on=n.prototype.addListener,n.prototype.once=function(e,t){function n(){this.removeListener(e,n),i||(i=!0,t.apply(this,arguments))}if(!r(t))throw TypeError("listener must be a function");var i=!1;return n.listener=t,this.on(e,n),this},n.prototype.removeListener=function(e,t){var n,i,a,l;if(!r(t))throw TypeError("listener must be a function");if(!this._events||!this._events[e])return this;if(n=this._events[e],a=n.length,i=-1,n===t||r(n.listener)&&n.listener===t)delete this._events[e],this._events.removeListener&&this.emit("removeListener",e,t);else if(o(n)){for(l=a;l-- >0;)if(n[l]===t||n[l].listener&&n[l].listener===t){i=l;break}if(i<0)return this;1===n.length?(n.length=0,delete this._events[e]):n.splice(i,1),this._events.removeListener&&this.emit("removeListener",e,t)}return this},n.prototype.removeAllListeners=function(e){var t,n;if(!this._events)return this;if(!this._events.removeListener)return 0===arguments.length?this._events={}:this._events[e]&&delete this._events[e],this;if(0===arguments.length){for(t in this._events)"removeListener"!==t&&this.removeAllListeners(t);return this.removeAllListeners("removeListener"),this._events={},this}if(n=this._events[e],r(n))this.removeListener(e,n);else if(n)for(;n.length;)this.removeListener(e,n[n.length-1]);return delete this._events[e],this},n.prototype.listeners=function(e){return this._events&&this._events[e]?r(this._events[e])?[this._events[e]]:this._events[e].slice():[]},n.prototype.listenerCount=function(e){if(this._events){var t=this._events[e];if(r(t))return 1;if(t)return t.length}return 0},n.listenerCount=function(e,t){return e.listenerCount(t)}},function(e,t,n){t=e.exports=n(42),t.Stream=t,t.Readable=t,t.Writable=n(24),t.Duplex=n(11),t.Transform=n(48),t.PassThrough=n(152)},function(e,t,n){"use strict";(function(t,r,i){function o(e){var t=this;this.next=null,this.entry=null,this.finish=function(){S(t,e)}}function a(e){return B.from(e)}function l(e){return B.isBuffer(e)||e instanceof P}function s(){}function u(e,t){x=x||n(11),e=e||{},this.objectMode=!!e.objectMode,t instanceof x&&(this.objectMode=this.objectMode||!!e.writableObjectMode);var r=e.highWaterMark,i=this.objectMode?16:16384;this.highWaterMark=r||0===r?r:i,this.highWaterMark=Math.floor(this.highWaterMark),this.finalCalled=!1,this.needDrain=!1,this.ending=!1,this.ended=!1,this.finished=!1,this.destroyed=!1;var a=!1===e.decodeStrings;this.decodeStrings=!a,this.defaultEncoding=e.defaultEncoding||"utf8",this.length=0,this.writing=!1,this.corked=0,this.sync=!0,this.bufferProcessing=!1,this.onwrite=function(e){y(t,e)},this.writecb=null,this.writelen=0,this.bufferedRequest=null,this.lastBufferedRequest=null,this.pendingcb=0,this.prefinished=!1,this.errorEmitted=!1,this.bufferedRequestCount=0,this.corkedRequestsFree=new o(this)}function c(e){if(x=x||n(11),!(D.call(c,this)||this instanceof x))return new c(e);this._writableState=new u(e,this),this.writable=!0,e&&("function"==typeof e.write&&(this._write=e.write),"function"==typeof e.writev&&(this._writev=e.writev),"function"==typeof e.destroy&&(this._destroy=e.destroy),"function"==typeof e.final&&(this._final=e.final)),N.call(this)}function d(e,t){var n=new Error("write after end");e.emit("error",n),O(t,n)}function f(e,t,n,r){var i=!0,o=!1;return null===n?o=new TypeError("May not write null values to stream"):"string"==typeof n||void 0===n||t.objectMode||(o=new TypeError("Invalid non-string/buffer chunk")),o&&(e.emit("error",o),O(r,o),i=!1),i}function h(e,t,n){return e.objectMode||!1===e.decodeStrings||"string"!=typeof t||(t=B.from(t,n)),t}function p(e,t,n,r,i,o){if(!n){var a=h(t,r,i);r!==a&&(n=!0,i="buffer",r=a)}var l=t.objectMode?1:r.length;t.length+=l;var s=t.length-1?r:O;c.WritableState=u;var I=n(15);I.inherits=n(12);var A={deprecate:n(151)},N=n(44),B=n(18).Buffer,P=i.Uint8Array||function(){},R=n(46);I.inherits(c,N),u.prototype.getBuffer=function(){for(var e=this.bufferedRequest,t=[];e;)t.push(e),e=e.next;return t},function(){try{Object.defineProperty(u.prototype,"buffer",{get:A.deprecate(function(){return this.getBuffer()},"_writableState.buffer is deprecated. Use _writableState.getBuffer instead.","DEP0003")})}catch(e){}}();var D;"function"==typeof Symbol&&Symbol.hasInstance&&"function"==typeof Function.prototype[Symbol.hasInstance]?(D=Function.prototype[Symbol.hasInstance],Object.defineProperty(c,Symbol.hasInstance,{value:function(e){return!!D.call(this,e)||e&&e._writableState instanceof u}})):D=function(e){return e instanceof this},c.prototype.pipe=function(){this.emit("error",new Error("Cannot pipe, not readable"))},c.prototype.write=function(e,t,n){var r=this._writableState,i=!1,o=l(e)&&!r.objectMode;return o&&!B.isBuffer(e)&&(e=a(e)),"function"==typeof t&&(n=t,t=null),o?t="buffer":t||(t=r.defaultEncoding),"function"!=typeof n&&(n=s),r.ended?d(this,n):(o||f(this,r,e,n))&&(r.pendingcb++,i=p(this,r,o,e,t,n)),i},c.prototype.cork=function(){this._writableState.corked++},c.prototype.uncork=function(){var e=this._writableState;e.corked&&(e.corked--,e.writing||e.corked||e.finished||e.bufferProcessing||!e.bufferedRequest||w(this,e))},c.prototype.setDefaultEncoding=function(e){if("string"==typeof e&&(e=e.toLowerCase()),!(["hex","utf8","utf-8","ascii","binary","base64","ucs2","ucs-2","utf16le","utf-16le","raw"].indexOf((e+"").toLowerCase())>-1))throw new TypeError("Unknown encoding: "+e);return this._writableState.defaultEncoding=e,this},c.prototype._write=function(e,t,n){n(new Error("_write() is not implemented"))},c.prototype._writev=null,c.prototype.end=function(e,t,n){var r=this._writableState;"function"==typeof e?(n=e,e=null,t=null):"function"==typeof t&&(n=t,t=null),null!==e&&void 0!==e&&this.write(e,t),r.corked&&(r.corked=1,this.uncork()),r.ending||r.finished||M(this,r,n)},Object.defineProperty(c.prototype,"destroyed",{get:function(){return void 0!==this._writableState&&this._writableState.destroyed},set:function(e){this._writableState&&(this._writableState.destroyed=e)}}),c.prototype.destroy=R.destroy,c.prototype._undestroy=R.undestroy,c.prototype._destroy=function(e,t){this.end(),t(e)}}).call(t,n(16),n(149).setImmediate,n(14))},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var o=function(){function e(e,t){for(var n=0;n1&&void 0!==arguments[1])||arguments[1];e=e||"",this.isMarkdownMode()?this.mdEditor.setValue(e,t):this.wwEditor.setValue(this.convertor.toHTML(e),t),this.eventManager.emit("setMarkdownAfter",e)}},{key:"setHtml",value:function(e){var t=!(arguments.length>1&&void 0!==arguments[1])||arguments[1];if(e=e||"",this.wwEditor.setValue(e),this.isMarkdownMode()){var n=this.convertor.toMarkdown(this.wwEditor.getValue(),this.toMarkOptions);this.mdEditor.setValue(n,t),this.eventManager.emit("setMarkdownAfter",n)}}},{key:"setValue",value:function(e){var t=!(arguments.length>1&&void 0!==arguments[1])||arguments[1];this.setMarkdown(e,t)}},{key:"getMarkdown",value:function(){return this.isMarkdownMode()?this.mdEditor.getValue():this.convertor.toMarkdown(this.wwEditor.getValue(),this.toMarkOptions)}},{key:"getHtml",value:function(){return this.isWysiwygMode()&&this.mdEditor.setValue(this.convertor.toMarkdown(this.wwEditor.getValue(),this.toMarkOptions)),this.convertor.toHTML(this.mdEditor.getValue())}},{key:"getValue",value:function(){return this.getMarkdown()}},{key:"insertText",value:function(e){this.isMarkdownMode()?this.mdEditor.replaceSelection(e):this.wwEditor.insertText(e)}},{key:"addWidget",value:function(e,t,n,r){this.getCurrentModeEditor().addWidget(e,t,n,r)}},{key:"height",value:function(e){return u.default.isExisty(e)&&("auto"===e?(this.options.el.classList.add("auto-height"),this.minHeight(this.minHeight())):(this.options.el.classList.remove("auto-height"),this.minHeight(e)),u.default.isNumber(e)&&(e+="px"),this.options.el.style.height=e,this._height=e),this._height}},{key:"minHeight",value:function(e){if(u.default.isExisty(e)){var t=this._ui.getEditorHeight(),n=this._ui.getEditorSectionHeight(),r=t-n;this._minHeight=e,e=parseInt(e,10),e=Math.max(e-r,0),this.wwEditor.setMinHeight(e),this.mdEditor.setMinHeight(e),this.preview.setMinHeight(e)}return this._minHeight}},{key:"getCurrentModeEditor",value:function(){return this.isMarkdownMode()?this.mdEditor:this.wwEditor}},{key:"isMarkdownMode",value:function(){return"markdown"===this.currentMode}},{key:"isWysiwygMode",value:function(){return"wysiwyg"===this.currentMode}},{key:"isViewer",value:function(){return!1}},{key:"getCurrentPreviewStyle",value:function(){return this.mdPreviewStyle}},{key:"changeMode",value:function(e,t){this.currentMode!==e&&(this.eventManager.emit("changeModeBefore",this.currentMode),this.currentMode=e,this.isWysiwygMode()?(this.layout.switchToWYSIWYG(),this.wwEditor.setValue(this.convertor.toHTML(this.mdEditor.getValue()),!t),this.eventManager.emit("changeModeToWysiwyg")):(this.layout.switchToMarkdown(),this.mdEditor.setValue(this.convertor.toMarkdown(this.wwEditor.getValue(),this.toMarkOptions),!t),this.getCodeMirror().refresh(),this.eventManager.emit("changeModeToMarkdown")),this.eventManager.emit("changeMode",e),t||this.focus())}},{key:"remove",value:function(){var e=this,t=pt.length-1;for(this.wwEditor.remove(),this.mdEditor.remove(),this.layout.remove(),this.getUI()&&this.getUI().remove(),this.eventManager.emit("removeEditor"),this.eventManager.events.forEach(function(t,n){e.off(n)}),this.eventManager=null;t>=0;t-=1)pt[t]===this&&pt.splice(t,1)}},{key:"hide",value:function(){this.eventManager.emit("hide",this)}},{key:"show",value:function(){this.eventManager.emit("show",this),this.getCodeMirror().refresh()}},{key:"scrollTop",value:function(e){return this.getCurrentModeEditor().scrollTop(e)}},{key:"setUI",value:function(e){this._ui=e}},{key:"getUI",value:function(){return this._ui}},{key:"reset",value:function(){this.wwEditor.reset(),this.mdEditor.reset()}},{key:"getRange",value:function(){return this.getCurrentModeEditor().getRange()}},{key:"getTextObject",value:function(e){return this.getCurrentModeEditor().getTextObject(e)}},{key:"getSelectedText",value:function(){var e=this.getRange();return this.getTextObject(e).getTextContent()||""}}],[{key:"getInstances",value:function(){return pt}},{key:"defineExtension",value:function(e,t){T.default.defineExtension(e,t)}},{key:"factory",value:function(t){return t.viewer?new N.default(t):new e(t)}}]),e}();gt.isViewer=!1,gt.i18n=P.default,gt.domUtils=$.default,gt.codeBlockManager=V.default,gt.Button=d.default,gt.WwCodeBlockManager=x.default,gt.WwTableManager=F.default,gt.WwTableSelectionManager=W.default,gt.CommandManager=E.default,gt.markdownitHighlight=I.default.getMarkdownitHighlightRenderer(),e.exports=gt},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(t,"__esModule",{value:!0});var l=function(){function e(e,t){for(var n=0;n1&&void 0!==arguments[1]?arguments[1]:{};i(this,e),this.editorContainerEl=t,this.cm=null,this._init(n)}return o(e,[{key:"_init",value:function(e){var t=document.createElement("textarea");this.editorContainerEl.appendChild(t),e=l.default.extend(!0,{lineWrapping:!0,theme:"default",extraKeys:{"Shift-Tab":"indentLess","Alt-Up":"replaceLineTextToUpper","Alt-Down":"replaceLineTextToLower"},indentUnit:4},e),this.cm=u.default.fromTextArea(t,e)}},{key:"getCurrentRange",value:function(){var e=this.cm.getCursor("from"),t=this.cm.getCursor("to");return{from:e,to:t,collapsed:e.line===t.line&&e.ch===t.ch}}},{key:"focus",value:function(){this.cm.focus()}},{key:"blur",value:function(){this.cm.getInputField().blur()}},{key:"remove",value:function(){this.cm.toTextArea()}},{key:"setValue",value:function(e){var t=!(arguments.length>1&&void 0!==arguments[1])||arguments[1];this.cm.setValue(e),t&&this.moveCursorToEnd(),this.cm.refresh()}},{key:"getValue",value:function(){return this.cm.getValue("\n")}},{key:"getEditor",value:function(){return this.cm}},{key:"reset",value:function(){this.setValue("")}},{key:"getCaretPosition",value:function(){return this.cm.cursorCoords()}},{key:"addWidget",value:function(e,t,n,r){r&&(e.ch+=r),this.cm.addWidget(e.end,t,!0,n)}},{key:"replaceSelection",value:function(e,t){t&&this.cm.setSelection(t.from,t.to),this.cm.replaceSelection(e),this.focus()}},{key:"replaceRelativeOffset",value:function(e,t,n){var r=this.cm.getCursor(),i={from:{line:r.line,ch:r.ch+t},to:{line:r.line,ch:r.ch+t+n}};this.replaceSelection(e,i)}},{key:"setHeight",value:function(e){this.getWrapperElement().style.height=e+"px"}},{key:"setMinHeight",value:function(e){this.getWrapperElement().style.minHeight=e+"px"}},{key:"getWrapperElement",value:function(){return this.cm.getWrapperElement()}},{key:"getCursor",value:function(e){return this.cm.getCursor(e)}},{key:"moveCursorToEnd",value:function(){var e=this.getEditor().getDoc(),t=e.lastLine();e.setCursor(t,e.getLine(t).length)}},{key:"moveCursorToStart",value:function(){var e=this.getEditor().getDoc(),t=e.firstLine();e.setCursor(t,0)}},{key:"scrollTop",value:function(e){return e&&this.cm.scrollTo(0,e),this.cm.getScrollInfo().top}},{key:"getRange",value:function(){var e=this.cm.getCursor("from"),t=this.cm.getCursor("to");return{start:{line:e.line,ch:e.ch},end:{line:t.line,ch:t.ch}}}},{key:"on",value:function(e,t){this.cm.on(e,t)}},{key:"off",value:function(e,t){this.cm.off(e,t)}}]),e}();t.default=c},function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(t,"__esModule",{value:!0});var i=function(){function e(e,t){for(var n=0;n\n/g,"
    "))}),this.eventManager.listen("previewNeedsRefresh",function(n){e.refresh(n||t)}),this.$el.on("scroll",function(t){e.eventManager.emit("scroll",{source:"preview",data:t})})}},{key:"render",value:function(e){l(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"render",this).call(this,e),this.eventManager.emit("previewRenderAfter",this)}}]),t}(u.default);t.default=c},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(t,"__esModule",{value:!0});var o=function(){function e(e,t){for(var n=0;n'),this.$el.append(this._$previewContent)}},{key:"refresh",value:function(e){this.render(this.convertor.toHTMLWithCodeHightlight(e))}},{key:"getHTML",value:function(){return this._$previewContent.html()}},{key:"setHTML",value:function(e){this._$previewContent.html(e)}},{key:"render",value:function(e){var t=this._$previewContent;e=this.eventManager.emit("previewBeforeHook",e)||e,t.empty(),t.html(e)}},{key:"setHeight",value:function(e){this.$el.get(0).style.height=e+"px"}},{key:"setMinHeight",value:function(e){this.$el.get(0).style.minHeight=e+"px"}},{key:"isVisible",value:function(){return"none"!==this.$el.css("display")}}]),e}();t.default=c},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){var n=(0,u.default)("
    ");return e=e.replace(//g,""),n.append(e),o(n),a(n),l(n,t)}function o(e){e.find("script, iframe, textarea, form, button, select, meta, style, link, title").remove()}function a(e){e.find("*").each(function(e,t){var n=t.attributes,r=d.default.toArray(n).filter(function(e){var t=e.name.match(f),n=e.name.match(h);return!t&&!n});d.default.forEachArray(r,function(e){n.getNamedItem(e.name)&&n.removeNamedItem(e.name)})})}function l(e,t){var n=void 0;if(t)n=e[0].innerHTML;else{for(var r=document.createDocumentFragment(),i=d.default.toArray(e[0].childNodes),o=i.length,a=0;a
    ",r="",i=0;i",v=function(){function e(t){i(this,e),this.wwe=t,this.eventManager=t.eventManager,this.name="table",this._lastCellNode=null,this._init()}return a(e,[{key:"_init",value:function(){this._initKeyHandler(),this._initEvent(),this.tableID=0}},{key:"_initEvent",value:function(){var e=this;this.eventManager.listen("wysiwygRangeChangeAfter.table",function(){var t=e.wwe.getEditor().getSelection(),n=e.isInTable(t);if(e._unwrapBlockInTable(),e._completeTableIfNeed(),!n){e.wwe.componentManager.getManager("tableSelection").removeClassAttrbuteFromAllCellsIfNeed()}e._insertDefaultBlockBetweenTable()}),this.eventManager.listen("wysiwygSetValueAfter.table",function(){e._unwrapBlockInTable(),e._insertDefaultBlockBetweenTable()}),this.eventManager.listen("wysiwygProcessHTMLText.table",function(e){return e.replace(/
    (<\/td>|<\/th>)/g,"$1")}),this.eventManager.listen("cut.table",function(){var t=e.wwe.componentManager.getManager("tableSelection"),n=t.getSelectedCells();n.length&&n.get().forEach(function(e){return(0,s.default)(e).html(g)}),t.removeClassAttrbuteFromAllCellsIfNeed()}),this.eventManager.listen("copyBefore.table",function(t){var n=t.$clipboardContainer;return e.updateTableHtmlOfClipboardIfNeed(n)}),this.onBindedPaste=this._onPaste.bind(this),this.wwe.getEditor().addEventListener("paste",this.onBindedPaste)}},{key:"updateTableHtmlOfClipboardIfNeed",value:function(e){var t=this,n=this.wwe.componentManager.getManager("tableSelection");if(n.getSelectedCells().length){n.createRangeBySelectedCells();var r=this.wwe.getEditor().getSelection().cloneContents();(0,s.default)(r).children().each(function(e,n){var r=(0,s.default)(n);t.isTableOrSubTableElement(n.nodeName)&&("TABLE"===n.nodeName&&0===r.find("thead").length&&0===r.find("tbody").length?r.remove():n.previousSibling&&"TABLE"===n.previousSibling.nodeName?n.previousSibling.appendChild(n):(t._completeIncompleteTable(n),"TABLE"!==n.nodeName&&"THEAD"!==n.nodeName&&(0,s.default)(n).closest("table").find("thead").remove()))}),e.append(r),e.find(".te-cell-selected").removeClass("te-cell-selected")}}},{key:"pasteClipboardData",value:function(e){this.wwe.componentManager.getManager("tableSelection").getSelectedCells().length||(this._expandTableIfNeed(e),this._pasteDataIntoTable(e))}},{key:"_onPaste",value:function(e){var t=this.wwe.getEditor().getSelection(),n=!f.default.isTextNode(t.commonAncestorContainer);this.isInTable(t)&&!t.collapsed&&n&&e.preventDefault()}},{key:"_initKeyHandler",value:function(){var e=this;this.keyEventHandlers={DEFAULT:function(t,n,r){var i=e.isInTable(n);i&&!e._isSingleModifierKey(r)?(e._recordUndoStateIfNeed(n),e._removeBRIfNeed(n),e._removeContentsAndChangeSelectionIfNeed(n,r,t)):!i&&e._lastCellNode&&e._recordUndoStateAndResetCellNode(n),i&&!e._isModifierKeyPushed(t)&&e.wwe.getEditor().modifyDocument(function(){e.wwe.componentManager.getManager("tableSelection").removeClassAttrbuteFromAllCellsIfNeed()})},ENTER:function(t,n){var r=void 0;return e._isAfterTable(n)?(t.preventDefault(),n.setStart(n.startContainer,n.startOffset-1),e.wwe.breakToNewDefaultBlock(n),r=!1):e._isBeforeTable(n)?(t.preventDefault(),e.wwe.breakToNewDefaultBlock(n,"before"),r=!1):e.isInTable(n)&&(e._appendBrIfTdOrThNotHaveAsLastChild(n),r=!1),r},BACK_SPACE:function(t,n,r){return e._handleBackspaceAndDeleteKeyEvent(t,n,r)},DELETE:function(t,n,r){return e._handleBackspaceAndDeleteKeyEvent(t,n,r)},TAB:function(){return e._moveCursorTo("next","cell")},"SHIFT+TAB":function(t){return e._moveCursorTo("previous","cell",t)},UP:function(t){return e._moveCursorTo("previous","row",t)},DOWN:function(t){return e._moveCursorTo("next","row",t)}},c.default.forEach(this.keyEventHandlers,function(t,n){return e.wwe.addKeyEventHandler(n,t)})}},{key:"isInTable",value:function(e){var t=void 0,n=void 0;return e.collapsed?(t=e.startContainer,n=!!(0,s.default)(t).closest("[contenteditable=true] table").length):(t=e.commonAncestorContainer,n=!!(0,s.default)(t).closest("[contenteditable=true] table").length||!!(0,s.default)(e.cloneContents()).find("table").length),n}},{key:"_isBeforeTable",value:function(e){return"TABLE"===f.default.getNodeName(f.default.getChildNodeByOffset(e.startContainer,e.startOffset))}},{key:"_isAfterTable",value:function(e){var t=f.default.getPrevOffsetNodeUntil(e.startContainer,e.startOffset);return"TABLE"===f.default.getNodeName(t)&&e.commonAncestorContainer===this.wwe.get$Body()[0]}},{key:"_handleBackspaceAndDeleteKeyEvent",value:function(e,t,n){var r="BACK_SPACE"===n,i=this.wwe.componentManager.getManager("tableSelection"),o=i.getSelectedCells(),a=!0;if(t.collapsed){if(this.isInTable(t))r?this._tableHandlerOnBackspace(t,e):this._tableHandlerOnDelete(t,e),this._insertBRIfNeed(t),this._removeContentsAndChangeSelectionIfNeed(t,n,e),a=!1;else if(!r&&this._isBeforeTable(t)||r&&this._isAfterTable(t)){e.preventDefault();var l=r?t.startOffset-1:t.startOffset;this._removeTable(t,f.default.getChildNodeByOffset(t.startContainer,l)),a=!1}}else if(this.isInTable(t)&&o.length>0){var s=this._removeContentsAndChangeSelectionIfNeed(t,n,e);s&&(e.preventDefault(),a=!1)}return a}},{key:"_tableHandlerOnBackspace",value:function(e,t){var n=f.default.getPrevOffsetNodeUntil(e.startContainer,e.startOffset,"TR"),r=f.default.getNodeName(n);n&&"TD"!==r&&"TH"!==r?"BR"===r&&1!==n.parentNode.childNodes.length&&(t.preventDefault(),(0,s.default)(n).remove()):t.preventDefault()}},{key:"isNonTextDeleting",value:function(e){var t=e.startContainer,n=t.nextSibling,r=f.default.getNodeName(n),i=f.default.getNodeName(t),o=i===r&&"TEXT"!==i,a=(!n||"BR"===r&&n.parentNode.lastChild===n)&&f.default.isTextNode(t)&&e.startOffset===t.nodeValue.length,l=!a&&(0,s.default)(t).parents("tr").children().last()[0]===t&&("TD"===i||"TH"===i);return o||a||l}},{key:"_tableHandlerOnDelete",value:function(e,t){this.isNonTextDeleting(e)&&(t.preventDefault(),e.startContainer.normalize())}},{key:"_appendBrIfTdOrThNotHaveAsLastChild",value:function(e){var t=f.default.getNodeName(e.startContainer),n=void 0;if("TD"===t||"TH"===t)n=e.startContainer;else{var r=(0,s.default)(e.startContainer).parentsUntil("tr");n=r[r.length-1]}"BR"===f.default.getNodeName(n.lastChild)||"DIV"===f.default.getNodeName(n.lastChild)||p||(0,s.default)(n).append((0,s.default)("
    ")[0])}},{key:"_unwrapBlockInTable",value:function(){this.wwe.get$Body().find("td div,th div,tr>br,td>br,th>br").each(function(e,t){if("BR"===f.default.getNodeName(t)){var n=f.default.getNodeName(t.parentNode),r=/TD|TH/.test(n),i=0===t.parentNode.textContent.length,o=t.parentNode.lastChild===t;("TR"===n||r&&!i&&o)&&(0,s.default)(t).remove()}else(0,s.default)(t).children().unwrap()})}},{key:"_insertDefaultBlockBetweenTable",value:function(){this.wwe.get$Body().find("table").each(function(e,t){t.nextElementSibling&&"TABLE"===t.nextElementSibling.nodeName&&(0,s.default)("

    ").insertAfter(t)})}},{key:"_removeTable",value:function(e,t){"TABLE"===t.tagName&&(this.wwe.getEditor().saveUndoState(e),this.wwe.saveSelection(e),(0,s.default)(t).remove(),this.wwe.restoreSavedSelection())}},{key:"_recordUndoStateIfNeed",value:function(e){var t=f.default.getParentUntil(e.startContainer,"TR");e.collapsed&&t&&this._lastCellNode!==t&&(this.wwe.getEditor().saveUndoState(e),this._lastCellNode=t)}},{key:"_recordUndoStateAndResetCellNode",value:function(e){this.wwe.getEditor().saveUndoState(e),this.resetLastCellNode()}},{key:"_pasteDataIntoTable",value:function(e){var t=this.wwe.getEditor().getSelection(),n=t.startContainer,r=n.parentNode,i=this._getTableDataFromTable(e),o="TD"===r.tagName||"TH"===r.tagName,a="TD"===n.tagName||"TH"===n.tagName,l=3===n.nodeType,u=h?"":"
    ",c=void 0,d=void 0,p=void 0,g=void 0;for(c=l&&o?r:a?n:(0,s.default)(n).find("th,td").get(0),d=c;i.length;){for(p=i.shift();d&&p.length;)g=p.shift(),g.length?d.textContent=g:d.innerHTML=u,d=f.default.getTableCellByDirection(d,"next");d=f.default.getSiblingRowCellByDirection(c,"next",!1),c=d}}},{key:"_getTableDataFromTable",value:function(e){var t=(0,s.default)(e),n=[];return t.find("tr").each(function(e,t){var r=[];(0,s.default)(t).children().each(function(e,t){r.push(t.textContent)}),r.length&&n.push(r)}),n}},{key:"_removeTableContents",value:function(e){this.wwe.getEditor().saveUndoState(),e.each(function(e,t){var n=h?"":"
    ";(0,s.default)(t).html(n)})}},{key:"wrapDanglingTableCellsIntoTrIfNeed",value:function(e){var t=e.children("td,th"),n=void 0;if(t.length){var r=(0,s.default)("");t.each(function(e,t){r.append(t)}),n=r.get(0)}return n}},{key:"wrapTrsIntoTbodyIfNeed",value:function(e){var t=e.children("tr"),n=t.find("th"),r=void 0;if(n.length&&n.each(function(e,t){var n=(0,s.default)(t),r=(0,s.default)("");r.html(n.html()),r.insertBefore(t),n.detach()}),t.length){var i=(0,s.default)("");t.each(function(e,t){i.append(t)}),r=i.get(0)}return r}},{key:"wrapTheadAndTbodyIntoTableIfNeed",value:function(e){var t=e.children("thead"),n=e.children("tbody"),r=(0,s.default)("
    "),i=void 0;return!n.length&&t.length?(r.append(t[0]),r.append(""),i=r.get(0)):n.length&&!t.length?(r.append(""),r.append(n[0]),i=r.get(0)):n.length&&t.length&&(r.append(t[0]),r.append(n[0]),i=r.get(0)),i}},{key:"isTableOrSubTableElement",value:function(e){return"TABLE"===e||"TBODY"===e||"THEAD"===e||"TR"===e||"TD"===e}},{key:"_stuffTableCellsIntoIncompleteRow",value:function(e,t){e.each(function(e,n){for(var r=(0,s.default)(n),i=r.find("th,td"),a=f.default.getNodeName(r.parent()[0]),l="THEAD"===a?"th":"td",u=i.length;u").get(0),e.prepend(r)):n&&(r=(0,s.default)("").get(0),e.append(r))}},{key:"tableCellAppendAidForTableElement",value:function(e){var t=(0,s.default)(e);this._addTbodyOrTheadIfNeed(t),this._addTrIntoContainerIfNeed(t);var n=t.find("tr"),r=this.prepareToTableCellStuffing(n),i=r.maximumCellLength;r.needTableCellStuffingAid&&this._stuffTableCellsIntoIncompleteRow(n,i)}},{key:"_generateTheadAndTbodyFromTbody",value:function(e){var t=(0,s.default)(""),n=(0,s.default)("");return t.append(o((0,s.default)(e).find("tr").eq(0).find("td").length,"th")),n.append(t),{thead:n[0],tbody:e}}},{key:"_generateTheadAndTbodyFromThead",value:function(e){var t=(0,s.default)(""),n=(0,s.default)("");return t.append(o((0,s.default)(e).find("th").length,"td")),n.append(t),{thead:e,tbody:n[0]}}},{key:"_generateTheadAndTbodyFromTr",value:function(e){var t=(0,s.default)(e),n=(0,s.default)(""),r=(0,s.default)(""),i=void 0,a=void 0;return"TH"===t.children()[0].tagName?(i=e,a=(0,s.default)(""+o(t.find("th").length,"td")+"").get(0)):(i=(0,s.default)(""+o(t.find("td").length,"th")+"").get(0),a=e),n.append(i),r.append(a),{thead:n[0],tbody:r[0]}}},{key:"_completeIncompleteTable",value:function(e,t){var n=e.tagName,r=void 0,i=void 0;t=!!c.default.isUndefined(t)||t,"TABLE"===n?r=e:(r=(0,s.default)("
    "),r.insertAfter(e),"TBODY"===n?i=this._generateTheadAndTbodyFromTbody(e):"THEAD"===n?i=this._generateTheadAndTbodyFromThead(e):"TR"===n&&(i=this._generateTheadAndTbodyFromTr(e)),t&&r.append(i.thead),r.append(i.tbody)),this.tableCellAppendAidForTableElement(r)}},{key:"_completeTableIfNeed",value:function(){var e=this;this.wwe.getEditor().get$Body().children().each(function(t,n){var r=(0,s.default)(n);e.isTableOrSubTableElement(n.nodeName)&&("TABLE"===n.nodeName&&0===r.find("thead").length&&0===r.find("tbody").length&&r.remove(),e._completeIncompleteTable(n))})}},{key:"resetLastCellNode",value:function(){this._lastCellNode=null}},{key:"setLastCellNode",value:function(e){this._lastCellNode=e}},{key:"_isSingleModifierKey",value:function(e){return"META"===e||"SHIFT"===e||"ALT"===e||"CONTROL"===e}},{key:"_isModifierKeyPushed",value:function(e){return e.metaKey||e.ctrlKey||e.altKey||e.shiftKey}},{key:"_addTrIntoContainerIfNeed",value:function(e){e.children().each(function(e,t){0===(0,s.default)(t).find("tr").length&&(0,s.default)(t).append((0,s.default)("")[0])})}},{key:"_expandTableIfNeed",value:function(e){var t=this.wwe.getEditor().getSelection().cloneRange(),n=(0,s.default)(t.startContainer).parents("table"),r=this._getColumnAndRowDifference(e,t);r.column<0&&this._appendCellForAllRow(n,r.column),r.row<0&&this._appendRow(n,r.row)}},{key:"_getColumnAndRowDifference",value:function(e,t){var n=this._getTableDataFromTable(e),r=n.length,i=n[0].length,o=(0,s.default)(t.startContainer).closest("th,td"),a=o.parent(),l=f.default.getNodeOffsetOfParent(o[0]),u=f.default.getNodeOffsetOfParent(o[0].parentNode),c=a.parents("table"),d=c.find("tr").eq(0).children().length,h=c.find("tr").length;return a.parents("tbody").length&&(u+=1),{row:h-(u+r),column:d-(l+i)}}},{key:"_appendCellForAllRow",value:function(e,t){var n=h?"":"
    ";e.find("tr").each(function(e,r){for(var i=void 0,o=t;o<0;o+=1)i=0===e?"th":"td",(0,s.default)(r).append((0,s.default)("<"+i+">"+n+"")[0])})}},{key:"_appendRow",value:function(e,t){var n=e.find("tr").last().clone(),r=h?"":"
    ";for(n.find("td").html(r);t<0;t+=1)e.find("tbody").append(n.clone()[0])}},{key:"_getSiblingTextNodeByDirection",value:function(e,t){var n=e.previousSibling&&"BR"===e.previousSibling.nodeName&&e.previousSibling.previousSibling&&3===e.previousSibling.previousSibling.nodeType,r=e.nextSibling&&"BR"===e.nextSibling.nodeName&&e.nextSibling.nextSibling&&3===e.nextSibling.nextSibling.nodeType,i=void 0;return t&&r?i=e.nextSibling.nextSibling:!t&&n&&(i=e.previousSibling.previousSibling),i}},{key:"_changeSelectionToTargetCell",value:function(e,t,n,r){var i=t.startContainer,o="next"===n,a="row"===r,l=void 0,u=void 0;if(a){if(f.default.isTextNode(i)&&(l=this._getSiblingTextNodeByDirection(i,o)))return u=l.length"))}},{key:"destroy",value:function(){var e=this;this.eventManager.removeEventHandler("wysiwygRangeChangeAfter.table"),this.eventManager.removeEventHandler("wysiwygSetValueAfter.table"),this.eventManager.removeEventHandler("wysiwygProcessHTMLText.table"),this.eventManager.removeEventHandler("cut.table"),this.eventManager.removeEventHandler("copyBefore.table"),this.wwe.getEditor().removeEventListener("paste",this.onBindedPaste),c.default.forEach(this.keyEventHandlers,function(t,n){return e.wwe.removeKeyEventHandler(n,t)})}}]),e}();t.default=v},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(t,"__esModule",{value:!0});var o=function(){function e(e,t){for(var n=0;n0;return s?c?(t.setStart(i,0),t.setEnd(r,1)):(t.setStart(r,0),t.setEnd(i,1)):u?(t.setStart(r,0),t.setEnd(i,1)):(t.setStart(i,0),t.setEnd(r,1)),t}},{key:"getSelectionRangeFromTable",value:function(e,t){var n=d.default.getNodeOffsetOfParent,r=n(e.parentNode),i=n(t.parentNode),o=n(e),a=n(t),s=d.default.getParentUntil(e,"TABLE"),u=d.default.getParentUntil(t,"TABLE"),c="TBODY"===d.default.getNodeName(s)&&"THEAD"===d.default.getNodeName(u),f=s!==u,h=!!(0,l.default)(e).parents("tbody").length&&!!(0,l.default)(t).parents("tbody").length,p={row:r,cell:o},g={row:i,cell:a},v=void 0,m=void 0;return c?p.row+=1:f?g.row+=1:h&&(p.row+=1,g.row+=1),r>i||r===i&&o>a?(v=g,m=p):(v=p,m=g),{from:v,to:m}}},{key:"highlightTableCellsBy",value:function(e,t){var n=(0,l.default)(e).parents("[contenteditable=true] table").find("tr"),r=this.getSelectionRangeFromTable(e,t),i=r.from.row,o=r.from.cell,a=r.to.row,s=r.to.cell;n.each(function(e,t){(0,l.default)(t).find("td,th").each(function(t,n){var r=(0,l.default)(n),u=e===i,c=e===a;u&&ts||ea?r.removeClass("te-cell-selected"):r.addClass("te-cell-selected")})})}},{key:"removeClassAttrbuteFromAllCellsIfNeed",value:function(){this.wwe.get$Body().find("td.te-cell-selected,th.te-cell-selected").each(function(e,t){var n=(0,l.default)(t);n.removeClass("te-cell-selected"),n.attr("class").length||n.removeAttr("class")})}},{key:"getSelectedCells",value:function(){return this.wwe.get$Body().find(".te-cell-selected")}},{key:"createRangeBySelectedCells",value:function(){var e=this.wwe.getEditor(),t=e.getSelection().cloneRange(),n=this.getSelectedCells(),r=this.wwe.componentManager.getManager("table"),i=n.first().get(0),o=n.last().get(0);n.length&&r.isInTable(t)&&(t.setStart(i,0),t.setEnd(o,o.childNodes.length),e.setSelection(t))}},{key:"styleToSelectedCells",value:function(e){this.createRangeBySelectedCells(),e(this.wwe.getEditor())}},{key:"destroy",value:function(){this.eventManager.removeEventHandler("mousedown.tableSelection"),this.eventManager.removeEventHandler("mouseover.tableSelection"),this.eventManager.removeEventHandler("mouseup.tableSelection"),this.eventManager.removeEventHandler("copyBefore.tableSelection"),this.eventManager.removeEventHandler("pasteBefore.tableSelection")}}]),e}();t.default=f},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e){return e.replace(/[<>&]/g,function(e){return h[e]||e})}Object.defineProperty(t,"__esModule",{value:!0});var a=function(){function e(e,t){for(var n=0;n":">"},p=/\u200B/g,g=function(){function e(t){i(this,e),this.wwe=t,this.eventManager=t.eventManager,this.name="codeblock",this._init()}return a(e,[{key:"_init",value:function(){this._initKeyHandler(),this._initEvent()}},{key:"_initKeyHandler",value:function(){this.wwe.addKeyEventHandler("BACK_SPACE",this._removeCodeblockIfNeed.bind(this))}},{key:"_initEvent",value:function(){var e=this;this.eventManager.listen("wysiwygSetValueAfter",function(){e.splitCodeblockToEachLine()}),this.eventManager.listen("wysiwygProcessHTMLText",function(t){return e._mergeCodeblockEachlinesFromHTMLText(t)})}},{key:"prepareToPasteOnCodeblock",value:function(e){var t=this.wwe.getEditor().getSelection().cloneRange(),n=this.wwe.getEditor().getDocument().createDocumentFragment();return 1===e.length&&this._isCodeBlock(e[0])?n.appendChild(this._copyCodeblockTypeFromRangeCodeblock(e.shift(),t)):n.appendChild(this._copyCodeblockTypeFromRangeCodeblock(this.convertToCodeblock(e),t)),n}},{key:"convertToCodeblock",value:function(e){for(var t=(0,s.default)("
    "),n=this,r=e.shift();c.default.isTruthy(r);)t.append(n._makeCodeBlockLineHtml(c.default.isString(r)?r:r.textContent)),r=e.shift();return t.attr("data-te-codeblock",""),t[0]}},{key:"_copyCodeblockTypeFromRangeCodeblock",value:function(e,t){var n=f.default.getParentUntil(t.commonAncestorContainer,this.wwe.get$Body()[0]);if("PRE"===f.default.getNodeName(n)){var r=(0,s.default)(n).prop("attributes");c.default.forEach(r,function(t){(0,s.default)(e).attr(t.name,t.value)})}return e}},{key:"_mergeCodeblockEachlinesFromHTMLText",value:function(e){return e=e.replace(/(.*?)<\/pre>/g,function(e,t,n){return n=n.replace(/
    /g,"\n"),n=n.replace(/
    /g,""),n=n.replace(/\n$/,""),"
    "+n+"
    "})}},{key:"splitCodeblockToEachLine",value:function(e){var t=this;e||(e=this.wwe.get$Body()),(0,s.default)(e).find("pre").each(function(e,n){var r=(0,s.default)(n),i=r.find("code").attr("data-language"),o=void 0;r.children().length>1&&(o=[],r.children().each(function(e,t){"DIV"!==t.nodeName&&"P"!==t.nodeName||(0,s.default)(t).find("br").length||(0,s.default)(t).append("
    ")})),r.find("br").replaceWith("\n"),o=r.text().replace(/\s+$/,"").split(/\n/g),i&&(r.attr("data-language",i),r.addClass("lang-"+i)),r.empty(),c.default.forEach(o,function(e){r.append(t._makeCodeBlockLineHtml(e))}),r.attr("data-te-codeblock","")})}},{key:"_makeCodeBlockLineHtml",value:function(e){return"
    "+(e=e?o(e):"
    ")+"
    "}},{key:"_removeCodeblockIfNeed",value:function(e,t){var n=this;if(!this.isInCodeBlock(t))return!0;var r=(0,s.default)(t.startContainer).closest("pre"),i=(0,s.default)(r).find("div").eq(0),o=i.text().replace(p,"");return 0!==t.startOffset&&0!==o.length||!((0,s.default)(r).find("div").length<=1)||(this.wwe.getEditor().modifyBlocks(function(){var e=n.wwe.getEditor().getDocument().createDocumentFragment(),t=void 0;return t=0===o.length?"
    ":i.html().replace(p,""),(0,s.default)(e).append((0,s.default)("
    "+t+"
    ")),e}),!1)}},{key:"isInCodeBlock",value:function(e){var t=void 0;return t=e.collapsed?e.startContainer:e.commonAncestorContainer,this._isCodeBlock(t)}},{key:"_isCodeBlock",value:function(e){return!!(0,s.default)(e).closest("pre").length}}]),e}();t.default=g},function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(t,"__esModule",{value:!0});var i=function(){function e(e,t){for(var n=0;n=0&&n.splice(r,1)}},{key:"_removeEventHandlerWithTypeInfo",value:function(e,t){var n=[],r=this.events.get(e);r&&(r.map(function(e){e.namespace!==t&&n.push(e)}),this.events.set(e,n))}}]),e}();t.default=s},function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(t,"__esModule",{value:!0});var i=function(){function e(e,t){for(var n=0;n/gi,"
    ");for(var t=/(]*)(onerror\s*=\s*[\"']?[^\"']*[\"']?)(.*)/i;t.exec(e);)e=e.replace(t,"$1$3");var n=A.render(e);return n=this._removeBrToMarkPassAttributeInCode(n)}},{key:"_markdownToHtml",value:function(e){e=e.replace(/
    /gi,"
    ");for(var t=/(]*)(onerror\s*=\s*[\"']?[^\"']*[\"']?)(.*)/i;t.exec(e);)e=e.replace(t,"$1$3");var n=N.render(e);return n=this._removeBrToMarkPassAttributeInCode(n)}},{key:"_removeBrToMarkPassAttributeInCode",value:function(e){var t=(0,l.default)("
    ");return t.html(e),t.find("code, pre").each(function(e,t){var n=(0,l.default)(t);n.html(n.html().replace(/<br data-tomark-pass>/,"<br>"))}),e=t.html()}},{key:"toHTMLWithCodeHightlight",value:function(e){var t=this._markdownToHtmlWithCodeHighlight(e);return t=this.eventManager.emitReduce("convertorAfterMarkdownToHtmlConverted",t)}},{key:"toHTML",value:function(e){var t=this._markdownToHtml(e);return t=this.eventManager.emitReduce("convertorAfterMarkdownToHtmlConverted",t)}},{key:"initHtmlSanitizer",value:function(){this.eventManager.listen("convertorAfterMarkdownToHtmlConverted",function(e){return(0,g.default)(e,!0)})}},{key:"toMarkdown",value:function(e,t){var n=[];e=this.eventManager.emitReduce("convertorBeforeHtmlToMarkdownConverted",e);var r=(0,h.default)(this._appendAttributeForBrIfNeed(e),t);return r=this.eventManager.emitReduce("convertorAfterHtmlToMarkdownConverted",r),u.default.forEach(r.split("\n"),function(e,t){var r=/^\|[^|]*\|/gi;/`[^`]*
    [^`]*`/gi.test(e)||r.test(e)||(e=e.replace(/
    /gi,"
    \n")),n[t]=e}),n.join("\n")}},{key:"_appendAttributeForBrIfNeed",value:function(e){var t=/
    /gi,n=/

    /gi,r=/

    (.)/gi,i=/([^>]|<\/b>|<\/i>|<\/s>|]*>)/,o=/

    /,a=new RegExp(i.source+o.source,"g");e=e.replace(t,"
    "),e=e.replace(n,"

    ");var s=document.createElement("div"),u=(0,l.default)(s);return u.html(e),u.find("pre br,code br").each(function(e,t){t.hasAttribute("data-tomark-pass")&&t.removeAttribute("data-tomark-pass")}),e=u.html().replace(/
    /gi,"
    "),e=e.replace(t,"
    "),e=e.replace(r,"

    $1"),e=e.replace(a,"$1

    ")}}],[{key:"getMarkdownitHighlightRenderer",value:function(){return A}}]),e}();t.default=B},function(e,t){e.exports=r},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(t,"__esModule",{value:!0});var l=function(){function e(e,t){for(var n=0;n0&&void 0!==arguments[0]?arguments[0]:{};i(this,t);var n=o(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,{tagName:"div",className:"te-tab"}));return n.sections=e.sections,n._$activeButton=null,n._render(e),n._initEvent(e),n}return a(t,e),l(t,[{key:"_initEvent",value:function(e){var t=e.onItemClick;t&&this.on("itemClick",t),this.on("click button",this._onTabButton.bind(this))}},{key:"_render",value:function(e){for(var t=e.items,n=e.initName,r=[],i=0,o=t.length;i'+t[i]+"");this.$el.html(r.join("")),this.activate(n)}},{key:"activate",value:function(e){var t=this.$el.find('button:contains("'+e+'")');this._activateTabByButton(t)}},{key:"_onTabButton",value:function(e){var t=(0,u.default)(e.target);this._activateTabByButton(t),this.trigger("itemClick",t.text())}},{key:"_activateTabByButton",value:function(e){this._isActivatedButton(e)||this._updateClassByButton(e)}},{key:"_updateClassByButton",value:function(e){if(this._$activeButton){var t=this._$activeButton.attr("data-index");this._$activeButton.removeClass("te-tab-active"),this.sections&&this.sections[t].removeClass("te-tab-active")}e.addClass("te-tab-active"),this._$activeButton=e;var n=e.attr("data-index");this.sections&&this.sections[n].addClass("te-tab-active")}},{key:"_isActivatedButton",value:function(e){return this._$activeButton&&this._$activeButton.text()===e.text()}}]),t}(d.default);t.default=f},function(e,t,n){function r(){i.call(this)}e.exports=r;var i=n(22).EventEmitter;n(12)(r,i),r.Readable=n(23),r.Writable=n(153),r.Duplex=n(154),r.Transform=n(155),r.PassThrough=n(156),r.Stream=r,r.prototype.pipe=function(e,t){function n(t){e.writable&&!1===e.write(t)&&u.pause&&u.pause()}function r(){u.readable&&u.resume&&u.resume()}function o(){c||(c=!0,e.end())}function a(){c||(c=!0,"function"==typeof e.destroy&&e.destroy())}function l(e){if(s(),0===i.listenerCount(this,"error"))throw e}function s(){u.removeListener("data",n),e.removeListener("drain",r),u.removeListener("end",o),u.removeListener("close",a),u.removeListener("error",l),e.removeListener("error",l),u.removeListener("end",s),u.removeListener("close",s),e.removeListener("close",s)}var u=this;u.on("data",n),e.on("drain",r),e._isStdio||t&&!1===t.end||(u.on("end",o),u.on("close",a));var c=!1;return u.on("error",l),e.on("error",l),u.on("end",s),u.on("close",s),e.on("close",s),e.emit("pipe",u),e}},function(e,t,n){"use strict";(function(t,r){function i(e){return D.from(e)}function o(e){return D.isBuffer(e)||e instanceof j}function a(e,t,n){if("function"==typeof e.prependListener)return e.prependListener(t,n);e._events&&e._events[t]?B(e._events[t])?e._events[t].unshift(n):e._events[t]=[n,e._events[t]]:e.on(t,n)}function l(e,t){N=N||n(11),e=e||{},this.objectMode=!!e.objectMode,t instanceof N&&(this.objectMode=this.objectMode||!!e.readableObjectMode);var r=e.highWaterMark,i=this.objectMode?16:16384;this.highWaterMark=r||0===r?r:i,this.highWaterMark=Math.floor(this.highWaterMark),this.buffer=new W,this.length=0,this.pipes=null,this.pipesCount=0,this.flowing=null,this.ended=!1,this.endEmitted=!1,this.reading=!1,this.sync=!0,this.needReadable=!1,this.emittedReadable=!1,this.readableListening=!1,this.resumeScheduled=!1,this.destroyed=!1,this.defaultEncoding=e.defaultEncoding||"utf8",this.awaitDrain=0,this.readingMore=!1,this.decoder=null,this.encoding=null,e.encoding&&(U||(U=n(47).StringDecoder),this.decoder=new U(e.encoding),this.encoding=e.encoding)}function s(e){if(N=N||n(11),!(this instanceof s))return new s(e);this._readableState=new l(e,this),this.readable=!0,e&&("function"==typeof e.read&&(this._read=e.read),"function"==typeof e.destroy&&(this._destroy=e.destroy)),R.call(this)}function u(e,t,n,r,o){var a=e._readableState;if(null===t)a.reading=!1,g(e,a);else{var l;o||(l=d(a,t)),l?e.emit("error",l):a.objectMode||t&&t.length>0?("string"==typeof t||a.objectMode||Object.getPrototypeOf(t)===D.prototype||(t=i(t)),r?a.endEmitted?e.emit("error",new Error("stream.unshift() after end event")):c(e,a,t,!0):a.ended?e.emit("error",new Error("stream.push() after EOF")):(a.reading=!1,a.decoder&&!n?(t=a.decoder.write(t),a.objectMode||0!==t.length?c(e,a,t,!1):y(e,a)):c(e,a,t,!1))):r||(a.reading=!1)}return f(a)}function c(e,t,n,r){t.flowing&&0===t.length&&!t.sync?(e.emit("data",n),e.read(0)):(t.length+=t.objectMode?1:n.length,r?t.buffer.unshift(n):t.buffer.push(n),t.needReadable&&v(e)),y(e,t)}function d(e,t){var n;return o(t)||"string"==typeof t||void 0===t||e.objectMode||(n=new TypeError("Invalid non-string/buffer chunk")),n}function f(e){return!e.ended&&(e.needReadable||e.length=K?e=K:(e--,e|=e>>>1,e|=e>>>2,e|=e>>>4,e|=e>>>8,e|=e>>>16,e++),e}function p(e,t){return e<=0||0===t.length&&t.ended?0:t.objectMode?1:e!==e?t.flowing&&t.length?t.buffer.head.data.length:t.length:(e>t.highWaterMark&&(t.highWaterMark=h(e)),e<=t.length?e:t.ended?t.length:(t.needReadable=!0,0))}function g(e,t){if(!t.ended){if(t.decoder){var n=t.decoder.end();n&&n.length&&(t.buffer.push(n),t.length+=t.objectMode?1:n.length)}t.ended=!0,v(e)}}function v(e){var t=e._readableState;t.needReadable=!1,t.emittedReadable||(F("emitReadable",t.flowing),t.emittedReadable=!0,t.sync?A(m,e):m(e))}function m(e){F("emit readable"),e.emit("readable"),C(e)}function y(e,t){t.readingMore||(t.readingMore=!0,A(_,e,t))}function _(e,t){for(var n=t.length;!t.reading&&!t.flowing&&!t.ended&&t.length=t.length?(n=t.decoder?t.buffer.join(""):1===t.buffer.length?t.buffer.head.data:t.buffer.concat(t.length),t.buffer.clear()):n=M(e,t.buffer,t.decoder),n}function M(e,t,n){var r;return eo.length?o.length:e;if(a===o.length?i+=o:i+=o.slice(0,e),0===(e-=a)){a===o.length?(++r,n.next?t.head=n.next:t.head=t.tail=null):(t.head=n,n.data=o.slice(a));break}++r}return t.length-=r,i}function O(e,t){var n=D.allocUnsafe(e),r=t.head,i=1;for(r.data.copy(n),e-=r.data.length;r=r.next;){var o=r.data,a=e>o.length?o.length:e;if(o.copy(n,n.length-e,0,a),0===(e-=a)){a===o.length?(++i,r.next?t.head=r.next:t.head=t.tail=null):(t.head=r,r.data=o.slice(a));break}++i}return t.length-=i,n}function x(e){var t=e._readableState;if(t.length>0)throw new Error('"endReadable()" called on non-empty stream');t.endEmitted||(t.ended=!0,A(L,t,e))}function L(e,t){e.endEmitted||0!==e.length||(e.endEmitted=!0,t.readable=!1,t.emit("end"))}function I(e,t){for(var n=0,r=e.length;n=t.highWaterMark||t.ended))return F("read: emitReadable",t.length,t.ended),0===t.length&&t.ended?x(this):v(this),null;if(0===(e=p(e,t))&&t.ended)return 0===t.length&&x(this),null;var r=t.needReadable;F("need readable",r),(0===t.length||t.length-e0?T(e,t):null,null===i?(t.needReadable=!0,e=0):t.length-=e,0===t.length&&(t.ended||(t.needReadable=!0),n!==e&&t.ended&&x(this)),null!==i&&this.emit("data",i),i},s.prototype._read=function(e){this.emit("error",new Error("_read() is not implemented"))},s.prototype.pipe=function(e,t){function n(e,t){F("onunpipe"),e===f&&t&&!1===t.hasUnpiped&&(t.hasUnpiped=!0,o())}function i(){F("onend"),e.end()}function o(){F("cleanup"),e.removeListener("close",u),e.removeListener("finish",c),e.removeListener("drain",v),e.removeListener("error",s),e.removeListener("unpipe",n),f.removeListener("end",i),f.removeListener("end",d),f.removeListener("data",l),m=!0,!h.awaitDrain||e._writableState&&!e._writableState.needDrain||v()}function l(t){F("ondata"),y=!1,!1!==e.write(t)||y||((1===h.pipesCount&&h.pipes===e||h.pipesCount>1&&-1!==I(h.pipes,e))&&!m&&(F("false write response, pause",f._readableState.awaitDrain),f._readableState.awaitDrain++,y=!0),f.pause())}function s(t){F("onerror",t),d(),e.removeListener("error",s),0===P(e,"error")&&e.emit("error",t)}function u(){e.removeListener("finish",c),d()}function c(){F("onfinish"),e.removeListener("close",u),d()}function d(){F("unpipe"),f.unpipe(e)}var f=this,h=this._readableState;switch(h.pipesCount){case 0:h.pipes=e;break;case 1:h.pipes=[h.pipes,e];break;default:h.pipes.push(e)}h.pipesCount+=1,F("pipe count=%d opts=%j",h.pipesCount,t);var p=(!t||!1!==t.end)&&e!==r.stdout&&e!==r.stderr,g=p?i:d;h.endEmitted?A(g):f.once("end",g),e.on("unpipe",n);var v=b(f);e.on("drain",v);var m=!1,y=!1;return f.on("data",l),a(e,"error",s),e.once("close",u),e.once("finish",c),e.emit("pipe",f),h.flowing||(F("pipe resume"),f.resume()),e},s.prototype.unpipe=function(e){var t=this._readableState,n={hasUnpiped:!1};if(0===t.pipesCount)return this;if(1===t.pipesCount)return e&&e!==t.pipes?this:(e||(e=t.pipes),t.pipes=null,t.pipesCount=0,t.flowing=!1,e&&e.emit("unpipe",this,n),this);if(!e){var r=t.pipes,i=t.pipesCount;t.pipes=null,t.pipesCount=0,t.flowing=!1;for(var o=0;o=r())throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+r().toString(16)+" bytes");return 0|e}function g(e){return+e!=e&&(e=0),o.alloc(+e)}function v(e,t){if(o.isBuffer(e))return e.length;if("undefined"!=typeof ArrayBuffer&&"function"==typeof ArrayBuffer.isView&&(ArrayBuffer.isView(e)||e instanceof ArrayBuffer))return e.byteLength;"string"!=typeof e&&(e=""+e);var n=e.length;if(0===n)return 0;for(var r=!1;;)switch(t){case"ascii":case"latin1":case"binary":return n;case"utf8":case"utf-8":case void 0:return q(e).length;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return 2*n;case"hex":return n>>>1;case"base64":return Y(e).length;default:if(r)return q(e).length;t=(""+t).toLowerCase(),r=!0}}function m(e,t,n){var r=!1;if((void 0===t||t<0)&&(t=0),t>this.length)return"";if((void 0===n||n>this.length)&&(n=this.length),n<=0)return"";if(n>>>=0,t>>>=0,n<=t)return"";for(e||(e="utf8");;)switch(e){case"hex":return A(this,t,n);case"utf8":case"utf-8":return O(this,t,n);case"ascii":return L(this,t,n);case"latin1":case"binary":return I(this,t,n);case"base64":return S(this,t,n);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return N(this,t,n);default:if(r)throw new TypeError("Unknown encoding: "+e);e=(e+"").toLowerCase(),r=!0}}function y(e,t,n){var r=e[t];e[t]=e[n],e[n]=r}function _(e,t,n,r,i){if(0===e.length)return-1;if("string"==typeof n?(r=n,n=0):n>2147483647?n=2147483647:n<-2147483648&&(n=-2147483648),n=+n,isNaN(n)&&(n=i?0:e.length-1),n<0&&(n=e.length+n),n>=e.length){if(i)return-1;n=e.length-1}else if(n<0){if(!i)return-1;n=0}if("string"==typeof t&&(t=o.from(t,r)),o.isBuffer(t))return 0===t.length?-1:b(e,t,n,r,i);if("number"==typeof t)return t&=255,o.TYPED_ARRAY_SUPPORT&&"function"==typeof Uint8Array.prototype.indexOf?i?Uint8Array.prototype.indexOf.call(e,t,n):Uint8Array.prototype.lastIndexOf.call(e,t,n):b(e,[t],n,r,i);throw new TypeError("val must be string, number or Buffer")}function b(e,t,n,r,i){function o(e,t){return 1===a?e[t]:e.readUInt16BE(t*a)}var a=1,l=e.length,s=t.length;if(void 0!==r&&("ucs2"===(r=String(r).toLowerCase())||"ucs-2"===r||"utf16le"===r||"utf-16le"===r)){if(e.length<2||t.length<2)return-1;a=2,l/=2,s/=2,n/=2}var u;if(i){var c=-1;for(u=n;ul&&(n=l-s),u=n;u>=0;u--){for(var d=!0,f=0;fi&&(r=i):r=i;var o=t.length;if(o%2!=0)throw new TypeError("Invalid hex string");r>o/2&&(r=o/2);for(var a=0;a239?4:o>223?3:o>191?2:1;if(i+l<=n){var s,u,c,d;switch(l){case 1:o<128&&(a=o);break;case 2:s=e[i+1],128==(192&s)&&(d=(31&o)<<6|63&s)>127&&(a=d);break;case 3:s=e[i+1],u=e[i+2],128==(192&s)&&128==(192&u)&&(d=(15&o)<<12|(63&s)<<6|63&u)>2047&&(d<55296||d>57343)&&(a=d);break;case 4:s=e[i+1],u=e[i+2],c=e[i+3],128==(192&s)&&128==(192&u)&&128==(192&c)&&(d=(15&o)<<18|(63&s)<<12|(63&u)<<6|63&c)>65535&&d<1114112&&(a=d)}}null===a?(a=65533,l=1):a>65535&&(a-=65536,r.push(a>>>10&1023|55296),a=56320|1023&a),r.push(a),i+=l}return x(r)}function x(e){var t=e.length;if(t<=Z)return String.fromCharCode.apply(String,e);for(var n="",r=0;rr)&&(n=r);for(var i="",o=t;on)throw new RangeError("Trying to access beyond buffer length")}function P(e,t,n,r,i,a){if(!o.isBuffer(e))throw new TypeError('"buffer" argument must be a Buffer instance');if(t>i||te.length)throw new RangeError("Index out of range")}function R(e,t,n,r){t<0&&(t=65535+t+1);for(var i=0,o=Math.min(e.length-n,2);i>>8*(r?i:1-i)}function D(e,t,n,r){t<0&&(t=4294967295+t+1);for(var i=0,o=Math.min(e.length-n,4);i>>8*(r?i:3-i)&255}function j(e,t,n,r,i,o){if(n+r>e.length)throw new RangeError("Index out of range");if(n<0)throw new RangeError("Index out of range")}function $(e,t,n,r,i){return i||j(e,t,n,4,3.4028234663852886e38,-3.4028234663852886e38),J.write(e,t,n,r,23,4),n+4}function H(e,t,n,r,i){return i||j(e,t,n,8,1.7976931348623157e308,-1.7976931348623157e308),J.write(e,t,n,r,52,8),n+8}function F(e){if(e=U(e).replace(ee,""),e.length<2)return"";for(;e.length%4!=0;)e+="=";return e}function U(e){return e.trim?e.trim():e.replace(/^\s+|\s+$/g,"")}function W(e){return e<16?"0"+e.toString(16):e.toString(16)}function q(e,t){t=t||1/0;for(var n,r=e.length,i=null,o=[],a=0;a55295&&n<57344){if(!i){if(n>56319){(t-=3)>-1&&o.push(239,191,189);continue}if(a+1===r){(t-=3)>-1&&o.push(239,191,189);continue}i=n;continue}if(n<56320){(t-=3)>-1&&o.push(239,191,189),i=n;continue}n=65536+(i-55296<<10|n-56320)}else i&&(t-=3)>-1&&o.push(239,191,189);if(i=null,n<128){if((t-=1)<0)break;o.push(n)}else if(n<2048){if((t-=2)<0)break;o.push(n>>6|192,63&n|128)}else if(n<65536){if((t-=3)<0)break;o.push(n>>12|224,n>>6&63|128,63&n|128)}else{if(!(n<1114112))throw new Error("Invalid code point");if((t-=4)<0)break;o.push(n>>18|240,n>>12&63|128,n>>6&63|128,63&n|128)}}return o}function V(e){for(var t=[],n=0;n>8,i=n%256,o.push(i),o.push(r);return o}function Y(e){return X.toByteArray(F(e))}function z(e,t,n,r){for(var i=0;i=t.length||i>=e.length);++i)t[i+n]=e[i];return i}function G(e){return e!==e}/*! - * The buffer module from node.js, for the browser. - * - * @author Feross Aboukhadijeh - * @license MIT - */ -var X=n(145),J=n(146),Q=n(43);t.Buffer=o,t.SlowBuffer=g,t.INSPECT_MAX_BYTES=50,o.TYPED_ARRAY_SUPPORT=void 0!==e.TYPED_ARRAY_SUPPORT?e.TYPED_ARRAY_SUPPORT:function(){try{var e=new Uint8Array(1);return e.__proto__={__proto__:Uint8Array.prototype,foo:function(){return 42}},42===e.foo()&&"function"==typeof e.subarray&&0===e.subarray(1,1).byteLength}catch(e){return!1}}(),t.kMaxLength=r(),o.poolSize=8192,o._augment=function(e){return e.__proto__=o.prototype,e},o.from=function(e,t,n){return a(null,e,t,n)},o.TYPED_ARRAY_SUPPORT&&(o.prototype.__proto__=Uint8Array.prototype,o.__proto__=Uint8Array,"undefined"!=typeof Symbol&&Symbol.species&&o[Symbol.species]===o&&Object.defineProperty(o,Symbol.species,{value:null,configurable:!0})),o.alloc=function(e,t,n){return s(null,e,t,n)},o.allocUnsafe=function(e){return u(null,e)},o.allocUnsafeSlow=function(e){return u(null,e)},o.isBuffer=function(e){return!(null==e||!e._isBuffer)},o.compare=function(e,t){if(!o.isBuffer(e)||!o.isBuffer(t))throw new TypeError("Arguments must be Buffers");if(e===t)return 0;for(var n=e.length,r=t.length,i=0,a=Math.min(n,r);i0&&(e=this.toString("hex",0,n).match(/.{2}/g).join(" "),this.length>n&&(e+=" ... ")),""},o.prototype.compare=function(e,t,n,r,i){if(!o.isBuffer(e))throw new TypeError("Argument must be a Buffer");if(void 0===t&&(t=0),void 0===n&&(n=e?e.length:0),void 0===r&&(r=0),void 0===i&&(i=this.length),t<0||n>e.length||r<0||i>this.length)throw new RangeError("out of range index");if(r>=i&&t>=n)return 0;if(r>=i)return-1;if(t>=n)return 1;if(t>>>=0,n>>>=0,r>>>=0,i>>>=0,this===e)return 0;for(var a=i-r,l=n-t,s=Math.min(a,l),u=this.slice(r,i),c=e.slice(t,n),d=0;di)&&(n=i),e.length>0&&(n<0||t<0)||t>this.length)throw new RangeError("Attempt to write outside buffer bounds");r||(r="utf8");for(var o=!1;;)switch(r){case"hex":return w(this,e,t,n);case"utf8":case"utf-8":return k(this,e,t,n);case"ascii":return E(this,e,t,n);case"latin1":case"binary":return C(this,e,t,n);case"base64":return T(this,e,t,n);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return M(this,e,t,n);default:if(o)throw new TypeError("Unknown encoding: "+r);r=(""+r).toLowerCase(),o=!0}},o.prototype.toJSON=function(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}};var Z=4096;o.prototype.slice=function(e,t){var n=this.length;e=~~e,t=void 0===t?n:~~t,e<0?(e+=n)<0&&(e=0):e>n&&(e=n),t<0?(t+=n)<0&&(t=0):t>n&&(t=n),t0&&(i*=256);)r+=this[e+--t]*i;return r},o.prototype.readUInt8=function(e,t){return t||B(e,1,this.length),this[e]},o.prototype.readUInt16LE=function(e,t){return t||B(e,2,this.length),this[e]|this[e+1]<<8},o.prototype.readUInt16BE=function(e,t){return t||B(e,2,this.length),this[e]<<8|this[e+1]},o.prototype.readUInt32LE=function(e,t){return t||B(e,4,this.length),(this[e]|this[e+1]<<8|this[e+2]<<16)+16777216*this[e+3]},o.prototype.readUInt32BE=function(e,t){return t||B(e,4,this.length),16777216*this[e]+(this[e+1]<<16|this[e+2]<<8|this[e+3])},o.prototype.readIntLE=function(e,t,n){e|=0,t|=0,n||B(e,t,this.length);for(var r=this[e],i=1,o=0;++o=i&&(r-=Math.pow(2,8*t)),r},o.prototype.readIntBE=function(e,t,n){e|=0,t|=0,n||B(e,t,this.length);for(var r=t,i=1,o=this[e+--r];r>0&&(i*=256);)o+=this[e+--r]*i;return i*=128,o>=i&&(o-=Math.pow(2,8*t)),o},o.prototype.readInt8=function(e,t){return t||B(e,1,this.length),128&this[e]?-1*(255-this[e]+1):this[e]},o.prototype.readInt16LE=function(e,t){t||B(e,2,this.length);var n=this[e]|this[e+1]<<8;return 32768&n?4294901760|n:n},o.prototype.readInt16BE=function(e,t){t||B(e,2,this.length);var n=this[e+1]|this[e]<<8;return 32768&n?4294901760|n:n},o.prototype.readInt32LE=function(e,t){return t||B(e,4,this.length),this[e]|this[e+1]<<8|this[e+2]<<16|this[e+3]<<24},o.prototype.readInt32BE=function(e,t){return t||B(e,4,this.length),this[e]<<24|this[e+1]<<16|this[e+2]<<8|this[e+3]},o.prototype.readFloatLE=function(e,t){return t||B(e,4,this.length),J.read(this,e,!0,23,4)},o.prototype.readFloatBE=function(e,t){return t||B(e,4,this.length),J.read(this,e,!1,23,4)},o.prototype.readDoubleLE=function(e,t){return t||B(e,8,this.length),J.read(this,e,!0,52,8)},o.prototype.readDoubleBE=function(e,t){return t||B(e,8,this.length),J.read(this,e,!1,52,8)},o.prototype.writeUIntLE=function(e,t,n,r){if(e=+e,t|=0,n|=0,!r){P(this,e,t,n,Math.pow(2,8*n)-1,0)}var i=1,o=0;for(this[t]=255&e;++o=0&&(o*=256);)this[t+i]=e/o&255;return t+n},o.prototype.writeUInt8=function(e,t,n){return e=+e,t|=0,n||P(this,e,t,1,255,0),o.TYPED_ARRAY_SUPPORT||(e=Math.floor(e)),this[t]=255&e,t+1},o.prototype.writeUInt16LE=function(e,t,n){return e=+e,t|=0,n||P(this,e,t,2,65535,0),o.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8):R(this,e,t,!0),t+2},o.prototype.writeUInt16BE=function(e,t,n){return e=+e,t|=0,n||P(this,e,t,2,65535,0),o.TYPED_ARRAY_SUPPORT?(this[t]=e>>>8,this[t+1]=255&e):R(this,e,t,!1),t+2},o.prototype.writeUInt32LE=function(e,t,n){return e=+e,t|=0,n||P(this,e,t,4,4294967295,0),o.TYPED_ARRAY_SUPPORT?(this[t+3]=e>>>24,this[t+2]=e>>>16,this[t+1]=e>>>8,this[t]=255&e):D(this,e,t,!0),t+4},o.prototype.writeUInt32BE=function(e,t,n){return e=+e,t|=0,n||P(this,e,t,4,4294967295,0),o.TYPED_ARRAY_SUPPORT?(this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e):D(this,e,t,!1),t+4},o.prototype.writeIntLE=function(e,t,n,r){if(e=+e,t|=0,!r){var i=Math.pow(2,8*n-1);P(this,e,t,n,i-1,-i)}var o=0,a=1,l=0;for(this[t]=255&e;++o>0)-l&255;return t+n},o.prototype.writeIntBE=function(e,t,n,r){if(e=+e,t|=0,!r){var i=Math.pow(2,8*n-1);P(this,e,t,n,i-1,-i)}var o=n-1,a=1,l=0;for(this[t+o]=255&e;--o>=0&&(a*=256);)e<0&&0===l&&0!==this[t+o+1]&&(l=1),this[t+o]=(e/a>>0)-l&255;return t+n},o.prototype.writeInt8=function(e,t,n){return e=+e,t|=0,n||P(this,e,t,1,127,-128),o.TYPED_ARRAY_SUPPORT||(e=Math.floor(e)),e<0&&(e=255+e+1),this[t]=255&e,t+1},o.prototype.writeInt16LE=function(e,t,n){return e=+e,t|=0,n||P(this,e,t,2,32767,-32768),o.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8):R(this,e,t,!0),t+2},o.prototype.writeInt16BE=function(e,t,n){return e=+e,t|=0,n||P(this,e,t,2,32767,-32768),o.TYPED_ARRAY_SUPPORT?(this[t]=e>>>8,this[t+1]=255&e):R(this,e,t,!1),t+2},o.prototype.writeInt32LE=function(e,t,n){return e=+e,t|=0,n||P(this,e,t,4,2147483647,-2147483648),o.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8,this[t+2]=e>>>16,this[t+3]=e>>>24):D(this,e,t,!0),t+4},o.prototype.writeInt32BE=function(e,t,n){return e=+e,t|=0,n||P(this,e,t,4,2147483647,-2147483648),e<0&&(e=4294967295+e+1),o.TYPED_ARRAY_SUPPORT?(this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e):D(this,e,t,!1),t+4},o.prototype.writeFloatLE=function(e,t,n){return $(this,e,t,!0,n)},o.prototype.writeFloatBE=function(e,t,n){return $(this,e,t,!1,n)},o.prototype.writeDoubleLE=function(e,t,n){return H(this,e,t,!0,n)},o.prototype.writeDoubleBE=function(e,t,n){return H(this,e,t,!1,n)},o.prototype.copy=function(e,t,n,r){if(n||(n=0),r||0===r||(r=this.length),t>=e.length&&(t=e.length),t||(t=0),r>0&&r=this.length)throw new RangeError("sourceStart out of bounds");if(r<0)throw new RangeError("sourceEnd out of bounds");r>this.length&&(r=this.length),e.length-t=0;--i)e[i+t]=this[i+n];else if(a<1e3||!o.TYPED_ARRAY_SUPPORT)for(i=0;i>>=0,n=void 0===n?this.length:n>>>0,e||(e=0);var a;if("number"==typeof e)for(a=t;a>5==6?2:e>>4==14?3:e>>3==30?4:-1}function l(e,t,n){var r=t.length-1;if(r=0?(i>0&&(e.lastNeed=i-1),i):--r=0?(i>0&&(e.lastNeed=i-2),i):--r=0?(i>0&&(2===i?i=0:e.lastNeed=i-3),i):0)}function s(e,t,n){if(128!=(192&t[0]))return e.lastNeed=0,"�".repeat(n);if(e.lastNeed>1&&t.length>1){if(128!=(192&t[1]))return e.lastNeed=1,"�".repeat(n+1);if(e.lastNeed>2&&t.length>2&&128!=(192&t[2]))return e.lastNeed=2,"�".repeat(n+2)}}function u(e){var t=this.lastTotal-this.lastNeed,n=s(this,e,t);return void 0!==n?n:this.lastNeed<=e.length?(e.copy(this.lastChar,t,0,this.lastNeed),this.lastChar.toString(this.encoding,0,this.lastTotal)):(e.copy(this.lastChar,t,0,e.length),void(this.lastNeed-=e.length))}function c(e,t){var n=l(this,e,t);if(!this.lastNeed)return e.toString("utf8",t);this.lastTotal=n;var r=e.length-(n-this.lastNeed);return e.copy(this.lastChar,0,r),e.toString("utf8",t,r)}function d(e){var t=e&&e.length?this.write(e):"";return this.lastNeed?t+"�".repeat(this.lastTotal-this.lastNeed):t}function f(e,t){if((e.length-t)%2==0){var n=e.toString("utf16le",t);if(n){var r=n.charCodeAt(n.length-1);if(r>=55296&&r<=56319)return this.lastNeed=2,this.lastTotal=4,this.lastChar[0]=e[e.length-2],this.lastChar[1]=e[e.length-1],n.slice(0,-1)}return n}return this.lastNeed=1,this.lastTotal=2,this.lastChar[0]=e[e.length-1],e.toString("utf16le",t,e.length-1)}function h(e){var t=e&&e.length?this.write(e):"";if(this.lastNeed){var n=this.lastTotal-this.lastNeed;return t+this.lastChar.toString("utf16le",0,n)}return t}function p(e,t){var n=(e.length-t)%3;return 0===n?e.toString("base64",t):(this.lastNeed=3-n,this.lastTotal=3,1===n?this.lastChar[0]=e[e.length-1]:(this.lastChar[0]=e[e.length-2],this.lastChar[1]=e[e.length-1]),e.toString("base64",t,e.length-n))}function g(e){var t=e&&e.length?this.write(e):"";return this.lastNeed?t+this.lastChar.toString("base64",0,3-this.lastNeed):t}function v(e){return e.toString(this.encoding)}function m(e){return e&&e.length?this.write(e):""}var y=n(18).Buffer,_=y.isEncoding||function(e){switch((e=""+e)&&e.toLowerCase()){case"hex":case"utf8":case"utf-8":case"ascii":case"binary":case"base64":case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":case"raw":return!0;default:return!1}};t.StringDecoder=o,o.prototype.write=function(e){if(0===e.length)return"";var t,n;if(this.lastNeed){if(void 0===(t=this.fillLast(e)))return"";n=this.lastNeed,this.lastNeed=0}else n=0;return n0}).reduce(function(e,t){return e||!g(t)},!1),i=r?n.shift():[],o=n.slice(1).reduce(function(e,t){return e||!g(t[0])},!1),a=o?n.map(function(e){return e.shift()}):[];return o&&i.shift(),n=n[0].map(function(e,t){return n.map(function(e){return parseFloat(e[t])})}),{categories:a,series:n.map(function(e,t){return r?{name:i[t],data:e}:{data:e}})}}function f(e,t){var n=function(e){var n=d(e);t(n)},r=function(){return t(null)};M.default.get(e).done(n).fail(r)}function h(e){var t=["type","url"],n={};return O.default.isUndefined(e)?n:(e.split(j).forEach(function(e){var r=e.split(H),i=r[0],o=r.slice(1),a=o.join(H);if(i=i.trim(),0!==a.length){try{a=JSON.parse(a.trim())}catch(e){a=a.trim()}var l=i.split("."),s=l.slice(0),u=s[0];O.default.inArray(u,t)>=0?s.unshift("editorChart"):1===s.length?s.unshift("chart"):"x"!==u&&"y"!==u||(s[0]=u+"Axis");for(var c=n,d=0;d';return setTimeout(function(){var n=document.querySelector("#"+t);try{l(e,function(e){var t=e.data,r=e.options;r=v(r,n);var i=r.editorChart.type;F.indexOf(i)<0?n.innerHTML="invalid chart type. type: bar, column, line, area, pie":U.indexOf(i)>-1&&t.categories.length!==t.series[0].data.length?n.innerHTML="invalid chart data":L.default[i](n,t,r)})}catch(e){n.innerHTML="invalid chart data"}},0),n}function y(e){return e.reduce(function(e,t){var n=t.map(function(e){return!g(e)&&e.indexOf(" ")>=0&&(e='"'+e+'"'),e});return e.push(n.join("\t")),e},[])}function _(e){var t=e.wwEditor.componentManager;t.removeManager("codeblock"),t.addManager(function(e){function t(){return i(this,t),o(this,(t.__proto__||Object.getPrototypeOf(t)).apply(this,arguments))}return a(t,e),E(t,[{key:"convertToCodeblock",value:function(e){if(1!==e.length||"TABLE"!==e[0].tagName)return C(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"convertToCodeblock",this).call(this,e);var n=(0,M.default)("
    "),r=e.shift(),i=[].slice.call(r.rows).map(function(e){return[].slice.call(e.cells).map(function(e){return e.innerText.trim()})}),o=y(i);return n.append(o.reduce(function(e,t){return e+"
    "+t+"
    "},[])),n.attr("data-te-codeblock",""),n[0]}}]),t}(P))}function b(e,t,n){var r="markdown"===t&&e.getTokenAt(n.from).state.overlay.codeBlock;return r=r||"codeblock"===t,r=r&&"wysiwyg"!==t}function w(e,t){var n=t.source,r=t.data;if(b(e,n,r)){var i=r.text.join("\n");if(0===c(i,"\t")){B.default.COLUMN_SEPARATOR="\t";var o=y(B.default.parse(i));r.update(r.from,r.to,o)}}}function k(e){var t=e.options.codeBlockLanguages;t&&t.indexOf(D)<0&&t.push(D),R.setReplacer(D,m),e.isViewer()||(_(e),e.eventManager.listen("pasteBefore",function(t){return w(e.mdEditor.cm,t)}))}Object.defineProperty(t,"__esModule",{value:!0}),t.detectDelimiter=t.parseDSV2ChartData=t.parseCode2ChartOption=t.parseURL2ChartData=t.parseCode2DataAndOptions=void 0;var E=function(){function e(e,t){for(var n=0;nt))return e;e=r(e,u,1,i)}d=i.getLine(e)}while(l.test(d));return e}function i(e,t){for(var n=e,r=t.getLine(e);l.test(r);)n-=1,r=t.getLine(n);return e===n?n=-1:n+=1,n}var o=n(10),a=function(e){return e&&e.__esModule?e:{default:e}}(o),l=/^(\s*)((\d+)([.)]\s(?:\[(?:x|\s)\]\s)?))(.*)/;a.default.commands.indentLessOrderedList=function(e){return e.getOption("disableInput")?a.default.Pass:(e.execCommand("indentLess"),e.execCommand("fixOrderedListNumber"),null)},a.default.commands.fixOrderedListNumber=function(e){if(e.getOption("disableInput"))return a.default.Pass;for(var t=e.listSelections(),n=0;n=0){var u=e.getLine(s),c=l.exec(u),d=c[1],f=c[3];r(s,d.length,parseInt(f,10),e)}}return null}},function(e,t,n){"use strict";var r=n(10),i=function(e){return e&&e.__esModule?e:{default:e}}(r);i.default.overlayMode=function(e,t,n){return{startState:function(){return{base:i.default.startState(e),overlay:i.default.startState(t),basePos:0,baseCur:null,overlayPos:0,overlayCur:null,streamSeen:null}},copyState:function(n){return{base:i.default.copyState(e,n.base),overlay:i.default.copyState(t,n.overlay),basePos:n.basePos,baseCur:null,overlayPos:n.overlayPos,overlayCur:null}},token:function(r,i){return(r!=i.streamSeen||Math.min(i.basePos,i.overlayPos)=0&&(i.indentationDiff<4&&(i.indentation-=i.indentationDiff),i.list=null),i.indentation>0?(i.list=null,i.listDepth=Math.floor(i.indentation/4)):(i.list=!1,i.listDepth=0));var c=null;if(i.indentationDiff>=4)return e.skipToEnd(),s||o(i.prevLine)?(i.indentation-=4,i.indentedCode=!0,T):null;if(e.eatSpace())return null;if((c=e.match(q))&&c[1].length<=6)return i.header=c[1].length,t.highlightFormatting&&(i.formatting="header"),i.f=i.inline,d(i);if(!(o(i.prevLine)||i.quote||l||s)&&(c=e.match(V)))return i.header="="==c[0].charAt(0)?1:2,t.highlightFormatting&&(i.formatting="header"),i.f=i.inline,d(i);if(e.eat(">"))return i.quote=a?1:i.quote+1,t.highlightFormatting&&(i.formatting="quote"),e.eatSpace(),d(i);if("["===e.peek())return r(e,i,m);if(e.match(H,!0))return i.hr=!0,L;if((o(i.prevLine)||l)&&(e.match(F,!1)||e.match(U,!1))){var f=null;return e.match(F,!0)?f="ul":(e.match(U,!0),f="ol"),i.indentation+=4,i.list=!0,i.listDepth++,t.taskLists&&e.match(W,!1)&&(i.taskList=!0,i.task=!0),i.f=i.inline,t.highlightFormatting&&(i.formatting=["list","list-"+f]),d(i)}return t.fencedCodeBlocks&&(c=e.match(Y,!0))?(i.fencedChars=c[1],i.localMode=n(c[2]),i.localMode&&(i.localState=i.localMode.startState()),i.f=i.block=u,t.highlightFormatting&&(i.formatting="code-block"),i.code=!0,d(i)):r(e,i,i.inline)}function s(e,t){var n=k.token(e,t.htmlState);return(w&&null===t.htmlState.tagStart&&!t.htmlState.context&&t.htmlState.tokenize.isInText||t.md_inside&&e.current().indexOf(">")>-1)&&(t.f=h,t.block=l,t.htmlState=null),n}function u(e,t){return e.sol()&&t.fencedChars&&e.match(t.fencedChars,!1)?(t.localMode=t.localState=null,t.f=t.block=c,null):t.localMode?t.localMode.token(e,t.localState):(e.skipToEnd(),T)}function c(e,n){e.match(n.fencedChars),n.block=l,n.f=h,n.fencedChars=null,t.highlightFormatting&&(n.formatting="code-block"),n.code=!0;var r=d(n);return n.code=!1,r}function d(e){var n=[];if(e.formatting){n.push(A),"string"==typeof e.formatting&&(e.formatting=[e.formatting]);for(var r=0;r=e.quote?n.push(A+"-"+e.formatting[r]+"-"+e.quote):n.push("error"))}if(e.taskOpen)return n.push("meta"),n.length?n.join(" "):null;if(e.taskClosed)return n.push("property"),n.length?n.join(" "):null;if(e.linkHref?n.push(R,"url"):(e.strong&&n.push(j),e.em&&n.push(D),e.strikethrough&&n.push($),e.linkText&&n.push(P),e.code&&n.push(T)),e.header&&(n.push(C),n.push(C+"-"+e.header)),e.quote&&(n.push(M),!t.maxBlockquoteDepth||t.maxBlockquoteDepth>=e.quote?n.push(M+"-"+e.quote):n.push(M+"-"+t.maxBlockquoteDepth)),!1!==e.list){var i=(e.listDepth-1)%3;i?1===i?n.push(O):n.push(x):n.push(S)}return e.trailingSpaceNewLine?n.push("trailing-space-new-line"):e.trailingSpace&&n.push("trailing-space-"+(e.trailingSpace%2?"a":"b")),n.length?n.join(" "):null}function f(e,t){if(e.match(K,!0))return d(t)}function h(e,n){var r=n.text(e,n);if(void 0!==r)return r;if(n.list)return n.list=null,d(n);if(n.taskList){return"x"!==e.match(W,!0)[1]?n.taskOpen=!0:n.taskClosed=!0,t.highlightFormatting&&(n.formatting="task"),n.taskList=!1,d(n)}if(n.taskOpen=!1,n.taskClosed=!1,n.header&&e.match(/^#+$/,!0))return t.highlightFormatting&&(n.formatting="header"),d(n);var i=e.sol(),o=e.next();if("\\"===o&&(e.next(),t.highlightFormatting)){var a=d(n);return a?a+" formatting-escape":"formatting-escape"}if(n.linkTitle){n.linkTitle=!1;var l=o;"("===o&&(l=")"),l=(l+"").replace(/([.?*+^$[\]\\(){}|-])/g,"\\$1");var s="^\\s*(?:[^"+l+"\\\\]+|\\\\\\\\|\\\\.)"+l;if(e.match(new RegExp(s),!0))return R}if("`"===o){var u=n.formatting;t.highlightFormatting&&(n.formatting="code");var c=d(n),f=e.pos;e.eatWhile("`");var h=1+e.pos-f;return n.code?h===E?(n.code=!1,c):(n.formatting=u,d(n)):(E=h,n.code=!0,d(n))}if(n.code)return d(n);if("!"===o&&e.match(/\[[^\]]*\] ?(?:\(|\[)/,!1))return e.match(/\[[^\]]*\]/),I;if("["===o&&e.match(/.*\](\(.*\)| ?\[.*\])/,!1))return n.linkText=!0,t.highlightFormatting&&(n.formatting="link"),d(n);if("]"===o&&n.linkText&&e.match(/\(.*\)| ?\[.*\]/,!1)){t.highlightFormatting&&(n.formatting="link");var a=d(n);return n.linkText=!1,n.inline=n.f=g,a}if("<"===o&&e.match(/^(https?|ftps?):\/\/(?:[^\\>]|\\.)+>/,!1)){n.f=n.inline=p,t.highlightFormatting&&(n.formatting="link");var a=d(n);return a?a+=" ":a="",a+N}if("<"===o&&e.match(/^[^> \\]+@(?:[^\\>]|\\.)+>/,!1)){n.f=n.inline=p,t.highlightFormatting&&(n.formatting="link");var a=d(n);return a?a+=" ":a="",a+B}var v=!1;if(!t.underscoresBreakWords&&"_"===o&&"_"!==e.peek()&&e.match(/(\w)/,!1)){var m=e.pos-2;if(m>=0){var y=e.string.charAt(m);"_"!==y&&y.match(/(\w)/,!1)&&(v=!0)}}if("*"===o||"_"===o&&!v)if(i&&" "===e.peek());else{if(n.strong===o&&e.eat(o)){t.highlightFormatting&&(n.formatting="strong");var c=d(n);return n.strong=!1,c}if(!n.strong&&e.eat(o))return n.strong=o,t.highlightFormatting&&(n.formatting="strong"),d(n);if(n.em===o){t.highlightFormatting&&(n.formatting="em");var c=d(n);return n.em=!1,c}if(!n.em)return n.em=o,t.highlightFormatting&&(n.formatting="em"),d(n)}else if(" "===o&&(e.eat("*")||e.eat("_"))){if(" "===e.peek())return d(n);e.backUp(1)}if(t.strikethrough)if("~"===o&&e.eatWhile(o)){if(n.strikethrough){t.highlightFormatting&&(n.formatting="strikethrough");var c=d(n);return n.strikethrough=!1,c}if(e.match(/^[^\s]/,!1))return n.strikethrough=!0,t.highlightFormatting&&(n.formatting="strikethrough"),d(n)}else if(" "===o&&e.match(/^~~/,!0)){if(" "===e.peek())return d(n);e.backUp(2)}return" "===o&&(e.match(/ +$/,!1)?n.trailingSpace++:n.trailingSpace&&(n.trailingSpaceNewLine=!0)),d(n)}function p(e,n){if(">"===e.next()){n.f=n.inline=h,t.highlightFormatting&&(n.formatting="link");var r=d(n);return r?r+=" ":r="",r+N}return e.match(/^[^>]+/,!0),N}function g(e,n){if(e.eatSpace())return null;var r=e.next();return"("===r||"["===r?(n.f=n.inline=v("("===r?")":"]"),t.highlightFormatting&&(n.formatting="link-string"),n.linkHref=!0,d(n)):"error"}function v(e){return function(n,r){if(n.next()===e){r.f=r.inline=h,t.highlightFormatting&&(r.formatting="link-string");var i=d(r);return r.linkHref=!1,i}return n.match(b(e),!0)&&n.backUp(1),r.linkHref=!0,d(r)}}function m(e,n){return e.match(/^[^\]]*\]:/,!1)?(n.f=y,e.next(),t.highlightFormatting&&(n.formatting="link"),n.linkText=!0,d(n)):r(e,n,h)}function y(e,n){if(e.match(/^\]:/,!0)){n.f=n.inline=_,t.highlightFormatting&&(n.formatting="link");var r=d(n);return n.linkText=!1,r}return e.match(/^[^\]]+/,!0),P}function _(e,t){return e.eatSpace()?null:(e.match(/^[^\s]+/,!0),void 0===e.peek()?t.linkTitle=!0:e.match(/^(?:\s+(?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\)))?/,!0),t.f=t.inline=h,R+" url")}function b(e){return z[e]||(e=(e+"").replace(/([.?*+^$[\]\\(){}|-])/g,"\\$1"),z[e]=new RegExp("^(?:[^\\\\]|\\\\.)*?("+e+")")),z[e]}var w=i.default.modes.hasOwnProperty("xml"),k=i.default.getMode(e,w?{name:"xml",htmlMode:!0}:"text/plain");void 0===t.highlightFormatting&&(t.highlightFormatting=!1),void 0===t.maxBlockquoteDepth&&(t.maxBlockquoteDepth=0),void 0===t.underscoresBreakWords&&(t.underscoresBreakWords=!0),void 0===t.taskLists&&(t.taskLists=!1),void 0===t.strikethrough&&(t.strikethrough=!1);var E=0,C="header",T="comment",M="quote",S="variable-2",O="variable-3",x="keyword",L="hr",I="tag",A="formatting",N="link",B="link",P="link",R="string",D="em",j="strong",$="strikethrough",H=/^([*\-_])(?:\s*\1){2,}\s*$/,F=/^[*\-+]\s+/,U=/^[0-9]+([.)])\s+/,W=/^\[(x| )\](?=\s)/,q=t.allowAtxHeaderWithoutSpace?/^(#+)/:/^(#+)(?: |$)/,V=/^ *(?:\={1,}|-{1,})\s*$/,K=/^[^#!\[\]*_\\<>` "'(~]+/,Y=new RegExp("^("+(!0===t.fencedCodeBlocks?"~~~+|```+":t.fencedCodeBlocks)+")[ \\t]*([\\w+#]*)"),z=[],G={startState:function(){return{f:l,prevLine:null,thisLine:null,block:l,htmlState:null,indentation:0,inline:h,text:f,formatting:!1,linkText:!1,linkHref:!1,linkTitle:!1,em:!1,strong:!1,header:0,hr:!1,task:!1,taskList:!1,list:!1,listDepth:0,quote:0,trailingSpace:0,trailingSpaceNewLine:!1,strikethrough:!1,fencedChars:null}},copyState:function(e){return{f:e.f,prevLine:e.prevLine,thisLine:e.this,block:e.block,htmlState:e.htmlState&&i.default.copyState(k,e.htmlState),indentation:e.indentation,localMode:e.localMode,localState:e.localMode?i.default.copyState(e.localMode,e.localState):null,inline:e.inline,text:e.text,formatting:!1,linkTitle:e.linkTitle,code:e.code,em:e.em,strong:e.strong,strikethrough:e.strikethrough,header:e.header,hr:e.hr,taskList:e.taskList,task:e.task,list:e.list,listDepth:e.listDepth,quote:e.quote,indentedCode:e.indentedCode,trailingSpace:e.trailingSpace,trailingSpaceNewLine:e.trailingSpaceNewLine,md_inside:e.md_inside,fencedChars:e.fencedChars}},token:function(e,t){if(t.formatting=!1,e!=t.thisLine){var n=t.header||t.hr;if(t.header=0,t.hr=!1,e.match(/^\s*$/,!0)||n){if(a(t),!n)return null;t.prevLine=null}t.prevLine=t.thisLine,t.thisLine=e,t.taskList=!1,t.task=!1,t.trailingSpace=0,t.trailingSpaceNewLine=!1,t.f=t.block;var r=e.match(/^\s*/,!0)[0].replace(/\t/g," ").length,i=4*Math.floor((r-t.indentation)/4);i>4&&(i=4);var o=t.indentation+i;if(t.indentationDiff=o-t.indentation,t.indentation=o,r>0)return null}return t.f(e,t)},innerMode:function(e){return e.block==s?{state:e.htmlState,mode:k}:e.localState?{state:e.localState,mode:e.localMode}:{state:e,mode:G}},blankLine:a,getType:d,closeBrackets:"()[]{}''\"\"``",fold:"markdown"};return G},"xml"),i.default.defineMIME("text/x-markdown","markdown")},function(e,t,n){"use strict";var r=n(10),i=function(e){return e&&e.__esModule?e:{default:e}}(r);i.default.defineMode("gfm",function(e,t){function n(e){return e.code=!1,null}var r=0,o={startState:function(){return{code:!1,codeBlock:!1,ateSpace:!1}},copyState:function(e){return{code:e.code,codeBlock:e.codeBlock,ateSpace:e.ateSpace}},token:function(e,t){if(t.combineTokens=null,t.codeBlock)return e.match(/^```+/)?(t.codeBlock=!1,null):(e.skipToEnd(),null);if(e.sol()&&(t.code=!1),e.sol()&&e.match(/^```+/))return e.skipToEnd(),t.codeBlock=!0,null;if("`"===e.peek()){e.next();var n=e.pos;e.eatWhile("`");var i=1+e.pos-n;return t.code?i===r&&(t.code=!1):(r=i,t.code=!0),null}return t.code?(e.next(),null):e.eatSpace()?(t.ateSpace=!0,null):((e.sol()||t.ateSpace)&&(t.ateSpace=!1),e.next(),null)},blankLine:n},a={underscoresBreakWords:!1,taskLists:!0,fencedCodeBlocks:"```",strikethrough:!0};for(var l in t)a[l]=t[l];return a.name="markdown",i.default.overlayMode(i.default.getMode(e,a),o)},"markdown"),i.default.defineMIME("text/x-gfm","gfm")},function(e,t,n){"use strict";var r=n(10),i=function(e){return e&&e.__esModule?e:{default:e}}(r),o=/^(\s*)(>[> ]*|[*+-]\s(?:\[(?:x|\s)\]\s)?|(\d+)([.)]\s(?:\[(?:x|\s)\]\s)?))(\s*)/,a=/^(\s*)(>[> ]*|[*+-]\s(?:\[(?:x|\s)\]\s)?|(\d+)([.)]\s(?:\[(?:x|\s)\]\s)?))(\s*)$/,l=/^ *(`{3,}|~{3,})[ \.]*\S+ */,s=/[*+-]\s/;i.default.commands.subListIndentTab=function(e){if(e.getOption("disableInput"))return i.default.Pass;for(var t=e.listSelections(),n=0;n0)e.replaceRange("",{line:u.line,ch:0},{line:u.line,ch:h.length}),n[r]="\n";else if(p)n[r]="\n\n```";else{var m,y=g[1],_=g[5];m=y.length===u.ch?"":s.test(g[2])||g[2].indexOf(">")>=0?g[2]:parseInt(g[3],10)+1+g[4],n[r]="\n"+y+m+_}}e.replaceSelections(n),p&&e.setCursor(u.line+1,0)}},function(e,t,n){"use strict";function r(e){return i(e)&&e.anchor.ch===e.head.ch}function i(e){return e.anchor.line===e.head.line}function o(e,t,n,i){var o=e.getLine(n.line),a=e.getLine(n.line+i),l={anchor:t,head:n};e.replaceRange(a,{line:n.line,ch:0},{line:n.line,ch:o.length},"+input"),e.replaceRange(o,{line:n.line+i,ch:0},{line:n.line+i,ch:a.length},"+input"),r(l)?e.setCursor({line:n.line+i,ch:n.ch}):e.setSelection({line:t.line+i,ch:t.ch},{line:n.line+i,ch:n.ch})}function a(e,t,n,r){var i=e.getRange({line:t.line,ch:0},{line:n.line,ch:e.getLine(n.line).length}),o=r>0?n:t,a=e.getLine(o.line+r),l=void 0;l=r>0?t:n,e.replaceRange(a,{line:l.line,ch:0},{line:l.line,ch:e.getLine(l.line).length},"+input"),e.replaceRange(i,{line:t.line+r,ch:0},{line:n.line+r,ch:e.getLine(n.line+r).length},"+input"),e.setSelection({line:t.line+r,ch:t.ch},{line:n.line+r,ch:n.ch})}var l=n(10),s=function(e){return e&&e.__esModule?e:{default:e}}(l);s.default.commands.replaceLineTextToUpper=function(e){if(e.getOption("disableInput"))return s.default.Pass;for(var t=e.listSelections(),n=0;n0)o(e,u,c,-1);else if(!r(l)){var d=u.line0){var f=u.line===d?u:c,h=u.line===d?c:u;a(e,f,h,-1)}}}},s.default.commands.replaceLineTextToLower=function(e){if(e.getOption("disableInput"))return s.default.Pass;for(var t=e.listSelections(),n=0;n?!@#$%^&*()_=+\\\/'";: \r[\]]*\|+)+/i,u=/^#+\s/,c=/^ {0,3}(```|\||>)/,d=function(){function e(t){r(this,e),this.mde=t,this.eventManager=t.eventManager,this.name="list"}return i(e,[{key:"isListOrParagraph",value:function(e){return!c.test(e)&&!s.test(e)&&!u.test(e)}},{key:"appendBlankLineIfNeed",value:function(e,t,n,r){var i=e.getDoc(),o=0,a=r!==n,l=i.getLine(this._getEndLineNumberOfList(i,n)+1),s=i.getLine(this._getStartLineNumberOfList(i,r)-1),u=i.getLine(t+1);(a&&this._isNeedAppendBlankLine(l)||!a&&this._isNeedAppendBlankLine(u))&&i.replaceRange("\n",{line:t,ch:i.getLine(t).length});var c=i.getLine(t-1);if((a&&this._isNeedAppendBlankLine(s)||!a&&this._isNeedAppendBlankLine(c))&&(i.replaceRange("\n",{line:r,ch:0}),o+=1),!a){var d=t+o;e.setCursor(d,i.getLine(d).length)}}},{key:"_isNeedAppendBlankLine",value:function(e){return e&&0!==e.length&&!this._isAList(e)}},{key:"createSortedLineRange",value:function(e){var t=e.from.line>e.to.line;return{start:{line:t?e.to.line:e.from.line,ch:0}.line,end:{line:t?e.from.line:e.to.line,ch:0}.line}}},{key:"expandLineRangeIfNeed",value:function(e,t,n){var r=this.createSortedLineRange(t),i=r.start,o=r.end,a=this._isDifferentListType(n,e.getLine(i)),l=this._isDifferentListType(n,e.getLine(o));return a&&(i=this._getStartLineNumberOfList(e,i)),l&&(o=this._getEndLineNumberOfList(e,o)),{start:i,end:o}}},{key:"replaceLineText",value:function(e,t,n,r){var i=e.getLine(t),o={line:t,ch:0},a={line:t,ch:i.length};i=i.replace(n,r),e.replaceRange(i,o,a)}},{key:"_isDifferentListType",value:function(e,t){return t&&0!==t.length&&e.call(this,t)}},{key:"_isAList",value:function(e){return e&&0!==e.length&&this._isListLine(e)}},{key:"_isListLine",value:function(e){return!!(e.match(l)||e.match(a)||e.match(o))}},{key:"_getStartLineNumberOfList",value:function(e,t){var n=void 0;for(n=t;n>0;n-=1){var r=e.getLine(n-1);if(!r||!this._isListLine(r))break}return n}},{key:"_getEndLineNumberOfList",value:function(e,t){var n=e.lineCount(),r=void 0;for(r=t;r(
    |
    |
    |
    )<\/\1>/g,U=/(?:
    |
    |
    |
    )<\/(.+?)>/g,W=/\b(H[\d]|LI|P|BLOCKQUOTE|TD|PRE)\b/,q="undefined"!=typeof MutationObserver,V=function(){function e(t,n){var r=this,o=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};i(this,e),this.componentManager=new D.default(this),this.eventManager=n,this.$editorContainerEl=t,this._height=0,this._silentChange=!1,this._keyEventHandlers={},this._managers={},this._options=l.default.extend({useCommandShortcut:!0},o),this._initEvent(),this._initDefaultKeyEventHandler(),this.debouncedPostProcessForChange=u.default.debounce(function(){return r.postProcessForChange()},0)}return o(e,[{key:"init",value:function(){var e=(0,l.default)("
    ");this.$editorContainerEl.append(e),this.editor=new I.default(e[0],{blockTag:"DIV",leafNodeNames:{HR:!1}}),this._options.useCommandShortcut||this.editor.blockCommandShortcuts(),this._clipboardManager=new h.default(this),this._initSquireEvent(),this._clipboardManager.init(),this.get$Body().addClass("tui-editor-contents"),this.$editorContainerEl.css("position","relative"),this.codeBlockGadget=new $.default({eventManager:this.eventManager,container:this.$editorContainerEl,wysiwygEditor:this})}},{key:"_preprocessForInlineElement",value:function(e){return e.replace(/
    ( *)
    $1B|>STRONG|^B$|^STRONG$)/.test(t.path),italic:/(>I|>EM|^I$|^EM$)/.test(t.path),strike:/(^S>|>S$|>S>|^S$)/.test(t.path),code:/CODE/.test(t.path),codeBlock:/PRE/.test(t.path),quote:/BLOCKQUOTE/.test(t.path),list:/LI(?!.task-list-item)/.test(e._getLastLiString(t.path)),task:/LI.task-list-item/.test(e._getLastLiString(t.path)),source:"wysiwyg"};e.eventManager.emit("stateChange",n)}),t.addEventListener("willPaste",function(t){e.eventManager.emit("willPaste",{source:"wysiwyg",data:t})})}},{key:"_getLastLiString",value:function(e){var t=/LI[^UO]*$/.exec(e);return t?t[0]:""}},{key:"_onKeyDown",value:function(e){var t=H.convert(e);e.keyCode&&(this.eventManager.emit("keyMap",{source:"wysiwyg",keyMap:t,data:e}),e.defaultPrevented||this.eventManager.emit("wysiwygKeyEvent",{keyMap:t,data:e}))}},{key:"_initDefaultKeyEventHandler",value:function(){var e=this;this.addKeyEventHandler("ENTER",function(t,n){e._isInOrphanText(n)&&e.defer(function(){e._wrapDefaultBlockToOrphanTexts(),e.breakToNewDefaultBlock(n,"before")}),e.defer(function(){e._scrollToRangeIfNeed()})}),this.addKeyEventHandler("TAB",function(t){var n=e.getEditor(),r=n.getSelection(),i=r.collapsed&&e._isCursorNotInRestrictedAreaOfTabAction(n),o=!r.collapsed&&d.default.isTextNode(r.commonAncestorContainer);return t.preventDefault(),!i&&!o||(n.insertPlainText("    "),!1)})}},{key:"_wrapDefaultBlockToOrphanTexts",value:function(){this.get$Body().contents().filter(this.findTextNodeFilter).each(function(e,t){t.nextSibling&&"BR"===t.nextSibling.tagName&&(0,l.default)(t.nextSibling).remove(),(0,l.default)(t).wrap("
    ")})}},{key:"_scrollToRangeIfNeed",value:function(){var e=this.$editorContainerEl,t=this.getRange();if(this.getEditor().getCursorPosition(t).top-e.offset().top>=e.height()){var n=t.endContainer;n instanceof Element||(n=n.parentNode),n.scrollIntoView(!1)}}},{key:"_isInOrphanText",value:function(e){return e.startContainer.nodeType===Node.TEXT_NODE&&e.startContainer.parentNode===this.get$Body()[0]}},{key:"_wrapDefaultBlockTo",value:function(e){this.saveSelection(e),this._joinSplitedTextNodes(),this.restoreSavedSelection(),e=this.getRange();var t=e.startContainer,n=e.startOffset,r=this.getEditor().createDefaultBlock([e.startContainer]),i=d.default.getChildNodeByOffset(e.startContainer,e.startOffset);i?e.setStartBefore(i):e.selectNodeContents(e.startContainer),e.collapse(!0),e.insertNode(r),e.setStart(t,n),e.collapse(!0),this.setRange(e)}},{key:"findTextNodeFilter",value:function(){return this.nodeType===Node.TEXT_NODE}},{key:"_joinSplitedTextNodes",value:function(){var e=void 0,t=void 0,n=[];this.get$Body().contents().filter(this.findTextNodeFilter).each(function(r,i){e===i.previousSibling?(t.nodeValue+=i.nodeValue,n.push(i)):t=i,e=i}),(0,l.default)(n).remove()}},{key:"saveSelection",value:function(e){e||(e=this.getRange()),this.getEditor()._saveRangeToBookmark(e)}},{key:"restoreSavedSelection",value:function(){this.setRange(this.getEditor()._getRangeAndRemoveBookmark())}},{key:"reset",value:function(){this.setValue("")}},{key:"changeBlockFormatTo",value:function(e){this.getEditor().changeBlockFormatTo(e),this.eventManager.emit("wysiwygRangeChangeAfter",this)}},{key:"makeEmptyBlockCurrentSelection",value:function(){var e=this;this.getEditor().modifyBlocks(function(t){return t.textContent||(t=e.getEditor().createDefaultBlock()),t})}},{key:"focus",value:function(){var e=this.scrollTop();this.editor.focus(),e!==this.scrollTop()&&this.scrollTop(e)}},{key:"blur",value:function(){this.editor.blur()}},{key:"remove",value:function(){this.getEditor().destroy(),this.editor=null,this.$body=null,this.eventManager=null}},{key:"setHeight",value:function(e){this._height=e,this.$editorContainerEl.css("overflow","auto"),this.$editorContainerEl.css("height","100%"),this.$editorContainerEl.parent().height(e);var t=parseInt(this.$editorContainerEl.css("padding-top"),10)-parseInt(this.$editorContainerEl.css("padding-bottom"),10),n=parseInt(this.get$Body().css("margin-top"),10)-parseInt(this.get$Body().css("margin-bottom"),10);this.get$Body().css("min-height",e-n-t+"px")}},{key:"setMinHeight",value:function(e){this.get$Body().get(0).style.minHeight=e+"px"}},{key:"setValue",value:function(e){var t=!(arguments.length>1&&void 0!==arguments[1])||arguments[1];e=this.eventManager.emitReduce("wysiwygSetValueBefore",e),this.editor.setHTML(e),this.eventManager.emit("wysiwygSetValueAfter",this),this.eventManager.emit("contentChangedFromWysiwyg",this),t&&this.moveCursorToEnd(),this.getEditor().preserveLastLine(),this.getEditor().removeLastUndoStack(),this.getEditor().saveUndoState()}},{key:"insertText",value:function(e){this.editor.insertPlainText(e)}},{key:"getValue",value:function(){this._prepareGetHTML();var e=this.editor.getHTML();return e=e.replace(F,function(e,t){return"li"===t?e:"td"===t||"th"===t?"<"+t+">":"
    "}),e=e.replace(U,""),e=e.replace(/]*>/g,""),e=e.replace(/<\/div>/g,"
    "),e=this.eventManager.emitReduce("wysiwygProcessHTMLText",e)}},{key:"_prepareGetHTML",value:function(){var e=this;this.getEditor().modifyDocument(function(){e._joinSplitedTextNodes(),e.eventManager.emit("wysiwygGetValueBefore",e)})}},{key:"postProcessForChange",value:function(){var e=this;this.isEditorValid()&&this.getEditor().modifyDocument(function(){e.eventManager.emit("wysiwygRangeChangeAfter",e)})}},{key:"readySilentChange",value:function(){q&&!this.getEditor().isIgnoreChange()&&(this._silentChange=!0)}},{key:"getEditor",value:function(){return this.editor}},{key:"replaceSelection",value:function(e,t){this.getEditor().replaceSelection(e,t)}},{key:"replaceRelativeOffset",value:function(e,t,n){this.getEditor().replaceRelativeOffset(e,t,n)}},{key:"addWidget",value:function(e,t,n,r){var i=this.getEditor().getSelectionPosition(e,n,r),o=this.$editorContainerEl.offset();this.$editorContainerEl.append(t),(0,l.default)(t).css({position:"absolute",top:i.top-o.top,left:i.left-o.left})}},{key:"get$Body",value:function(){return this.getEditor().get$Body()}},{key:"hasFormatWithRx",value:function(e){return this.getEditor().getPath().match(e)}},{key:"breakToNewDefaultBlock",value:function(e,t){var n=this.editor.createDefaultBlock(),r=d.default.getChildNodeByOffset(e.startContainer,e.startOffset)||d.default.getChildNodeByOffset(e.startContainer,e.startOffset-1),i=d.default.getParentUntil(r,this.get$Body()[0]);"before"===t?(0,l.default)(i).before(n):(0,l.default)(i).after(n),e.setStart(n,0),e.collapse(!0),this.setRange(e)}},{key:"replaceContentText",value:function(e,t,n){var r=(0,l.default)(e).html();(0,l.default)(e).html(r.replace(t,n))}},{key:"unwrapBlockTag",value:function(e){e||(e=function(e){return W.test(e)}),this.getEditor().changeBlockFormat(e),this.eventManager.emit("wysiwygRangeChangeAfter",this)}},{key:"moveCursorToEnd",value:function(){this.getEditor().moveCursorToEnd();var e=this.get$Body().get(0).childNodes;e.length>0&&e[e.length-1].scrollIntoView(!1),this._correctRangeAfterMoveCursor("end")}},{key:"moveCursorToStart",value:function(){this.getEditor().moveCursorToStart(),this.scrollTop(0)}},{key:"scrollTop",value:function(e){return u.default.isUndefined(e)?this.$editorContainerEl.scrollTop():this.$editorContainerEl.scrollTop(e)}},{key:"_correctRangeAfterMoveCursor",value:function(e){var t=this.getRange(),n=this.get$Body().get(0);if("start"===e)for(;n.firstChild;)n=n.firstChild;else for(;n.lastChild;)n=n.lastChild;"BR"===n.tagName?t.setStartBefore(n):t.setStartAfter(n),t.collapse(!0),this.setRange(t)}},{key:"getRange",value:function(){return this.getEditor().getSelection().cloneRange()}},{key:"setRange",value:function(e){this.getEditor().setSelection(e)}},{key:"getTextObject",value:function(e){return new P.default(this,e)}},{key:"defer",value:function(e,t){var n=this,r=t||0;setTimeout(function(){n.isEditorValid()&&e(n)},r)}},{key:"isEditorValid",value:function(){return this.getEditor()&&l.default.contains(this.$editorContainerEl[0].ownerDocument,this.$editorContainerEl[0])}},{key:"_isCursorNotInRestrictedAreaOfTabAction",value:function(e){return!e.hasFormat("li")&&!e.hasFormat("blockquote")&&!e.hasFormat("table")}}],[{key:"factory",value:function(t,n,r){var i=new e(t,n,r);return i.init(),i.componentManager.addManager(g.default),i.componentManager.addManager(m.default),i.componentManager.addManager(w.default),i.componentManager.addManager(_.default),i.componentManager.addManager(E.default),i.componentManager.addManager(T.default),i.componentManager.addManager(S.default),i.componentManager.addManager(x.default),i}}]),e}();t.default=V},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(t,"__esModule",{value:!0});var o=function(){function e(e,t){for(var n=0;n");this._extendRange(i),o.append(i.cloneContents()),this._updateCopyDataForListTypeIfNeed(i,o),this.wwe.eventManager.emit("copyBefore",{source:"wysiwyg",$clipboardContainer:o}),this._setClipboardData(r,o.html(),o.text())}}},{key:"_clearClipboardArea",value:function(){this._$clipboardArea&&(this._$clipboardArea.remove(),this._$clipboardArea=null)}},{key:"_onCopyAfter",value:function(){this.wwe.getEditor().get$Body().focus(),this._clearClipboardArea()}},{key:"_onCutAfter",value:function(){this.wwe.getEditor().getSelection().deleteContents(),this.wwe.getEditor().focus(),this._clearClipboardArea()}},{key:"_onWillPaste",value:function(e){var t=this,n=(0,l.default)("
    ").append(e.fragment.cloneNode(!0));this._setTableBookmark(n),this._pasteToTable(n)?e.preventDefault():(this._preparePaste(n),this._setTableBookmark(n),e.fragment=document.createDocumentFragment(),(0,l.default)(n[0].childNodes).each(function(t,n){e.fragment.appendChild(n)}));var r=function e(){t.wwe.getEditor().removeEventListener("input",e),t.wwe.eventManager.emit("wysiwygRangeChangeAfter",t),t._focusTableBookmark()};this.wwe.getEditor().addEventListener("input",r)}},{key:"_setClipboardData",value:function(e,t,n){u.default.browser.msie?(e.squirePrevented=!0,this._$clipboardArea=this._createClipboardArea(),this._$clipboardArea.html(t),this._$clipboardArea.focus(),window.getSelection().selectAllChildren(this._$clipboardArea[0])):(e.preventDefault(),e.stopPropagation(),e.clipboardData.setData("text/html",t),e.clipboardData.setData("text/plain",n))}},{key:"_createClipboardArea",value:function(){return(0,l.default)("
    ").attr({contenteditable:"true",style:"position:fixed; overflow:hidden; top:0; right:100%; width:1px; height:1px;"}).appendTo(document.body)}},{key:"_updateCopyDataForListTypeIfNeed",value:function(e,t){var n=e.commonAncestorContainer.nodeName;if("UL"===n||"OL"===n){var r=(0,l.default)("<"+n+" />");r.append(t.html()),t.html(""),t.append(r)}}},{key:"_removeEmptyFontElement",value:function(e){e.children("font").each(function(e,t){var n=(0,l.default)(t);n.text().trim()||n.remove()})}},{key:"_pasteToTable",value:function(e){var t=this.wwe.componentManager.getManager("table"),n=this.wwe.componentManager.getManager("tableSelection"),r=this.wwe.getEditor().getSelection(),i=t.isInTable(r),o=e.get(0),a=o.childNodes,l=1===a.length&&"TABLE"===a[0].nodeName,s=!1;return i&&(l?(t.pasteClipboardData(e.first()),e.html(""),s=!0):n.getSelectedCells().length&&(alert(g.default.get("Cannot paste values ​​other than a table in the cell selection state")),e.html(""),s=!0)),s}},{key:"_preparePaste",value:function(e){this._removeEmptyFontElement(e),this._pch.preparePaste(e),this.wwe.eventManager.emit("pasteBefore",{source:"wysiwyg",$clipboardContainer:e})}},{key:"_setTableBookmark",value:function(e){var t=(0,l.default)(e[0].childNodes).last();t[0]&&"TABLE"===t[0].nodeName&&t.addClass("tui-paste-table-bookmark")}},{key:"_focusTableBookmark",value:function(){var e=this.wwe.getEditor(),t=e.getSelection().cloneRange(),n=e.get$Body().find(".tui-paste-table-bookmark"),r=e.get$Body().find(".tui-paste-table-cell-bookmark");n.length&&(n.removeClass("tui-paste-table-bookmark"),t.setEndAfter(n[0]),t.collapse(!1),e.setSelection(t)),r.length&&(r.removeClass("tui-paste-table-cell-bookmark"),t.selectNodeContents(r[0]),t.collapse(!1),e.setSelection(t))}},{key:"_extendRange",value:function(e){(!d.default.isTextNode(e.commonAncestorContainer)||0===e.startOffset&&e.commonAncestorContainer.textContent.length===e.endOffset||"TD"===e.commonAncestorContainer.nodeName)&&(0===e.startOffset&&(e=this._extendStartRange(e)),e.endOffset===d.default.getOffsetLength(e.endContainer)&&(e=this._extendEndRange(e)),this._isWholeCommonAncestorContainerSelected(e)&&e.selectNode(e.commonAncestorContainer),this.wwe.getEditor().setSelection(e))}},{key:"_extendStartRange",value:function(e){for(var t=e.startContainer;t.parentNode!==e.commonAncestorContainer&&t.parentNode!==this.wwe.get$Body()[0]&&!t.previousSibling;)t=t.parentNode;return e.setStart(t.parentNode,d.default.getNodeOffsetOfParent(t)),e}},{key:"_extendEndRange",value:function(e){for(var t=e.endContainer,n=t.nextSibling;t.parentNode!==e.commonAncestorContainer&&t.parentNode!==this.wwe.get$Body()[0]&&(!n||"BR"===d.default.getNodeName(n)&&t.parentNode.lastChild===n);)t=t.parentNode,n=t.nextSibling;return e.setEnd(t.parentNode,d.default.getNodeOffsetOfParent(t)+1),e}},{key:"_isWholeCommonAncestorContainerSelected",value:function(e){return e.commonAncestorContainer.nodeType===Node.ELEMENT_NODE&&e.commonAncestorContainer!==this.wwe.get$Body()[0]&&0===e.startOffset&&e.endOffset===e.commonAncestorContainer.childNodes.length&&e.commonAncestorContainer===e.startContainer&&e.commonAncestorContainer===e.endContainer}}]),e}();t.default=v},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(t,"__esModule",{value:!0});var o=function(){function e(e,t){for(var n=0;n"),o=void 0,a=void 0,s=void 0;this._pasteFirstAid(e);var c=u.default.toArray(e[0].childNodes);for(c.length&&"DIV"===c[0].tagName&&(i.append(this._unwrapFragmentFirstChildForPasteAsInline(c[0])),c.shift());c.length;)a=c[0],o=d.default.getNodeName(a),s="LI"===o||"UL"===o||"OL"===o,n.isInCodeBlock(t)?i.append(n.prepareToPasteOnCodeblock(c)):s?(i.append(this._prepareToPasteList(c,t,r)),r=!0):i.append(c.shift());e.html(i.html())}},{key:"_wrapOrphanNodeWithDiv",value:function(e){var t=(0,l.default)("
    "),n=u.default.toArray(e[0].childNodes),r=void 0;return u.default.forEachArray(n,function(e){var n=3===e.nodeType,i=/^(SPAN|A|CODE|EM|I|STRONG|B|S|ABBR|ACRONYM|CITE|DFN|KBD|SAMP|VAR|BDO|Q|SUB|SUP)$/gi.test(e.tagName);n||i?(r||(r=document.createElement("div"),t.append(r)),r.appendChild(e)):(r&&"BR"!==r.lastChild.tagName&&r.appendChild((0,l.default)("
    ")[0]),r=null,t.append(e))}),t.html()}},{key:"_pasteFirstAid",value:function(e){var t=this,n="div, section, article, aside, nav, menus, p";e.html((0,h.default)(e.html(),!0)),e.find("*").each(function(e,n){t._removeStyles(n)}),this._unwrapIfNonBlockElementHasBr(e),this._unwrapNestedBlocks(e,n),this._removeUnnecessaryBlocks(e,n),e.html(this._wrapOrphanNodeWithDiv(e)),this._preElementAid(e),this._tableElementAid(e),e.children("br").remove()}},{key:"_preElementAid",value:function(e){this.wwe.componentManager.getManager("codeblock").splitCodeblockToEachLine(e)}},{key:"_unwrapIfNonBlockElementHasBr",value:function(e){e.find("span, a, b, em, i, s").each(function(e,t){var n=(0,l.default)(t).children("br");n.length&&"LI"!==t.nodeName&&"UL"!==t.nodeName&&n.eq(0).unwrap()})}},{key:"_unwrapNestedBlocks",value:function(e,t){e.find(":not(:has(*))").not("b,s,i,em,code,span").each(function(n,r){for(var i="BR"===r.nodeName?(0,l.default)(r.parentNode):(0,l.default)(r);i.parents(t).length;){var o=i.parent(t);o.length&&o[0]!==e[0]?i.unwrap():i=i.parent()}})}},{key:"_removeUnnecessaryBlocks",value:function(e,t){e.find(t).each(function(e,n){var r=(0,l.default)(n),i=n.tagName,o="DIV"===i,a=0!==r.parent("li").length,s=0!==r.parent("blockquote").length,u=r.children(t).length;o&&(a||s||!u)||r.replaceWith(r.html())})}},{key:"_removeStyles",value:function(e){var t=(0,l.default)(e),n=void 0;"SPAN"!==d.default.getNodeName(t[0])?t.removeAttr("style"):(t.attr("style")&&(n=t.css("color")),t.removeAttr("style"),n?t.css("color",n):t.contents().unwrap())}},{key:"_prepareToPasteList",value:function(e,t,n){var r=d.default.getNodeName(e[0]),i=e.shift(),o=this.wwe.getEditor().getDocument().createDocumentFragment();if("LI"!==r&&e.length&&"LI"===e[0].tagName&&(r="LI",i=this._makeNodeAndAppend({tagName:r},i)),"OL"===r||"UL"===r)!n&&this.wwe.getEditor().hasFormat("LI")?(0,l.default)(o).append(this._wrapCurrentFormat(i)):(0,l.default)(o).append(i);else if("LI"===r){var a=this.wwe.getEditor().getDocument().createDocumentFragment();for(a.appendChild(i);e.length&&"LI"===e[0].tagName;)a.appendChild(e.shift());!n&&this.wwe.getEditor().hasFormat("LI")?(0,l.default)(o).append(this._wrapCurrentFormat(a)):!t||"UL"!==t.commonAncestorName&&"OL"!==t.commonAncestorName?(0,l.default)(o).append(this._makeNodeAndAppend({tagName:"UL"},a)):(0,l.default)(o).append(this._makeNodeAndAppend({tagName:t.commonAncestorName},a))}return o}},{key:"_unwrapFragmentFirstChildForPasteAsInline",value:function(e){return(0,l.default)(e).find("br").remove(),e.childNodes}},{key:"_wrapCurrentFormat",value:function(e){var t=this,n=void 0;return this._eachCurrentPath(function(r){"DIV"!==r.tagName&&(n=d.default.isElemNode(e)?e.tagName:e.firstChild.tagName,r.tagName!==n&&(e=t._makeNodeAndAppend(r,e)))}),e}},{key:"_eachCurrentPath",value:function(e){for(var t=d.default.getPath(this.wwe.getEditor().getSelection().startContainer,this.wwe.get$Body()[0]),n=t.length-1;n>-1;n-=1)e(t[n])}},{key:"_makeNodeAndAppend",value:function(e,t){var n=(0,l.default)("<"+e.tagName+"/>");return n.append(t),e.id&&n.attr("id",e.id),e.className&&n.addClass(e.className),n[0]}},{key:"_tableElementAid",value:function(e){this._completeTableIfNeed(e),this._updateTableIDClassName(e)}},{key:"_completeTableIfNeed",value:function(e){var t=this.wwe.componentManager.getManager("table"),n=t.wrapDanglingTableCellsIntoTrIfNeed(e);n&&e.append(n);var r=t.wrapTrsIntoTbodyIfNeed(e);r&&e.append(r);var i=t.wrapTheadAndTbodyIntoTableIfNeed(e);i&&e.append(i)}},{key:"_updateTableIDClassName",value:function(e){var t=this.wwe.componentManager.getManager("table");e.find("table").each(function(e,t){(0,l.default)(t).removeClass(function(e,t){return t.replace(/.*\s*(te-content-table-\d+)\s*.*/,"$1")})}),e.find("table").each(function(e,n){(0,l.default)(n).addClass(t.getTableIDClassName())})}}]),e}();t.default=p},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(t,"__esModule",{value:!0});var o=function(){function e(e,t){for(var n=0;n(
    |
    ){0,}<\1>/g,":BLANK_LINE:<$1>")}},{key:"_convertToArbitraryNestingList",value:function(e){var t=document.createElement("div");t.innerHTML=e;for(var n=t.querySelector("li > ul, li > ol");null!==n;){var r=n.parentNode;r.parentNode.insertBefore(n,r.nextElementSibling),n=t.querySelector("li > ul, li > ol")}return t.innerHTML}},{key:"_convertFromArbitraryNestingList",value:function(e){var t=document.createElement("div");t.innerHTML=e;for(var n=t.querySelector("ol > ol, ol > ul, ul > ol, ul > ul");null!==n;){for(var r=n.previousElementSibling;"LI"!==r.tagName;)r=r.previousElementSibling;r.appendChild(n),n=t.querySelector("ol > ol, ol > ul, ul > ol, ul > ul")}return t.innerHTML}},{key:"getLinesOfSelection",value:function(e,t){var n=[],r=!1,i=!0,o=void 0;u.default.isTextNode(e)&&(e=(0,l.default)(e).parents("DIV,LI").first().get(0)),u.default.isTextNode(t)&&(t=(0,l.default)(t).parents("DIV,LI").first().get(0));for(var a=e;i&&(0,l.default)(a).is("DIV,LI");a=o)n.push(a),a===t?r=!0:o=this._getNextLine(a,t),i=o&&!r;return n}},{key:"_getNextLine",value:function(e,t){var n=e.nextElementSibling;return n?(0,l.default)(n).is("OL,UL")&&(n=n.querySelector("li")):n=e.parentNode.nextElementSibling,(0,l.default)(n).is("DIV,LI")||n===t?n:this._getNextLine(n)}},{key:"mergeList",value:function(e){var t=e.parentNode,n=t.previousElementSibling,r=t.nextElementSibling;t.firstElementChild===e&&n&&(0,l.default)(n).is("OL,UL")&&(this._mergeList(t,n),t=n),t.lastElementChild===e&&r&&(0,l.default)(r).is("OL,UL")&&this._mergeList(r,t)}},{key:"_mergeList",value:function(e,t){var n=e.firstElementChild;if(t&&(0,l.default)(t).is("OL,UL")){for(;n;){var r=n.nextElementSibling;t.appendChild(n),n=r}e.parentNode.removeChild(e)}}}]),e}();t.default=d},function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(t,"__esModule",{value:!0});var i=function(){function e(e,t){for(var n=0;n")})}}]),e}();t.default=d},function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(t,"__esModule",{value:!0});var i=function(){function e(e,t){for(var n=0;n");t.html(e),t.find("p").each(function(e,t){var n=t.innerHTML,r=n.split(/
    /gi),i=r.length-1,o=t.nextElementSibling||t.nextSibling,l="";l=r.map(function(e,t){var n="";return t>0&&t"),e&&(n="
    "+e+"
    "),n}),o&&"P"===o.nodeName&&l.push("

    "),(0,a.default)(t).replaceWith((0,a.default)(l.join("")))}),e=t.html()}return e}},{key:"_ensurePtagContentWrappedWithDiv",value:function(){this.wwe.get$Body().find("p").each(function(e,t){(0,a.default)(t).find("div").length<=0&&(0,a.default)(t).wrapInner("
    "),(0,a.default)(t).next().is("p")&&(0,a.default)(t).append("

    ")})}},{key:"_unwrapPtags",value:function(){this.wwe.get$Body().find("div").each(function(e,t){(0,a.default)(t).parent().is("p")&&(0,a.default)(t).unwrap()})}}]),e}();t.default=l},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(t,"__esModule",{value:!0});var o=function(){function e(e,t){for(var n=0;n")})}},{key:"_unwrapHeading",value:function(){this.wwe.unwrapBlockTag(function(e){return c.test(e)})}},{key:"_onEnter",value:function(e,t){var n=this;t.startOffset>0?this.wwe.defer(function(e){n._unwrapHeading(),e.getEditor().removeLastUndoStack()}):(e.preventDefault(),this._insertEmptyBlockToPrevious(t))}},{key:"_insertEmptyBlockToPrevious",value:function(e){this.wwe.getEditor().saveUndoState(e),(0,l.default)("

    ").insertBefore(u.default.getParentUntil(e.startContainer,this.wwe.get$Body()[0]))}},{key:"_removePrevTopNodeIfNeed",value:function(e,t){var n=!1;if(t.collapsed&&0===t.startOffset){var r=t.startContainer,i=u.default.getTopPrevNodeUnder(r,this.wwe.get$Body()[0]),o=i&&0===i.textContent.length,a=this.wwe.getEditor();0===r.textContent.length?n=this._removeHedingAndChangeSelection(e,t,i):o&&(e.preventDefault(),a.saveUndoState(t),(0,l.default)(i).remove(),n=!0)}return n}},{key:"_removeHedingAndChangeSelection",value:function(e,t,n){var r=t.startContainer,i=this.wwe.getEditor(),o=this.wwe.get$Body(),a=c.test(u.default.getNodeName(r)),s=a?r:(0,l.default)(r).parents("h1,h2,h3,h4,h5,h6")[0],d=n,f=1;return e.defaultPrevented||(e.preventDefault(),i.saveUndoState(t)),(0,l.default)(s).remove(),n||(d=o.children("div").first().get(0),f=0),t.setStart(d,f),t.collapse(!0),i.setSelection(t),!0}}]),e}();t.default=d},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(t,"__esModule",{value:!0});var l=function(){function e(e,t){for(var n=0;n1)throw new Error("too many"+e+"handlers in squire");var n=t[0].bind(this);t[0]=function(e){e.defaultPrevented||e.squirePrevented||n(e)}}},{key:"changeBlockFormat",value:function(e,t){var n=this;this.modifyBlocks(function(r){var i=void 0,o=void 0,a=void 0,l=void 0,s=void 0,u=void 0,c=void 0;if(r.childNodes.length?i=r.childNodes.item(0):(i=n.createDefaultBlock(),r.appendChild(i)),e){for(;i.firstChild;)i=i.firstChild;for(c=function(e){l.appendChild(e)};i!==r;){if(s=i.tagName,d.default.isFunction(e)?e(s):s===e){l=i.childNodes.item(0),(!g.default.isElemNode(l)||i.childNodes.length>1)&&(l=n.createDefaultBlock(),d.default.forEachArray(d.default.toArray(i.childNodes),c),(u=l.lastChild)&&"BR"===g.default.getNodeName(u)&&l.removeChild(u)),a=t?n.createElement(t,[l]):l,o=n.getDocument().createDocumentFragment(),o.appendChild(a),r=o;break}i=i.parentNode}}return o&&e||!t||"DIV"!==g.default.getNodeName(r.childNodes[0])||(r=n.createElement(t,[r.childNodes[0]])),r})}},{key:"changeBlockFormatTo",value:function(e){this.changeBlockFormat(function(e){return v.test(e)},e)}},{key:"getCaretPosition",value:function(){return this.getCursorPosition()}},{key:"replaceSelection",value:function(e,t){t&&this.setSelection(t),this._ignoreChange=!0,this.insertHTML(e)}},{key:"replaceRelativeOffset",value:function(e,t,n){var r=this.getSelection().cloneRange();this._replaceRelativeOffsetOfSelection(e,t,n,r)}},{key:"_replaceRelativeOffsetOfSelection",value:function(e,t,n,r){var i=void 0,o=void 0,a=void 0,l=r.endContainer,s=r.endOffset;"TEXT"!==g.default.getNodeName(l)&&(l=this._getClosestTextNode(l,s))&&(s=g.default.isTextNode(l)?l.nodeValue.length:l.textContent.length),l?(i=this.getSelectionInfoByOffset(l,s+t),r.setStart(i.element,i.offset),a=s+(t+n),o=this.getSelectionInfoByOffset(l,a),r.setEnd(o.element,o.offset),this.replaceSelection(e,r)):this.replaceSelection(e)}},{key:"_getClosestTextNode",value:function(e,t){var n=g.default.getChildNodeByOffset(e,t-1);return"TEXT"!==g.default.getNodeName(n)&&(n=n.previousSibling),n}},{key:"getSelectionInfoByOffset",value:function(e,t){var n=void 0,r=void 0,i=void 0,o=void 0,a=t>=0?"next":"previous",l=Math.abs(t),s=n;for(n="next"===a?e:e.previousSibling,i=l,o=0;n&&(r=g.default.isTextNode(n)?n.nodeValue.length:n.textContent.length,o+=r,!(l<=o));)i-=r,g.default.getTextLength(n)>0&&(s=n),n=n[a+"Sibling"];return n||(n=s,i=g.default.getTextLength(n)),"previous"===a&&(i=g.default.getTextLength(n)-i),{element:n,offset:i}}},{key:"getSelectionPosition",value:function(e,t,n){var r=this.createElement("INPUT"),i=e.cloneRange(),o=this.getSelectionInfoByOffset(e.endContainer,e.endOffset+(n||0));i.setStart(i.startContainer,i.startOffset),i.setEnd(o.element,o.offset),this._ignoreChange=!0,this.insertElement(r,i);var a=(0,u.default)(r).offset();return"over"!==t&&(a.top+=(0,u.default)(r).outerHeight()),r.parentNode.removeChild(r),e.setStart(e.endContainer,e.endOffset),e.collapse(!0),this.setSelection(e),a}},{key:"removeLastUndoStack",value:function(){this._undoStack.length&&(this._undoStackLength-=1,this._undoIndex-=1,this._undoStack.pop(),this._isInUndoState=!1)}},{key:"replaceParent",value:function(e,t,n){var r=(0,u.default)(e).closest(t);r.length&&(r.wrapInner("<"+n+"/>"),r.children().unwrap())}},{key:"preserveLastLine",value:function(){var e=this.get$Body().children().last();"DIV"!==g.default.getNodeName(e[0])&&(this._ignoreChange=!0,(0,u.default)(this.createDefaultBlock()).insertAfter(e))}},{key:"scrollTop",value:function(e){return d.default.isUndefined(e)?this.get$Body().scrollTop():this.get$Body().scrollTop(e)}},{key:"isIgnoreChange",value:function(){return this._ignoreChange}},{key:"focus",value:function(){h.default.prototype.focus.call(this)}},{key:"blockCommandShortcuts",value:function(){var e=this,t=/Mac/.test(navigator.platform),n=t?"meta":"ctrl";["b","i","u","shift-7","shift-5","shift-6","shift-8","shift-9","[","]"].forEach(function(t){e.setKeyHandler(n+"-"+t,function(e,t){t.preventDefault()})})}}]),t}(h.default);t.default=y},function(e,t){e.exports=o},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(t,"__esModule",{value:!0});var o=function(){function e(e,t){for(var n=0;n0&&e.setStart(e.startContainer,e.startOffset-1)}},{key:"expandEndOffset",value:function(){var e=this._range;u.default.isTextNode(e.endContainer)&&e.endOffsettext"),this.$el.append(this._$languageLabel),this._$buttonOpenModalEditor=(0,c.default)(''),this.$el.append(this._$buttonOpenModalEditor)}},{key:"_initDOMEvent",value:function(){var e=this;this._$buttonOpenModalEditor.on("click",function(){return e._openPopupCodeBlockEditor()})}},{key:"_openPopupCodeBlockEditor",value:function(){this._eventManager.emit("openPopupCodeBlockEditor",this.getAttachedElement())}},{key:"_updateLanguage",value:function(){var e=this.getAttachedElement(),t=e?e.getAttribute("data-language"):null;this._$languageLabel.text(t||"text")}},{key:"syncLayout",value:function(){var e=(0,c.default)(this.getAttachedElement()),t=e.offset();t.left=t.left+(e.outerWidth()-250),this.$el.offset(t),this.$el.height(30),this.$el.width(250)}},{key:"onShow",value:function(){var e=this;s(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"onShow",this).call(this),this._onAttachedElementChange=function(){return e._updateLanguage()},(0,c.default)(this.getAttachedElement()).on("language-changed",this._onAttachedElementChange),this._updateLanguage()}},{key:"onHide",value:function(){(0,c.default)(this.getAttachedElement()).off("language-changed",this._onAttachedElementChange),s(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"onHide",this).call(this)}}]),t}(f.default);t.default=h},function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(t,"__esModule",{value:!0});var i=function(){function e(e,t){for(var n=0;n'),this.$el.css({position:"absolute",display:"none","z-index":1}),this._$container.append(this.$el)}},{key:"_initEvent",value:function(){var e=this;this._eventManager.listen("change",this._onChange.bind(this)),this._eventManager.listen("mouseover",this._onMouseOver.bind(this)),this._eventManager.listen("focus",function(){e.setVisibility(!1)}),this._eventManager.listen("mousedown",function(){e.setVisibility(!1)})}},{key:"_onChange",value:function(){this._$attachedElement&&a.default.contains(document,this._$attachedElement[0])?this.syncLayout():this.setVisibility(!1)}},{key:"_onMouseOver",value:function(e){var t=e.data,n=(0,a.default)(t.target),r=n.closest(this._attachedSelector);r.length?(this._$attachedElement=r,this.setVisibility(!0)):n.closest(this.$el).length?this.setVisibility(!0):this.active||this.setVisibility(!1)}},{key:"syncLayout",value:function(){this.$el.offset(this._$attachedElement.offset()),this.$el.width(this._$attachedElement.outerWidth()),this.$el.height(this._$attachedElement.outerHeight())}},{key:"getAttachedElement",value:function(){return this._$attachedElement?this._$attachedElement.get(0):null}},{key:"getVisibility",value:function(){return"block"===this.$el.css("display")}},{key:"setVisibility",value:function(e){e&&this._$attachedElement?this.getVisibility()||(this.$el.css("display","block"),this.syncLayout(),this.onShow()):e||this.getVisibility()&&(this.$el.css("display","none"),this.onHide())}},{key:"onShow",value:function(){}},{key:"onHide",value:function(){this.active=!1,this._$attachedElement=null}}]),e}();t.default=l},function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(t,"__esModule",{value:!0});var i=function(){function e(e,t){for(var n=0;n','
    ','
    ','
    ','
    ',"
    ",'
    ','
    ',"
    ","
    "].join(""),s=function(){function e(t,n){r(this,e),this.$el=(0,a.default)(t.el),this.height=t.height,this.type=t.initialEditType,this.eventManager=n,this.init(),this._initEvent()}return i(e,[{key:"init",value:function(){this._renderLayout(),this._initMarkdownAndPreviewSection(),this._initWysiwygSection()}},{key:"_initEvent",value:function(){this.eventManager.listen("hide",this.hide.bind(this)),this.eventManager.listen("show",this.show.bind(this))}},{key:"_renderLayout",value:function(){this.$el.css("box-sizing","border-box"),this.$containerEl=(0,a.default)(l).appendTo(this.$el)}},{key:"switchToWYSIWYG",value:function(){this.$containerEl.removeClass("te-md-mode"),this.$containerEl.addClass("te-ww-mode")}},{key:"switchToMarkdown",value:function(){this.$containerEl.removeClass("te-ww-mode"),this.$containerEl.addClass("te-md-mode")}},{key:"_initMarkdownAndPreviewSection",value:function(){this.$mdEditorContainerEl=this.$containerEl.find(".te-md-container .te-editor"),this.$previewEl=this.$containerEl.find(".te-md-container .te-preview")}},{key:"_initWysiwygSection",value:function(){this.$wwEditorContainerEl=this.$containerEl.find(".te-ww-container .te-editor")}},{key:"_verticalSplitStyle",value:function(){this.$containerEl.find(".te-md-container").removeClass("te-preview-style-tab"),this.$containerEl.find(".te-md-container").addClass("te-preview-style-vertical")}},{key:"_tabStyle",value:function(){this.$containerEl.find(".te-md-container").removeClass("te-preview-style-vertical"),this.$containerEl.find(".te-md-container").addClass("te-preview-style-tab")}},{key:"changePreviewStyle",value:function(e){"tab"===e?this._tabStyle():"vertical"===e&&this._verticalSplitStyle()}},{key:"hide",value:function(){this.$el.find(".tui-editor").addClass("te-hide")}},{key:"show",value:function(){this.$el.find(".tui-editor").removeClass("te-hide")}},{key:"remove",value:function(){this.$el.find(".tui-editor").remove()}},{key:"getEditorEl",value:function(){return this.$containerEl}},{key:"getPreviewEl",value:function(){return this.$previewEl}},{key:"getMdEditorContainerEl",value:function(){return this.$mdEditorContainerEl}},{key:"getWwEditorContainerEl",value:function(){return this.$wwEditorContainerEl}}]),e}();t.default=s},function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(t,"__esModule",{value:!0});var i=function(){function e(e,t){for(var n=0;n/g,">").replace(/"/g,""").replace(/'/g,"'")}var a=function(e){e.core.ruler.after("block","tui-code-block",function(e){var t,n,a=e.tokens;for(n=0;n=2&&"list"===e.parentType)break;r++}else{if(u=0,!(e.sCount[r]-e.blkIndent>=4))break;r++,i=r}return e.line=i,o=e.push("code_block","code",0),o.content=e.getLines(t,i,4+e.blkIndent,!0),o.map=[t,e.line],!0}},function(e,t,n){"use strict";function r(e){switch(e){case 9:case 32:return!0}return!1}e.exports=function(e,t,n,i){var o,a,l,s,u,c,d,f,h,p,g,v,m,y,_,b,w,k,E,C,T=e.lineMax,M=e.bMarks[t]+e.tShift[t],S=e.eMarks[t],O=/(?:-|\*|\d+\.) {1,4}(?:> {0,3})[^>]*$/,x=e.src.split("\n"),L=x[t];if(e.sCount[t]-e.blkIndent>=4)return!1;if(62!==e.src.charCodeAt(M++))return!1;if(L.match(O))return!1;if(i)return!0;for(s=h=e.sCount[t]+M-(e.bMarks[t]+e.tShift[t]),32===e.src.charCodeAt(M)?(M++,s++,h++,o=!1,b=!0):9===e.src.charCodeAt(M)?(b=!0,(e.bsCount[t]+h)%4==3?(M++,s++,h++,o=!1):o=!0):b=!1,p=[e.bMarks[t]],e.bMarks[t]=M;M=S,y=[e.sCount[t]],e.sCount[t]=h-s,_=[e.tShift[t]],e.tShift[t]=M-e.bMarks[t],k=e.md.block.ruler.getRules("blockquote"),m=e.parentType,e.parentType="blockquote",C=!1,f=t+1;f=S));f++)if(62!==e.src.charCodeAt(M++)||C){if(c)break;for(w=!1,l=0,u=k.length;l=S,g.push(e.bsCount[f]),e.bsCount[f]=e.sCount[f]+1+(b?1:0),y.push(e.sCount[f]),e.sCount[f]=h-s,_.push(e.tShift[f]),e.tShift[f]=M-e.bMarks[f]}for(v=e.blkIndent,e.blkIndent=0,E=e.push("blockquote_open","blockquote",1),E.markup=">",E.map=d=[t,0],e.md.block.tokenize(e,t,f),E=e.push("blockquote_close","blockquote",-1),E.markup=">",e.lineMax=T,e.parentType=m,d[1]=e.line,l=0;l<_.length;l++)e.bMarks[l+t]=p[l],e.tShift[l+t]=_[l],e.sCount[l+t]=y[l],e.bsCount[l+t]=g[l];return e.blkIndent=v,!0}},function(e,t,n){"use strict";function r(e,t){var n=e.bMarks[t]+e.blkIndent,r=e.eMarks[t];return e.src.substr(n,r-n)}function i(e){var t,n=[],r=0,i=e.length,o=0,a=0,l=!1,s=0;for(t=e.charCodeAt(r);rn)return!1;if(c=t+1,e.sCount[c]=e.eMarks[c])return!1;if(124!==(a=e.src.charCodeAt(s))&&45!==a&&58!==a)return!1;if(l=r(e,t+1),!/^[-:| ]+$/.test(l))return!1;for(d=l.split("|"),p=[],u=0;ug)return!1;if(f|$))/i,/<\/(script|pre|style)>/i,!0],[/^/,!0],[/^<\?/,/\?>/,!0],[/^/,!0],[/^/,!0],[new RegExp("^<("+r.join("|")+")","i"),/^\/?>$/,!0],[new RegExp("^|$))","i"),/^$/,!0],[/^(?:<[A-Za-z][A-Za-z0-9\-]*(?:\s+[a-zA-Z_:][a-zA-Z0-9:._-]*(?:\s*=\s*(?:[^"'=<>`\x00-\x20]+|'[^']*'|"[^"]*"))?)*\s*\/?>|<\/[A-Za-z][A-Za-z0-9\-]*\s*>)\s*$/,/^$/,!1]];e.exports=function(e,t,n,r){var o,a,l,s,u=e.bMarks[t]+e.tShift[t],c=e.eMarks[t];if(!e.md.options.html)return!1;if(60!==e.src.charCodeAt(u))return!1;for(s=e.src.slice(u,c),o=0;o18;e.target.hasAttribute("data-te-task")&&!t&&((0,l.default)(e.target).toggleClass("checked"),this.eventManager.emit("change",{source:"viewer",data:e}))}},{key:"setMarkdown",value:function(e){this.markdownValue=e=e||"",this.preview.refresh(this.markdownValue),this.eventManager.emit("setMarkdownAfter",this.markdownValue)}},{key:"setValue",value:function(e){this.setMarkdown(e)}},{key:"on",value:function(e,t){this.eventManager.listen(e,t)}},{key:"off",value:function(e){this.eventManager.removeEventHandler(e)}},{key:"remove",value:function(){this.eventManager.emit("removeEditor"),this.preview.$el.off("mousedown",l.default.proxy(this._toggleTask,this)),this.options=null,this.eventManager=null,this.commandManager=null,this.convertor=null,this.preview=null}},{key:"addHook",value:function(e,t){this.eventManager.removeEventHandler(e),this.eventManager.listen(e,t)}},{key:"isViewer",value:function(){return!0}},{key:"isMarkdownMode",value:function(){return!1}},{key:"isWysiwygMode",value:function(){return!1}}],[{key:"defineExtension",value:function(e,t){m.default.defineExtension(e,t)}}]),e}();C.isViewer=!0,C.domUtils=w.default,C.codeBlockManager=E.default,C.markdownitHighlight=_.default.getMarkdownitHighlightRenderer(),C.i18n=null,C.Button=null,C.WwCodeBlockManager=null,C.WwTableManager=null,C.WwTableSelectionManager=null,e.exports=C},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(t,"__esModule",{value:!0});var o=function(){function e(e,t){for(var n=0;n\n
    \n
    \n
    \n
    \n').appendTo(e),this._editorSection=this.$el.find(".te-editor-section").get(0),this._editorSection.appendChild(this._editor.layout.getEditorEl().get(0)),this._initToolbar(),this._initModeSwitch(),this._initPopupAddLink(),this._initPopupAddImage(),this._initPopupAddTable(),this._initPopupAddHeading(),this._initPopupTableUtils(),this._initPopupCodeBlockLanguages(),this._initPopupCodeBlockEditor(),this._initMarkdownTab()}},{key:"_initEvent",value:function(){this._editor.eventManager.listen("hide",this.hide.bind(this)),this._editor.eventManager.listen("show",this.show.bind(this)),this._editor.eventManager.listen("changeMode",this._markdownTabControl.bind(this)),this._editor.eventManager.listen("changePreviewStyle",this._markdownTabControl.bind(this))}},{key:"_initToolbar",value:function(){this.toolbar=new u.default(this._editor.eventManager),this.$el.find(".te-toolbar-section").append(this.toolbar.$el)}},{key:"_initModeSwitch",value:function(){var e=this;this._modeSwitch=new g.default("markdown"===this._initialEditType?g.default.TYPE.MARKDOWN:g.default.TYPE.WYSIWYG),this.$el.find(".te-mode-switch-section").append(this._modeSwitch.$el),this._modeSwitch.on("modeSwitched",function(t,n){return e._editor.changeMode(n)})}},{key:"_initMarkdownTab",value:function(){var e=this._editor;this.markdownTab=new d.default({initName:I.default.get("Write"),items:[I.default.get("Write"),I.default.get("Preview")],sections:[e.layout.getMdEditorContainerEl(),e.layout.getPreviewEl()]}),this._$markdownTabSection=this.$el.find(".te-markdown-tab-section"),this._$markdownTabSection.append(this.markdownTab.$el),this.markdownTab.on("itemClick",function(t,n){n===I.default.get("Preview")?e.eventManager.emit("previewNeedsRefresh"):e.getCodeMirror().focus()})}},{key:"_markdownTabControl",value:function(){this._editor.isMarkdownMode()&&"tab"===this._editor.getCurrentPreviewStyle()?(this._$markdownTabSection.show(),this.markdownTab.activate(I.default.get("Write"))):this._$markdownTabSection.hide()}},{key:"_initPopupAddLink",value:function(){this.popupAddLink=new m.default({$target:this.$el,editor:this._editor})}},{key:"_initPopupAddImage",value:function(){this.popupAddImage=new _.default({$target:this.$el,eventManager:this._editor.eventManager})}},{key:"_initPopupAddTable",value:function(){this.popupAddTable=new E.default({$target:this.$el,eventManager:this._editor.eventManager,$button:this.$el.find("button.tui-table"),css:{position:"absolute"}})}},{key:"_initPopupAddHeading",value:function(){this.popupAddHeading=new T.default({$target:this.$el,eventManager:this._editor.eventManager,$button:this.$el.find("button.tui-heading"),css:{position:"absolute"}})}},{key:"_initPopupTableUtils",value:function(){var e=this;this._editor.eventManager.listen("contextmenu",function(t){(0,l.default)(t.data.target).parents("[contenteditable=true] table").length>0&&(t.data.preventDefault(),e._editor.eventManager.emit("openPopupTableUtils",t.data))}),this.popupTableUtils=new w.default({$target:this.$el,eventManager:this._editor.eventManager})}},{key:"_initPopupCodeBlockLanguages",value:function(){var e=this._editor;this.popupCodeBlockLanguages=new S.default({$target:this.$el,eventManager:e.eventManager,languages:e.options.codeBlockLanguages})}},{key:"_initPopupCodeBlockEditor",value:function(){this.popupCodeBlockEditor=new x.default({$target:this.$el,eventManager:this._editor.eventManager,convertor:this._editor.convertor})}},{key:"getEditorSectionHeight",value:function(){var e=this._editorSection.getBoundingClientRect();return e.bottom-e.top}},{key:"getEditorHeight",value:function(){var e=this._container.getBoundingClientRect();return e.bottom-e.top}},{key:"hide",value:function(){this.$el.addClass("te-hide")}},{key:"show",value:function(){this.$el.removeClass("te-hide")}},{key:"remove",value:function(){this.$el.remove(),N.default.hide()}},{key:"createPopup",value:function(e){return new h.default(e)}}]),e}();t.default=B},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(t,"__esModule",{value:!0});var l=function(){function e(e,t){for(var n=0;n=0;n-=1)d.default.isNumber(t)?this._addButton(e[n],t):this._addButton(e);else this._addButton(e,t)}},{key:"_addButton",value:function(e,t){var n=this._setButton(e,t).$el;d.default.isNumber(t)?this.$buttonContainer.find(".tui-toolbar-icons").eq(t-1).before(n):this.$buttonContainer.append(n)}},{key:"addDivider",value:function(){var e=(0,u.default)('
    ');return this.$buttonContainer.append(e),e}},{key:"_setButton",value:function(e,t){var n=this.eventManager;return e instanceof g.default||(e=new g.default(e)),e.on("command",function(e,t){return n.emit("command",t)}),e.on("event",function(e,t){return n.emit(t)}),d.default.isNumber(t)?this.buttons.splice(t,0,e):this.buttons.push(e),e}},{key:"_initButton",value:function(e){var t=this;this.buttonOptions={heading:{className:"tui-heading",event:"openHeadingSelect",tooltip:m.default.get("Headings")},bold:{className:"tui-bold",command:"Bold",tooltip:m.default.get("Bold"),state:"bold"},italic:{className:"tui-italic",command:"Italic",tooltip:m.default.get("Italic"),state:"italic"},strike:{className:"tui-strike",command:"Strike",tooltip:m.default.get("Strike"),state:"strike"},ul:{className:"tui-ul",command:"UL",tooltip:m.default.get("Unordered list")},ol:{className:"tui-ol",command:"OL",tooltip:m.default.get("Ordered list")},task:{className:"tui-task",command:"Task",tooltip:m.default.get("Task")},hr:{className:"tui-hrline",command:"HR",tooltip:m.default.get("Line")},table:{className:"tui-table",event:"openPopupAddTable",tooltip:m.default.get("Insert table")},image:{className:"tui-image",event:"openPopupAddImage",tooltip:m.default.get("Insert image")},link:{className:"tui-link",event:"openPopupAddLink",tooltip:m.default.get("Insert link")},quote:{className:"tui-quote",command:"Blockquote",tooltip:m.default.get("Blockquote"),state:"quote"},codeBlock:{className:"tui-codeblock",command:"CodeBlock",tooltip:m.default.get("Insert CodeBlock"),state:"codeBlock"},code:{className:"tui-code",command:"Code",tooltip:m.default.get("Code"),state:"code"}},d.default.forEach(e,function(e){"|"===e?t.addDivider():t.buttonOptions[e]&&t.addButton(new g.default(t.buttonOptions[e]))})}}]),t}(h.default);t.default=y},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(t,"__esModule",{value:!0});var l=function(){function e(e,t){for(var n=0;n'+g.default.get("Markdown")+""),this.buttons.$wysiwyg=(0,u.default)('"),this.$el.append(this.buttons.$markdown),this.$el.append(this.buttons.$wysiwyg),this.on("click .markdown",this._changeMarkdown.bind(this)),this.on("click .wysiwyg",this._changeWysiwyg.bind(this))}},{key:"_changeMarkdown",value:function(){this._switchType(v)}},{key:"_changeWysiwyg",value:function(){this._switchType("wysiwyg")}},{key:"_setActiveButton",value:function(e){this.buttons.$markdown.removeClass("active"),this.buttons.$wysiwyg.removeClass("active"),this.buttons["$"+e].addClass("active")}},{key:"_switchType",value:function(e){this.type!==e&&(this.type=e,this._setActiveButton(e),this.trigger("modeSwitched",this.type))}}]),t}(h.default);m.TYPE={MARKDOWN:v,WYSIWYG:"wysiwyg"},t.default=m},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(t,"__esModule",{value:!0});var l=function(){function e(e,t){for(var n=0;n\n \n \n \n
    \n \n \n
    \n ";return e=c.default.extend({header:!0,title:p.default.get("Insert link"),className:"te-popup-add-link tui-editor-popup",content:n},e),o(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e))}return a(t,e),l(t,[{key:"_initInstance",value:function(e){s(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"_initInstance",this).call(this,e),this._editor=e.editor,this._eventManager=e.editor.eventManager}},{key:"_initDOM",value:function(){s(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"_initDOM",this).call(this);var e=this.$el.get(0);this._inputText=e.querySelector(".te-link-text-input"),this._inputURL=e.querySelector(".te-url-input")}},{key:"_initDOMEvent",value:function(){var e=this;s(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"_initDOMEvent",this).call(this),this.on("click .te-close-button",function(){return e.hide()}),this.on("click .te-ok-button",function(){return e._addLink()}),this.on("shown",function(){var t=e._inputText,n=e._inputURL,r=e._editor.getSelectedText().trim();t.value=r,g.exec(r)&&(n.value=r),r.length>0&&n.value.length<1?n.focus():(t.focus(),t.setSelectionRange(0,r.length))}),this.on("hidden",function(){e._resetInputs()})}},{key:"_initEditorEvent",value:function(){var e=this;s(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"_initEditorEvent",this).call(this);var n=this._eventManager;n.listen("focus",function(){return e.hide()}),n.listen("closeAllPopup",function(){return e.hide()}),n.listen("openPopupAddLink",function(){n.emit("closeAllPopup"),e.show()})}},{key:"_addLink",value:function(){var e=this._getValue(),t=e.url,n=e.linkText;return this._clearValidationStyle(),n.length<1?void this._inputText.classList.add("wrong"):t.length<1?void this._inputURL.classList.add("wrong"):(this._eventManager.emit("command","AddLink",{linkText:n,url:t}),void this.hide())}},{key:"_getValue",value:function(){return{url:this._inputURL.value,linkText:this._inputText.value}}},{key:"_clearValidationStyle",value:function(){this._inputURL.classList.remove("wrong"),this._inputText.classList.remove("wrong")}},{key:"_resetInputs",value:function(){this._inputText.value="",this._inputURL.value="",this._clearValidationStyle()}}]),t}(f.default);t.default=v},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(t,"__esModule",{value:!0});var l=function(){function e(e,t){for(var n=0;n
    \n
    \n \n \n
    \n
    \n \n \n
    \n \n \n
    \n \n \n
    \n ";return e=c.default.extend({header:!0,title:v.default.get("Insert image"),className:"te-popup-add-image tui-editor-popup",content:n},e),o(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e))}return a(t,e),l(t,[{key:"_initInstance",value:function(e){s(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"_initInstance",this).call(this,e),this.eventManager=e.eventManager}},{key:"_initDOM",value:function(){s(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"_initDOM",this).call(this);var e=this.$el;this._$imageUrlInput=e.find("."+m),this._$imageFileInput=e.find("."+y),this._$altTextInput=e.find("."+_);var n=e.find("."+k),r=e.find("."+E),i=this.$body.find("."+C);this.tab=new p.default({initName:v.default.get("File"),items:[v.default.get("File"),v.default.get("URL")],sections:[n,r]}),i.append(this.tab.$el)}},{key:"_initDOMEvent",value:function(){var e=this;s(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"_initDOMEvent",this).call(this),this.on("shown",function(){return e._$imageUrlInput.focus()}),this.on("hidden",function(){return e._resetInputs()}),this.on("change ."+y,function(){var t=e._$imageFileInput.val().split("\\").pop();e._$altTextInput.val(t)}),this.on("click ."+w,function(){return e.hide()}),this.on("click ."+b,function(){var t=e._$imageUrlInput.val(),n=e._$altTextInput.val();if(t)e._applyImage(t,n);else{var r=e._$imageFileInput.get(0).files.item(0),i=function(t,r){return e._applyImage(t,n||r)};e.eventManager.emit("addImageBlobHook",r,i,"ui")}e.hide()}),this.tab.on("itemClick",function(){return e._resetInputs()})}},{key:"_initEditorEvent",value:function(){var e=this;s(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"_initEditorEvent",this).call(this),this.eventManager.listen("focus",function(){return e.hide()}),this.eventManager.listen("closeAllPopup",function(){return e.hide()}),this.eventManager.listen("openPopupAddImage",function(){e.eventManager.emit("closeAllPopup"),e.show()})}},{key:"_applyImage",value:function(e,t){this.eventManager.emit("command","AddImage",{imageUrl:e,altText:t||"image"}),this.hide()}},{key:"_resetInputs",value:function(){this.$el.find("input").val("")}}]),t}(f.default);t.default=T},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(t,"__esModule",{value:!0});var l=function(){function e(e,t){for(var n=0;n\n \n \n \n
    \n \n \n \n
    \n \n ";return e=f.default.extend({header:!1,className:"te-popup-table-utils",content:n},e),o(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e))}return a(t,e),l(t,[{key:"_initInstance",value:function(e){s(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"_initInstance",this).call(this,e),this.eventManager=e.eventManager}},{key:"_initDOMEvent",value:function(){var e=this;s(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"_initDOMEvent",this).call(this),this.on("click .te-table-add-row",function(){return e.eventManager.emit("command","AddRow")}),this.on("click .te-table-add-col",function(){return e.eventManager.emit("command","AddCol")}),this.on("click .te-table-remove-row",function(){return e.eventManager.emit("command","RemoveRow")}),this.on("click .te-table-col-align-left",function(){return e.eventManager.emit("command","AlignCol","left")}),this.on("click .te-table-col-align-center",function(){return e.eventManager.emit("command","AlignCol","center")}),this.on("click .te-table-col-align-right",function(){return e.eventManager.emit("command","AlignCol","right")}),this.on("click .te-table-remove-col",function(){return e.eventManager.emit("command","RemoveCol")}),this.on("click .te-table-remove",function(){return e.eventManager.emit("command","RemoveTable")})}},{key:"_initEditorEvent",value:function(){var e=this;s(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"_initEditorEvent",this).call(this),this.eventManager.listen("focus",function(){return e.hide()}),this.eventManager.listen("mousedown",function(){return e.hide()}),this.eventManager.listen("closeAllPopup",function(){return e.hide()}),this.eventManager.listen("openPopupTableUtils",function(t){var n=e.$el.parent().offset(),r=t.clientX-n.left,i=t.clientY-n.top+(0,c.default)(window).scrollTop();e.eventManager.emit("closeAllPopup"),e.$el.css({position:"absolute",top:i+5,left:r+10}),e.show()})}}]),t}(p.default);t.default=m},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(t,"__esModule",{value:!0});var l=function(){function e(e,t){for(var n=0;n\n
    \n
    \n
    \n
    \n

    \n',p=function(e){function t(e){return i(this,t),e=c.default.extend({header:!1,className:"te-popup-add-table",content:h},e),o(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e))}return a(t,e),l(t,[{key:"_initInstance",value:function(e){s(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"_initInstance",this).call(this,e),this._selectedBound={},this._tableBound={},this._eventManager=e.eventManager,this.$button=e.$button}},{key:"_initDOM",value:function(){s(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"_initDOM",this).call(this),this._cacheElements(),this._setTableSizeByBound(5,7)}},{key:"_initDOMEvent",value:function(e){var n=this;s(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"_initDOMEvent",this).call(this,e),this.on("mousemove .te-table-selection",function(e){var t=e.pageX-n._selectionOffset.left,r=e.pageY-n._selectionOffset.top,i=n._getSelectionBoundByOffset(t,r);n._resizeTableBySelectionIfNeed(i.col,i.row),n._setSelectionAreaByBound(i.col,i.row),n._setDisplayText(i.col,i.row),n._setSelectedBound(i.col,i.row)}),this.on("click .te-table-selection",function(){var e=n._getSelectedTableSize();n._eventManager.emit("command","Table",e.col,e.row)})}},{key:"_initEditorEvent",value:function(){var e=this;s(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"_initEditorEvent",this).call(this),this._eventManager.listen("focus",function(){return e.hide()}),this._eventManager.listen("closeAllPopup",function(){return e.hide()}),this._eventManager.listen("openPopupAddTable",function(){e._eventManager.emit("closeAllPopup");var t=e.$button,n=t.position();e.$el.css({top:n.top+t.outerHeight(!0),left:n.left}),e.show(),e._selectionOffset=e.$el.find(".te-table-selection").offset()})}},{key:"_cacheElements",value:function(){this.$header=this.$el.find(".te-table-header"),this.$body=this.$el.find(".te-table-body"),this.$selection=this.$el.find(".te-selection-area"),this.$desc=this.$el.find(".te-description")}},{key:"_resizeTableBySelectionIfNeed",value:function(e,t){var n=this._getResizedTableBound(e,t);n&&this._setTableSizeByBound(n.col,n.row)}},{key:"_getResizedTableBound",value:function(e,t){var n=void 0,r=void 0,i=void 0;return e>=5&&e<9?n=e+1:e<5&&(n=5),t>=7&&t<14?r=t+1:t<7&&(r=7),this._isNeedResizeTable(n,r)&&(i={row:r||this._tableBound.row,col:n||this._tableBound.col}),i}},{key:"_isNeedResizeTable",value:function(e,t){return e&&e!==this._tableBound.col||t&&t!==this._tableBound.row}},{key:"_getBoundByOffset",value:function(e,t){return{row:parseInt(t/17,10),col:parseInt(e/25,10)}}},{key:"_getOffsetByBound",value:function(e,t){return{x:25*e+25,y:17*t+17}}},{key:"_setTableSizeByBound",value:function(e,t){var n=this._getOffsetByBound(e,t-1);this._setTableSize(n.x,n.y),this._tableBound.row=t,this._tableBound.col=e}},{key:"_getSelectionBoundByOffset",value:function(e,t){var n=this._getBoundByOffset(e,t);return n.row<1?n.row=1:n.row>this._tableBound.row&&(n.row=this._tableBound.row),n.col<1?n.col=1:n.col>this._tableBound.col&&(n.col=this._tableBound.col),n}},{key:"_setSelectionAreaByBound",value:function(e,t){var n=this._getOffsetByBound(e,t);this._setSelectionArea(n.x,n.y)}},{key:"_setSelectedBound",value:function(e,t){this._selectedBound.col=e,this._selectedBound.row=t}},{key:"_getSelectedTableSize",value:function(){return{row:this._selectedBound.row+1,col:this._selectedBound.col+1}}},{key:"_setDisplayText",value:function(e,t){this.$desc.html(e+1+" x "+(t+1))}},{key:"_setTableSize",value:function(e,t){e+=1,t+=1,this.$header.css({height:17,width:e}),this.$body.css({height:t,width:e}),this.$el.css({width:e+30})}},{key:"_setSelectionArea",value:function(e,t){e+=1,t+=1,this.$selection.css({height:t,width:e})}}]),t}(f.default);p.CELL_WIDTH=25,p.CELL_HEIGHT=17,p.MIN_ROW_SELECTION_INDEX=1,p.MIN_COL_SELECTION_INDEX=1,t.default=p},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(t,"__esModule",{value:!0});var l=function(){function e(e,t){for(var n=0;n\n
  • '+v.default.get("Heading")+' 2

  • \n
  • '+v.default.get("Heading")+' 3

  • \n
  • '+v.default.get("Heading")+' 4

  • \n
  • '+v.default.get("Heading")+' 5
  • \n
  • '+v.default.get("Heading")+' 6
  • \n
  • '+v.default.get("Paragraph")+"
  • \n \n ";return e=f.default.extend({header:!1,className:"te-heading-add",content:n},e),o(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e))}return a(t,e),l(t,[{key:"_initInstance",value:function(e){s(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"_initInstance",this).call(this,e),this._eventManager=e.eventManager,this._$button=e.$button}},{key:"_initDOMEvent",value:function(){var e=this;s(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"_initDOMEvent",this).call(this),this.on("click li",function(t){var n=(0,c.default)(t.target).closest("li");e._eventManager.emit("command",n.data("type"),n.data("value"))})}},{key:"_initEditorEvent",value:function(){var e=this;s(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"_initEditorEvent",this).call(this),this._eventManager.listen("focus",this.hide.bind(this)),this._eventManager.listen("closeAllPopup",this.hide.bind(this)),this._eventManager.listen("openHeadingSelect",function(){e._eventManager.emit("closeAllPopup");var t=e._$button,n=t.position();e.$el.css({top:n.top+t.outerHeight(!0),left:n.left}),e.show()})}}]),t}(p.default);t.default=m},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(t,"__esModule",{value:!0});var l=function(){function e(e,t){for(var n=0;n'+e+"")}),e=f.default.extend({header:!1,className:"te-popup-code-block-languages",content:n.join("")},e),o(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e))}return a(t,e),l(t,[{key:"_initInstance",value:function(e){s(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"_initInstance",this).call(this,e),this._onSelectedLanguage=null,this._onDismissed=null,this._currentButton=null,this._$buttons=null,this._languages=e.languages,this.eventManager=e.eventManager}},{key:"_initDOM",value:function(e){s(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"_initDOM",this).call(this,e),this.$el.css("z-index",1e4),this._$buttons=this.$el.find("button"),this._activateButtonByIndex(0)}},{key:"_initDOMEvent",value:function(){var e=this;s(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"_initDOMEvent",this).call(this);var n=function(t){var n=(0,c.default)(t.target).data("lang");e._onSelectedLanguage&&e._onSelectedLanguage(n),e.hide()};this._languages.forEach(function(t){return e.on("mousedown ."+g+t,n)})}},{key:"_initEditorEvent",value:function(){var e=this;s(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"_initEditorEvent",this).call(this),this.eventManager.listen("openPopupCodeBlockLanguages",function(t){e.show(t.callback);var n=e.$el.get(0).style;return n.top=t.offset.top+"px",n.left=t.offset.left+"px",e.setCurrentLanguage(t.language),e}),this.eventManager.listen("focus",function(){return e.hide()}),this.eventManager.listen("mousedown",function(){return e.hide()}),this.eventManager.listen("closeAllPopup",function(){return e.hide()}),this.eventManager.listen("closePopupCodeBlockLanguages",function(){return e.hide()}),this.eventManager.listen("scroll",function(){return e.hide()})}},{key:"_activateButtonByIndex",value:function(e){this._currentButton&&(0,c.default)(this._currentButton).removeClass("active"),this._currentButton=this._$buttons.get(e),(0,c.default)(this._currentButton).addClass("active"),this._currentButton.scrollIntoView()}},{key:"prev",value:function(){var e=this._$buttons.index(this._currentButton)-1;e<0&&(e=this._$buttons.length-1),this._activateButtonByIndex(e)}},{key:"next",value:function(){var e=this._$buttons.index(this._currentButton)+1;e>=this._$buttons.length&&(e=0),this._activateButtonByIndex(e)}},{key:"getCurrentLanguage",value:function(){return(0,c.default)(this._currentButton).data("lang")}},{key:"setCurrentLanguage",value:function(e){var t=this._$buttons.filter("."+g+e);if(t.length>0){var n=this._$buttons.index(t);this._activateButtonByIndex(n)}}},{key:"show",value:function(e){this._onSelectedLanguage=e.selected,this._onDismissed=e.dismissed,s(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"show",this).call(this)}},{key:"hide",value:function(){this._onDismissed&&this._onDismissed(),this._onSelectedLanguage=null,this._onDismissed=null,s(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"hide",this).call(this)}}]),t}(p.default);t.default=v},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(t,"__esModule",{value:!0});var l=function(){function e(e,t){for(var n=0;n\n \n \n \n',x=function(e){function t(e){i(this,t);var n='\n
    \n
    \n \n \n
    \n ";return e=f.default.extend({header:!0,title:"CodeBlock Editor",content:n,className:"tui-popup-code-block-editor",headerButtons:O,modal:!0},e),o(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e))}return a(t,e),l(t,[{key:"_initInstance",value:function(e){s(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"_initInstance",this).call(this,e),this.eventManager=e.eventManager,this.convertor=e.convertor}},{key:"_initDOM",value:function(e){s(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"_initDOM",this).call(this,e);var n=this.$el.get(0);this._body=n.querySelector("."+T+"body"),this._toggleFitButton=n.querySelector("."+T+"toggle-fit"),this._togglePreviewButton=n.querySelector("."+T+"toggle-preview"),this._toggleScrollButton=n.querySelector("."+T+"toggle-scroll"),this._okButton=n.querySelector("."+M),this._closeButton=n.querySelector("."+S),this._codeMirrorWrapper=this._createCodeBlockEditor(),this._previewWrapper=this._createPreview(),this._scrollSyncSplit=new v.default(this._body,this._codeMirrorWrapper,this._previewWrapper),this._updateFitWindowButton(),this._updatePreviewButton(),this._updateScrollButton(),this._codeBlockLanguagesCombo=this._createCodeBlockLanguagesCombo()}},{key:"_initDOMEvent",value:function(){var e=this;s(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"_initDOMEvent",this).call(this),this.on("scroll",function(e){return e.preventDefault()}),this.on("click ."+T+"toggle-fit",function(){return e._toggleFitToWindow()}),this.on("click ."+T+"toggle-preview",function(){return e._togglePreview()}),this.on("click ."+T+"toggle-scroll",function(){return e._toggleScroll()}),this.on("click ."+M,function(){return e._save()}),this.on("click ."+S,function(){return e.hide()}),this.on("click ."+T+"close",function(){return e.hide()}),this.on("click ."+T+"editor-wrapper",function(t){t.target===e._codeMirrorWrapper&&e._focusEditor(!0)})}},{key:"_initEditorEvent",value:function(){var e=this;s(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"_initEditorEvent",this).call(this),this.eventManager.listen("openPopupCodeBlockEditor",function(t){return e.eventManager.emit("closeAllPopup"),e.show(t),e}),this.eventManager.listen("closeAllPopup",this.hide.bind(this)),this.eventManager.listen("closePopupCodeBlockEditor",this.hide.bind(this))}},{key:"_createCodeBlockEditor",value:function(){var e=document.createElement("div");return e.classList.add(T+"editor-wrapper"),this._codeBlockEditor=new y.default(e,this.eventManager),e}},{key:"_createPreview",value:function(){var e=document.createElement("div");return this._codeBlockPreview=new b.default((0,c.default)(e),this.eventManager,this.convertor,this._codeBlockEditor),e}},{key:"_createCodeBlockLanguagesCombo",value:function(){var e=this,t=this.getTitleElement(),n=new k.default(this.eventManager);return n.setOnLanguageSelected(function(t){e._codeBlockEditor.setLanguage(t),e._codeBlockEditor.refresh(),e._focusEditor()}),t.innerHTML="CodeBlock Editor",t.appendChild(n.getElement()),n}},{key:"_updateFitWindowButton",value:function(){(0,c.default)(this._toggleFitButton).toggleClass("active",this.isFitToWindow())}},{key:"_updatePreviewButton",value:function(){(0,c.default)(this._togglePreviewButton).toggleClass("active",this._scrollSyncSplit.isSplitView())}},{key:"_updateScrollButton",value:function(){this._scrollSyncSplit.isSplitView()?this._toggleScrollButton.style.display="inline-block":this._toggleScrollButton.style.display="none",(0,c.default)(this._toggleScrollButton).toggleClass("active",this._scrollSyncSplit.isScrollSynced())}},{key:"_focusEditor",value:function(e){this._codeBlockEditor.focus(),e?this._codeBlockEditor.moveCursorToEnd():this._codeBlockEditor.moveCursorToStart()}},{key:"_togglePreview",value:function(){this._scrollSyncSplit.toggleSplitView(),this._updatePreviewButton(),this._updateScrollButton(),this._codeBlockEditor.refresh()}},{key:"_toggleFitToWindow",value:function(){this.toggleFitToWindow(),this._updateFitWindowButton(),this._codeBlockEditor.refresh()}},{key:"_toggleScroll",value:function(){this._scrollSyncSplit.toggleScrollSync(),this._updateScrollButton()}},{key:"_save",value:function(){this._codeBlockEditor.save(this._codeBlockElement),this.hide()}},{key:"_load",value:function(e){this._codeBlockElement=e,this._codeBlockEditor.load(e),this._codeBlockLanguagesCombo.setLanguage(this._codeBlockEditor.getLanguage()),this._focusEditor(),this._codeBlockPreview.refresh()}},{key:"show",value:function(e){if(s(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"show",this).call(this),!e)throw new Error("should be called with codeBlockElement");this._load(e)}},{key:"hide",value:function(){this.setFitToWindow(!1),this._codeBlockEditor&&this._codeBlockEditor.clear(),this._codeBlockPreview&&this._codeBlockPreview.clear(),this._codeBlockElement=null,s(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"hide",this).call(this)}}]),t}(p.default);t.default=x},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(t,"__esModule",{value:!0});var o=function(){function e(e,t){for(var n=0;n3&&void 0!==arguments[3]?arguments[3]:{};i(this,e),o=u.default.extend({showScrollSyncButton:!1,scrollSync:!0,splitView:!0},o),this._baseElement=t,this._contentElements=[],this._initDom(n,r,o),this._initDomEvent()}return o(e,[{key:"_initDom",value:function(e,t,n){var r=document.createElement("div");r.className="tui-split-scroll",this._el=r;var i=document.createElement("div");i.className="tui-split-scroll-wrapper",this._scrollWrapper=i,this._setScrollSync(n.scrollSync),this.setSplitView(n.splitView);var o=document.createElement("div");o.className="tui-split-scroll-content",this._contentWrapper=o;var a=document.createElement("div");a.className="tui-splitter",this._baseElement.appendChild(r),r.appendChild(i),i.appendChild(o),i.appendChild(a),this._setLeft(e),this._setRight(t)}},{key:"_initDomEvent",value:function(){this._contentWrapper.addEventListener("scroll",this.sync.bind(this))}},{key:"_requireScrollIntoView",value:function(e){var t=e.target,n=t.getBoundingClientRect(),r=n.top,i=n.bottom,o=void 0,a=void 0,s=void 0;if(this.isScrollSynced())s=this._contentWrapper;else if((0,l.default)(t).parents(this._contentElements.left).length)s=this._contentElements.left;else{if(!(0,l.default)(t).parents(this._contentElements.right).length)return;s=this._contentElements.right}var u=s.getBoundingClientRect();o=u.top,a=u.bottom,ra&&(s.scrollTop=s.scrollTop+i-a),this.sync()}},{key:"_setContentElement",value:function(e,t){var n=this,r=this._contentElements[t];r&&((0,l.default)(r).off("requireScrollIntoView"),this._contentWrapper.removeChild(r)),e.classList.add(c[t]),this._contentWrapper.appendChild(e),(0,l.default)(e).on("requireScrollIntoView",function(e){return n._requireScrollIntoView(e)}),(0,l.default)(e).on("requireScrollSync",function(){return n.sync()}),this._contentElements[t]=e,this.sync()}},{key:"_setLeft",value:function(e){this._setContentElement(e,"left")}},{key:"_setRight",value:function(e){this._setContentElement(e,"right")}},{key:"_setScrollSync",value:function(e){(0,l.default)(this._el).toggleClass("scroll-sync",e)}},{key:"toggleScrollSync",value:function(){this._el.classList.toggle("scroll-sync")}},{key:"setSplitView",value:function(e){(0,l.default)(this._el).toggleClass("single-content",!e)}},{key:"toggleSplitView",value:function(){this._el.classList.toggle("single-content")}},{key:"isScrollSynced",value:function(){return this._el.classList.contains("scroll-sync")}},{key:"isSplitView",value:function(){return!this._el.classList.contains("single-content")}},{key:"sync",value:function(){if(this._contentElements.left&&this._contentElements.right){var e=this._contentWrapper.clientHeight,t=this._contentWrapper.scrollTop,n=this._contentElements.left,r=this._contentElements.right,i=n.offsetHeight-e>0?n:r,o=i===n?r:n,a=i.offsetHeight,l=Math.max(a-e,0),s=Math.max(o.offsetHeight,e),u=a-s;i.style.top="0px",o.style.top=t/l*u+"px"}}},{key:"scrollTop",value:function(e){this._contentWrapper.scrollTop=e}}]),e}();t.default=d},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(t,"__esModule",{value:!0});var l=function(){function e(e,t){for(var n=0;n0?document.createTextNode(t):document.createElement("br"),n.appendChild(r)}),e.setAttribute("data-language",this._language),(0,u.default)(e).trigger("language-changed")}},{key:"clear",value:function(){this.setLanguage(""),this.setEditorCodeText("")}},{key:"getLanguage",value:function(){return this._language}},{key:"setLanguage",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"";this._language=e}},{key:"getEditorCodeText",value:function(){return this.getValue()}},{key:"setEditorCodeText",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"";this.setValue(e)}},{key:"refresh",value:function(){this.cm.refresh()}}]),t}(d.default);t.default=f},function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function i(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function o(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(t,"__esModule",{value:!0});var a=function(){function e(e,t){for(var n=0;n').get(0),this._wrapper=(0,l.default)('').get(0),this._wrapper.appendChild(this._inputLanguage)}},{key:"_initDOMEvent",value:function(){var e=this;this._inputLanguage.addEventListener("keydown",function(t){return e._onKeyEvent(t)}),this._inputLanguage.addEventListener("focus",function(){return e._showPopupCodeBlockLanguages()}),this._inputLanguage.addEventListener("focusout",function(){return e._onFocusOut()}),this._wrapper.addEventListener("mousedown",function(t){t.target===e._wrapper&&(t.preventDefault(),e._toggleFocus())})}},{key:"_showPopupCodeBlockLanguages",value:function(){var e=this,t=this._inputLanguage.getBoundingClientRect();this._wrapper.classList.toggle("active",!0),this.active=!0,this._popupCodeBlockLanguages=this._eventManager.emitReduce("openPopupCodeBlockLanguages",{language:this._prevStoredLanguage,offset:{left:t.left,top:t.bottom},callback:{selected:function(t){return e._onLanguageSelectedFromList(t)},dismissed:function(){e._popupCodeBlockLanguages=null}}})}},{key:"_toggleFocus",value:function(){var e=this._inputLanguage;this._wrapper.classList.contains("active")?e.blur():e.focus()}},{key:"_onFocusOut",value:function(){this._wrapper.classList.toggle("active",!1),this._inputLanguage.value=this._prevStoredLanguage,this._hidePopupCodeBlockLanguages()}},{key:"_onKeyEvent",value:function(e){if(this._popupCodeBlockLanguages)switch(e.which){case d.default.keyCode("UP"):this._popupCodeBlockLanguages.prev(),e.preventDefault();break;case d.default.keyCode("DOWN"):this._popupCodeBlockLanguages.next(),e.preventDefault();break;case d.default.keyCode("ENTER"):case d.default.keyCode("TAB"):var t=this._popupCodeBlockLanguages.getCurrentLanguage();this._inputLanguage.value=t,this._storeInputLanguage(),e.preventDefault();break;default:this._popupCodeBlockLanguages.hide()}else e.which!==d.default.keyCode("ENTER")&&e.which!==d.default.keyCode("TAB")||(this._storeInputLanguage(),e.preventDefault())}},{key:"_onLanguageSelectedFromList",value:function(e){this._inputLanguage.value=e,this._storeInputLanguage()}},{key:"setOnLanguageSelected",value:function(e){this._onLanguageSelected=e}},{key:"_hidePopupCodeBlockLanguages",value:function(){this._eventManager.emit("closePopupCodeBlockLanguages")}},{key:"setLanguage",value:function(e){this._prevStoredLanguage=e,this._inputLanguage.value=e}},{key:"_storeInputLanguage",value:function(){var e=this._inputLanguage.value;this.setLanguage(e),this._onLanguageSelected&&this._onLanguageSelected(e),this._hidePopupCodeBlockLanguages()}},{key:"getElement",value:function(){return this._wrapper}}]),e}();t.default=f},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(2),i=function(e){return e&&e.__esModule?e:{default:e}}(r),o=/^[*_]{2,}[^*_]*[*_]{2,}$/,a=i.default.command("markdown",{name:"Bold",keyMap:["CTRL+B","META+B"],exec:function(e){var t=e.getEditor(),n=t.getDoc(),r=n.getCursor(),i=n.getSelection(),o=!i;if(o&&r.ch>1){i=this.expendSelection(n,r)||i}var a=this.isNeedRemove(i),l=a?this.remove(i):this.append(i);n.replaceSelection(l,"around"),o&&!a&&this.setCursorToCenter(n,r),t.focus()},isNeedRemove:function(e){return o.test(e)},append:function(e){return"**"+e+"**"},remove:function(e){return e.substr(2,e.length-4)},expendSelection:function(e,t){var n=e.getSelection(),r=void 0,i={line:t.line,ch:t.ch-2},o={line:t.line,ch:t.ch+2};return e.setSelection(i,o),"****"===n||"____"===n?r=n:e.setSelection(t),r},setCursorToCenter:function(e,t){e.setCursor(t.line,t.ch+2)}});t.default=a},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(2),i=function(e){return e&&e.__esModule?e:{default:e}}(r),o=/^[*_]{3,}[^*_]*[*_]{3,}$/,a=/^[*_][^*_]*[*_]$/,l=i.default.command("markdown",{name:"Italic",keyMap:["CTRL+I","META+I"],exec:function(e){var t=e.getEditor(),n=t.getDoc(),r=n.getCursor(),i=n.getSelection(),o=!i,a=!1,l=void 0;o&&(r.ch>2&&(l=this.expendWithBoldSelection(n,r))&&(a="with"),"with"!==a&&r.ch>1&&(a=this.expendOnlyBoldSelection(n,r)),!a&&r.ch>0&&(this.expendSelection(n,r),i=l||i));var s=this.isNeedRemove(i),u=s?this.remove(i):this.append(i);n.replaceSelection(u,"around"),o&&this.setCursorToCenter(n,r,s),t.focus()},isNeedRemove:function(e){return a.test(e)||o.test(e)},append:function(e){return"_"+e+"_"},remove:function(e){return e.substr(1,e.length-2)},expendWithBoldSelection:function(e,t){var n=e.getSelection(),r=void 0,i={line:t.line,ch:t.ch-3},o={line:t.line,ch:t.ch+3};return e.setSelection(i,o),"******"===n||"______"===n?r=n:e.setSelection(t),r},expendOnlyBoldSelection:function(e,t){var n=e.getSelection(),r=!1,i={line:t.line,ch:t.ch-2},o={line:t.line,ch:t.ch+2};return e.setSelection(i,o),"****"!==n&&"____"!==n||(e.setSelection(t),r="only"),r},expendSelection:function(e,t){var n=e.getSelection(),r=void 0,i={line:t.line,ch:t.ch-2},o={line:t.line,ch:t.ch+2};return e.setSelection(i,o),"****"===n||"____"===n?r=n:e.setSelection(t),r},setCursorToCenter:function(e,t,n){var r=n?-1:1;e.setCursor(t.line,t.ch+r)}});t.default=l},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(2),i=function(e){return e&&e.__esModule?e:{default:e}}(r),o=/^[~~](.*[\s\n]*.*)*[~~]$/,a=i.default.command("markdown",{name:"Strike",keyMap:["CTRL+S","META+S"],exec:function(e){var t=e.getEditor(),n=t.getDoc(),r=n.getCursor(),i=n.getSelection(),o=this.hasStrikeSyntax(i),a=void 0;a=o?this.remove(i):this.append(i),n.replaceSelection(a,"around"),!i&&!o&&this.setCursorToCenter(n,r,o),t.focus()},hasStrikeSyntax:function(e){return o.test(e)},append:function(e){return"~~"+e+"~~"},remove:function(e){return e.substr(2,e.length-4)},setCursorToCenter:function(e,t,n){var r=n?-2:2;e.setCursor(t.line,t.ch+r)}});t.default=a},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(2),i=function(e){return e&&e.__esModule?e:{default:e}}(r),o=i.default.command("markdown",{name:"Blockquote",keyMap:["CTRL+Q","META+Q"],exec:function(e){for(var t=e.getEditor(),n=t.getDoc(),r=e.getCurrentRange(),i={line:r.from.line,ch:0},o={line:r.to.line,ch:n.getLineHandle(r.to.line).text.length},a=n.getRange(i,o),l=a.split("\n"),s=l.length,u=0;u"+l[u];n.replaceRange(l.join("\n"),i,o),r.to.ch+=1,n.setCursor(r.to),t.focus()}});t.default=o},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){var n=e.match(u),r="";do{r+="#",t-=1}while(t>0);if(n){e=e.split(n[0])[1]}return r+" "+e}Object.defineProperty(t,"__esModule",{value:!0});var o=n(1),a=r(o),l=n(2),s=r(l),u=/^#+\s/g,c=s.default.command("markdown",{name:"Heading",exec:function(e,t){var n=e.getEditor(),r=n.getDoc(),o=e.getCurrentRange(),l={line:o.from.line,ch:0},s={line:o.to.line,ch:r.getLineHandle(o.to.line).text.length},u=r.getLine(s.line).length,c=r.getRange(l,s),d=c.split("\n");a.default.forEachArray(d,function(e,n){d[n]=i(e,t)}),r.replaceRange(d.join("\n"),l,s),o.to.ch+=r.getLine(s.line).length-u,r.setSelection(l,o.to),n.focus()}});t.default=c},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e){var t=/^(#{1,6}| *((?:\*|-|\d\.)(?: \[[ xX]])?)) /;return e.replace(t,"")}Object.defineProperty(t,"__esModule",{value:!0});var o=n(1),a=r(o),l=n(2),s=r(l),u=s.default.command("markdown",{name:"Paragraph",exec:function(e){var t=e.getEditor(),n=t.getDoc(),r=e.getCurrentRange(),o={line:r.from.line,ch:0},l={line:r.to.line,ch:n.getLineHandle(r.to.line).text.length},s=n.getLine(l.line).length,u=n.getRange(o,l),c=u.split("\n");a.default.forEachArray(c,function(e,t){c[t]=i(e)}),n.replaceRange(c.join("\n"),o,l),r.to.ch+=n.getLine(l.line).length-s,n.setSelection(o,l),t.focus()}});t.default=u},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(2),i=function(e){return e&&e.__esModule?e:{default:e}}(r),o=i.default.command("markdown",{name:"HR",keyMap:["CTRL+L","META+L"],exec:function(e){var t=e.getEditor(),n=t.getDoc(),r="",i=e.getCurrentRange(),o={line:i.from.line,ch:i.from.ch},a={line:i.to.line,ch:i.to.ch};i.collapsed&&(r=n.getLine(o.line),o.ch=0,a.ch=n.getLineHandle(i.to.line).text.length),n.getLine(o.line).length?r+="\n\n* * *\n\n":r+="\n* * *\n",n.replaceRange(r,o,a),t.focus()}});t.default=o},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var i=n(2),o=r(i),a=n(20),l=r(a),s=l.default.decodeURIGraceful,u=l.default.encodeMarkdownCharacters,c=l.default.escapeMarkdownCharacters,d=o.default.command("markdown",{name:"AddLink",exec:function(e,t){var n=e.getEditor(),r=n.getDoc(),i=e.getCurrentRange(),o={line:i.from.line,ch:i.from.ch},a={line:i.to.line,ch:i.to.ch},l=t.linkText,d=t.url;l=s(l),l=c(l),d=u(d);var f="["+l+"]("+d+")";r.replaceRange(f,o,a),n.focus()}});t.default=d},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(2),i=function(e){return e&&e.__esModule?e:{default:e}}(r),o=i.default.command("markdown",{name:"AddImage",exec:function(e,t){var n=e.getEditor(),r=n.getDoc(),i=e.getCurrentRange(),o={line:i.from.line,ch:i.from.ch},a={line:i.to.line,ch:i.to.ch},l="!["+t.altText+"]("+t.imageUrl+")";r.replaceRange(l,o,a,"+addImage"),n.focus()}});t.default=o},function(e,t,n){"use strict";function r(e){return!(!e||!e.match(s)&&!e.match(a))}Object.defineProperty(t,"__esModule",{value:!0});var i=n(2),o=function(e){return e&&e.__esModule?e:{default:e}}(i),a=/^[ \t]*[\d]+\. .*/,l=/^[ \t]*[-*] .*/,s=/^[ \t]*[-*]( \[[ xX]])? .*/,u=o.default.command("markdown",{name:"UL",keyMap:["CTRL+U","META+U"],exec:function(e){for(var t=e.getEditor(),n=t.getDoc(),i=e.getCurrentRange(),o=e.componentManager.getManager("list"),a=o.expandLineRangeIfNeed(n,i,r),s=a.start,u=a.end,c=void 0,d=void 0,f=s;f<=u&&(d={line:f,ch:0},c=n.getLine(f),o.isListOrParagraph(c));f+=1)r(c)?o.replaceLineText(n,f,/[\d]+\. /,"* "):c.match(l)||n.replaceRange("* ",d),f===u&&o.appendBlankLineIfNeed(t,f,u,s);t.focus()}});t.default=u},function(e,t,n){"use strict";function r(e){return!(!e||!e.match(s)&&!e.match(l))}Object.defineProperty(t,"__esModule",{value:!0});var i=n(2),o=function(e){return e&&e.__esModule?e:{default:e}}(i),a=/^[ \t]*[\d]+\. .*/,l=/^[ \t]*[-*] .*/,s=/^[ \t]*[-*]( \[[ xX]])? .*/,u=o.default.command("markdown",{name:"OL",keyMap:["CTRL+O","META+O"],exec:function(e){for(var t=e.getEditor(),n=t.getDoc(),i=e.getCurrentRange(),o=e.componentManager.getManager("list"),l=o.expandLineRangeIfNeed(n,i,r),s=l.start,u=l.end,c=1,d=void 0,f=void 0,h=s;h<=u&&(f={line:h,ch:0},d=n.getLine(h),o.isListOrParagraph(d));h+=1)r(d)?o.replaceLineText(n,h,/[*-] /,c+". "):d.match(a)||n.replaceRange(c+". ",f),c+=1,h===u&&o.appendBlankLineIfNeed(t,h,u,s);t.focus()}});t.default=u},function(e,t,n){"use strict";function r(e,t){for(var n="|",r="|",i=0;e;)t?(n+=" "+t[i]+" |",i+=1):n+=" |",r+=" --- |",e-=1;return n+"\n"+r+"\n"}function i(e,t,n){for(var r="",i=e,o=0;o0&&(s+="\n"),s+=r(t,o),s+=i(t,n-1,o),l.replaceSelection(s),o||a.setCursor(a.getCursor().line-n,2),e.focus()}});t.default=l},function(e,t,n){"use strict";function r(e){return!(!e||!e.match(l)&&!e.match(a))}Object.defineProperty(t,"__esModule",{value:!0});var i=n(2),o=function(e){return e&&e.__esModule?e:{default:e}}(i),a=/^[ \t]*[\d]+\. .*/,l=/^[ \t]*[-*] .*/,s=/^[ \t]*[-*]( \[[ xX]])? .*/,u=/([*-] |[\d]+\. )(\[[ xX]] )/,c=o.default.command("markdown",{name:"Task",keyMap:["CTRL+T","META+T"],exec:function(e){for(var t=e.getEditor(),n=t.getDoc(),i=e.getCurrentRange(),o=e.componentManager.getManager("list"),a=o.createSortedLineRange(i),l=a.start,c=a.end,d=void 0,f=void 0,h=l;h<=c;h+=1){f={line:h,ch:0},d=n.getLine(h);var p=!!d.match(u);if(!o.isListOrParagraph(d))break;r(d)&&p?o.replaceLineText(n,h,u,"$1"):r(d)&&!p?o.replaceLineText(n,h,/([*-] |[\d]+\. )/,"$1[ ] "):d.match(s)||n.replaceRange("* [ ] ",f),h===c&&o.appendBlankLineIfNeed(t,h,c,l)}t.focus()}});t.default=c},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(2),i=function(e){return e&&e.__esModule?e:{default:e}}(r),o=i.default.command("markdown",{name:"Code",keyMap:["SHIFT+CTRL+C","SHIFT+META+C"],exec:function(e){var t=e.getEditor(),n=t.getDoc(),r=n.getSelection(),i=t.getCursor();n.replaceSelection(this.append(r),"around"),r||n.setCursor(i.line,i.ch+1),t.focus()},append:function(e){return"`"+e+"`"}});t.default=o},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(2),i=function(e){return e&&e.__esModule?e:{default:e}}(r),o=i.default.command("markdown",{name:"CodeBlock",keyMap:["SHIFT+CTRL+P","SHIFT+META+P"],exec:function(e){var t=e.getEditor(),n=t.getDoc(),r=e.getCurrentRange(),i=["```",n.getSelection(),"```"],o=1;0!==r.from.ch&&(i.unshift(""),o+=1),r.to.ch!==n.getLine(r.to.line).length&&i.push(""),n.replaceSelection(i.join("\n")),t.setCursor(r.from.line+o,0),t.focus()}});t.default=o},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e){e.hasFormat("b")||e.hasFormat("strong")?e.changeFormat(null,{tag:"b"}):e.hasFormat("a")||e.hasFormat("PRE")||(e.hasFormat("code")&&e.changeFormat(null,{tag:"code"}),e.bold())}Object.defineProperty(t,"__esModule",{value:!0});var o=n(2),a=r(o),l=n(3),s=r(l),u=a.default.command("wysiwyg",{name:"Bold",keyMap:["CTRL+B","META+B"],exec:function(e){var t=e.getEditor(),n=e.componentManager.getManager("tableSelection");e.focus(),t.hasFormat("table")&&n.getSelectedCells().length?n.styleToSelectedCells(i):i(t);var r=t.getSelection();t.hasFormat("table")&&!s.default.isTextNode(r.commonAncestorContainer)&&(r.collapse(!0),t.setSelection(r))}});t.default=u},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e){e.hasFormat("i")||e.hasFormat("em")?e.changeFormat(null,{tag:"i"}):e.hasFormat("a")||e.hasFormat("PRE")||(e.hasFormat("code")&&e.changeFormat(null,{tag:"code"}),e.italic())}Object.defineProperty(t,"__esModule",{value:!0});var o=n(2),a=r(o),l=n(3),s=r(l),u=a.default.command("wysiwyg",{name:"Italic",keyMap:["CTRL+I","META+I"],exec:function(e){var t=e.getEditor(),n=t.getSelection(),r=e.componentManager.getManager("tableSelection");e.focus(),t.hasFormat("table")&&r.getSelectedCells().length?r.styleToSelectedCells(i):i(t),t.hasFormat("table")&&!s.default.isTextNode(n.commonAncestorContainer)&&(n.collapse(!0),t.setSelection(n))}});t.default=u},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e){e.hasFormat("S")?e.changeFormat(null,{tag:"S"}):e.hasFormat("a")||e.hasFormat("PRE")||(e.hasFormat("code")&&e.changeFormat(null,{tag:"code"}),e.strikethrough())}Object.defineProperty(t,"__esModule",{value:!0});var o=n(2),a=r(o),l=n(3),s=r(l),u=a.default.command("wysiwyg",{name:"Strike",keyMap:["CTRL+S","META+S"],exec:function(e){var t=e.getEditor(),n=t.getSelection(),r=e.componentManager.getManager("tableSelection");e.focus(),t.hasFormat("table")&&r.getSelectedCells().length?r.styleToSelectedCells(i):i(t),t.hasFormat("table")&&!s.default.isTextNode(n.commonAncestorContainer)&&(n.collapse(!0),t.setSelection(n))}});t.default=u},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(2),i=function(e){return e&&e.__esModule?e:{default:e}}(r),o=i.default.command("wysiwyg",{name:"Blockquote",keyMap:["CTRL+Q","META+Q"],exec:function(e){var t=e.getEditor();e.focus(),t.hasFormat("TABLE")||t.hasFormat("PRE")||(e.unwrapBlockTag(),t.increaseQuoteLevel())}});t.default=o},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(2),i=function(e){return e&&e.__esModule?e:{default:e}}(r),o=i.default.command("wysiwyg",{name:"AddImage",exec:function(e,t){var n=e.getEditor();e.focus(),n.hasFormat("PRE")||n.insertImage(t.imageUrl,{alt:t.altText})}});t.default=o},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var i=n(0),o=r(i),a=n(2),l=r(a),s=n(20),u=r(s),c=u.default.decodeURIGraceful,d=u.default.encodeMarkdownCharacters,f=l.default.command("wysiwyg",{name:"AddLink",exec:function(e,t){var n=e.getEditor(),r=t.url,i=t.linkText;if(i=c(i),r=d(r),e.focus(),!n.hasFormat("PRE"))if(n.removeAllFormatting(),n.getSelectedText())n.makeLink(r);else{var a=n.createElement("A",{href:r});(0,o.default)(a).text(i),n.insertElement(a)}}});t.default=f},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var i=n(2),o=r(i),a=n(3),l=r(a),s=o.default.command("wysiwyg",{name:"HR",keyMap:["CTRL+L","META+L"],exec:function(e){var t=e.getEditor(),n=t.getSelection(),r=void 0,i=void 0,o=void 0;if(n.collapsed&&!t.hasFormat("TABLE")&&!t.hasFormat("PRE")){r=l.default.getChildNodeByOffset(n.startContainer,n.startOffset),i=l.default.getTopNextNodeUnder(r,e.get$Body()[0]),i||(i=t.createDefaultBlock(),e.get$Body().append(i));var a=t.createElement("HR");t.modifyBlocks(function(e){return e.appendChild(a),e}),o=a.previousSibling,o&&l.default.isTextNode(o)&&0===l.default.getTextLength(o)&&a.parentNode.removeChild(o),n.selectNodeContents(i),n.collapse(!0),t.setSelection(n)}e.focus()}});t.default=s},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var i=n(0),o=r(i),a=n(2),l=r(a),s=l.default.command("wysiwyg",{name:"Heading",exec:function(e,t){var n=e.getEditor();e.focus(),n.hasFormat("TABLE")||n.hasFormat("PRE")||n.modifyBlocks(function(e){return(0,o.default)(e).children("h1, h2, h3, h4, h5, h6, div").each(function(e,n){var r="",i=(0,o.default)(n);if(i.is("DIV"))i.wrap(r);else{var a=(0,o.default)(r);a.insertBefore(n),a.html(i.html()),i.remove()}}),e})}});t.default=s},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var i=n(0),o=r(i),a=n(2),l=r(a),s=l.default.command("wysiwyg",{name:"Paragraph",exec:function(e){var t=e.getEditor();e.focus(),t.hasFormat("TABLE")||t.hasFormat("PRE")||t.modifyBlocks(function(e){var t=(0,o.default)(document.createDocumentFragment());return(0,o.default)(e).children().each(function(e,n){n.nodeName.match(/h\d/i)?t.append((0,o.default)(n).children()):n.nodeName.match(/ul|ol/i)?(0,o.default)(n).find("li").each(function(e,n){t.append((0,o.default)(n).children())}):t.append(n)}),t[0]})}});t.default=s},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(2),i=function(e){return e&&e.__esModule?e:{default:e}}(r),o=i.default.command("wysiwyg",{name:"UL",keyMap:["CTRL+U","META+U"],exec:function(e){var t=e.getEditor(),n=t.getSelection(),r=e.componentManager.getManager("list"),i=n,o=i.startContainer,a=i.endContainer,l=i.startOffset,s=i.endOffset;e.focus(),t.saveUndoState(n);for(var u=r.getLinesOfSelection(o,a),c=[],d=0;d",t&&(n+=t[r],r+=1),n+="",e-=1;return n+=""}function o(e,t,n){for(var r="",i=e,o=0;o";for(var a=0;a",n&&(r+=n[i],i+=1),r+="";r+=""}return r+=""}Object.defineProperty(t,"__esModule",{value:!0});var a=n(2),l=function(e){return e&&e.__esModule?e:{default:e}}(a),s=l.default.command("wysiwyg",{name:"Table",exec:function(e,t,n,a){var l=e.getEditor(),s=e.componentManager.getManager("table").getTableIDClassName(),u=void 0;if(!l.getSelection().collapsed||l.hasFormat("TABLE")||l.hasFormat("PRE"))return void e.focus();u='',u+=i(t,a),u+=o(t,n-1,a),u+="
    ",l.insertHTML(u),e.focus(),a||r(l,e.get$Body().find("."+s))}});t.default=s},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e){var t=e.componentManager.getManager("tableSelection"),n=t.getSelectedCells(),r=1;if(n.length>1){var i=n.first().get(0),o=n.last().get(0),a=t.getSelectionRangeFromTable(i,o);r=a.to.row-a.from.row+1}return r}function o(e){var t=e.clone(),n=c.default.browser.msie?"":"
    ";return t.find("td").html(n),t}function a(e,t){var n=e.getSelection();n.selectNodeContents(t.find("td")[0]),n.collapse(!0),e.setSelection(n)}Object.defineProperty(t,"__esModule",{value:!0});var l=n(0),s=r(l),u=n(1),c=r(u),d=n(2),f=r(d),h=f.default.command("wysiwyg",{name:"AddRow",exec:function(e){var t=e.getEditor(),n=t.getSelection().cloneRange(),r=i(e),l=void 0,u=void 0;if(e.focus(),t.hasFormat("TD")){t.saveUndoState(n),l=(0,s.default)(n.startContainer).closest("tr");for(var c=0;c0){var i=n.get(0).parentNode.querySelectorAll("td, th").length;r=Math.min(i,n.length)}return r}function o(e){var t=e.startContainer;return t="TD"===g.default.getNodeName(t)||"TH"===g.default.getNodeName(t)?(0,u.default)(t):(0,u.default)(t).parentsUntil("tr")}function a(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:1,n=e.index(),r=void 0;e.parents("table").find("tr").each(function(e,i){for(var o="TBODY"===g.default.getNodeName(i.parentNode),a=d.default.browser.msie,l=i.children[n],s=0;s1){t.saveUndoState(n);var d=u.last().next()[0]?u.last().next():u.first().prev();d.length&&i(t,n,d,l),u.remove()}o.removeClassAttrbuteFromAllCellsIfNeed()}});t.default=d},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e){var t=e.startContainer;return t="TD"===h.default.getNodeName(t)||"TH"===h.default.getNodeName(t)?(0,u.default)(t):(0,u.default)(t).parentsUntil("tr")}function o(e){for(var t=e.length,n=0;n0&&a(e.eq(n))}}function a(e){var t=e.index();e.parents("table").find("tr").each(function(e,n){(0,u.default)(n).children().eq(t).remove()})}function l(e,t,n){var r=t.get(0);if(t.length&&u.default.contains(document,t)){var i=e.getSelection();i.selectNodeContents(t[0]),i.collapse(!0),e.setSelection(i),n.setLastCellNode(r)}}Object.defineProperty(t,"__esModule",{value:!0});var s=n(0),u=r(s),c=n(2),d=r(c),f=n(3),h=r(f),p=d.default.command("wysiwyg",{name:"RemoveCol",exec:function(e){var t=e.getEditor(),n=t.getSelection().cloneRange(),r=e.componentManager.getManager("table"),s=e.componentManager.getManager("tableSelection"),c=(0,u.default)(n.startContainer).closest("table").find("thead tr th").length>1;if(e.focus(),n.collapse(!0),t.setSelection(n),t.hasFormat("TR",null,n)&&c){t.saveUndoState(n);var d=void 0,f=void 0,h=s.getSelectedCells();if(h.length>1){var p=h.last(),g=h.first();d=p.next().length>0?p.next():g.prev(),o(h)}else f=i(n),d=f.next().length?f.next():f.prev(),a(f);l(t,d,r)}}});t.default=p},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t,n){var r=n.isDivided||!1,i=n.startColumnIndex,o=n.endColumnIndex,a=e.find("tr").eq(0).find("td,th").length;e.find("tr").each(function(e,n){(0,s.default)(n).children("td,th").each(function(e,n){r&&(i<=e&&e<=a||e<=o)?(0,s.default)(n).attr("align",t):i<=e&&e<=o&&(0,s.default)(n).attr("align",t)})})}function o(e,t){var n=e.find("tr").eq(0).find("td,th").length,r=t.from,i=t.to,o=void 0,a=void 0,l=void 0;return r.row===i.row?(o=r.cell,a=i.cell):r.row
    ")[0]]:(r=e.extractContents(),i=u.default.toArray(r.childNodes)),n.convertToCodeblock(i).innerHTML}Object.defineProperty(t,"__esModule",{value:!0});var a=n(0),l=r(a),s=n(1),u=r(s),c=n(2),d=r(c),f=0,h=d.default.command("wysiwyg",{name:"CodeBlock",keyMap:["SHIFT+CTRL+P","SHIFT+META+P"],exec:function(e,t){var n=e.getEditor(),r=n.getSelection().cloneRange();if(!n.hasFormat("PRE")&&!n.hasFormat("TABLE")){var a='data-te-codeblock class = "te-content-codeblock-'+f+'"';t&&(a+=' data-language="'+t+'"');var l=o(r,e);n.insertHTML("
    "+l+"
    "),i(e.get$Body().find(".te-content-codeblock-"+f),e),f+=1}e.focus()}});t.default=h},function(e,t,n){"use strict";var r=n(5);(function(e){return e&&e.__esModule?e:{default:e}})(r).default.setLanguage(["en","en_US"],{Markdown:"Markdown",WYSIWYG:"WYSIWYG",Write:"Write",Preview:"Preview",Headings:"Headings",Paragraph:"Paragraph",Bold:"Bold",Italic:"Italic",Strike:"Strike",Code:"Inline code",Line:"Line",Blockquote:"Blockquote","Unordered list":"Unordered list","Ordered list":"Ordered list",Task:"Task","Insert link":"Insert link","Insert CodeBlock":"Insert codeBlock","Insert table":"Insert table","Insert image":"Insert image",Heading:"Heading","Image URL":"Image URL","Select image file":"Select image file",Description:"Description",OK:"OK",Cancel:"Cancel",File:"File",URL:"URL","Link text":"Link text","Add row":"Add row","Add col":"Add col","Remove row":"Remove row","Remove col":"Remove col","Align left":"Align left","Align center":"Align center","Align right":"Align right","Remove table":"Remove table","Would you like to paste as table?":"Would you like to paste as table?","Text color":"Text color","Auto scroll enabled":"Auto scroll enabled","Auto scroll disabled":"Auto scroll disabled","Cannot paste values ​​other than a table in the cell selection state":"Cannot paste values ​​other than a table in the cell selection state.","Choose language":"Choose language"})},function(e,t,n){"use strict";var r=n(5);(function(e){return e&&e.__esModule?e:{default:e}})(r).default.setLanguage(["ko","ko_KR"],{Markdown:"마크다운",WYSIWYG:"위지윅",Write:"편집하기",Preview:"미리보기",Headings:"제목크기",Paragraph:"본문",Bold:"굵게",Italic:"기울임꼴",Strike:"취소선",Code:"인라인 코드",Line:"문단나눔",Blockquote:"인용구","Unordered list":"글머리 기호","Ordered list":"번호 매기기",Task:"체크박스","Insert link":"링크 삽입","Insert CodeBlock":"코드블럭 삽입","Insert table":"표 삽입","Insert image":"이미지 삽입",Heading:"제목","Image URL":"이미지 주소","Select image file":"이미지 파일을 선택하세요.",Description:"설명",OK:"확인",Cancel:"취소",File:"파일",URL:"주소","Link text":"링크 텍스트","Add row":"행 추가","Add col":"열 추가","Remove row":"행 삭제","Remove col":"열 삭제","Align left":"왼쪽 정렬","Align center":"가운데 정렬","Align right":"오른쪽 정렬","Remove table":"표 삭제","Would you like to paste as table?":"표형태로 붙여 넣겠습니까?","Text color":"글자 색상","Auto scroll enabled":"자동 스크롤 켜짐","Auto scroll disabled":"자동 스크롤 꺼짐","Cannot paste values ​​other than a table in the cell selection state.":"셀 선택 상태에서는 테이블 이외의 값은 붙여넣을 수 없습니다.","Choose language":"언어 선택"})},function(e,t,n){"use strict";var r=n(5);(function(e){return e&&e.__esModule?e:{default:e}})(r).default.setLanguage(["zh","zh_CN"],{Markdown:"Markdown",WYSIWYG:"所见即所得",Write:"编辑",Preview:"预览",Headings:"标题",Paragraph:"文本",Bold:"加粗",Italic:"斜体字",Strike:"删除线",Code:"内嵌代码",Line:"画水平线",Blockquote:"引用块","Unordered list":"无序列表","Ordered list":"有序列表",Task:"任务","Insert link":"插入链接","Insert CodeBlock":"插入代码块","Insert table":"插入表格","Insert image":"插入图片",Heading:"标题","Image URL":"图片网址","Select image file":"选择映像文件",Description:"说明",OK:"确认",Cancel:"取消",File:"文件",URL:"URL","Link text":"链接文本","Add row":"添加一行","Add col":"添加列","Remove row":"删除行","Remove col":"删除列","Align left":"左对齐","Align center":"居中对齐","Align right":"右对齐","Remove table":"删除表","Would you like to paste as table?":"你想粘贴表吗?","Text color":"文字色相","Auto scroll enabled":"自动滚动启用","Auto scroll disabled":"自动的滚动作非使用","Cannot paste values ​​other than a table in the cell selection state":"在单元格选择状态下无法粘贴表格以外的值。","Choose language":"选择语言"})},function(e,t,n){"use strict";var r=n(5);(function(e){return e&&e.__esModule?e:{default:e}})(r).default.setLanguage(["ja","ja_JP"],{Markdown:"マークダウン",WYSIWYG:"WYSIWYG",Write:"編集する",Preview:"プレビュー",Headings:"見出し",Paragraph:"本文",Bold:"太字",Italic:"イタリック",Strike:"ストライク",Code:"インラインコード",Line:"ライン",Blockquote:"引用","Unordered list":"番号なしリスト","Ordered list":"順序付きリスト",Task:"タスク","Insert link":"リンク挿入","Insert CodeBlock":"コードブロック挿入","Insert table":"テーブル挿入","Insert image":"画像挿入",Heading:"見出し","Image URL":"イメージURL","Select image file":"画像ファイル選択",Description:"ディスクリプション ",OK:"はい",Cancel:"キャンセル",File:"ファイル",URL:"URL","Link text":"リンクテキスト","Add row":"行追加","Add col":"列追加","Remove row":"行削除","Remove col":"列削除","Align left":"左揃え","Align center":"中央揃え","Align right":"右揃え","Remove table":"テーブル削除","Would you like to paste as table?":"テーブルを貼り付けますか?","Text color":"文字色相","Auto scroll enabled":"自動スクロールが有効","Auto scroll disabled":"自動スクロールを無効に","Cannot paste values ​​other than a table in the cell selection state":"表以外の値をセル選択状態に貼り付けることはできません。","Choose language":"言語選択"})},function(e,t,n){"use strict";var r=n(5);(function(e){return e&&e.__esModule?e:{default:e}})(r).default.setLanguage(["nl","nl_NL"],{Markdown:"Markdown",WYSIWYG:"WYSIWYG",Write:"Write",Preview:"Preview",Headings:"Koppen",Paragraph:"tekst",Bold:"Vet",Italic:"Cursief",Strike:"Doorhalen",Code:"Inline Code",Line:"Regel",Blockquote:"Citaatblok","Unordered list":"Opsomming","Ordered list":"Genummerde opsomming",Task:"Taak","Insert link":"Link invoegen","Insert CodeBlock":"Codeblok toevoegen","Insert table":"Tabel invoegen","Insert image":"Afbeelding invoegen",Heading:"Kop","Image URL":"Afbeelding URL","Select image file":"Selecteer een afbeelding",Description:"Omschrijving",OK:"OK",Cancel:"Annuleren",File:"Bestand",URL:"URL","Link text":"Link tekst","Add row":"Rij toevoegen","Add col":"Kolom toevoegen","Remove row":"Rij verwijderen","Remove col":"Kolom verwijderen","Align left":"Links uitlijnen","Align center":"Centreren","Align right":"Rechts uitlijnen","Remove table":"Verwijder tabel","Would you like to paste as table?":"Wil je dit als tabel plakken?","Text color":"Tekstkleur","Auto scroll enabled":"Autoscroll ingeschakeld","Auto scroll disabled":"Autoscroll uitgeschakeld","Cannot paste values ​​other than a table in the cell selection state":"Kan geen waardes anders dan de tabel in de cell plakken","Choose language":"Kies een taal"})},function(e,t,n){"use strict";"function"==typeof Symbol&&Symbol.iterator;!function(r){var i={};i.RELAXED=!1,i.IGNORE_RECORD_LENGTH=!1,i.IGNORE_QUOTES=!1,i.LINE_FEED_OK=!0,i.CARRIAGE_RETURN_OK=!0,i.DETECT_TYPES=!0,i.IGNORE_QUOTE_WHITESPACE=!0,i.DEBUG=!1,i.COLUMN_SEPARATOR=",",i.ERROR_EOF="UNEXPECTED_END_OF_FILE",i.ERROR_CHAR="UNEXPECTED_CHARACTER",i.ERROR_EOL="UNEXPECTED_END_OF_RECORD",i.WARN_SPACE="UNEXPECTED_WHITESPACE";i.parse=function(e){var t=i.result=[];i.COLUMN_SEPARATOR=i.COLUMN_SEPARATOR instanceof RegExp?new RegExp("^"+i.COLUMN_SEPARATOR.source):i.COLUMN_SEPARATOR,i.offset=0,i.str=e,i.record_begin(),i.debug("parse()",e);for(var n;;){if(n=e[i.offset++],i.debug("c",n),null==n){i.escaped&&i.error(i.ERROR_EOF),i.record&&(i.token_end(),i.record_end()),i.debug("...bail",n,i.state,i.record),i.reset();break}if(null==i.record){if(i.RELAXED&&("\n"==n||"\r"==n&&"\n"==e[i.offset+1]))continue;i.record_begin()}if(0==i.state){if((" "===n||"\t"===n)&&'"'==i.next_nonspace()){if(i.RELAXED||i.IGNORE_QUOTE_WHITESPACE)continue;i.warn(i.WARN_SPACE)}if('"'==n&&!i.IGNORE_QUOTES){i.debug("...escaped start",n),i.escaped=!0,i.state=1;continue}i.state=1}1==i.state&&i.escaped?'"'==n?'"'==e[i.offset]?(i.debug("...escaped quote",n),i.token+='"',i.offset++):(i.debug("...escaped end",n),i.escaped=!1,i.state=2):(i.token+=n,i.debug("...escaped add",n,i.token)):"\r"==n?("\n"==e[i.offset]?i.offset++:i.CARRIAGE_RETURN_OK||i.error(i.ERROR_CHAR),i.token_end(),i.record_end()):"\n"==n?(i.LINE_FEED_OK||i.RELAXED||i.error(i.ERROR_CHAR),i.token_end(),i.record_end()):i.test_regex_separator(e)||i.COLUMN_SEPARATOR==n?i.token_end():1==i.state?(i.token+=n,i.debug("...add",n,i.token)):" "===n||"\t"===n?i.IGNORE_QUOTE_WHITESPACE||i.error(i.WARN_SPACE):i.RELAXED||i.error(i.ERROR_CHAR)}return t},i.stream=function(){var e=n(41),t=new e.Transform({objectMode:!0});return t.EOL="\n",t.prior="",t.emitter=function(e){return function(t){e.push(i.parse(t+e.EOL))}}(t),t._transform=function(e,t,n){var r=""==this.prior?e.toString().split(this.EOL):(this.prior+e.toString()).split(this.EOL);this.prior=r.pop(),r.forEach(this.emitter),n()},t._flush=function(e){""!=this.prior&&(this.emitter(this.prior),this.prior=""),e()},t},i.test_regex_separator=function(e){if(!(i.COLUMN_SEPARATOR instanceof RegExp))return!1;var t;return e=e.slice(i.offset-1),t=i.COLUMN_SEPARATOR.exec(e),t&&(i.offset+=t[0].length-1),null!==t},i.stream.json=function(){var e=n(157),t=(n(41),new streamTransform({objectMode:!0}));return t._transform=function(n,r,i){t.push(JSON.stringify(n.toString())+e.EOL),i()},t},i.reset=function(){i.state=null,i.token=null,i.escaped=null,i.record=null,i.offset=null,i.result=null,i.str=null},i.next_nonspace=function(){for(var e,t=i.offset;t0&&i.record.length!=i.result[0].length&&i.error(i.ERROR_EOL),i.result.push(i.record),i.debug("record end",i.record),i.record=null},i.resolve_type=function(e){return e.match(/^[-+]?[0-9]+(\.[0-9]+)?([eE][-+]?[0-9]+)?$/)?e=parseFloat(e):e.match(/^(true|false)$/i)?e=Boolean(e.match(/true/i)):"undefined"===e?e=void 0:"null"===e&&(e=null),e},i.token_begin=function(){i.state=0,i.token=""},i.token_end=function(){i.DETECT_TYPES&&(i.token=i.resolve_type(i.token)),i.record.push(i.token),i.debug("token end",i.token),i.token_begin()},i.debug=function(){i.DEBUG&&console.log(arguments)},i.dump=function(e){return[e,"at char",i.offset,":",i.str.substr(i.offset-50,50).replace(/\r/gm,"\\r").replace(/\n/gm,"\\n").replace(/\t/gm,"\\t")].join(" ")},i.error=function(e){var t=i.dump(e);throw i.reset(),t},i.warn=function(e){if(i.DEBUG){var t=i.dump(e);try{return void console.warn(t)}catch(e){}try{console.log(t)}catch(e){}}},void 0!==e&&e.exports?e.exports=i:t.CSV=i}()},function(e,t,n){"use strict";function r(e){var t=e.length;if(t%4>0)throw new Error("Invalid string. Length must be a multiple of 4");return"="===e[t-2]?2:"="===e[t-1]?1:0}function i(e){return 3*e.length/4-r(e)}function o(e){var t,n,i,o,a,l=e.length;o=r(e),a=new d(3*l/4-o),n=o>0?l-4:l;var s=0;for(t=0;t>16&255,a[s++]=i>>8&255,a[s++]=255&i;return 2===o?(i=c[e.charCodeAt(t)]<<2|c[e.charCodeAt(t+1)]>>4,a[s++]=255&i):1===o&&(i=c[e.charCodeAt(t)]<<10|c[e.charCodeAt(t+1)]<<4|c[e.charCodeAt(t+2)]>>2,a[s++]=i>>8&255,a[s++]=255&i),a}function a(e){return u[e>>18&63]+u[e>>12&63]+u[e>>6&63]+u[63&e]}function l(e,t,n){for(var r,i=[],o=t;os?s:a+16383));return 1===r?(t=e[n-1],i+=u[t>>2],i+=u[t<<4&63],i+="=="):2===r&&(t=(e[n-2]<<8)+e[n-1],i+=u[t>>10],i+=u[t>>4&63],i+=u[t<<2&63],i+="="),o.push(i),o.join("")}t.byteLength=i,t.toByteArray=o,t.fromByteArray=s;for(var u=[],c=[],d="undefined"!=typeof Uint8Array?Uint8Array:Array,f="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",h=0,p=f.length;h>1,c=-7,d=n?i-1:0,f=n?-1:1,h=e[t+d];for(d+=f,o=h&(1<<-c)-1,h>>=-c,c+=l;c>0;o=256*o+e[t+d],d+=f,c-=8);for(a=o&(1<<-c)-1,o>>=-c,c+=r;c>0;a=256*a+e[t+d],d+=f,c-=8);if(0===o)o=1-u;else{if(o===s)return a?NaN:1/0*(h?-1:1);a+=Math.pow(2,r),o-=u}return(h?-1:1)*a*Math.pow(2,o-r)},t.write=function(e,t,n,r,i,o){var a,l,s,u=8*o-i-1,c=(1<>1,f=23===i?Math.pow(2,-24)-Math.pow(2,-77):0,h=r?0:o-1,p=r?1:-1,g=t<0||0===t&&1/t<0?1:0;for(t=Math.abs(t),isNaN(t)||t===1/0?(l=isNaN(t)?1:0,a=c):(a=Math.floor(Math.log(t)/Math.LN2),t*(s=Math.pow(2,-a))<1&&(a--,s*=2),t+=a+d>=1?f/s:f*Math.pow(2,1-d),t*s>=2&&(a++,s/=2),a+d>=c?(l=0,a=c):a+d>=1?(l=(t*s-1)*Math.pow(2,i),a+=d):(l=t*Math.pow(2,d-1)*Math.pow(2,i),a=0));i>=8;e[n+h]=255&l,h+=p,l/=256,i-=8);for(a=a<0;e[n+h]=255&a,h+=p,a/=256,u-=8);e[n+h-p]|=128*g}},function(e,t){},function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function i(e,t,n){e.copy(t,n)}var o=n(18).Buffer;e.exports=function(){function e(){r(this,e),this.head=null,this.tail=null,this.length=0}return e.prototype.push=function(e){var t={data:e,next:null};this.length>0?this.tail.next=t:this.head=t,this.tail=t,++this.length},e.prototype.unshift=function(e){var t={data:e,next:this.head};0===this.length&&(this.tail=t),this.head=t,++this.length},e.prototype.shift=function(){if(0!==this.length){var e=this.head.data;return 1===this.length?this.head=this.tail=null:this.head=this.head.next,--this.length,e}},e.prototype.clear=function(){this.head=this.tail=null,this.length=0},e.prototype.join=function(e){if(0===this.length)return"";for(var t=this.head,n=""+t.data;t=t.next;)n+=e+t.data;return n},e.prototype.concat=function(e){if(0===this.length)return o.alloc(0);if(1===this.length)return this.head.data;for(var t=o.allocUnsafe(e>>>0),n=this.head,r=0;n;)i(n.data,t,r),r+=n.data.length,n=n.next;return t},e}()},function(e,t,n){function r(e,t){this._id=e,this._clearFn=t}var i=Function.prototype.apply;t.setTimeout=function(){return new r(i.call(setTimeout,window,arguments),clearTimeout)},t.setInterval=function(){return new r(i.call(setInterval,window,arguments),clearInterval)},t.clearTimeout=t.clearInterval=function(e){e&&e.close()},r.prototype.unref=r.prototype.ref=function(){},r.prototype.close=function(){this._clearFn.call(window,this._id)},t.enroll=function(e,t){clearTimeout(e._idleTimeoutId),e._idleTimeout=t},t.unenroll=function(e){clearTimeout(e._idleTimeoutId),e._idleTimeout=-1},t._unrefActive=t.active=function(e){clearTimeout(e._idleTimeoutId);var t=e._idleTimeout;t>=0&&(e._idleTimeoutId=setTimeout(function(){e._onTimeout&&e._onTimeout()},t))},n(150),t.setImmediate=setImmediate,t.clearImmediate=clearImmediate},function(e,t,n){(function(e,t){!function(e,n){"use strict";function r(e){"function"!=typeof e&&(e=new Function(""+e));for(var t=new Array(arguments.length-1),n=0;n')}),p=e.getUI().toolbar.addDivider(),e.getUI().toolbar.addButton(d),t(),e.on("changeMode",t),e.on("changePreviewStyle",t),e.addCommand("markdown",{name:"scrollSyncToggle",exec:function(){u=!u,d._onOut(),u?(d.$el.addClass("active"),d.tooltip=r.active):(d.$el.removeClass("active"),d.tooltip=r.inActive),d._onOver()}})),i.on("change",function(){s=!1,o.makeSectionList()}),e.on("previewRenderAfter",function(){o.sectionMatch(),l.syncPreviewScrollTopToMarkdown(),s=!0}),e.eventManager.listen("scroll",function(t){u&&(s&&e.preview.isVisible()?"markdown"!==t.source||l.isMarkdownScrollEventBlocked?"preview"!==t.source||l.isPreviewScrollEventBlocked||l.syncMarkdownScrollTopToPreview():l.syncPreviewScrollTopToMarkdown():l.saveScrollInfo())})}}Object.defineProperty(t,"__esModule",{value:!0});var o=n(0),a=r(o),l=n(4),s=r(l),u=n(159),c=r(u),d=n(160),f=r(d),h=s.default.Button;s.default.defineExtension("scrollSync",i),t.default=i},function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(t,"__esModule",{value:!0});var i=function(){function e(e,t){for(var n=0;n0?e.start-1:0,"local")}},{key:"_getEditorLineHeightGapInSection",value:function(e,t){var n=this.cm.heightAtLine(t,"local");return n-=this.cm.heightAtLine(e.start>0?e.start-1:0,"local"),Math.max(n,0)}},{key:"_getEditorSectionScrollRatio",value:function(e,t){var n=e.end===e.start;return n?0:this._getEditorLineHeightGapInSection(e,t)/this._getEditorSectionHeight(e)}},{key:"_getScrollFactorsOfEditor",value:function(){var e=this.cm,t=e.getScrollInfo(),n=void 0,r=void 0,i=void 0,o=void 0;t=this._fallbackScrollInfoIfIncorrect(t);var a=t.height-t.top<=t.clientHeight;return a?o={isEditorBottom:a}:(n=e.coordsChar({left:t.left,top:t.top},"local").line,r=this.sectionManager.sectionByLine(n),i=this._getEditorSectionScrollRatio(r,n),o={section:r,sectionRatio:i}),o}},{key:"_getScrollInfoForMarkdown",value:function(){var e=this,t=this.sectionManager.getSectionList(),n=void 0;return a.default.forEachArray(t,function(t){var r=t.$previewSectionEl,i=r.parent().parent(),o=i[0].clientHeight-i.scrollTop()<=i[0].height,a=!0;return o?(n={isPreviewBottom:o},a=!1):e._isTopSection(i,r)&&(n={section:t,sectionRatio:e._getMarkdownEditorScrollRatio(i,r)},a=!1),a}),n}},{key:"_getMarkdownEditorScrollRatio",value:function(e,t){return(e.scrollTop()-t[0].offsetTop)/t.height()}},{key:"_getScrollTopForPreview",value:function(){var e=void 0,t=this._getScrollFactorsOfEditor(),n=t.section,r=t.sectionRatio;return t.isEditorBottom?e=this.$contents.height():n.$previewSectionEl&&(e=n.$previewSectionEl[0].offsetTop,e+=n.$previewSectionEl.height()*r-20),e=e&&Math.max(e,0)}},{key:"_getScrollTopForMarkdown",value:function(){var e=void 0,t=this._getScrollInfoForMarkdown(),n=t.sectionRatio;if(t.isPreviewBottom)e=this.cm.getScrollInfo().height;else if(t.section){var r=t.section,i=this.cm.charCoords({line:r.start,char:0},"local"),o=this.cm.charCoords({line:r.end,char:0},"local");e=i.top,e+=(o.top-i.top)*n}return e=e&&Math.max(e,0)}},{key:"syncPreviewScrollTopToMarkdown",value:function(){var e=this,t=this.$previewContainerEl,n=t.scrollTop(),r=this._getScrollTopForPreview();this.isPreviewScrollEventBlocked=!0,this._animateRun(n,r,function(n){clearTimeout(e.releaseTimer),t.scrollTop(n),e.releaseTimer=setTimeout(function(){e.isPreviewScrollEventBlocked=!1},15)})}},{key:"syncMarkdownScrollTopToPreview",value:function(){var e=this,t=this.cm,n=t.getScrollInfo(),r=n.top,i=this._getScrollTopForMarkdown();this.isMarkdownScrollEventBlocked=!0,this._animateRun(r,i,function(n){clearTimeout(e.releaseTimer),t.scrollTo(0,n),e.releaseTimer=setTimeout(function(){e.isMarkdownScrollEventBlocked=!1},15)})}},{key:"_animateRun",value:function(e,t,n){function r(){var l=Date.now(),s=(l-o)/200,u=void 0;s<1?(u=e+i*Math.cos((1-s)*Math.PI/2),n(Math.ceil(u)),a._currentTimeoutId=setTimeout(r,1)):(n(t),a._currentTimeoutId=null)}var i=t-e,o=Date.now(),a=this;this._currentTimeoutId&&clearTimeout(this._currentTimeoutId),r()}},{key:"_fallbackScrollInfoIfIncorrect",value:function(e){return e.height<0&&this._savedScrollInfo?this._savedScrollInfo:e}},{key:"saveScrollInfo",value:function(){this._savedScrollInfo=this.cm.getScrollInfo()}},{key:"_isTopSection",value:function(e,t){var n=e.scrollTop(),r=t[0].offsetTop,i=t.height(),o=n>=r-57,a=n>r+i;return o&&!a}}]),e}();t.default=l},function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function i(){return this.nodeType===Node.ELEMENT_NODE}Object.defineProperty(t,"__esModule",{value:!0});var o=function(){function e(e,t){for(var n=0;n ?)+\s/,d=/^ {0,3}!\[([^[\]]*)]\(([^)]*)\)/,f=/^ *(?:={1,}|-{1,})\s*$/,h=/^ *(`{3,}|~{3,})[ ]*$/,p=/^ *(`{3,}|~{3,})[ .]*(\S+)? */,g=/\s/g,v=function(){function e(t,n){r(this,e),this.cm=t,this.preview=n,this.$previewContent=n.$el.find(".tui-editor-contents"),this._sectionList=null,this._currentSection=null}return o(e,[{key:"_addNewSection",value:function(e,t){var n=this._makeSectionData(e,t);this._sectionList.push(n),this._currentSection=n}},{key:"getSectionList",value:function(){return this._sectionList||this.makeSectionList(),this._sectionList}},{key:"_makeSectionData",value:function(e,t){return{start:e,end:t,$previewSectionEl:null}}},{key:"_updateCurrentSectionEnd",value:function(e){this._currentSection.end=e}},{key:"_eachLineState",value:function(e){var t=void 0,n=void 0,r=void 0,i=void 0,o=void 0,a=!0,l=!1,s=!1,u="",c=!1,d=!1,f=void 0,h=this.cm.getDoc().lineCount();for(n=0;n
    ");r.$previewSectionEl=(0,l.default)(e).wrapAll(i).parent()}})}},{key:"_getPreviewSections",value:function(){var e=[],t=0,n=!1;return e[0]=[],this.$previewContent.contents().filter(i).each(function(r,i){var o="P"===i.tagName,a=i.tagName.match(/^(H1|H2|H3|H4|H5|H6)$/),l=o&&"IMG"===i.childNodes[0].nodeName;(a||l||n)&&e[t].length&&(e.push([]),t+=1,n=!1),l&&(n=!0),e[t].push(i)}),e}},{key:"sectionByLine",value:function(e){var t=void 0,n=this.getSectionList(),r=n.length;for(t=0;t"+e+"
    "),r=n.find("table");return r.length&&(r.get().forEach(function(e){var n=t(e);(0,d.default)(e).replaceWith(n)}),e=n.html()),e}function s(e){var t=e.command;if(t.isWWType())switch(t.getName()){case"AddRow":e.command=T.default;break;case"AddCol":e.command=S.default;break;case"RemoveRow":e.command=x.default;break;case"RemoveCol":e.command=I.default;break;case"AlignCol":e.command=N.default}}function u(e){e.listen("convertorAfterMarkdownToHtmlConverted",function(e){return l(e,g.default)}),e.listen("convertorBeforeHtmlToMarkdownConverted",function(e){return l(e,m.default)}),e.listen("addCommandBefore",s)}var c=n(0),d=r(c),f=n(4),h=r(f);n(162);var p=n(163),g=r(p),v=n(164),m=r(v),y=n(165),_=r(y),b=n(166),w=r(b),k=n(167),E=r(k),C=n(168),T=r(C),M=n(169),S=r(M),O=n(170),x=r(O),L=n(171),I=r(L),A=n(172),N=r(A),B=n(173),P=r(B),R=n(174),D=r(R),j=n(175),$=r(j);h.default.defineExtension("table",i)},function(e,t,n){"use strict";var r=n(4),i=function(e){return e&&e.__esModule?e:{default:e}}(r),o=i.default.i18n;o&&(o.setLanguage(["ko","ko_KR"],{"Merge cells":"셀 병합","Unmerge cells":"셀 병합해제","Cannot change part of merged cell":"병합 된 셀의 일부를 변경할 수 없습니다.","Cannot paste row merged cells into the table header":"테이블 헤더에는 행 병합된 셀을 붙여넣을 수 없습니다."}),o.setLanguage(["en","en_US"],{"Merge cells":"Merge cells","Unmerge cells":"Unmerge cells","Cannot change part of merged cell":"Cannot change part of merged cell.","Cannot paste row merged cells into the table header":"Cannot paste row merged cells into the table header."}),o.setLanguage(["ja","ja_JP"],{"Merge cells":"セルの結合","Unmerge cells":"セルの結合を解除","Cannot change part of merged cell":"結合されたセルの一部を変更することはできません。","Cannot paste row merged cells into the table header":"行にマージされたセルをヘッダーに貼り付けることはできません。"}),o.setLanguage(["nl","nl_NL"],{"Merge cells":"cellen samenvoegen","Unmerge cells":"Samenvoegen cellen ongedaan maken","Cannot change part of merged cell":"Kan geen deel uit van samengevoegde cel te veranderen.","Cannot paste row merged cells into the table header":"Kan niet plakken rij samengevoegde cellen in de koptekst. "}),o.setLanguage(["zh","zh_CN"],{"Merge cells":"合并单元格","Unmerge cells":"取消合并单元格","Cannot change part of merged cell":"无法更改合并单元格的一部分。","Cannot paste row merged cells into the table header":"无法将行合并单元格粘贴到标题中。"}))},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t,n){var r=new RegExp("^((?:"+n+"=[0-9]+:)?)"+t+"=([0-9]+):(.*)"),i=r.exec(e),o=1;return i&&(o=parseInt(i[2],10),e=i[1]+i[3]),[o,e]}function o(e){var t=e.nodeName,n=e.align||"",r=e.innerHTML.trim(),o=null,a=null,l=i(r,"@cols","@rows");o=l[0],r=l[1];var s=i(r,"@rows","@cols");return a=s[0],r=s[1],{nodeName:t,colspan:o,rowspan:a,content:r,align:n}}function a(e){return e.find("tr").get().map(function(e){return(0,p.default)(e).find("td, th").get().map(o)})}function l(e,t){var n=-1;return v.default.forEach(e,function(e,r){var i=!0;return t(e,r)&&(n=r,i=!1),i}),n}function s(e){var t=l(e,function(e){return"TD"===e[0].nodeName});return[e.slice(0,t),e.slice(t)]}function u(e){e.forEach(function(e){var t=e.length,n=0;e.forEach(function(e){n+=e.colspan-1}),e.splice(t-n)})}function c(e){var t=e.map(function(e,t){return t}),n=t.map(function(){return 0});return e.forEach(function(e,r){var i=e.filter(function(e){return e.rowspan>1}),o=r+1;i.forEach(function(e){var r=e.colspan,i=o+(e.rowspan-1);t.slice(o,i).forEach(function(e){n[e]+=r})})}),n}function d(e){var t=c(e);e.forEach(function(e,n){e.splice(e.length-t[n])})}function f(e){var t=a((0,p.default)(e)),n=s(t),r=n[0],i=n[1];return u(r),u(i),d(i),(0,p.default)(y.default.createTableHtml(t))[0]}Object.defineProperty(t,"__esModule",{value:!0}),t._extractPropertiesForMerge=i,t._parseTableCell=o,t._createTableObjectFrom$Table=a,t._divideTrs=s,t._mergeByColspan=u,t._getRemovalTdCountsByRowspan=c,t._mergeByRowspan=d,t.default=f;var h=n(0),p=r(h),g=n(1),v=r(g),m=n(7),y=r(m)},function(e,t,n){"use strict";function r(e){var t=(0,a.default)(e),n=t.attr("colspan")||"",r=t.attr("rowspan")||"",i=t.html();n&&(i="@cols="+n+":"+i),r&&(i="@rows="+r+":"+i),i&&t.html(i)}function i(e){return(0,a.default)(e).find("td, th").get().forEach(r),e}Object.defineProperty(t,"__esModule",{value:!0}),t._prependMergeSyntaxToContent=r,t.default=i;var o=n(0),a=function(e){return e&&e.__esModule?e:{default:e}}(o)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){return d.default.range(0,t).map(function(){return e}).join("")}function o(e){var t=e.align,n=(e.textContent||e.innerText).replace(p,""),r=n.length,o="",a="";return t&&("left"===t?(o=":",r-=1):"right"===t?(a=":",r-=1):"center"===t&&(a=":",o=":",r-=2)),r=Math.max(r,3),o+i("-",r)+a}function a(e){var t=0;return e.filter(function(e){return(0,u.default)(e).attr("colspan")}).forEach(function(e){t+=parseInt((0,u.default)(e).attr("colspan"),10)-1}),t}function l(e,t){var n=(0,u.default)(e).find("th").get(),r=n.map(function(e){return" "+o(e)+" |"}).join("");return r+=i(" --- |",a(n)),t?t+"|"+r+"\n":""}Object.defineProperty(t,"__esModule",{value:!0}),t._getAdditionalThCount=a,t._createTheadMarkdown=l;var s=n(0),u=r(s),c=n(1),d=r(c),f=n(39),h=r(f),p=/@cols=[0-9]+:/g;t.default=h.default.Renderer.factory(h.default.gfmRenderer,{THEAD:l})},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function l(e,t){var n=!1;return f.default.forEach(e,function(e){return!(n=t(e))}),n}Object.defineProperty(t,"__esModule",{value:!0});var s=function(){function e(e,t){for(var n=0;n1});return r&&i}},{key:"_isExactlyFit",value:function(e,t,n){return t%e.length==0&&n%e[0].length==0}},{key:"_updateClipboardTableData",value:function(e,t,n){var r=e.length,i=e[0].length,o=parseInt(t/r,10),a=parseInt(n/i,10);if(o>1){var l=JSON.parse(JSON.stringify(e));f.default.range(0,o-1).forEach(function(){var t=JSON.parse(JSON.stringify(l));e.push.apply(e,t)})}if(a>1){var s=JSON.parse(JSON.stringify(e));f.default.range(0,a-1).forEach(function(){var t=JSON.parse(JSON.stringify(s));e.forEach(function(e,n){e.push.apply(e,t[n])})})}}},{key:"_updateTableDataByClipboardData",value:function(e,t,n){var r=n.rowIndex,i=n.colIndex;e.forEach(function(e,n){var o=r+n;e.forEach(function(e,n){var r=i+n,a=t[o][r];e.nodeName=a.nodeName,t[o][r]=e})})}},{key:"_isPossibleToPaste",value:function(e,t,n){var r=t.rowIndex,i=t.colIndex,o=n.rowIndex,a=n.colIndex,s=e.slice(r,o+1),u=s[0].slice(i,a+1),c=!l(u,function(e){return f.default.isExisty(e.rowMergeWith)});if(c){c=!l(f.default.pluck(s,i),function(e){return f.default.isExisty(e.colMergeWith)})}if(c&&e.length>o+1){c=!l(e[o+1].slice(i,a+1),function(e){return f.default.isExisty(e.rowMergeWith)})}if(c&&e[0].length>a+1){c=!l(f.default.pluck(s,a+1),function(e){return f.default.isExisty(e.colMergeWith)})}return c}},{key:"_spliceClipboardData",value:function(e,t,n){e.splice(t),e.forEach(function(e){e.splice(n)})}},{key:"_bookmarkLastTd",value:function(e){var t=e.rowIndex,n=e.colIndex,r=this.wwe.getEditor(),i=r.get$Body().find(".tui-paste-table-bookmark"),o=v.default.createTableData(i),a=o[t][n];t=f.default.isExisty(a.rowMergeWith)?a.rowMergeWith:t,n=f.default.isExisty(a.colMergeWith)?a.colMergeWith:n;var l=o[t][n].elementIndex,s=i.find("tr").eq(l.rowIndex).children()[l.colIndex];i.removeClass("tui-paste-table-bookmark"),(0,c.default)(s).addClass("tui-paste-table-cell-bookmark")}},{key:"_updateClipboardDataForPasteToSamllerSelectedArea",value:function(e,t,n,r,i){var o=!0,a={rowIndex:0,colIndex:0},l={rowIndex:n-1,colIndex:r-1};return this._isPossibleToPaste(e,a,l)?(this._spliceClipboardData(e,n,r),this._updateTableDataByClipboardData(e,t,i)):o=!1,o}},{key:"_pasteToSelectedArea",value:function(e,t,n,r){var i=b.default.getTableSelectionRange(n,r),o=i.start,a=i.end,l=a.rowIndex-o.rowIndex+1,s=a.colIndex-o.colIndex+1,u=t.length,c=t[0].length,d=l>=u&&s>=c,f=k.get("Cannot change part of merged cell"),h=!0,p=void 0;this._hasRowMergedHeader(t,n,o)?(f=k.get("Cannot paste row merged cells into the table header"),h=!1):this._isExactlyFit(t,l,s)?(p=a,this._updateClipboardTableData(t,l,s),this._updateTableDataByClipboardData(t,n,o)):d?(p={rowIndex:o.rowIndex+u-1,colIndex:o.colIndex+c-1},this._isPossibleToPaste(n,o,p)?this._updateTableDataByClipboardData(t,n,o):h=!1):(p={rowIndex:o.rowIndex+l-1,colIndex:o.colIndex+s-1},h=this._updateClipboardDataForPasteToSamllerSelectedArea(t,n,l,s,o)),h?(n.className+=" tui-paste-table-bookmark",y.default.replaceTable(e,n),this._bookmarkLastTd(p)):(alert(f),this.wwe.focus())}},{key:"_findEndCellIndex",value:function(e,t){var n=t.rowIndex,r=t.colIndex;return{rowIndex:n+e.length-1,colIndex:r+e[0].length-1}}},{key:"_expandRow",value:function(e,t){var n=e.length,r=e[0].length,i=f.default.range(n,n+t).map(function(e){return f.default.range(0,r).map(function(t){return v.default.createBasicCell(e,t)})});e.push.apply(e,i)}},{key:"_expandCoumn",value:function(e,t){var n=e[0].length,r=f.default.range(n,n+t);e.forEach(function(e,t){var n=e[0].nodeName,i=r.map(function(e){return v.default.createBasicCell(t,e,n)});e.push.apply(e,i)})}},{key:"_expandTableDataIfNeed",value:function(e,t,n){var r=n.rowIndex-e.length+1,i=n.colIndex-e[0].length+1;r>0&&this._expandRow(e,r),i>0&&this._expandCoumn(e,i)}},{key:"_pasteAllClipboardTableData",value:function(e,t,n,r){var i=this._findEndCellIndex(t,r);if(this._hasRowMergedHeader(t,n,r))return alert(k.get("Cannot paste row merged cells into the table header")),void this.wwe.focus();this._expandTableDataIfNeed(n,r,i),this._isPossibleToPaste(n,r,i)?(this._updateTableDataByClipboardData(t,n,r),n.className+=" tui-paste-table-bookmark",y.default.replaceTable(e,n),this._bookmarkLastTd(i)):(alert(k.get("Cannot change part of merged cell")),this.wwe.focus())}},{key:"pasteClipboardData",value:function(e){var t=v.default.createTableData(e),n=this.wwe.componentManager.getManager("tableSelection"),r=n.getSelectedCells(),i=(0,c.default)(this._findStartCell(r)),o=i.closest("table"),a=v.default.createTableData(o),l=this._findStartCellIndex(a,i);r.length>1?this._pasteToSelectedArea(o,t,a,r):this._pasteAllClipboardTableData(o,t,a,l)}}]),t}(w);t.default=E},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(t,"__esModule",{value:!0});var l=function(){function e(e,t){for(var n=0;nt&&(s.rowspan+=1,a=d.default.extend({},r))}else r.rowspan>1&&(r.rowspan+=1,a=i(t));return a||(a=g.default.createBasicCell(t+1,o)),n=a,a})}function a(e,t){var n=t.start.rowIndex,r=t.end,i=g.default.findRowMergedLastIndex(e,r.rowIndex,r.colIndex),a=d.default.range(n,i+1).map(function(){return o(e,i)});e.splice.apply(e,[i+1,0].concat(a))}function l(e,t,n){var r=g.default.createTableData(e),i=g.default.findRowMergedLastIndex(r,t,n)+1,o=g.default.findElementIndex(r,i,n);return e.find("tr").eq(o.rowIndex).find("td")[o.colIndex]}Object.defineProperty(t,"__esModule",{value:!0}),t._createNewRow=o,t._addRow=a;var s=n(0),u=r(s),c=n(1),d=r(c),f=n(4),h=r(f),p=n(6),g=r(p),v=n(8),m=r(v),y=n(7),_=r(y),b=h.default.CommandManager,w=void 0;b&&(w=b.command("wysiwyg",{name:"AddRow",exec:function(e){var t=e.getEditor(),n=t.getSelection().cloneRange();if(e.focus(),t.hasFormat("TABLE")){var r=(0,u.default)(n.startContainer),i=r.closest("table"),o=g.default.createTableData(i),s=e.componentManager.getManager("tableSelection").getSelectedCells(),c=m.default.getTableSelectionRange(o,s,r);t.saveUndoState(n),a(o,c);var d=_.default.replaceTable(i,o),f=l(d,c.end.rowIndex,c.start.colIndex);_.default.focusToCell(t,n,f)}}})),t.default=w},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){return{nodeName:t,colMergeWith:e}}function o(e,t,n,r){var o=e[n],a=void 0;if(f.default.isExisty(o.colMergeWith)){var l=o.colMergeWith,s=e[l],u=l+s.colspan-1;f.default.isExisty(s.rowMergeWith)&&r?a=f.default.extend({},r):u>n&&(s.colspan+=1,a=f.default.extend({},o))}else o.colspan>1&&(o.colspan+=1,a=i(n,o.nodeName));return a||(a=v.default.createBasicCell(t,n+1,o.nodeName)),a}function a(e,t,n){var r=f.default.range(t,n+1),i=[],a=null;return e.forEach(function(e,t){var l=r.map(function(r,i){var l=a?a[i-1]:null;return o(e,t,n,l)});a=l,i.push(l)}),i}function l(e,t){var n=t.end,r=v.default.findColMergedLastIndex(e,n.rowIndex,n.colIndex),i=a(e,t.start.colIndex,r),o=r+1;e.forEach(function(e,t){e.splice.apply(e,[o,0].concat(i[t]))})}function s(e,t,n){var r=v.default.createTableData(e),i=v.default.findColMergedLastIndex(r,t,n)+1,o=v.default.findElementIndex(r,t,i);return e.find("tr").eq(o.rowIndex).find("td, th")[o.colIndex]}Object.defineProperty(t,"__esModule",{value:!0}),t._createNewColumns=a,t._addColumns=l;var u=n(0),c=r(u),d=n(1),f=r(d),h=n(4),p=r(h),g=n(6),v=r(g),m=n(8),y=r(m),_=n(7),b=r(_),w=p.default.CommandManager,k=void 0;w&&(k=w.command("wysiwyg",{name:"AddCol",exec:function(e){var t=e.getEditor(),n=t.getSelection().cloneRange();if(e.focus(),t.hasFormat("TABLE")){var r=(0,c.default)(n.startContainer),i=r.closest("table"),o=v.default.createTableData(i),a=e.componentManager.getManager("tableSelection").getSelectedCells(),u=y.default.getTableSelectionRange(o,a,r);t.saveUndoState(n),l(o,u);var d=b.default.replaceTable(i,o),f=s(d,u.start.rowIndex,u.end.colIndex);b.default.focusToCell(t,n,f)}}})),t.default=k},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t,n){d.default.range(t,n+1).forEach(function(t){e[t].forEach(function(r,i){if(d.default.isExisty(r.rowMergeWith)){var o=e[r.rowMergeWith][i];o.rowspan&&(o.rowspan-=1)}else if(r.rowspan>1){var a=t+r.rowspan-1;r.rowspan-=n-t+1,a>n&&(e[n+1][i]=d.default.extend({},r))}})})}function o(e,t,n){e.slice(n+1).forEach(function(e){e.forEach(function(e){d.default.isExisty(e.rowMergeWith)&&e.rowMergeWith>=t&&(e.rowMergeWith=n+1)})})}function a(e,t){var n=t.start.rowIndex,r=t.end,a=g.default.findRowMergedLastIndex(e,r.rowIndex,r.colIndex);if(0!==n||0!==a){n=Math.max(n,1),a=Math.max(a,1);var l=a-n+1;e.length-l<2?e.splice(0,e.length):(i(e,n,a),o(e,n,a),e.splice(n,l))}}function l(e,t,n){var r=g.default.createTableData(e);r.length-11){var o=t+r.colspan-1;r.colspan-=n-t+1,o>n&&(e[n+1]=d.default.extend({},r))}})})}function o(e,t,n){e.forEach(function(e){e.slice(n+1).forEach(function(e){d.default.isExisty(e.colMergeWith)&&e.colMergeWith>=t&&(e.colMergeWith=n+1)})})}function a(e,t){var n=t.start.colIndex,r=t.end,a=g.default.findColMergedLastIndex(e,r.rowIndex,r.colIndex),l=a-n+1;i(e,n,a),o(e,n,a),e.forEach(function(e){e.splice(n,l)})}function l(e,t,n){var r=g.default.createTableData(e);r[0].length-1=o[0].length?h-1:h,v=l(f,c.start.rowIndex,p);_.default.focusToCell(t,n,v)}}}})),t.default=w},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t,n,r){u.default.range(t,n+1).forEach(function(t){var n=e[t];u.default.isExisty(n.colMergeWith)?e[n.colMergeWith].align=r:n.align=r})}function o(e,t){var n=h.default.findElementRowIndex(t),r=h.default.findElementColIndex(t);return e.find("tr").eq(n).find("td, th")[r]}Object.defineProperty(t,"__esModule",{value:!0});var a=n(0),l=r(a),s=n(1),u=r(s),c=n(4),d=r(c),f=n(6),h=r(f),p=n(8),g=r(p),v=n(7),m=r(v),y=d.default.CommandManager,_=void 0;y&&(_=y.command("wysiwyg",{name:"AlignCol",exec:function(e,t){var n=e.getEditor(),r=n.getSelection().cloneRange();if(e.focus(),n.hasFormat("TABLE")){var a=(0,l.default)(r.startContainer),s=a.closest("table"),u=h.default.createTableData(s),c=e.componentManager.getManager("tableSelection").getSelectedCells(),d=g.default.getTableSelectionRange(u,c,a);i(u[0],d.start.colIndex,d.end.colIndex,t);var f=m.default.replaceTable(s,u),p=o(f,a);m.default.focusToCell(n,r,p)}}})),t.default=_},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t,n){var r,i=n+1,o=(r=[]).concat.apply(r,e.map(function(e){return e.slice(t,i)})),a=o.filter(function(e){var t=e.content;return t&&t!==E});return a.length?a[0].content:E}function o(e,t,n){var r,i=n+1,o=e.map(function(e){return e.slice(t,i)});(r=[]).concat.apply(r,o).slice(1).forEach(function(e){var t=e.nodeName;h.default.forEach(e,function(t,n){return delete e[n]}),e.nodeName=t})}function a(e,t,n,r){var i=n+1;e.forEach(function(e){e.slice(t,i).forEach(function(e){e.rowMergeWith=r})})}function l(e,t,n,r){var i=n+1;e.forEach(function(e){e.slice(t,i).forEach(function(e){e.colMergeWith=r})})}function s(e,t){var n=t.start,r=t.end,s=n.rowIndex,u=n.colIndex,c=r.rowIndex,d=r.colIndex,f=e[s][u],h=e.slice(s,c+1),p=c-s+1,g=d-u+1;f.rowspan=p,f.colspan=g,f.content=i(h,u,d),o(h,u,d),p>1&&a(h.slice(1),u,d,s),g>1&&l(h,u+1,d,u)}function u(e,t,n){var r=m.default.createTableData(e),i=m.default.findElementIndex(r,t,n);return e.find("tr").eq(i.rowIndex).find("td, th")[i.colIndex]}Object.defineProperty(t,"__esModule",{value:!0}),t._mergeCells=s;var c=n(0),d=r(c),f=n(1),h=r(f),p=n(4),g=r(p),v=n(6),m=r(v),y=n(8),_=r(y),b=n(7),w=r(b),k=g.default.CommandManager,E=h.default.browser.msie?"":"
    ",C=void 0;k&&(C=k.command("wysiwyg",{name:"MergeCells",exec:function(e){var t=e.getEditor();if(e.focus(),t.hasFormat("TABLE")){var n=e.componentManager.getManager("tableSelection"),r=n.getSelectedCells();if(!(r.length<2||n.hasSelectedBothThAndTd(r))){var i=t.getSelection().cloneRange(),o=(0,d.default)(i.startContainer),a=o.closest("table"),l=m.default.createTableData(a),c=_.default.getTableSelectionRange(l,r,o);s(l,c);var f=w.default.replaceTable(a,l),h=u(f,c.start.rowIndex,c.start.colIndex);w.default.focusToCell(t,i,h)}}}})),t.default=C},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){var n,r=t.start,i=t.end,o=r.colIndex,a=i.colIndex+1,l=e.slice(r.rowIndex,i.rowIndex+1),s=l.map(function(e){return e.slice(o,a)});return!!(n=[]).concat.apply(n,s).filter(function(e){return e.colspan>1||e.rowspan>1}).length}function o(e,t,n,r,i){var o=t+r,a=n+i,l=d.default.range(n,a);d.default.range(t,o).forEach(function(n){var r=e[n],i=n===t?1:0;l.slice(i).forEach(function(e){r[e]=g.default.createBasicCell(n,e,r[e].nodeName)})})}function a(e,t){var n=t.start,r=t.end,i=d.default.range(n.colIndex,r.colIndex+1);d.default.range(n.rowIndex,r.rowIndex+1).forEach(function(t){i.forEach(function(n){var r=e[t][n],i=r.colspan,a=r.rowspan;(i>1||a>1)&&(r.colspan=1,r.rowspan=1,o(e,t,n,a,i))})})}function l(e,t,n){var r=g.default.createTableData(e),i=g.default.findElementIndex(r,t,n);return e.find("tr").eq(i.rowIndex).find("td, th")[i.colIndex]}Object.defineProperty(t,"__esModule",{value:!0}),t._hasMergedCell=i,t._unmergeCells=a;var s=n(0),u=r(s),c=n(1),d=r(c),f=n(4),h=r(f),p=n(6),g=r(p),v=n(8),m=r(v),y=n(7),_=r(y),b=h.default.CommandManager,w=void 0;b&&(w=b.command("wysiwyg",{name:"UnmergeCells",exec:function(e){var t=e.getEditor(),n=t.getSelection().cloneRange();if(e.focus(),t.hasFormat("TABLE")){var r=(0,u.default)(n.startContainer),o=r.closest("table"),s=g.default.createTableData(o),c=e.componentManager.getManager("tableSelection").getSelectedCells(),d=m.default.getTableSelectionRange(s,c,r);if(i(s,d)){a(s,d);var f=_.default.replaceTable(o,s),h=l(f,d.start.rowIndex,d.start.colIndex);_.default.focusToCell(t,n,h)}}}})),t.default=w},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e){var t=['",'",'",'","
    ",'",'","
    ",'",'",'","
    ",'"].join(""),n=(0,s.default)(t);e.setContent(n)}function o(e,t,n){var r=e.$content,i=(0,s.default)(r[5]),o=(0,s.default)(r[6]),a=(0,s.default)(r[7]);e.on("click .te-table-merge",function(){t.emit("command","MergeCells")}),e.on("click .te-table-unmerge",function(){t.emit("command","UnmergeCells")}),t.listen("openPopupTableUtils",function(){var e=n.getSelectedCells(),t=e.length;t?(t<2||n.hasSelectedBothThAndTd(e)?i.hide():i.show(),e.is("[rowspan], [colspan]")?o.show():o.hide(),a.show()):(i.hide(),o.hide(),a.hide())})}function a(e,t,n){i(e),o(e,t,n)}Object.defineProperty(t,"__esModule",{value:!0});var l=n(0),s=r(l),u=n(4),c=r(u),d=c.default.i18n;t.default={updateContextMenu:a}},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e){var t=e.options.colorSyntax,n=void 0===t?{}:t,r=n.preset,i=n.useCustomSyntax,s=void 0!==i&&i;e.eventManager.listen("convertorAfterMarkdownToHtmlConverted",function(e){return s?e.replace(y,function(e,t,n){return l(n,t).result}):e}),e.eventManager.listen("convertorAfterHtmlToMarkdownConverted",function(e){var t=s?b:_;return e.replace(t,function(e,t,n){return t.match(w)&&(t=u(t)),s?a(n,t).result:e.replace(/ ?class="colour" ?/g," ").replace(w,t)})}),e.isViewer()||"default"!==e.getUI().name||(e.addCommand("markdown",{name:"color",exec:function(e,t){var n=e.getEditor(),r=n.getCursor("from"),i=n.getCursor("to"),o=void 0,u=void 0;if(t){if(s){var c=a(n.getSelection(),t);o=c.result,u=c.from,n.replaceSelection(o)}else{var d=l(n.getSelection(),t);o=d.result,u=d.from,n.replaceSelection(o)}n.setSelection({line:r.line,ch:r.ch+u},{line:i.line,ch:r.line===i.line?i.ch+u:i.ch}),e.focus()}}}),e.addCommand("wysiwyg",{name:"color",exec:function(e,t){var n=e.getEditor();t&&(n.hasFormat("PRE")||(t===k?n.changeFormat(null,{class:"colour",tag:"span"}):n.setTextColour(t)),e.focus())}}),o(e,r))}function o(e,t){var n=e.i18n;e.eventManager.addEventType("colorButtonClicked"),e.getUI().toolbar.addButton({className:"tui-color",event:"colorButtonClicked",tooltip:n.get("Text color")},4);var r=e.getUI().toolbar.$el.find("button.tui-color"),i=(0,h.default)("
    "),o=(0,h.default)(''),a={container:i[0]};t&&(a.preset=t);var l=g.default.create(a),s=l.getColor();i.append(o);var u=e.getUI().createPopup({header:!1,title:!1,content:i,className:"tui-popup-color",$target:e.getUI().$el,css:{width:"auto",position:"absolute"}});e.eventManager.listen("focus",function(){u.hide()}),e.eventManager.listen("colorButtonClicked",function(){if(e.eventManager.emit("closeAllPopup"),u.isShow())u.hide();else{var t=r.position();u.$el.css({top:t.top+r.outerHeight(!0),left:t.left}),u.show(),l.slider.toggle(!0)}}),e.eventManager.listen("closeAllPopup",function(){u.hide()}),e.eventManager.listen("removeEditor",function(){l.off("selectColor")}),l.on("selectColor",function(t){s=t.color,"palette"===t.origin&&(e.exec("color",s),u.hide())}),u.$el.find(".te-apply-button").on("click",function(){e.exec("color",s)})}function a(e,t){return s("{color:"+t+"}",e,"{color}")}function l(e,t){return s('',e,"")}function s(e,t,n){return{result:""+e+t+n,from:e.length,to:e.length+t.length}}function u(e){return e.replace(w,function(e,t,n,r){return"#"+c(t)+c(n)+c(r)})}function c(e){var t=parseInt(e,10);return t=t.toString(16),t=d(t)}function d(e){var t="00"+e;return t.substr(t.length-2)}Object.defineProperty(t,"__esModule",{value:!0});var f=n(0),h=r(f),p=n(177),g=r(p),v=n(4),m=r(v),y=/\{color:(.+?)}(.*?)\{color}/g,_=/(.*?)/g,b=/(.*?)<\/span>/g,w=/rgb\((\d+)[, ]+(\d+)[, ]+(\d+)\)/g,k="#181818";m.default.defineExtension("colorSyntax",i),t.default=i},function(e,t){e.exports=s},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e){function t(e){var t=void 0;try{if(!a.default)throw new Error("plantuml-encoder dependency required");t=''}catch(e){t="Error occurred on encoding uml: "+e.message}return t}var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},r=n.rendererURL,i=void 0===r?c:r,o=e.options.codeBlockLanguages;o&&o.indexOf(d)<0&&o.push(d),u.setReplacer(d,t)}Object.defineProperty(t,"__esModule",{value:!0});var o=n(179),a=r(o),l=n(4),s=r(l),u=s.default.codeBlockManager,c="http://www.plantuml.com/plantuml/png/",d="uml";s.default.defineExtension("uml",i),t.default=i},function(e,t){e.exports=u},function(e,t,n){"use strict";var r=n(0),i=function(e){return e&&e.__esModule?e:{default:e}}(r),o=n(25);i.default.fn.tuiEditor=function(){var e=void 0,t=void 0,n=this.get(0);if(n){for(var r=arguments.length,a=Array(r),l=0;l Date: Sun, 10 Mar 2019 19:07:01 +0800 Subject: [PATCH 10/22] Feat: Folder share --- application/index/controller/Share.php | 40 +++- application/index/controller/Viewer.php | 15 +- application/index/model/FileManage.php | 24 +- application/index/model/ShareHandler.php | 24 +- application/index/view/error.html | 6 +- application/index/view/home/home.html | 139 ++++++++---- application/index/view/home/home1.html | 100 --------- application/index/view/share/share_dir.html | 210 ++++++++++-------- .../index/view/share/share_dir_old.html | 105 +++++++++ application/index/view/viewer/markdown.html | 45 +++- application/index/view/viewer/video.html | 49 +++- application/route.php | 3 + 12 files changed, 506 insertions(+), 254 deletions(-) delete mode 100644 application/index/view/home/home1.html create mode 100644 application/index/view/share/share_dir_old.html diff --git a/application/index/controller/Share.php b/application/index/controller/Share.php index 61733de7..59f2902d 100644 --- a/application/index/controller/Share.php +++ b/application/index/controller/Share.php @@ -35,9 +35,10 @@ class Share extends Controller{ 'dirData' => $shareObj->dirData, 'shareData' => $shareObj->shareData, 'loginStatus' => $this->userObj->loginStatus, - 'userData' => $this->userObj->userSQLData, + 'userData' => $this->userObj->getInfo(), 'groupData' => $shareObj->shareOwner->groupData, 'allowPreview' => Option::getValue("allowdVisitorDownload"), + 'path' => empty(input("get.path"))?"/":input("get.path"), ]); }else{ return view('share_single', [ @@ -85,6 +86,20 @@ class Share extends Controller{ } } + public function Content(){ + $shareId = input('param.key'); + $filePath = input('get.path'); + $shareObj = new ShareHandler($shareId,false); + if(empty($filePath)){ + //todo 单文件时 + }else{ + $contentHandller = $shareObj->getContent($this->userObj,$filePath); + } + if(!$contentHandller[0]){ + return json(["result"=>["success"=>false,"error"=>$contentHandller[1]]]); + } + } + public function chekPwd(){ $shareId = input('key'); $inputPwd = input('password'); @@ -122,7 +137,7 @@ class Share extends Controller{ $shareId = input('param.key'); $reqPathTo = stripslashes(json_decode(file_get_contents("php://input"),true)['path']); $shareObj = new ShareHandler($shareId,false); - return $shareObj->ListFile($reqPathTo); + return json($shareObj->ListFile($reqPathTo)); } public function ListPic(){ @@ -133,8 +148,8 @@ class Share extends Controller{ } public function Thumb(){ - $shareId = input('get.shareKey'); - $filePath = input('get.path'); + $shareId = input('param.key'); + $filePath = urldecode(input('get.path')); if(input("get.isImg") != "true"){ return ""; } @@ -147,6 +162,23 @@ class Share extends Controller{ } } + public function DocPreview(){ + $shareId = input('param.key'); + $filePath = urldecode(input('get.path')); + $shareObj = new ShareHandler($shareId,false); + if(empty($filePath)){ + //TODO 单文件时 + }else{ + $Redirect = $shareObj->getDocPreview($this->userObj,$filePath); + } + + if($Redirect[0]){ + $this->redirect($Redirect[1],302); + }else{ + $this->error($Redirect[1],403,$this->siteOptions); + } + } + public function Delete(){ $shareId = input('post.id'); $shareObj = new ShareHandler($shareId,false); diff --git a/application/index/controller/Viewer.php b/application/index/controller/Viewer.php index 014bf946..94ae7a39 100644 --- a/application/index/controller/Viewer.php +++ b/application/index/controller/Viewer.php @@ -7,6 +7,7 @@ use \app\index\model\Option; use \app\index\model\User; use think\Session; use \app\index\model\FileManage; +use \app\index\model\ShareHandler; class Viewer extends Controller{ @@ -26,12 +27,17 @@ class Viewer extends Controller{ $pathSplit = explode("/",urldecode($path)); $userInfo = $this->userObj->getInfo(); $groupData = $this->userObj->getGroupData(); + $url = "/File/Preview?action=preview&path=".$path; + if(input("get.share")==true){ + $url = "/Share/Preview/".input("get.shareKey")."/?path=".$path; + } return view('video', [ 'options' => Option::getValues(['basic']), 'userInfo' => $userInfo, 'groupData' => $groupData, - 'url' => "/File/Preview?action=preview&path=".$path, + 'url' => $url, 'fileName' => end($pathSplit), + 'isSharePage' => input("?get.share")?"true":"false", ]); } @@ -40,13 +46,18 @@ class Viewer extends Controller{ $pathSplit = explode("/",urldecode($path)); $userInfo = $this->userObj->getInfo(); $groupData = $this->userObj->getGroupData(); + $url = "/File/Content?action=preview&path=".$path; + if(input("get.share")==true){ + $url = "/Share/Content/".input("get.shareKey")."/?path=".$path; + } return view('markdown', [ 'options' => Option::getValues(['basic']), 'userInfo' => $userInfo, 'groupData' => $groupData, - 'url' => "/File/Content?action=preview&path=".$path, + 'url' => $url, 'fileName' => end($pathSplit), 'path' => urldecode($path), + 'isSharePage' => input("?get.share")?"true":"false", ]); } diff --git a/application/index/model/FileManage.php b/application/index/model/FileManage.php index 8b9f9aac..473d6ca4 100644 --- a/application/index/model/FileManage.php +++ b/application/index/model/FileManage.php @@ -636,11 +636,14 @@ class FileManage extends Model{ } /** - * [List description] - * @param [type] $path [description] - * @param [type] $uid [description] + * 列出文件 + * + * @param 路径 $path + * @param 用户UID $uid + * @param boolean $isShare 是否为分享模式下列出文件 + * @return void */ - static function ListFile($path,$uid){ + static function ListFile($path,$uid,$isShare=false,$originPath=null){ $fileList = Db::name('files')->where('upload_user',$uid)->where('dir',$path)->select(); $dirList = Db::name('folders')->where('owner',$uid)->where('position',$path)->select(); $count= 0; @@ -657,6 +660,12 @@ class FileManage extends Model{ $fileListData['result'][$count]['id'] = $value['id']; $fileListData['result'][$count]['pic'] = ""; $fileListData['result'][$count]['path'] = $value['position']; + if($isShare){ + if (substr($value['position'], 0, strlen($originPath)) == $originPath) { + $value['position'] = substr($value['position'], strlen($originPath)); + } + $fileListData['result'][$count]['path'] = ($value['position']=="")?"/":$value['position']; + } $count++; } foreach ($fileList as $key => $value) { @@ -665,10 +674,15 @@ class FileManage extends Model{ $fileListData['result'][$count]['size'] = $value['size']; $fileListData['result'][$count]['date'] = $value['upload_date']; $fileListData['result'][$count]['type'] = 'file'; - $fileListData['result'][$count]['name2'] = $value["dir"]; $fileListData['result'][$count]['id'] = $value["id"]; $fileListData['result'][$count]['pic'] = $value["pic_info"]; $fileListData['result'][$count]['path'] = $value['dir']; + if($isShare){ + if (substr($value['dir'], 0, strlen($originPath)) == $originPath) { + $value['dir'] = substr($value['dir'], strlen($originPath)); + } + $fileListData['result'][$count]['path'] = ($value['dir']=="")?"/":$value['dir']; + } $count++; } diff --git a/application/index/model/ShareHandler.php b/application/index/model/ShareHandler.php index fb59a8db..3305e076 100644 --- a/application/index/model/ShareHandler.php +++ b/application/index/model/ShareHandler.php @@ -95,6 +95,28 @@ class ShareHandler extends Model{ return $fileObj->getThumb(); } + public function getDocPreview($user,$path){ + $checkStatus = $this->checkSession($user); + if(!$checkStatus[0]){ + return [$checkStatus[0],$checkStatus[1]]; + } + $reqPath = Db::name('folders')->where('position_absolute',$this->shareData["source_name"])->find(); + $fileObj = new FileManage($reqPath["position_absolute"].$path,$this->shareData["owner"]); + $tmpUrl = $fileObj->signTmpUrl(); + return[true,"http://view.officeapps.live.com/op/view.aspx?src=".urlencode($tmpUrl)]; + } + + public function getContent($user,$path=null){ + $checkStatus = $this->checkSession($user); + if(!$checkStatus[0]){ + return [$checkStatus[0],$checkStatus[1]]; + } + $reqPath = Db::name('folders')->where('position_absolute',$this->shareData["source_name"])->find(); + $fileObj = new FileManage($reqPath["position_absolute"].$path,$this->shareData["owner"]); + $fileObj->getContent(); + exit(); + } + public function checkSession($user){ if($this->lockStatus){ return [false,"会话过期,请刷新页面"]; @@ -146,7 +168,7 @@ class ShareHandler extends Model{ } $reqPath = Db::name('folders')->where('position_absolute',$this->shareData["source_name"])->find(); $path = $path == "/"?"":$path; - return FileManage::ListFile($this->shareData["source_name"].$path,$this->shareData["owner"]); + return FileManage::ListFile($this->shareData["source_name"].$path,$this->shareData["owner"],true,$this->shareData["source_name"]); } public function Preview($user){ diff --git a/application/index/view/error.html b/application/index/view/error.html index c7e74ff2..806ca31d 100644 --- a/application/index/view/error.html +++ b/application/index/view/error.html @@ -1,6 +1,4 @@ -{extend name="header_public" /} -{block name="title"}错误提示 - {$options.siteName}{/block} -{block name="content"} + @@ -19,6 +17,4 @@
    -{$options.js_code} -{/block} \ No newline at end of file diff --git a/application/index/view/home/home.html b/application/index/view/home/home.html index 41d59e95..06a53f5d 100644 --- a/application/index/view/home/home.html +++ b/application/index/view/home/home.html @@ -1,6 +1,7 @@ - + + @@ -8,7 +9,7 @@ manifest.json provides metadata used when your web app is added to the homescreen on Android. See https://developers.google.com/web/fundamentals/web-app-manifest/ --> - + 我的文件 - {$options.siteName} - - - + colorTheme = { + "palette": { + "common": { + "black": "#000", + "white": "#fff" + }, + "background": { + "paper": "#fff", + "default": "#fafafa" + }, + "primary": { + "light": "#7986cb", + "main": "#3f51b5", + "dark": "#303f9f", + "contrastText": "#fff" + }, + "secondary": { + "light": "#ff4081", + "main": "#f50057", + "dark": "#c51162", + "contrastText": "#fff" + }, + "error": { + "light": "#e57373", + "main": "#f44336", + "dark": "#d32f2f", + "contrastText": "#fff" + }, + "text": { + "primary": "rgba(0, 0, 0, 0.87)", + "secondary": "rgba(0, 0, 0, 0.54)", + "disabled": "rgba(0, 0, 0, 0.38)", + "hint": "rgba(0, 0, 0, 0.38)" + }, + "explorer": { + "filename": "#474849", + "icon": "#8f8f8f", + "bgSelected": "#D5DAF0", + "emptyIcon": "#e8e8e8", + } + } + }; + isHomePage = true; + isSharePage = false; + uploadConfig = { + saveType: "{$policyData.policy_type}", + maxSize: "{$policyData.max_size}mb", + allowedType: [{$extLimit}], + allowSource: "{$policyData.origin_link}", + upUrl: "{$policyData.server}", + allowShare: "{$groupData.allow_share}", + allowRemoteDownload: "{:explode(",",$groupData.aria2)[0]}", + allowTorrentDownload: "{:explode(",",$groupData.aria2)[1]}", + }; + apiURL = { + imgThumb: "/File/Thumb", + preview: "/File/Preview", + download: "/File/Download", + docPreiview: '/File/DocPreview', + listFile:"/File/ListFile" + }; + userInfo = { + uid: {$userInfo.uid}, + nick: "{$userInfo.userNick}", + email: "{$userInfo.userMail}", + group: "{$userInfo.groupData.group_name}", + groupId: {$userInfo.groupData.id}, + groupColor: "{$userInfo.groupData.color}", + }; + siteInfo = { + mainTitle: "{$options.siteName}", + }; + path = "{$path}"; + mediaType = {}, + isMobile = window.innerWidth < 600; + + + + + @@ -71,10 +115,13 @@ To begin the development, run `npm start` or `yarn start`. To create a production bundle, use `npm run build` or `yarn build`. --> - - - - - - - + + + + + + + + + + \ No newline at end of file diff --git a/application/index/view/home/home1.html b/application/index/view/home/home1.html deleted file mode 100644 index 76332275..00000000 --- a/application/index/view/home/home1.html +++ /dev/null @@ -1,100 +0,0 @@ - - - - - - - 我的文件 - {$options.siteName} - - - - - - - - - - - - - - - - - -
    - {include file="navbar_home" /} - - -
    - -
    -
    - - - - - -{$options.js_code} - diff --git a/application/index/view/share/share_dir.html b/application/index/view/share/share_dir.html index 7dddde73..8337ff77 100644 --- a/application/index/view/share/share_dir.html +++ b/application/index/view/share/share_dir.html @@ -1,80 +1,95 @@ -{extend name="header_dir_share" /} -{block name="title"}{$dirData.folder_name} - {$options.siteName}{/block} -{block name="content"} - - - - - - - - + + + + + + + + + + {$dirData.folder_name} - {$options.siteName} + - - - - - - - - - - {$options.js_code} -{/block} \ No newline at end of file + mediaType = {}, + isMobile = window.innerWidth < 600; + + + + + + +
    + + + + + + + + + + + + + \ No newline at end of file diff --git a/application/index/view/share/share_dir_old.html b/application/index/view/share/share_dir_old.html new file mode 100644 index 00000000..7dddde73 --- /dev/null +++ b/application/index/view/share/share_dir_old.html @@ -0,0 +1,105 @@ +{extend name="header_dir_share" /} +{block name="title"}{$dirData.folder_name} - {$options.siteName}{/block} +{block name="content"} + + + + + + + + + + + + + + + + + + + + + + {$options.js_code} +{/block} \ No newline at end of file diff --git a/application/index/view/viewer/markdown.html b/application/index/view/viewer/markdown.html index d0ac0ec6..a253493e 100644 --- a/application/index/view/viewer/markdown.html +++ b/application/index/view/viewer/markdown.html @@ -21,7 +21,50 @@ --> {$fileName} - {$options.siteName} - - + + diff --git a/application/route.php b/application/route.php index 183ce4c9..87882181 100644 --- a/application/route.php +++ b/application/route.php @@ -24,4 +24,7 @@ Route::rule([ 'Member/Avatar/:uid/:size' => ['Member/Avatar',[],['uid'=>'\d+']], 'Profile/:uid' => ['Profile/index',[],['uid'=>'\d+']], 'Callback/Payment/Jinshajiang' => 'index/Callback/Jinshajiang', + 'Share/Thumb/:key' => 'index/Share/Thumb', + 'Share/DocPreview/:key' => 'index/Share/DocPreview', + 'Share/Content/:key' => 'index/Share/Content', ]); \ No newline at end of file From 53c79bfa65bee46f2eb484480f9a7fe07a5a3798 Mon Sep 17 00:00:00 2001 From: HFO4 <912394456@qq.com> Date: Mon, 11 Mar 2019 15:04:35 +0800 Subject: [PATCH 11/22] Feat: Single file share --- application/index/controller/Share.php | 13 +- application/index/controller/Viewer.php | 4 + application/index/model/ShareHandler.php | 32 +- application/index/view/home/home.html | 6 +- application/index/view/share/share_dir.html | 12 +- .../index/view/share/share_single.html | 255 ++- ...are_dir_old.html => share_single_old.html} | 81 +- application/index/view/viewer/markdown.html | 1 + application/index/view/viewer/video.html | 5 +- static/js/filemanager_share.js | 1451 ----------------- static/js/share_dir.js | 119 -- 11 files changed, 236 insertions(+), 1743 deletions(-) rename application/index/view/share/{share_dir_old.html => share_single_old.html} (51%) delete mode 100644 static/js/filemanager_share.js delete mode 100644 static/js/share_dir.js diff --git a/application/index/controller/Share.php b/application/index/controller/Share.php index 59f2902d..1f9d051b 100644 --- a/application/index/controller/Share.php +++ b/application/index/controller/Share.php @@ -47,8 +47,9 @@ class Share extends Controller{ 'fileData' => $shareObj->fileData, 'shareData' => $shareObj->shareData, 'loginStatus' => $this->userObj->loginStatus, - 'userData' => $this->userObj->userSQLData, + 'userData' => $this->userObj->getInfo(), 'allowPreview' => Option::getValue("allowdVisitorDownload"), + 'path' => empty(input("get.path"))?"/":input("get.path"), ]); } }else{ @@ -67,7 +68,7 @@ class Share extends Controller{ public function getDownloadUrl(){ $shareId = input('key'); $shareObj = new ShareHandler($shareId,false); - return $shareObj->getDownloadUrl($this->userObj); + return json($shareObj->getDownloadUrl($this->userObj)); } public function Download(){ @@ -91,9 +92,9 @@ class Share extends Controller{ $filePath = input('get.path'); $shareObj = new ShareHandler($shareId,false); if(empty($filePath)){ - //todo 单文件时 + $contentHandller = $shareObj->getContent($this->userObj,$filePath,false); }else{ - $contentHandller = $shareObj->getContent($this->userObj,$filePath); + $contentHandller = $shareObj->getContent($this->userObj,$filePath,true); } if(!$contentHandller[0]){ return json(["result"=>["success"=>false,"error"=>$contentHandller[1]]]); @@ -167,9 +168,9 @@ class Share extends Controller{ $filePath = urldecode(input('get.path')); $shareObj = new ShareHandler($shareId,false); if(empty($filePath)){ - //TODO 单文件时 + $Redirect = $shareObj->getDocPreview($this->userObj,$filePath,false); }else{ - $Redirect = $shareObj->getDocPreview($this->userObj,$filePath); + $Redirect = $shareObj->getDocPreview($this->userObj,$filePath,true); } if($Redirect[0]){ diff --git a/application/index/controller/Viewer.php b/application/index/controller/Viewer.php index 94ae7a39..dd77076f 100644 --- a/application/index/controller/Viewer.php +++ b/application/index/controller/Viewer.php @@ -30,6 +30,8 @@ class Viewer extends Controller{ $url = "/File/Preview?action=preview&path=".$path; if(input("get.share")==true){ $url = "/Share/Preview/".input("get.shareKey")."/?path=".$path; + }else if(input("get.single")==true){ + $url = "/Share/Preview/".input("get.shareKey"); } return view('video', [ 'options' => Option::getValues(['basic']), @@ -49,6 +51,8 @@ class Viewer extends Controller{ $url = "/File/Content?action=preview&path=".$path; if(input("get.share")==true){ $url = "/Share/Content/".input("get.shareKey")."/?path=".$path; + }else if(input("get.single")==true){ + $url = "/Share/Content/".input("get.shareKey"); } return view('markdown', [ 'options' => Option::getValues(['basic']), diff --git a/application/index/model/ShareHandler.php b/application/index/model/ShareHandler.php index 3305e076..5e4823dc 100644 --- a/application/index/model/ShareHandler.php +++ b/application/index/model/ShareHandler.php @@ -95,24 +95,44 @@ class ShareHandler extends Model{ return $fileObj->getThumb(); } - public function getDocPreview($user,$path){ + public function getDocPreview($user,$path,$inFolder){ $checkStatus = $this->checkSession($user); if(!$checkStatus[0]){ return [$checkStatus[0],$checkStatus[1]]; } - $reqPath = Db::name('folders')->where('position_absolute',$this->shareData["source_name"])->find(); - $fileObj = new FileManage($reqPath["position_absolute"].$path,$this->shareData["owner"]); + if($inFolder){ + $reqPath = Db::name('folders')->where('position_absolute',$this->shareData["source_name"])->find(); + $fileObj = new FileManage($reqPath["position_absolute"].$path,$this->shareData["owner"]); + }else{ + $reqPath = Db::name('files')->where('id',$this->shareData["source_name"])->find(); + if($reqPath["dir"] == "/"){ + $reqPath["dir"] = $reqPath["dir"].$reqPath["orign_name"]; + }else{ + $reqPath["dir"] = $reqPath["dir"]."/".$reqPath["orign_name"]; + } + $fileObj = new FileManage($reqPath["dir"],$this->shareData["owner"]); + } $tmpUrl = $fileObj->signTmpUrl(); return[true,"http://view.officeapps.live.com/op/view.aspx?src=".urlencode($tmpUrl)]; } - public function getContent($user,$path=null){ + public function getContent($user,$path=null,$inFolder){ $checkStatus = $this->checkSession($user); if(!$checkStatus[0]){ return [$checkStatus[0],$checkStatus[1]]; } - $reqPath = Db::name('folders')->where('position_absolute',$this->shareData["source_name"])->find(); - $fileObj = new FileManage($reqPath["position_absolute"].$path,$this->shareData["owner"]); + if($inFolder){ + $reqPath = Db::name('folders')->where('position_absolute',$this->shareData["source_name"])->find(); + $fileObj = new FileManage($reqPath["position_absolute"].$path,$this->shareData["owner"]); + }else{ + $reqPath = Db::name('files')->where('id',$this->shareData["source_name"])->find(); + if($reqPath["dir"] == "/"){ + $reqPath["dir"] = $reqPath["dir"].$reqPath["orign_name"]; + }else{ + $reqPath["dir"] = $reqPath["dir"]."/".$reqPath["orign_name"]; + } + $fileObj = new FileManage($reqPath["dir"],$this->shareData["owner"]); + } $fileObj->getContent(); exit(); } diff --git a/application/index/view/home/home.html b/application/index/view/home/home.html index 06a53f5d..a59ab323 100644 --- a/application/index/view/home/home.html +++ b/application/index/view/home/home.html @@ -64,6 +64,7 @@ } }; isHomePage = true; + pageId=""; isSharePage = false; uploadConfig = { saveType: "{$policyData.policy_type}", @@ -118,10 +119,11 @@ + + - - + \ No newline at end of file diff --git a/application/index/view/share/share_dir.html b/application/index/view/share/share_dir.html index 8337ff77..8403abd5 100644 --- a/application/index/view/share/share_dir.html +++ b/application/index/view/share/share_dir.html @@ -65,6 +65,7 @@ }; isHomePage = false; isSharePage = true; + pageId=""; apiURL = { imgThumb: "/Share/Thumb/{$shareData.share_key}", preview: "/Share/Preview/{$shareData.share_key}", @@ -129,13 +130,12 @@ --> - - - - - - + + + + + \ No newline at end of file diff --git a/application/index/view/share/share_single.html b/application/index/view/share/share_single.html index 5b39c099..e0df9d2d 100644 --- a/application/index/view/share/share_single.html +++ b/application/index/view/share/share_single.html @@ -1,131 +1,96 @@ -{extend name="header_public" /} -{block name="title"}{$fileData.orign_name} - {$options.siteName}{/block} -{block name="content"} - - - - - - - - -
    - - - +

    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 diff --git a/thinkphp/tests/extensions/7.0/apcu.so b/thinkphp/tests/extensions/7.0/apcu.so deleted file mode 100644 index c2f0ad1402d0e709af094ee60ff617c1f0a34bd5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 320965 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≶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 E4+;+smjD0& diff --git a/thinkphp/tests/extensions/7.0/memcached.so b/thinkphp/tests/extensions/7.0/memcached.so deleted file mode 100644 index 544ba6d52ee89046ac2ddab0d4acfe2d95e8bfda..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 323764 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 h1~w&V?BEM#C@~958OzT3EJU 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