summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.dockerignore1
-rw-r--r--.htaccess34
-rw-r--r--.travis.yml2
-rw-r--r--CONTRIBUTORS.md11
-rw-r--r--ChangeLog27
-rw-r--r--Makefile9
-rw-r--r--app/Api/Middleware/AuthenticationMiddleware.php1
-rw-r--r--app/Auth/ApiAccessTokenAuth.php119
-rw-r--r--app/Auth/DatabaseAuth.php2
-rw-r--r--app/Auth/LdapAuth.php2
-rw-r--r--app/Auth/RememberMeAuth.php4
-rw-r--r--app/Auth/ReverseProxyAuth.php2
-rw-r--r--app/Auth/TotpAuth.php2
-rw-r--r--app/Console/DatabaseMigrationCommand.php23
-rw-r--r--app/Console/DatabaseVersionCommand.php23
-rw-r--r--app/Controller/CommentController.php14
-rw-r--r--app/Controller/TaskAjaxController.php25
-rw-r--r--app/Controller/UserAjaxController.php10
-rw-r--r--app/Controller/UserApiAccessController.php50
-rw-r--r--app/Core/Base.php2
-rw-r--r--app/Core/Helper.php1
-rw-r--r--app/Core/Markdown.php7
-rw-r--r--app/Core/Session/SessionStorage.php1
-rw-r--r--app/Event/GenericEvent.php22
-rw-r--r--app/Event/ProjectFileEvent.php8
-rw-r--r--app/Filter/TaskStartsWithIdFilter.php38
-rw-r--r--app/Formatter/BaseFormatter.php14
-rw-r--r--app/Formatter/BaseTaskCalendarFormatter.php4
-rw-r--r--app/Formatter/TaskAutoCompleteFormatter.php28
-rw-r--r--app/Formatter/TaskSuggestMenuFormatter.php63
-rw-r--r--app/Formatter/UserMentionFormatter.php60
-rw-r--r--app/Helper/FormHelper.php44
-rw-r--r--app/Job/CommentEventJob.php4
-rw-r--r--app/Job/TaskEventJob.php3
-rw-r--r--app/Job/UserMentionJob.php72
-rw-r--r--app/Locale/bs_BA/translations.php9
-rw-r--r--app/Locale/cs_CZ/translations.php9
-rw-r--r--app/Locale/da_DK/translations.php9
-rw-r--r--app/Locale/de_DE/translations.php9
-rw-r--r--app/Locale/el_GR/translations.php9
-rw-r--r--app/Locale/es_ES/translations.php9
-rw-r--r--app/Locale/fi_FI/translations.php9
-rw-r--r--app/Locale/fr_FR/translations.php9
-rw-r--r--app/Locale/hu_HU/translations.php9
-rw-r--r--app/Locale/id_ID/translations.php9
-rw-r--r--app/Locale/it_IT/translations.php43
-rw-r--r--app/Locale/ja_JP/translations.php9
-rw-r--r--app/Locale/ko_KR/translations.php227
-rw-r--r--app/Locale/my_MY/translations.php9
-rw-r--r--app/Locale/nb_NO/translations.php9
-rw-r--r--app/Locale/nl_NL/translations.php9
-rw-r--r--app/Locale/pl_PL/translations.php9
-rw-r--r--app/Locale/pt_BR/translations.php9
-rw-r--r--app/Locale/pt_PT/translations.php9
-rw-r--r--app/Locale/ru_RU/translations.php9
-rw-r--r--app/Locale/sr_Latn_RS/translations.php9
-rw-r--r--app/Locale/sv_SE/translations.php9
-rw-r--r--app/Locale/th_TH/translations.php9
-rw-r--r--app/Locale/tr_TR/translations.php9
-rw-r--r--app/Locale/zh_CN/translations.php9
-rw-r--r--app/Model/ProjectPermissionModel.php24
-rw-r--r--app/Model/UserMentionModel.php62
-rw-r--r--app/Schema/Mysql.php12
-rw-r--r--app/Schema/Postgres.php12
-rw-r--r--app/Schema/Sql/mysql.sql78
-rw-r--r--app/Schema/Sql/postgres.sql572
-rw-r--r--app/Schema/Sqlite.php7
-rw-r--r--app/ServiceProvider/AuthenticationProvider.php3
-rw-r--r--app/ServiceProvider/ClassProvider.php1
-rw-r--r--app/ServiceProvider/CommandProvider.php4
-rw-r--r--app/ServiceProvider/DatabaseProvider.php41
-rw-r--r--app/ServiceProvider/JobProvider.php5
-rw-r--r--app/ServiceProvider/RouteProvider.php1
-rw-r--r--app/Subscriber/NotificationSubscriber.php38
-rw-r--r--app/Template/category/edit.php4
-rw-r--r--app/Template/category/index.php2
-rw-r--r--app/Template/column/create.php10
-rw-r--r--app/Template/comments/show.php1
-rw-r--r--app/Template/notification/comment_create.php2
-rw-r--r--app/Template/notification/comment_delete.php2
-rw-r--r--app/Template/notification/comment_update.php2
-rw-r--r--app/Template/notification/comment_user_mention.php2
-rw-r--r--app/Template/notification/task_assignee_change.php2
-rw-r--r--app/Template/notification/task_create.php2
-rw-r--r--app/Template/notification/task_update.php2
-rw-r--r--app/Template/notification/task_user_mention.php2
-rw-r--r--app/Template/swimlane/create.php6
-rw-r--r--app/Template/swimlane/edit.php6
-rw-r--r--app/Template/swimlane/edit_default.php2
-rw-r--r--app/Template/swimlane/table.php7
-rw-r--r--app/Template/task/changes.php6
-rw-r--r--app/Template/task_move_position/show.php55
-rw-r--r--app/Template/user_api_access/show.php17
-rw-r--r--app/Template/user_view/sidebar.php5
-rw-r--r--app/constants.php3
-rw-r--r--app/functions.php31
-rw-r--r--assets/css/app.min.css2
-rw-r--r--assets/js/app.min.js4
-rw-r--r--assets/js/components/accordion.js8
-rw-r--r--assets/js/components/chart-project-avg-time-column.js2
-rw-r--r--assets/js/components/chart-project-burndown.js11
-rw-r--r--assets/js/components/chart-project-cumulative-flow.js9
-rw-r--r--assets/js/components/chart-project-lead-cycle-time.js2
-rw-r--r--assets/js/components/chart-project-task-distribution.js2
-rw-r--r--assets/js/components/chart-project-time-comparison.js2
-rw-r--r--assets/js/components/chart-project-user-distribution.js2
-rw-r--r--assets/js/components/chart-task-time-column.js2
-rw-r--r--assets/js/components/external-task-view.js4
-rw-r--r--assets/js/components/submit-cancel.js81
-rw-r--r--assets/js/components/suggest-menu.js225
-rw-r--r--assets/js/components/task-move-position.js236
-rw-r--r--assets/js/components/text-editor.js65
-rw-r--r--assets/js/core/base.js76
-rw-r--r--assets/js/core/bootstrap.js5
-rw-r--r--assets/js/core/dom.js175
-rw-r--r--assets/js/core/html.js25
-rw-r--r--assets/js/core/http.js66
-rw-r--r--assets/js/core/utils.js34
-rw-r--r--assets/js/polyfills/matches.js14
-rw-r--r--assets/js/src/Accordion.js18
-rw-r--r--assets/js/src/App.js12
-rw-r--r--assets/js/src/BoardDragAndDrop.js2
-rw-r--r--assets/js/src/Bootstrap.js2
-rw-r--r--assets/js/src/Namespace.js125
-rw-r--r--assets/js/src/Notification.js9
-rw-r--r--assets/js/src/Popover.js4
-rw-r--r--assets/js/src/Screenshot.js2
-rw-r--r--assets/js/vendor.min.js15
-rw-r--r--assets/sass/_alert.sass8
-rw-r--r--assets/sass/_suggest_menu.sass28
-rw-r--r--assets/sass/app.sass1
-rwxr-xr-xcli (renamed from kanboard)5
-rw-r--r--config.default.php16
-rw-r--r--doc/api-authentication.markdown3
-rw-r--r--doc/api-json-rpc.markdown1
-rw-r--r--doc/cli.markdown55
-rw-r--r--doc/config.markdown14
-rw-r--r--doc/cronjob.markdown2
-rwxr-xr-xdoc/es_ES/cli.markdown56
-rwxr-xr-xdoc/es_ES/cronjob.markdown6
-rw-r--r--doc/es_ES/installation.markdown1
-rw-r--r--doc/es_ES/translations.markdown4
-rw-r--r--doc/fr_FR/index.markdown1
-rw-r--r--doc/fr_FR/installation.markdown1
-rw-r--r--doc/fr_FR/update.markdown21
-rw-r--r--doc/fr_FR/user-mentions.markdown13
-rw-r--r--doc/index.markdown2
-rw-r--r--doc/installation.markdown14
-rw-r--r--doc/nitrous.markdown10
-rw-r--r--doc/plugin-registration.markdown22
-rw-r--r--doc/postgresql-configuration.markdown8
-rw-r--r--doc/ru_RU/cli.markdown284
-rw-r--r--doc/ru_RU/cronjob.markdown15
-rw-r--r--doc/ru_RU/index.markdown1
-rw-r--r--doc/ru_RU/installation.markdown1
-rw-r--r--doc/ru_RU/translations.markdown87
-rw-r--r--doc/screenshots/mention-autocomplete.pngbin3066 -> 0 bytes
-rw-r--r--doc/screenshots/user-mentions.pngbin0 -> 5228 bytes
-rw-r--r--doc/solving-session-issue-windows-iis-ie.markdown19
-rw-r--r--doc/translations.markdown4
-rw-r--r--doc/update.markdown22
-rw-r--r--doc/user-mentions.markdown2
-rw-r--r--doc/worker.markdown4
-rw-r--r--docker/crontab/cronjob.alpine2
-rw-r--r--gulpfile.js14
-rwxr-xr-xnitrous-post-create.sh14
-rw-r--r--nitrous.json6
-rw-r--r--package.json7
-rw-r--r--tests/units/Auth/ApiAccessTokenAuthTest.php71
-rw-r--r--tests/units/Base.php1
-rw-r--r--tests/units/EventBuilder/CommentEventBuilderTest.php2
-rw-r--r--tests/units/EventBuilder/ProjectFileEventBuilderTest.php2
-rw-r--r--tests/units/EventBuilder/SubtaskEventBuilderTest.php2
-rw-r--r--tests/units/EventBuilder/TaskEventBuilderTest.php2
-rw-r--r--tests/units/EventBuilder/TaskFileEventBuilderTest.php2
-rw-r--r--tests/units/EventBuilder/TaskLinkEventBuilderTest.php2
-rw-r--r--tests/units/Filter/TaskStartsWithIdFilterTest.php103
-rw-r--r--tests/units/Formatter/TaskSuggestMenuFormatterTest.php39
-rw-r--r--tests/units/Formatter/UserMentionFormatterTest.php42
-rw-r--r--tests/units/FunctionTest.php32
-rw-r--r--tests/units/Helper/TextHelperTest.php7
-rw-r--r--tests/units/Job/CommentEventJobTest.php42
-rw-r--r--tests/units/Job/TaskEventJobTest.php40
-rw-r--r--tests/units/Job/UserMentionJobTest.php (renamed from tests/units/Model/UserMentionTest.php)74
-rw-r--r--tests/units/Model/ConfigModelTest.php125
-rw-r--r--tests/units/Model/ConfigTest.php116
-rw-r--r--tests/units/Model/ProjectPermissionModelTest.php21
187 files changed, 3566 insertions, 1414 deletions
diff --git a/.dockerignore b/.dockerignore
index 19c8e14b..8662306f 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -12,7 +12,6 @@ Makefile
*.sh
app.json
bower.json
-nitrous.json
package.json
Vagrantfile
web.config
diff --git a/.htaccess b/.htaccess
index 45123a98..2125df50 100644
--- a/.htaccess
+++ b/.htaccess
@@ -6,21 +6,21 @@
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [QSA,L]
+
+ ############################
+ ## Uncomment the two lines below to enable force HTTPS capabilities
+ ############################
+
+ # RewriteCond %{HTTPS} !=on
+ # RewriteRule ^/?(.*) https://%{SERVER_NAME}/$1 [R,L]
+
+ ###########################
+ ## Notes:
+ ## The first directive will check to make sure the connection is not already HTTPS
+ ##
+ ## The second directive will redirect users from their original location, to the same location but using HTTPS.
+ ## i.e. http://www.example.com/foo/ to https://www.example.com/foo/
+ ## The leading slash is made optional so that this will work either in httpd.conf
+ ## or .htaccess context
+ ############################
</IfModule>
-
-<FilesMatch "(kanboard|config.php|config.default.php)">
- <IfModule mod_version.c>
- <IfVersion >= 2.3>
- Require all denied
- </IfVersion>
- <IfVersion < 2.3>
- Order allow,deny
- Deny from all
- </IfVersion>
- </IfModule>
-
- <IfModule !mod_version.c>
- Order allow,deny
- Deny from all
- </IfModule>
-</FilesMatch>
diff --git a/.travis.yml b/.travis.yml
index c5300575..8c78bf8b 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -24,6 +24,8 @@ before_script:
- if [[ $TRAVIS_PHP_VERSION != 7.x ]]; then phpenv config-rm xdebug.ini; fi
- phpenv config-add tests/php.ini
- composer install
+ - npm install
+ - ./node_modules/.bin/jshint assets/js/{core,components}
script:
- phpunit -c tests/units.$DB.xml
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index 3a976930..b19698a8 100644
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -14,9 +14,11 @@ Contributors:
- [Anton](https://github.com/tester22)
- [Ashbike](https://github.com/ashbike)
- [Ashish Kulkarni](https://github.com/ashkulz)
+- [António Pereira](https://github.com/Shaxine)
- [Biniou180](https://github.com/Biniou180)
- [Bitcoin 333](https://github.com/bitcoin333)
- [Busfreak](https://github.com/Busfreak)
+- [Carlos Ferreira](https://github.com/acs-ferreira)
- [Christian González](https://github.com/nerdoc)
- [Christopher Geelen](https://github.com/cdgeelen)
- [Chorgroup](https://github.com/chorgroup)
@@ -32,9 +34,11 @@ Contributors:
- [Damian](https://github.com/dromek)
- [Daniel Raknes](https://github.com/danielraknes)
- [David-Norris](https://github.com/David-Norris)
+- [Diego Betto](https://github.com/diego-betto)
- [Dmitry](https://github.com/dmkcv)
- [Dj Padzensky](https://github.com/djpadz)
- [Draza (bdpsoft)](https://github.com/bdpsoft)
+- [erpnedir](https://github.com/erpnedir)
- [Eskiso](https://github.com/eSkiSo)
- [Esteban Monge](https://github.com/EstebanMonge)
- [Eugene (JohnBat26)](https://github.com/JohnBat26)
@@ -46,6 +50,7 @@ Contributors:
- [Floaltvater](https://github.com/floaltvater)
- [Gavlepeter](https://github.com/gavlepeter)
- [Gerardo Zamudio](https://github.com/gerardozamudio)
+- [Girish Ramakrishnan](https://github.com/gramakri)
- [Goofy](https://github.com/goofy-bz)
- [Hairetdin](https://github.com/hairetdin)
- [Hendrik Stocker](https://github.com/hendrik-stoker)
@@ -58,8 +63,9 @@ Contributors:
- [Jeff Guillou](https://github.com/jf-guillou)
- [Jesusaplsoft](https://github.com/jesusaplsoft)
- [Jesús Marín](https://github.com/alu0100502114)
+- [Jonas Oliveira Francisco](https://github.com/jonasof)
- [Jules Verhaeren](https://github.com/julesverhaeren)
-- [JunglaCODE]https://github.com/junglaCODE)
+- [JunglaCODE](https://github.com/junglaCODE)
- [Karol J](https://github.com/dzudek)
- [Kiswa](https://github.com/kiswa)
- [Kralo](https://github.com/kralo)
@@ -85,6 +91,7 @@ Contributors:
- [Moraxy](https://github.com/moraxy)
- [Muhaimin](https://github.com/infacq)
- [Nala Ginrut](https://github.com/NalaGinrut)
+- [Napier](https://github.com/napiera)
- [Nekohayo](https://github.com/nekohayo)
- [Ngtech](https://github.com/ngtech)
- [Nicolas LÅ“uillet](https://github.com/nicosomb)
@@ -106,6 +113,7 @@ Contributors:
- [Perburn](https://github.com/perburn)
- [Peripatetic-sojourner](https://github.com/peripatetic-sojourner)
- [Petja Touru](https://github.com/Petja)
+- [PhilLAL](https://github.com/PhilLAL)
- [Pierre-Alexis de Solminihac](https://github.com/pa-de-solminihac)
- [Piotr Zęgota](https://github.com/ZegalPL)
- [Rafaelrossa](https://github.com/rafaelrossa)
@@ -132,6 +140,7 @@ Contributors:
- [Torsten](https://github.com/misterfu)
- [Troloo](https://github.com/troloo)
- [Typz](https://github.com/Typz)
+- [Valentino Pistis](https://github.com/vpistis)
- [Vedovator](https://github.com/vedovator)
- [Vitaliy S. Orlov](https://github.com/orlov0562)
- [Vladimir Babin](https://github.com/Chiliec)
diff --git a/ChangeLog b/ChangeLog
index 8319bf87..48e3560d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,9 +1,36 @@
Version 1.0.35 (not released yet)
--------------------------------
+New features:
+
+* Add external tasks plugin interfaces
+* Add personal API access token for users
+* Rewrite of Markdown editor (remove CodeMirror)
+* Suggest menu for task ID and user mentions in Markdown editor
+* Add config parameter to disable automatic SQL migrations
+
Improvements:
* Add button to close inline popups
+* Simplify `.htaccess` to avoid potential issues with possible specific Apache configurations
+* Replace notifications Javascript code by CSS
+* Refactoring of user mentions job
+* Remove Nitrous installer
+* Update translations
+* Rewrite some components in Vanilla Javascript
+* Started Javascript code refactoring to avoid to much dependencies on jQuery
+* Remove dependency on VueJS and CoreMirror
+* Add P3P headers to avoid potential issues with IE
+
+Breaking changes:
+
+* Rename command line tool `./kanboard` to `./cli`
+
+Bug fixes:
+
+* Change column type for application settings value (field too small)
+* Fix link generation when user mention is followed by a punctuation mark
+* Make user mentions works again
Version 1.0.34 (11 Oct 2016)
---------------------------
diff --git a/Makefile b/Makefile
index c379966f..985aded7 100644
--- a/Makefile
+++ b/Makefile
@@ -9,6 +9,10 @@ static: clean
@ npm install
@ ./node_modules/.bin/gulp bower
@ ./node_modules/.bin/gulp vendor js css
+ @ ./node_modules/.bin/jshint assets/js/{core,components,polyfills}
+
+jshint:
+ @ ./node_modules/.bin/jshint assets/js/{core,components,polyfills}
archive:
@ echo "Build archive: version=${version}, destination=${dst}"
@@ -32,7 +36,6 @@ archive:
@ rm -rf ${BUILD_DIR}/kanboard/*.js
@ rm -rf ${BUILD_DIR}/kanboard/.dockerignore
@ rm -rf ${BUILD_DIR}/kanboard/docker
- @ rm -rf ${BUILD_DIR}/kanboard/nitrous*
@ cd ${BUILD_DIR}/kanboard && find ./vendor -name doc -type d -exec rm -rf {} +;
@ cd ${BUILD_DIR}/kanboard && find ./vendor -name notes -type d -exec rm -rf {} +;
@ cd ${BUILD_DIR}/kanboard && find ./vendor -name test -type d -exec rm -rf {} +;
@@ -60,8 +63,6 @@ test-mysql:
test-postgres:
@ ./vendor/bin/phpunit -c tests/units.postgres.xml
-unittest: test-sqlite test-mysql test-postgres
-
test-browser:
@ ./vendor/bin/phpunit -c tests/acceptance.xml
@@ -104,6 +105,8 @@ sql:
@ let pg_version=`psql -U postgres -A -c 'copy(select version from schema_version) to stdout;' kanboard` ;\
echo "INSERT INTO schema_version VALUES ('$$pg_version');" >> app/Schema/Sql/postgres.sql
+ @ grep -v "SET idle_in_transaction_session_timeout = 0;" app/Schema/Sql/postgres.sql > temp && mv temp app/Schema/Sql/postgres.sql
+
docker-image:
@ docker build -t kanboard/kanboard:latest .
diff --git a/app/Api/Middleware/AuthenticationMiddleware.php b/app/Api/Middleware/AuthenticationMiddleware.php
index 8e309593..c4fa874a 100644
--- a/app/Api/Middleware/AuthenticationMiddleware.php
+++ b/app/Api/Middleware/AuthenticationMiddleware.php
@@ -28,6 +28,7 @@ class AuthenticationMiddleware extends Base implements MiddlewareInterface
public function execute($username, $password, $procedureName)
{
$this->dispatcher->dispatch('app.bootstrap');
+ $this->sessionStorage->scope = 'API';
if ($this->isUserAuthenticated($username, $password)) {
$this->userSession->initialize($this->userModel->getByUsername($username));
diff --git a/app/Auth/ApiAccessTokenAuth.php b/app/Auth/ApiAccessTokenAuth.php
new file mode 100644
index 00000000..12ab21a7
--- /dev/null
+++ b/app/Auth/ApiAccessTokenAuth.php
@@ -0,0 +1,119 @@
+<?php
+
+namespace Kanboard\Auth;
+
+use Kanboard\Core\Base;
+use Kanboard\Core\Security\PasswordAuthenticationProviderInterface;
+use Kanboard\Model\UserModel;
+use Kanboard\User\DatabaseUserProvider;
+
+/**
+ * API Access Token Authentication Provider
+ *
+ * @package Kanboard\Auth
+ * @author Frederic Guillot
+ */
+class ApiAccessTokenAuth extends Base implements PasswordAuthenticationProviderInterface
+{
+ /**
+ * User properties
+ *
+ * @access protected
+ * @var array
+ */
+ protected $userInfo = array();
+
+ /**
+ * Username
+ *
+ * @access protected
+ * @var string
+ */
+ protected $username = '';
+
+ /**
+ * Password
+ *
+ * @access protected
+ * @var string
+ */
+ protected $password = '';
+
+ /**
+ * Get authentication provider name
+ *
+ * @access public
+ * @return string
+ */
+ public function getName()
+ {
+ return 'API Access Token';
+ }
+
+ /**
+ * Authenticate the user
+ *
+ * @access public
+ * @return boolean
+ */
+ public function authenticate()
+ {
+ if (! isset($this->sessionStorage->scope) || $this->sessionStorage->scope !== 'API') {
+ $this->logger->debug(__METHOD__.': Authentication provider skipped because invalid scope');
+ return false;
+ }
+
+ $user = $this->db
+ ->table(UserModel::TABLE)
+ ->columns('id', 'password')
+ ->eq('username', $this->username)
+ ->eq('api_access_token', $this->password)
+ ->notNull('api_access_token')
+ ->eq('is_active', 1)
+ ->findOne();
+
+ if (! empty($user)) {
+ $this->userInfo = $user;
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Get user object
+ *
+ * @access public
+ * @return \Kanboard\User\DatabaseUserProvider
+ */
+ public function getUser()
+ {
+ if (empty($this->userInfo)) {
+ return null;
+ }
+
+ return new DatabaseUserProvider($this->userInfo);
+ }
+
+ /**
+ * Set username
+ *
+ * @access public
+ * @param string $username
+ */
+ public function setUsername($username)
+ {
+ $this->username = $username;
+ }
+
+ /**
+ * Set password
+ *
+ * @access public
+ * @param string $password
+ */
+ public function setPassword($password)
+ {
+ $this->password = $password;
+ }
+}
diff --git a/app/Auth/DatabaseAuth.php b/app/Auth/DatabaseAuth.php
index ecb42c17..84a1e019 100644
--- a/app/Auth/DatabaseAuth.php
+++ b/app/Auth/DatabaseAuth.php
@@ -11,7 +11,7 @@ use Kanboard\User\DatabaseUserProvider;
/**
* Database Authentication Provider
*
- * @package auth
+ * @package Kanboard\Auth
* @author Frederic Guillot
*/
class DatabaseAuth extends Base implements PasswordAuthenticationProviderInterface, SessionCheckProviderInterface
diff --git a/app/Auth/LdapAuth.php b/app/Auth/LdapAuth.php
index a8dcfcb6..05ffbebf 100644
--- a/app/Auth/LdapAuth.php
+++ b/app/Auth/LdapAuth.php
@@ -12,7 +12,7 @@ use Kanboard\Core\Security\PasswordAuthenticationProviderInterface;
/**
* LDAP Authentication Provider
*
- * @package auth
+ * @package Kanboard\Auth
* @author Frederic Guillot
*/
class LdapAuth extends Base implements PasswordAuthenticationProviderInterface
diff --git a/app/Auth/RememberMeAuth.php b/app/Auth/RememberMeAuth.php
index 5d0a8b2e..e0f4ceb6 100644
--- a/app/Auth/RememberMeAuth.php
+++ b/app/Auth/RememberMeAuth.php
@@ -7,9 +7,9 @@ use Kanboard\Core\Security\PreAuthenticationProviderInterface;
use Kanboard\User\DatabaseUserProvider;
/**
- * Rember Me Cookie Authentication Provider
+ * RememberMe Cookie Authentication Provider
*
- * @package auth
+ * @package Kanboard\Auth
* @author Frederic Guillot
*/
class RememberMeAuth extends Base implements PreAuthenticationProviderInterface
diff --git a/app/Auth/ReverseProxyAuth.php b/app/Auth/ReverseProxyAuth.php
index fdf936b1..02afc302 100644
--- a/app/Auth/ReverseProxyAuth.php
+++ b/app/Auth/ReverseProxyAuth.php
@@ -10,7 +10,7 @@ use Kanboard\User\ReverseProxyUserProvider;
/**
* Reverse-Proxy Authentication Provider
*
- * @package auth
+ * @package Kanboard\Auth
* @author Frederic Guillot
*/
class ReverseProxyAuth extends Base implements PreAuthenticationProviderInterface, SessionCheckProviderInterface
diff --git a/app/Auth/TotpAuth.php b/app/Auth/TotpAuth.php
index 8e1ebe35..abfb2168 100644
--- a/app/Auth/TotpAuth.php
+++ b/app/Auth/TotpAuth.php
@@ -11,7 +11,7 @@ use Kanboard\Core\Security\PostAuthenticationProviderInterface;
/**
* TOTP Authentication Provider
*
- * @package auth
+ * @package Kanboard\Auth
* @author Frederic Guillot
*/
class TotpAuth extends Base implements PostAuthenticationProviderInterface
diff --git a/app/Console/DatabaseMigrationCommand.php b/app/Console/DatabaseMigrationCommand.php
new file mode 100644
index 00000000..252d4369
--- /dev/null
+++ b/app/Console/DatabaseMigrationCommand.php
@@ -0,0 +1,23 @@
+<?php
+
+namespace Kanboard\Console;
+
+use Kanboard\ServiceProvider\DatabaseProvider;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class DatabaseMigrationCommand extends DatabaseVersionCommand
+{
+ protected function configure()
+ {
+ $this
+ ->setName('db:migrate')
+ ->setDescription('Execute SQL migrations');
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+ parent::execute($input, $output);
+ DatabaseProvider::runMigrations($this->container['db']);
+ }
+}
diff --git a/app/Console/DatabaseVersionCommand.php b/app/Console/DatabaseVersionCommand.php
new file mode 100644
index 00000000..5b1f1ed1
--- /dev/null
+++ b/app/Console/DatabaseVersionCommand.php
@@ -0,0 +1,23 @@
+<?php
+
+namespace Kanboard\Console;
+
+use Kanboard\ServiceProvider\DatabaseProvider;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class DatabaseVersionCommand extends BaseCommand
+{
+ protected function configure()
+ {
+ $this
+ ->setName('db:version')
+ ->setDescription('Show database schema version');
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+ $output->writeln('<info>Current version: '.DatabaseProvider::getSchemaVersion($this->container['db']).'</info>');
+ $output->writeln('<info>Last version: '.\Schema\VERSION.'</info>');
+ }
+}
diff --git a/app/Controller/CommentController.php b/app/Controller/CommentController.php
index c61a0602..526bd2bf 100644
--- a/app/Controller/CommentController.php
+++ b/app/Controller/CommentController.php
@@ -48,6 +48,7 @@ class CommentController extends BaseController
*/
public function create(array $values = array(), array $errors = array())
{
+ $project = $this->getProject();
$task = $this->getTask();
if (empty($values)) {
@@ -57,10 +58,13 @@ class CommentController extends BaseController
);
}
- $this->response->html($this->template->render('comment/create', array(
+ $values['project_id'] = $task['project_id'];
+
+ $this->response->html($this->helper->layout->task('comment/create', array(
'values' => $values,
'errors' => $errors,
'task' => $task,
+ 'project' => $project,
)));
}
@@ -103,8 +107,14 @@ class CommentController extends BaseController
$task = $this->getTask();
$comment = $this->getComment();
+ if (empty($values)) {
+ $values = $comment;
+ }
+
+ $values['project_id'] = $task['project_id'];
+
$this->response->html($this->template->render('comment/edit', array(
- 'values' => empty($values) ? $comment : $values,
+ 'values' => $values,
'errors' => $errors,
'comment' => $comment,
'task' => $task,
diff --git a/app/Controller/TaskAjaxController.php b/app/Controller/TaskAjaxController.php
index f9feff15..609dd23c 100644
--- a/app/Controller/TaskAjaxController.php
+++ b/app/Controller/TaskAjaxController.php
@@ -5,8 +5,12 @@ namespace Kanboard\Controller;
use Kanboard\Filter\TaskIdExclusionFilter;
use Kanboard\Filter\TaskIdFilter;
use Kanboard\Filter\TaskProjectsFilter;
+use Kanboard\Filter\TaskStartsWithIdFilter;
+use Kanboard\Filter\TaskStatusFilter;
use Kanboard\Filter\TaskTitleFilter;
use Kanboard\Formatter\TaskAutoCompleteFormatter;
+use Kanboard\Formatter\TaskSuggestMenuFormatter;
+use Kanboard\Model\TaskModel;
/**
* Task Ajax Controller
@@ -19,7 +23,6 @@ class TaskAjaxController extends BaseController
/**
* Task auto-completion (Ajax)
*
- * @access public
*/
public function autocomplete()
{
@@ -46,4 +49,24 @@ class TaskAjaxController extends BaseController
$this->response->json($filter->format(new TaskAutoCompleteFormatter($this->container)));
}
}
+
+ /**
+ * Task ID suggest menu
+ */
+ public function suggest()
+ {
+ $taskId = $this->request->getIntegerParam('search');
+ $projectIds = $this->projectPermissionModel->getActiveProjectIds($this->userSession->getId());
+
+ if (empty($projectIds)) {
+ $this->response->json(array());
+ } else {
+ $filter = $this->taskQuery
+ ->withFilter(new TaskProjectsFilter($projectIds))
+ ->withFilter(new TaskStatusFilter(TaskModel::STATUS_OPEN))
+ ->withFilter(new TaskStartsWithIdFilter($taskId));
+
+ $this->response->json($filter->format(new TaskSuggestMenuFormatter($this->container)));
+ }
+ }
}
diff --git a/app/Controller/UserAjaxController.php b/app/Controller/UserAjaxController.php
index ed180471..d93bfe9a 100644
--- a/app/Controller/UserAjaxController.php
+++ b/app/Controller/UserAjaxController.php
@@ -4,6 +4,7 @@ namespace Kanboard\Controller;
use Kanboard\Filter\UserNameFilter;
use Kanboard\Formatter\UserAutoCompleteFormatter;
+use Kanboard\Formatter\UserMentionFormatter;
use Kanboard\Model\UserModel;
/**
@@ -35,9 +36,14 @@ class UserAjaxController extends BaseController
public function mention()
{
$project_id = $this->request->getStringParam('project_id');
- $query = $this->request->getStringParam('q');
+ $query = $this->request->getStringParam('search');
$users = $this->projectPermissionModel->findUsernames($project_id, $query);
- $this->response->json($users);
+
+ $this->response->json(
+ UserMentionFormatter::getInstance($this->container)
+ ->withUsers($users)
+ ->format()
+ );
}
/**
diff --git a/app/Controller/UserApiAccessController.php b/app/Controller/UserApiAccessController.php
new file mode 100644
index 00000000..e03514d5
--- /dev/null
+++ b/app/Controller/UserApiAccessController.php
@@ -0,0 +1,50 @@
+<?php
+
+namespace Kanboard\Controller;
+
+use Kanboard\Core\Security\Token;
+
+/**
+ * Class UserApiAccessController
+ *
+ * @package Kanboard\Controller
+ * @author Frederic Guillot
+ */
+class UserApiAccessController extends BaseController
+{
+ public function show()
+ {
+ $user = $this->getUser();
+
+ return $this->response->html($this->helper->layout->user('user_api_access/show', array(
+ 'user' => $user,
+ 'title' => t('API User Access'),
+ )));
+ }
+
+ public function generate()
+ {
+ $user = $this->getUser();
+ $this->checkCSRFParam();
+
+ $this->userModel->update(array(
+ 'id' => $user['id'],
+ 'api_access_token' => Token::getToken(),
+ ));
+
+ $this->response->redirect($this->helper->url->to('UserApiAccessController', 'show', array('user_id' => $user['id'])));
+ }
+
+ public function remove()
+ {
+ $user = $this->getUser();
+ $this->checkCSRFParam();
+
+ $this->userModel->update(array(
+ 'id' => $user['id'],
+ 'api_access_token' => null,
+ ));
+
+ $this->response->redirect($this->helper->url->to('UserApiAccessController', 'show', array('user_id' => $user['id'])));
+ }
+} \ No newline at end of file
diff --git a/app/Core/Base.php b/app/Core/Base.php
index 3dbf47f9..e7ccafaa 100644
--- a/app/Core/Base.php
+++ b/app/Core/Base.php
@@ -126,7 +126,6 @@ use Pimple\Container;
* @property \Kanboard\Model\TransitionModel $transitionModel
* @property \Kanboard\Model\UserModel $userModel
* @property \Kanboard\Model\UserLockingModel $userLockingModel
- * @property \Kanboard\Model\UserMentionModel $userMentionModel
* @property \Kanboard\Model\UserNotificationModel $userNotificationModel
* @property \Kanboard\Model\UserNotificationTypeModel $userNotificationTypeModel
* @property \Kanboard\Model\UserNotificationFilterModel $userNotificationFilterModel
@@ -178,6 +177,7 @@ use Pimple\Container;
* @property \Kanboard\Job\ProjectFileEventJob $projectFileEventJob
* @property \Kanboard\Job\NotificationJob $notificationJob
* @property \Kanboard\Job\ProjectMetricJob $projectMetricJob
+ * @property \Kanboard\Job\UserMentionJob $userMentionJob
* @property \Psr\Log\LoggerInterface $logger
* @property \PicoDb\Database $db
* @property \Symfony\Component\EventDispatcher\EventDispatcher $dispatcher
diff --git a/app/Core/Helper.php b/app/Core/Helper.php
index b5c560af..9660c348 100644
--- a/app/Core/Helper.php
+++ b/app/Core/Helper.php
@@ -12,6 +12,7 @@ use Pimple\Container;
*
* @property \Kanboard\Helper\AppHelper $app
* @property \Kanboard\Helper\AssetHelper $asset
+ * @property \Kanboard\Helper\AvatarHelper $avatar
* @property \Kanboard\Helper\BoardHelper $board
* @property \Kanboard\Helper\CalendarHelper $calendar
* @property \Kanboard\Helper\DateHelper $dt
diff --git a/app/Core/Markdown.php b/app/Core/Markdown.php
index b5abe5ed..799aefb4 100644
--- a/app/Core/Markdown.php
+++ b/app/Core/Markdown.php
@@ -86,7 +86,7 @@ class Markdown extends Parsedown
*/
protected function inlineUserLink(array $Excerpt)
{
- if (! $this->isPublicLink && preg_match('/^@([^\s]+)/', $Excerpt['text'], $matches)) {
+ if (! $this->isPublicLink && preg_match('/^@([^\s,!.:?]+)/', $Excerpt['text'], $matches)) {
$user_id = $this->container['userModel']->getIdByUsername($matches[1]);
if (! empty($user_id)) {
@@ -125,7 +125,10 @@ class Markdown extends Parsedown
array(
'token' => $token,
'task_id' => $task_id,
- )
+ ),
+ false,
+ '',
+ true
);
}
diff --git a/app/Core/Session/SessionStorage.php b/app/Core/Session/SessionStorage.php
index 9e93602c..e6478d8d 100644
--- a/app/Core/Session/SessionStorage.php
+++ b/app/Core/Session/SessionStorage.php
@@ -19,6 +19,7 @@ namespace Kanboard\Core\Session;
* @property bool $hasSubtaskInProgress
* @property bool $hasRememberMe
* @property bool $boardCollapsed
+ * @property string $scope
* @property bool $twoFactorBeforeCodeCalled
* @property string $twoFactorSecret
* @property string $oauthState
diff --git a/app/Event/GenericEvent.php b/app/Event/GenericEvent.php
index 94a51479..e87d9481 100644
--- a/app/Event/GenericEvent.php
+++ b/app/Event/GenericEvent.php
@@ -14,6 +14,28 @@ class GenericEvent extends BaseEvent implements ArrayAccess
$this->container = $values;
}
+ public function getTaskId()
+ {
+ if (isset($this->container['task']['id'])) {
+ return $this->container['task']['id'];
+ }
+
+ if (isset($this->container['task_id'])) {
+ return $this->container['task_id'];
+ }
+
+ return null;
+ }
+
+ public function getProjectId()
+ {
+ if (isset($this->container['task']['project_id'])) {
+ return $this->container['task']['project_id'];
+ }
+
+ return null;
+ }
+
public function getAll()
{
return $this->container;
diff --git a/app/Event/ProjectFileEvent.php b/app/Event/ProjectFileEvent.php
index 5d57e463..e1d29c48 100644
--- a/app/Event/ProjectFileEvent.php
+++ b/app/Event/ProjectFileEvent.php
@@ -4,4 +4,12 @@ namespace Kanboard\Event;
class ProjectFileEvent extends GenericEvent
{
+ public function getProjectId()
+ {
+ if (isset($this->container['file']['project_id'])) {
+ return $this->container['file']['project_id'];
+ }
+
+ return null;
+ }
}
diff --git a/app/Filter/TaskStartsWithIdFilter.php b/app/Filter/TaskStartsWithIdFilter.php
new file mode 100644
index 00000000..8b7cc678
--- /dev/null
+++ b/app/Filter/TaskStartsWithIdFilter.php
@@ -0,0 +1,38 @@
+<?php
+
+namespace Kanboard\Filter;
+
+use Kanboard\Core\Filter\FilterInterface;
+use Kanboard\Model\TaskModel;
+
+/**
+ * Class TaskIdSearchFilter
+ *
+ * @package Kanboard\Filter
+ * @author Frederic Guillot
+ */
+class TaskStartsWithIdFilter extends BaseFilter implements FilterInterface
+{
+ /**
+ * Get search attribute
+ *
+ * @access public
+ * @return string[]
+ */
+ public function getAttributes()
+ {
+ return array('starts_with_id');
+ }
+
+ /**
+ * Apply filter
+ *
+ * @access public
+ * @return FilterInterface
+ */
+ public function apply()
+ {
+ $this->query->ilike('CAST('.TaskModel::TABLE.'.id AS CHAR(8))', $this->value.'%');
+ return $this;
+ }
+}
diff --git a/app/Formatter/BaseFormatter.php b/app/Formatter/BaseFormatter.php
index 89c48437..0d62628e 100644
--- a/app/Formatter/BaseFormatter.php
+++ b/app/Formatter/BaseFormatter.php
@@ -4,7 +4,6 @@ namespace Kanboard\Formatter;
use Kanboard\Core\Base;
use PicoDb\Table;
-use Pimple\Container;
/**
* Class BaseFormatter
@@ -23,19 +22,6 @@ abstract class BaseFormatter extends Base
protected $query;
/**
- * Get object instance
- *
- * @static
- * @access public
- * @param Container $container
- * @return static
- */
- public static function getInstance(Container $container)
- {
- return new static($container);
- }
-
- /**
* Set query
*
* @access public
diff --git a/app/Formatter/BaseTaskCalendarFormatter.php b/app/Formatter/BaseTaskCalendarFormatter.php
index 8fab3e9a..3d9ead4d 100644
--- a/app/Formatter/BaseTaskCalendarFormatter.php
+++ b/app/Formatter/BaseTaskCalendarFormatter.php
@@ -2,8 +2,6 @@
namespace Kanboard\Formatter;
-use Kanboard\Core\Filter\FormatterInterface;
-
/**
* Common class to handle calendar events
*
@@ -34,7 +32,7 @@ abstract class BaseTaskCalendarFormatter extends BaseFormatter
* @access public
* @param string $start_column Column name for the start date
* @param string $end_column Column name for the end date
- * @return FormatterInterface
+ * @return $this
*/
public function setColumns($start_column, $end_column = '')
{
diff --git a/app/Formatter/TaskAutoCompleteFormatter.php b/app/Formatter/TaskAutoCompleteFormatter.php
index 2d9f7341..3a4f1e1a 100644
--- a/app/Formatter/TaskAutoCompleteFormatter.php
+++ b/app/Formatter/TaskAutoCompleteFormatter.php
@@ -14,6 +14,20 @@ use Kanboard\Model\TaskModel;
*/
class TaskAutoCompleteFormatter extends BaseFormatter implements FormatterInterface
{
+ protected $limit = 25;
+
+ /**
+ * Limit number of results
+ *
+ * @param $limit
+ * @return $this
+ */
+ public function withLimit($limit)
+ {
+ $this->limit = $limit;
+ return $this;
+ }
+
/**
* Apply formatter
*
@@ -22,11 +36,15 @@ class TaskAutoCompleteFormatter extends BaseFormatter implements FormatterInterf
*/
public function format()
{
- $tasks = $this->query->columns(
- TaskModel::TABLE.'.id',
- TaskModel::TABLE.'.title',
- ProjectModel::TABLE.'.name AS project_name'
- )->asc(TaskModel::TABLE.'.id')->findAll();
+ $tasks = $this->query
+ ->columns(
+ TaskModel::TABLE.'.id',
+ TaskModel::TABLE.'.title',
+ ProjectModel::TABLE.'.name AS project_name'
+ )
+ ->asc(TaskModel::TABLE.'.id')
+ ->limit($this->limit)
+ ->findAll();
foreach ($tasks as &$task) {
$task['value'] = $task['title'];
diff --git a/app/Formatter/TaskSuggestMenuFormatter.php b/app/Formatter/TaskSuggestMenuFormatter.php
new file mode 100644
index 00000000..518f99e6
--- /dev/null
+++ b/app/Formatter/TaskSuggestMenuFormatter.php
@@ -0,0 +1,63 @@
+<?php
+
+namespace Kanboard\Formatter;
+
+use Kanboard\Core\Filter\FormatterInterface;
+use Kanboard\Model\ProjectModel;
+use Kanboard\Model\TaskModel;
+
+/**
+ * Class TaskSuggestMenuFormatter
+ *
+ * @package Kanboard\Formatter
+ * @author Frederic Guillot
+ */
+class TaskSuggestMenuFormatter extends BaseFormatter implements FormatterInterface
+{
+ protected $limit = 25;
+
+ /**
+ * Limit number of results
+ *
+ * @param $limit
+ * @return $this
+ */
+ public function withLimit($limit)
+ {
+ $this->limit = $limit;
+ return $this;
+ }
+
+ /**
+ * Apply formatter
+ *
+ * @access public
+ * @return mixed
+ */
+ public function format()
+ {
+ $result = array();
+ $tasks = $this->query
+ ->columns(
+ TaskModel::TABLE.'.id',
+ TaskModel::TABLE.'.title',
+ ProjectModel::TABLE.'.name AS project_name'
+ )
+ ->asc(TaskModel::TABLE.'.id')
+ ->limit($this->limit)
+ ->findAll();
+
+ foreach ($tasks as $task) {
+ $html = '#'.$task['id'].' ';
+ $html .= $this->helper->text->e($task['title']).' ';
+ $html .= '<small>'.$this->helper->text->e($task['project_name']).'</small>';
+
+ $result[] = array(
+ 'value' => (string) $task['id'],
+ 'html' => $html,
+ );
+ }
+
+ return $result;
+ }
+}
diff --git a/app/Formatter/UserMentionFormatter.php b/app/Formatter/UserMentionFormatter.php
new file mode 100644
index 00000000..395fc463
--- /dev/null
+++ b/app/Formatter/UserMentionFormatter.php
@@ -0,0 +1,60 @@
+<?php
+
+namespace Kanboard\Formatter;
+
+/**
+ * Class UserMentionFormatter
+ *
+ * @package Kanboard\Formatter
+ * @author Frederic Guillot
+ */
+class UserMentionFormatter extends BaseFormatter
+{
+ protected $users = array();
+
+ /**
+ * Set users
+ *
+ * @param array $users
+ * @return $this
+ */
+ public function withUsers(array $users) {
+ $this->users = $users;
+ return $this;
+ }
+
+ /**
+ * Apply formatter
+ *
+ * @access public
+ * @return array
+ */
+ public function format()
+ {
+ $result = array();
+
+ foreach ($this->users as $user) {
+ $html = $this->helper->avatar->small(
+ $user['id'],
+ $user['username'],
+ $user['name'],
+ $user['email'],
+ $user['avatar_path'],
+ 'avatar-inline'
+ );
+
+ $html .= ' '.$this->helper->text->e($user['username']);
+
+ if (! empty($user['name'])) {
+ $html .= ' <small>'.$this->helper->text->e($user['name']).'</small>';
+ }
+
+ $result[] = array(
+ 'value' => $user['username'],
+ 'html' => $html,
+ );
+ }
+
+ return $result;
+ }
+} \ No newline at end of file
diff --git a/app/Helper/FormHelper.php b/app/Helper/FormHelper.php
index 629de9ff..9eabd724 100644
--- a/app/Helper/FormHelper.php
+++ b/app/Helper/FormHelper.php
@@ -131,16 +131,34 @@ class FormHelper extends Base
* Display a checkbox field
*
* @access public
- * @param string $name Field name
- * @param string $label Form label
- * @param string $value Form value
- * @param boolean $checked Field selected or not
- * @param string $class CSS class
+ * @param string $name Field name
+ * @param string $label Form label
+ * @param string $value Form value
+ * @param boolean $checked Field selected or not
+ * @param string $class CSS class
+ * @param array $attributes
* @return string
*/
- public function checkbox($name, $label, $value, $checked = false, $class = '')
+ public function checkbox($name, $label, $value, $checked = false, $class = '', array $attributes = array())
{
- return '<label><input type="checkbox" name="'.$name.'" class="'.$class.'" value="'.$this->helper->text->e($value).'" '.($checked ? 'checked="checked"' : '').'>&nbsp;'.$this->helper->text->e($label).'</label>';
+ $htmlAttributes = '';
+
+ if ($checked) {
+ $attributes['checked'] = 'checked';
+ }
+
+ foreach ($attributes as $attribute => $attributeValue) {
+ $htmlAttributes .= sprintf('%s="%s"', $attribute, $this->helper->text->e($attributeValue));
+ }
+
+ return sprintf(
+ '<label><input type="checkbox" name="%s" class="%s" value="%s" %s>&nbsp;%s</label>',
+ $name,
+ $class,
+ $this->helper->text->e($value),
+ $htmlAttributes,
+ $this->helper->text->e($label)
+ );
}
/**
@@ -195,15 +213,25 @@ class FormHelper extends Base
{
$params = array(
'name' => $name,
- 'text' => isset($values[$name]) ? $this->helper->text->e($values[$name]) : '',
+ 'text' => isset($values[$name]) ? $values[$name] : '',
'css' => $this->errorClass($errors, $name),
'required' => isset($attributes['required']) && $attributes['required'],
'tabindex' => isset($attributes['tabindex']) ? $attributes['tabindex'] : '-1',
'labelPreview' => t('Preview'),
'labelWrite' => t('Write'),
'placeholder' => t('Write your text in Markdown'),
+ 'autofocus' => isset($attributes['autofocus']) && $attributes['autofocus'],
+ 'suggestOptions' => array(
+ 'triggers' => array(
+ '#' => $this->helper->url->to('TaskAjaxController', 'suggest', array('search' => 'SEARCH_TERM')),
+ )
+ ),
);
+ if (isset($values['project_id'])) {
+ $params['suggestOptions']['triggers']['@'] = $this->helper->url->to('UserAjaxController', 'mention', array('project_id' => $values['project_id'], 'search' => 'SEARCH_TERM'));
+ }
+
$html = '<div class="js-text-editor" data-params=\''.json_encode($params, JSON_HEX_APOS).'\'></div>';
$html .= $this->errorList($errors, $name);
diff --git a/app/Job/CommentEventJob.php b/app/Job/CommentEventJob.php
index 47cf8020..62fae40a 100644
--- a/app/Job/CommentEventJob.php
+++ b/app/Job/CommentEventJob.php
@@ -31,7 +31,6 @@ class CommentEventJob extends BaseJob
*
* @param int $commentId
* @param string $eventName
- * @return $this
*/
public function execute($commentId, $eventName)
{
@@ -43,7 +42,8 @@ class CommentEventJob extends BaseJob
$this->dispatcher->dispatch($eventName, $event);
if ($eventName === CommentModel::EVENT_CREATE) {
- $this->userMentionModel->fireEvents($event['comment']['comment'], CommentModel::EVENT_USER_MENTION, $event);
+ $userMentionJob = $this->userMentionJob->withParams($event['comment']['comment'], CommentModel::EVENT_USER_MENTION, $event);
+ $this->queueManager->push($userMentionJob);
}
}
}
diff --git a/app/Job/TaskEventJob.php b/app/Job/TaskEventJob.php
index 7d026a68..acc7fca3 100644
--- a/app/Job/TaskEventJob.php
+++ b/app/Job/TaskEventJob.php
@@ -69,7 +69,8 @@ class TaskEventJob extends BaseJob
$this->dispatcher->dispatch($eventName, $event);
if ($eventName === TaskModel::EVENT_CREATE) {
- $this->userMentionModel->fireEvents($event['task']['description'], TaskModel::EVENT_USER_MENTION, $event);
+ $userMentionJob = $this->userMentionJob->withParams($event['task']['description'], TaskModel::EVENT_USER_MENTION, $event);
+ $this->queueManager->push($userMentionJob);
}
}
}
diff --git a/app/Job/UserMentionJob.php b/app/Job/UserMentionJob.php
new file mode 100644
index 00000000..bbb27131
--- /dev/null
+++ b/app/Job/UserMentionJob.php
@@ -0,0 +1,72 @@
+<?php
+
+namespace Kanboard\Job;
+
+use Kanboard\Event\GenericEvent;
+use Kanboard\Model\UserModel;
+
+/**
+ * Class UserMentionJob
+ *
+ * @package Kanboard\Job
+ * @author Frederic Guillot
+ */
+class UserMentionJob extends BaseJob
+{
+ /**
+ * Set job parameters
+ *
+ * @param string $text
+ * @param string $eventName
+ * @param GenericEvent $event
+ * @return $this
+ */
+ public function withParams($text, $eventName, GenericEvent $event)
+ {
+ $this->jobParams = array($text, $eventName, $event->getAll());
+ return $this;
+ }
+
+ /**
+ * Execute job
+ *
+ * @param string $text
+ * @param string $eventName
+ * @param array $eventData
+ */
+ public function execute($text, $eventName, array $eventData)
+ {
+ $event = new GenericEvent($eventData);
+ $users = $this->getMentionedUsers($text);
+
+ foreach ($users as $user) {
+ if ($this->projectPermissionModel->isMember($event->getProjectId(), $user['id'])) {
+ $event['mention'] = $user;
+ $this->dispatcher->dispatch($eventName, $event);
+ }
+ }
+ }
+
+ /**
+ * Get list of mentioned users
+ *
+ * @access public
+ * @param string $text
+ * @return array
+ */
+ public function getMentionedUsers($text)
+ {
+ $users = array();
+
+ if (preg_match_all('/@([^\s,!.:?]+)/', $text, $matches)) {
+ $users = $this->db->table(UserModel::TABLE)
+ ->columns('id', 'username', 'name', 'email', 'language')
+ ->eq('notifications_enabled', 1)
+ ->neq('id', $this->userSession->getId())
+ ->in('username', array_unique($matches[1]))
+ ->findAll();
+ }
+
+ return $users;
+ }
+}
diff --git a/app/Locale/bs_BA/translations.php b/app/Locale/bs_BA/translations.php
index cb9ad9d5..e27a4501 100644
--- a/app/Locale/bs_BA/translations.php
+++ b/app/Locale/bs_BA/translations.php
@@ -1278,4 +1278,13 @@ return array(
// 'Moving a task is not permitted' => '',
// 'This value must be in the range %d to %d' => '',
// 'You are not allowed to move this task.' => '',
+ // 'API User Access' => '',
+ // 'Preview' => '',
+ // 'Write' => '',
+ // 'Write your text in Markdown' => '',
+ // 'New External Task: %s' => '',
+ // 'No personal API access token registered.' => '',
+ // 'Your personal API access token is "%s"' => '',
+ // 'Remove your token' => '',
+ // 'Generate a new token' => '',
);
diff --git a/app/Locale/cs_CZ/translations.php b/app/Locale/cs_CZ/translations.php
index 8541f303..5091de00 100644
--- a/app/Locale/cs_CZ/translations.php
+++ b/app/Locale/cs_CZ/translations.php
@@ -1278,4 +1278,13 @@ return array(
// 'Moving a task is not permitted' => '',
// 'This value must be in the range %d to %d' => '',
// 'You are not allowed to move this task.' => '',
+ // 'API User Access' => '',
+ // 'Preview' => '',
+ // 'Write' => '',
+ // 'Write your text in Markdown' => '',
+ // 'New External Task: %s' => '',
+ // 'No personal API access token registered.' => '',
+ // 'Your personal API access token is "%s"' => '',
+ // 'Remove your token' => '',
+ // 'Generate a new token' => '',
);
diff --git a/app/Locale/da_DK/translations.php b/app/Locale/da_DK/translations.php
index 78a6d35e..2ca864e5 100644
--- a/app/Locale/da_DK/translations.php
+++ b/app/Locale/da_DK/translations.php
@@ -1278,4 +1278,13 @@ return array(
// 'Moving a task is not permitted' => '',
// 'This value must be in the range %d to %d' => '',
// 'You are not allowed to move this task.' => '',
+ // 'API User Access' => '',
+ // 'Preview' => '',
+ // 'Write' => '',
+ // 'Write your text in Markdown' => '',
+ // 'New External Task: %s' => '',
+ // 'No personal API access token registered.' => '',
+ // 'Your personal API access token is "%s"' => '',
+ // 'Remove your token' => '',
+ // 'Generate a new token' => '',
);
diff --git a/app/Locale/de_DE/translations.php b/app/Locale/de_DE/translations.php
index 433b7a2f..950a3b77 100644
--- a/app/Locale/de_DE/translations.php
+++ b/app/Locale/de_DE/translations.php
@@ -1278,4 +1278,13 @@ return array(
'Moving a task is not permitted' => 'Verschieben einer Aufgabe ist nicht erlaubt',
'This value must be in the range %d to %d' => 'Dieser Wert muss im Bereich %d bis %d sein',
'You are not allowed to move this task.' => 'Sie haben nicht die Berechtigung, diese Aufgabe zu verschieben.',
+ // 'API User Access' => '',
+ // 'Preview' => '',
+ // 'Write' => '',
+ // 'Write your text in Markdown' => '',
+ // 'New External Task: %s' => '',
+ // 'No personal API access token registered.' => '',
+ // 'Your personal API access token is "%s"' => '',
+ // 'Remove your token' => '',
+ // 'Generate a new token' => '',
);
diff --git a/app/Locale/el_GR/translations.php b/app/Locale/el_GR/translations.php
index ad17b4ed..7b7d855e 100644
--- a/app/Locale/el_GR/translations.php
+++ b/app/Locale/el_GR/translations.php
@@ -1278,4 +1278,13 @@ return array(
// 'Moving a task is not permitted' => '',
// 'This value must be in the range %d to %d' => '',
// 'You are not allowed to move this task.' => '',
+ // 'API User Access' => '',
+ // 'Preview' => '',
+ // 'Write' => '',
+ // 'Write your text in Markdown' => '',
+ // 'New External Task: %s' => '',
+ // 'No personal API access token registered.' => '',
+ // 'Your personal API access token is "%s"' => '',
+ // 'Remove your token' => '',
+ // 'Generate a new token' => '',
);
diff --git a/app/Locale/es_ES/translations.php b/app/Locale/es_ES/translations.php
index b3a68751..984d42db 100644
--- a/app/Locale/es_ES/translations.php
+++ b/app/Locale/es_ES/translations.php
@@ -1278,4 +1278,13 @@ return array(
// 'Moving a task is not permitted' => '',
// 'This value must be in the range %d to %d' => '',
// 'You are not allowed to move this task.' => '',
+ // 'API User Access' => '',
+ // 'Preview' => '',
+ // 'Write' => '',
+ // 'Write your text in Markdown' => '',
+ // 'New External Task: %s' => '',
+ // 'No personal API access token registered.' => '',
+ // 'Your personal API access token is "%s"' => '',
+ // 'Remove your token' => '',
+ // 'Generate a new token' => '',
);
diff --git a/app/Locale/fi_FI/translations.php b/app/Locale/fi_FI/translations.php
index 733625b6..41e51fa1 100644
--- a/app/Locale/fi_FI/translations.php
+++ b/app/Locale/fi_FI/translations.php
@@ -1278,4 +1278,13 @@ return array(
// 'Moving a task is not permitted' => '',
// 'This value must be in the range %d to %d' => '',
// 'You are not allowed to move this task.' => '',
+ // 'API User Access' => '',
+ // 'Preview' => '',
+ // 'Write' => '',
+ // 'Write your text in Markdown' => '',
+ // 'New External Task: %s' => '',
+ // 'No personal API access token registered.' => '',
+ // 'Your personal API access token is "%s"' => '',
+ // 'Remove your token' => '',
+ // 'Generate a new token' => '',
);
diff --git a/app/Locale/fr_FR/translations.php b/app/Locale/fr_FR/translations.php
index 59f4609e..daac98ed 100644
--- a/app/Locale/fr_FR/translations.php
+++ b/app/Locale/fr_FR/translations.php
@@ -1279,4 +1279,13 @@ return array(
'Moving a task is not permitted' => 'Déplaçer une tâche n\'est pas autorisé',
'This value must be in the range %d to %d' => 'Cette valeur doit être définie entre %d et %d',
'You are not allowed to move this task.' => 'Vous n\'êtes pas autorisé à déplacer cette tâche.',
+ 'API User Access' => 'Accès utilisateur de l\'API',
+ 'Preview' => 'Aperçu',
+ 'Write' => 'Écrire',
+ 'Write your text in Markdown' => 'Écrivez votre texte en Markdown',
+ 'New External Task: %s' => 'Nouvelle tâche externe : %s',
+ 'No personal API access token registered.' => 'Aucun jeton d\'accès personnel à l\'API enregistré.',
+ 'Your personal API access token is "%s"' => 'Votre jeton d\'accès personnel à l\'API est « %s »',
+ 'Remove your token' => 'Supprimer votre jeton',
+ 'Generate a new token' => 'Générer un nouveau jeton',
);
diff --git a/app/Locale/hu_HU/translations.php b/app/Locale/hu_HU/translations.php
index b5a23428..784c27ba 100644
--- a/app/Locale/hu_HU/translations.php
+++ b/app/Locale/hu_HU/translations.php
@@ -1278,4 +1278,13 @@ return array(
// 'Moving a task is not permitted' => '',
// 'This value must be in the range %d to %d' => '',
// 'You are not allowed to move this task.' => '',
+ // 'API User Access' => '',
+ // 'Preview' => '',
+ // 'Write' => '',
+ // 'Write your text in Markdown' => '',
+ // 'New External Task: %s' => '',
+ // 'No personal API access token registered.' => '',
+ // 'Your personal API access token is "%s"' => '',
+ // 'Remove your token' => '',
+ // 'Generate a new token' => '',
);
diff --git a/app/Locale/id_ID/translations.php b/app/Locale/id_ID/translations.php
index e711a512..9398d51d 100644
--- a/app/Locale/id_ID/translations.php
+++ b/app/Locale/id_ID/translations.php
@@ -1278,4 +1278,13 @@ return array(
// 'Moving a task is not permitted' => '',
// 'This value must be in the range %d to %d' => '',
// 'You are not allowed to move this task.' => '',
+ // 'API User Access' => '',
+ // 'Preview' => '',
+ // 'Write' => '',
+ // 'Write your text in Markdown' => '',
+ // 'New External Task: %s' => '',
+ // 'No personal API access token registered.' => '',
+ // 'Your personal API access token is "%s"' => '',
+ // 'Remove your token' => '',
+ // 'Generate a new token' => '',
);
diff --git a/app/Locale/it_IT/translations.php b/app/Locale/it_IT/translations.php
index fa5f5105..65defe86 100644
--- a/app/Locale/it_IT/translations.php
+++ b/app/Locale/it_IT/translations.php
@@ -297,7 +297,7 @@ return array(
'Display another project' => 'Mostra un altro progetto',
'Created by %s' => 'Creato da %s',
'Tasks Export' => 'Export dei task',
- 'Start Date' => 'Data d\'inizio',
+ 'Start Date' => 'Data di inizio',
'End Date' => 'Data di fine',
'Execute' => 'Esegui',
'Task Id' => 'Id del task',
@@ -780,8 +780,8 @@ return array(
'Add task' => 'Aggiungi task',
'Start date:' => 'Data di inizio:',
'Due date:' => 'Data di completamento:',
- 'There is no start date or due date for this task.' => 'Nessuna data di inzio o di scadenza per questo task.',
- 'Moving or resizing a task will change the start and due date of the task.' => 'Spostando o ridimensionado un task ne modifca la data di inzio e di scadenza.',
+ 'There is no start date or due date for this task.' => 'Nessuna data di inizio o di scadenza per questo task.',
+ 'Moving or resizing a task will change the start and due date of the task.' => 'Spostando o ridimensionado un task ne modifca la data di inizio e di scadenza.',
'There is no task in your project.' => 'Non ci sono task nel tuo progetto.',
'Gantt chart' => 'Grafici Gantt',
'People who are project managers' => 'Persone che sono manager di progetto',
@@ -1184,7 +1184,7 @@ return array(
'Global tags' => 'Tag globali',
'There is no global tag at the moment.' => 'Non sono definiti tag globali al momento.',
'This field cannot be empty' => 'Questo campo non può essere vuoto',
- 'Close a task when there is no activity in an specific column' => 'Chiudi un task quando non vi è alcuna attività in un specifica colonna',
+ 'Close a task when there is no activity in an specific column' => 'Chiudi un task quando non vi è alcuna attività in una specifica colonna',
'%s removed a subtask for the task #%d' => '%s rimosso un subtask per il task #%d',
'%s removed a comment on the task #%d' => '%s rimosso un commento nel task #%d',
'Comment removed on task #%d' => 'Commento rimosso nel task #%d',
@@ -1234,17 +1234,17 @@ return array(
'Remove this role' => 'Cancella questo ruolo',
'There is no restriction for this role.' => 'Non ci sono restrizioni per questo ruolo.',
'Only moving task between those columns is permitted' => 'È permesso solo muovere i tast tra queste colonne',
- 'Close a task in a specific column when not moved during a given period' => 'Chiudi un task in una colonna specifica quando non è mosso per un determinato periodo',
+ 'Close a task in a specific column when not moved during a given period' => 'Chiudi un task in una colonna specifica quando non viene mosso per un determinato periodo',
'Edit columns' => 'Modifica colonne',
'The column restriction has been created successfully.' => 'La restrizione per le colonne è stata creata correttamente.',
'Unable to create this column restriction.' => 'Impossibile creare questa restrizione per colonne.',
'Column restriction removed successfully.' => 'Restrizione per colonne rimossa correttamente.',
'Unable to remove this restriction.' => 'Impossibile rimuovere questa restrizione.',
- 'Your custom project role has been created successfully.' => 'La regola per il progetto personalizzato è stata creata correttamente.',
- 'Unable to create custom project role.' => 'Impossibile creare la regola per il progetto personalizzato.',
- 'Your custom project role has been updated successfully.' => 'La regola per il progetto personalizzato è stata modificata correttamente.',
- 'Unable to update custom project role.' => 'Impossibile modificare correttamente la regola per il progetto personalizzato.',
- 'Custom project role removed successfully.' => 'Regola per il progetto personalizzato rimossa correttamente.',
+ 'Your custom project role has been created successfully.' => 'La regola personalizzata per il progetto è stata creata correttamente.',
+ 'Unable to create custom project role.' => 'Impossibile creare la regola personalizzata per il progetto.',
+ 'Your custom project role has been updated successfully.' => 'La regola personalizzata per il progetto è stata modificata correttamente.',
+ 'Unable to update custom project role.' => 'Impossibile modificare correttamente la regola personalizzata per il progetto.',
+ 'Custom project role removed successfully.' => 'Regola personalizzata per il progetto rimossa correttamente.',
'Unable to remove this project role.' => 'Impossibile rimuovere questa regola per il progetto.',
'The project restriction has been created successfully.' => 'La restrizione di progetto è stata creata con successo.',
'Unable to create this project restriction.' => 'Impossibile creare la restrizione di progetto.',
@@ -1257,10 +1257,10 @@ return array(
'Task creation is not permitted' => 'Creazione task non permessa',
'Closing or opening a task is not permitted' => 'Chiudere o aprire task non è permesso',
'New drag and drop restriction for the role "%s"' => 'Nuova restrizione "drag and drop" per la regola "%s"',
- 'People belonging to this role will be able to move tasks only between the source and the destination column.' => 'Gli utenti che appartengono a questa regola saranno in grado di muovere i task solo tra la colonna di origine e quella di destinazione',
- 'Remove a column restriction' => 'Rimuovere restrizione colonna',
+ 'People belonging to this role will be able to move tasks only between the source and the destination column.' => 'Gli utenti che appartengono a questa regola saranno in grado di spostare i task solo tra la colonna di origine e quella di destinazione',
+ 'Remove a column restriction' => 'Rimuovere una restrizione di colonna',
'Do you really want to remove this column restriction: "%s" to "%s"?' => 'Vuoi davvero rimuovere questa restrizione di colonna: "%s" a "%s"?',
- 'New column restriction for the role "%s"' => 'Nuova restrizione colonna per la regola "%s"',
+ 'New column restriction for the role "%s"' => 'Nuova restrizione di colonna per la regola "%s"',
'Rule' => 'Regola',
'Do you really want to remove this column restriction?' => 'Vuoi davvero rimuovere questa restrizione di colonna?',
'Custom roles' => 'Regole personalizzate',
@@ -1273,9 +1273,18 @@ return array(
'Restriction' => 'Restrizione',
'Remove a project restriction' => 'Rimuovi restrizione di progetto',
'Do you really want to remove this project restriction: "%s"?' => 'Vuoi davvero rimuovere questa restrizione di progetto: "%s"?',
- 'Duplicate to multiple projects' => 'Dupplica i più progetti',
- 'This field is required' => 'Questo campo è richiesto',
- 'Moving a task is not permitted' => 'Muovere task non è permesso',
+ 'Duplicate to multiple projects' => 'Duplica su più progetti',
+ 'This field is required' => 'Questo campo è obbligatorio',
+ 'Moving a task is not permitted' => 'Spostare task non è permesso',
'This value must be in the range %d to %d' => 'Questo valore deve essere compreso tra %d e %d',
- 'You are not allowed to move this task.' => 'Non ti è permesso muovere questo task.',
+ 'You are not allowed to move this task.' => 'Non ti è permesso spostare questo task.',
+ // 'API User Access' => '',
+ // 'Preview' => '',
+ // 'Write' => '',
+ // 'Write your text in Markdown' => '',
+ // 'New External Task: %s' => '',
+ // 'No personal API access token registered.' => '',
+ // 'Your personal API access token is "%s"' => '',
+ // 'Remove your token' => '',
+ // 'Generate a new token' => '',
);
diff --git a/app/Locale/ja_JP/translations.php b/app/Locale/ja_JP/translations.php
index b9feed07..d0487fb7 100644
--- a/app/Locale/ja_JP/translations.php
+++ b/app/Locale/ja_JP/translations.php
@@ -1278,4 +1278,13 @@ return array(
// 'Moving a task is not permitted' => '',
// 'This value must be in the range %d to %d' => '',
// 'You are not allowed to move this task.' => '',
+ // 'API User Access' => '',
+ // 'Preview' => '',
+ // 'Write' => '',
+ // 'Write your text in Markdown' => '',
+ // 'New External Task: %s' => '',
+ // 'No personal API access token registered.' => '',
+ // 'Your personal API access token is "%s"' => '',
+ // 'Remove your token' => '',
+ // 'Generate a new token' => '',
);
diff --git a/app/Locale/ko_KR/translations.php b/app/Locale/ko_KR/translations.php
index 5339111b..a613b467 100644
--- a/app/Locale/ko_KR/translations.php
+++ b/app/Locale/ko_KR/translations.php
@@ -402,9 +402,9 @@ return array(
'Refresh interval for private board' => '비공개 ë³´ë“œì˜ ê°±ì‹  빈ë„',
'Refresh interval for public board' => '공개 ë³´ë“œì˜ ê°±ì‹  빈ë„',
'Task highlight period' => 'í• ì¼ì˜ 하ì´ë¼ì´íŠ¸ 기간',
- // 'Period (in second) to consider a task was modified recently (0 to disable, 2 days by default)' => '',
- // 'Frequency in second (60 seconds by default)' => '',
- // 'Frequency in second (0 to disable this feature, 10 seconds by default)' => '',
+ 'Period (in second) to consider a task was modified recently (0 to disable, 2 days by default)' => '최근 ìˆ˜ì •ëœ ìž‘ì—… ê³ ë ¤ 기간(ì´ˆ), (비활성화:0, 기본값:2ì¼)',
+ 'Frequency in second (60 seconds by default)' => '초당 횟수(기본값:60초)',
+ 'Frequency in second (0 to disable this feature, 10 seconds by default)' => '초당 횟수(비활성화:0, 기본값:10초)',
'Application URL' => '애플리케ì´ì…˜ì˜ URL',
'Token regenerated.' => '토í°ì´ 다시 ìƒì„±ë˜ì—ˆìŠµë‹ˆë‹¤.',
'Date format' => 'ë°ì´í„° í¬ë©§',
@@ -555,18 +555,18 @@ return array(
'No results match:' => '결과가 ì¼ì¹˜í•˜ì§€ 않았습니다',
'Currency' => '통화',
'Private project' => 'ê°œì¸ í”„ë¡œì íŠ¸',
- // 'AUD - Australian Dollar' => '',
- // 'CAD - Canadian Dollar' => '',
- // 'CHF - Swiss Francs' => '',
+ 'AUD - Australian Dollar' => 'AUD - 호주 달러',
+ 'CAD - Canadian Dollar' => 'CAD -ìºë‚˜ë‹¤ 달러',
+ 'CHF - Swiss Francs' => 'CHF - 스위스 프랑',
'Custom Stylesheet' => '커스텀 ìŠ¤íƒ€ì¼ ì‹œíŠ¸',
'download' => '다운로드',
- // 'EUR - Euro' => '',
- // 'GBP - British Pound' => '',
- // 'INR - Indian Rupee' => '',
- // 'JPY - Japanese Yen' => '',
- // 'NZD - New Zealand Dollar' => '',
- // 'RSD - Serbian dinar' => '',
- // 'USD - US Dollar' => '',
+ 'EUR - Euro' => 'EUR - 유로',
+ 'GBP - British Pound' => 'GBP - ì˜êµ­ 파운드',
+ 'INR - Indian Rupee' => 'INR - ì¸ë„ 루피',
+ 'JPY - Japanese Yen' => 'JPY - ì¼ë³¸ ì—”',
+ 'NZD - New Zealand Dollar' => 'NZD - 뉴질랜드 달러',
+ 'RSD - Serbian dinar' => 'RSD - 세르비아 디나르',
+ 'USD - US Dollar' => 'USD - 미국 달러',
'Destination column' => 'ì´ë™ 후 컬럼',
'Move the task to another column when assigned to a user' => '사용ìžì˜ í• ë‹¹ì„ í•˜ë©´ í• ì¼ì„ 다른 ì»¬ëŸ¼ì— ì´ë™',
'Move the task to another column when assignee is cleared' => '사용ìžì˜ í• ë‹¹ì´ ì—†ì–´ì§€ë©´ í• ì¼ì„ 다른 ì»¬ëŸ¼ì— ì´ë™',
@@ -600,12 +600,12 @@ return array(
'Assign a color when the task is moved to a specific column' => 'ìƒì„¸ 컬럼으로 ì´ë™í•  í• ì¼ì˜ ìƒ‰ê¹”ì„ ì§€ì •í•˜ì„¸ìš”',
'%s via Kanboard' => '%s via E-board',
'Burndown chart' => '번다운 차트',
- // 'This chart show the task complexity over the time (Work Remaining).' => '',
+ 'This chart show the task complexity over the time (Work Remaining).' => 'ì´ ì°¨íŠ¸ëŠ” ì‹œê°„ì— ë”°ë¥¸ í• ì¼ì˜ ë³µìž¡ì„±ì„ ë³´ì—¬ì¤ë‹ˆë‹¤. (남아있는 ì¼)',
'Screenshot taken %s' => '스í¬ë¦°ìƒ·_%s',
'Add a screenshot' => '스í¬ë¦°ìƒ· 추가',
'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => '스í¬ë¦°ìƒ·ì„ CTRL+V í˜¹ì€ âŒ˜+V를 눌러 붙여넣기',
'Screenshot uploaded successfully.' => '스í¬ë¦°ìƒ·ì„ 업로드하였습니다',
- // 'SEK - Swedish Krona' => '',
+ 'SEK - Swedish Krona' => 'SEK - 스위스 í¬ë¡œë‚˜',
'Identifier' => 'ì‹ë³„ìž',
'Disable two factor authentication' => 'ì´ì¤‘ ì¸ì¦ 비활성화',
'Do you really want to disable the two factor authentication for this user: "%s"?' => '"%s" 담당ìžì˜ ì´ì¤‘ ì¸ì¦ì„ 비활성화 하시겠습니까?',
@@ -613,7 +613,7 @@ return array(
'Start to type task title...' => 'í• ì¼ ì œëª©ì„ ìž…ë ¥í•˜ì„¸ìš”',
'A task cannot be linked to itself' => 'í• ì¼ì„ ìžê¸°ìžì‹ ì—게 ì—°ê²°í•  수 없습니다',
'The exact same link already exists' => 'ë™ì¼í•œ ë§í¬ê°€ ì´ë¯¸ 존재합니다',
- // 'Recurrent task is scheduled to be generated' => '',
+ 'Recurrent task is scheduled to be generated' => '반복 í• ì¼ì´ ìƒì„±ëœ 예정입니다.',
'Score' => 'ì ìˆ˜',
'The identifier must be unique' => 'ì‹ë³„ìžëŠ” 유ì¼í•´ì•¼ 합니다',
'This linked task id doesn\'t exists' => 'ì—°ê²°ëœ í• ì¼ IDê°€ 존재하지 않습니다',
@@ -626,7 +626,7 @@ return array(
'Base date to calculate new due date' => '새로운 기본 종료날짜 계산',
'Action date' => '시작날짜',
'Base date to calculate new due date: ' => '새로운 기본 종료날짜 계산: ',
- // 'This task has created this child task: ' => '',
+ 'This task has created this child task: ' => 'ì´ í• ì¼ì€ 하위 í• ì¼ì„ 만들었습니다.',
'Day(s)' => 'ì¼',
'Existing due date' => '기존 종료날짜',
'Factor to calculate new due date: ' => '새로운 종료날짜 계산: ',
@@ -635,7 +635,7 @@ return array(
'This task has been created by: ' => 'í• ì¼ì„ 만들었습니다: ',
'Recurrent task has been generated:' => '반복 í• ì¼ì´ ìƒì„±ë˜ì—ˆìŠµë‹ˆë‹¤',
'Timeframe to calculate new due date: ' => '종료날짜 계산 단위',
- // 'Trigger to generate recurrent task: ' => '',
+ 'Trigger to generate recurrent task: ' => '반복 í• ì¼ ìƒì„± 트리거',
'When task is closed' => 'í• ì¼ì„ 마쳤ì„ë•Œ',
'When task is moved from first column' => 'í• ì¼ì´ 첫번째 컬럼으로 옮겨졌ì„ë•Œ',
'When task is moved to last column' => 'í• ì¼ì´ 마지막 컬럼으로 옮겨졌ì„ë•Œ',
@@ -649,7 +649,7 @@ return array(
'Subtasks time tracking' => '서브 í• ì¼ ì‹œê°„ 트래킹',
'User calendar view' => 'ë‹´ë‹¹ìž ë‹¬ë ¥ 보기',
'Automatically update the start date' => '시작ì¼ì— ìžë™ 갱신',
- // 'iCal feed' => '',
+ 'iCal feed' => 'iCal 피드',
'Preferences' => '우선권',
'Security' => '보안',
'Two factor authentication disabled' => 'ì´ì¤‘ ì¸ì¦ì´ 비활성화 ë˜ì—ˆìŠµë‹ˆë‹¤',
@@ -666,7 +666,7 @@ return array(
'Notification' => '알림',
'%s moved the task #%d to the first swimlane' => '%sê°€ í• ì¼ #%d를 첫번째 스웜레ì¸ìœ¼ë¡œ ì´ë™ì‹œì¼°ìŠµë‹ˆë‹¤',
'Swimlane' => '스윔레ì¸',
- // 'Gravatar' => '',
+ 'Gravatar' => 'Gravatar',
'%s moved the task %s to the first swimlane' => '%sê°€ í• ì¼ %s를 첫번째 스웜레ì¸ìœ¼ë¡œ ì´ë™ì‹œì¼°ìŠµë‹ˆë‹¤',
'%s moved the task %s to the swimlane "%s"' => '%sê°€ í• ì¼ %s를 %s 스웜레ì¸ìœ¼ë¡œ ì´ë™ì‹œì¼°ìŠµë‹ˆë‹¤',
'This report contains all subtasks information for the given date range.' => '해당 ê¸°ê°„ì˜ ëª¨ë“  서브 í• ì¼ ì •ë³´ê°€ ë³´ê³ ì„œì— í¬í•¨ë©ë‹ˆë‹¤',
@@ -695,7 +695,7 @@ return array(
'Only for tasks assigned to me' => 'ë‚´ê°€ 담당ìžì¸ ì¼',
'Only for tasks created by me' => 'ë‚´ê°€ 만든 ì¼',
'Only for tasks created by me and assigned to me' => 'ë‚´ê°€ 만들었거나 ë‚´ê°€ 담당ìžì¸ ì¼',
- // '%%Y-%%m-%%d' => '',
+ '%%Y-%%m-%%d' => '%%Y-%%m-%%d',
'Total for all columns' => '모든 컬럼',
'You need at least 2 days of data to show the chart.' => '차트를 보기 위하여 최소 2ì¼ì˜ ë°ì´í„°ê°€ 필요합니다',
'<15m' => '<15분',
@@ -781,12 +781,12 @@ return array(
'Start date:' => '시작ì¼:',
'Due date:' => '만기ì¼:',
'There is no start date or due date for this task.' => 'í• ì¼ì˜ ì‹œìž‘ì¼ ë˜ëŠ” 만기ì¼ì´ 없습니다',
- // 'Moving or resizing a task will change the start and due date of the task.' => '',
- // 'There is no task in your project.' => '',
+ 'Moving or resizing a task will change the start and due date of the task.' => 'í• ì¼ì˜ ì´ë™ í˜¹ì€ ë¦¬ì‚¬ì´ì§•ìœ¼ë¡œ 시작시간과 마ê°ì‹œê°„ì´ ë³€ê²½ë©ë‹ˆë‹¤.',
+ 'There is no task in your project.' => '프로ì íŠ¸ì— í• ì¼ì´ 없습니다.',
'Gantt chart' => '간트 차트',
'People who are project managers' => '프로ì íŠ¸ 매니저',
'People who are project members' => '프로ì íŠ¸ 멤버',
- // 'NOK - Norwegian Krone' => '',
+ 'NOK - Norwegian Krone' => 'NOK - ë…¸ë¥´ì›¨ì´ í¬ë¡œë„¤',
'Show this column' => '컬럼 ë³´ì´ê¸°',
'Hide this column' => '컬럼 숨기기',
'open file' => '열기',
@@ -802,14 +802,14 @@ return array(
'End date:' => '날짜 수정',
'There is no start date or end date for this project.' => 'ì´ í”„ë¡œì íŠ¸ì—는 시작날짜와 종료날짜가 없습니다',
'Projects Gantt chart' => '프로ì íŠ¸ 간트차트',
- // 'Change task color when using a specific task link' => '',
- // 'Task link creation or modification' => '',
+ 'Change task color when using a specific task link' => '특정 í• ì¼ ë§í¬ë¥¼ 사용할때 í• ì¼ì˜ 색깔 변경',
+ 'Task link creation or modification' => 'í• ì¼ ë§í¬ ìƒì„± í˜¹ì€ ìˆ˜ì •',
'Milestone' => '마ì¼ìŠ¤í†¤',
'Documentation: %s' => '문서: %s',
'Switch to the Gantt chart view' => '간트 차트 보기로 변경',
- // 'Reset the search/filter box' => '',
+ 'Reset the search/filter box' => '찾기/필터 박스 초기화',
'Documentation' => '문서',
- // 'Table of contents' => '',
+ 'Table of contents' => '목차',
'Gantt' => '간트',
'Author' => '글쓴ì´',
'Version' => '버전',
@@ -825,7 +825,7 @@ return array(
'Your custom filter have been updated successfully.' => 'ì‚¬ìš©ìž ì •ì˜ í•„í„°ê°€ 성공ì ìœ¼ë¡œ 수정ë˜ì—ˆìŠµë‹ˆë‹¤',
'Unable to update custom filter.' => 'ì •ì˜ í•„í„° 수정 비활성화',
'Web' => '웹',
- // 'New attachment on task #%d: %s' => '',
+ 'New attachment on task #%d: %s' => 'í• ì¼ #%dì˜ ìƒˆë¡œìš´ 첨부파ì¼: %s',
'New comment on task #%d' => 'í• ì¼ #%dì— ìƒˆë¡œìš´ ëŒ“ê¸€ì´ ë‹¬ë ¸ìŠµë‹ˆë‹¤',
'Comment updated on task #%d' => 'í• ì¼ #%dì— ëŒ“ê¸€ì´ ê°±ì‹  ë˜ì—ˆìŠµë‹ˆë‹¤',
'New subtask on task #%d' => '서브 í• ì¼ #%dì´ ê°±ì‹  ë˜ì—ˆìŠµë‹ˆë‹¤',
@@ -843,7 +843,7 @@ return array(
'No new notifications.' => 'ì•Œë¦¼ì´ ì—†ìŠµë‹ˆë‹¤',
'Mark all as read' => 'ëª¨ë‘ ì½ìŒ',
'Mark as read' => 'ì½ìŒ',
- // 'Total number of tasks in this column across all swimlanes' => '',
+ 'Total number of tasks in this column across all swimlanes' => '모든 스웜ë¼ì¸ ì¹¼ëŸ¼ì˜ í• ì¼ ìˆ˜',
'Collapse swimlane' => '스웜ë¼ì¸ 붕괴',
'Expand swimlane' => '스웜ë¼ì¸ 확장',
'Add a new filter' => '새로운 필터 추가',
@@ -866,7 +866,7 @@ return array(
'Single Quote' => '따옴표',
'%s attached a file to the task #%d' => '%sê°€ í• ì¼ #%dì— íŒŒì¼ì„ 추가하였습니다',
'There is no column or swimlane activated in your project!' => '프로ì íŠ¸ì— í™œì„±í™”ëœ ì»¬ëŸ¼ì´ë‚˜ 스웜ë¼ì¸ì´ 없습니다',
- // 'Append filter (instead of replacement)' => '',
+ 'Append filter (instead of replacement)' => '필터 (변경 대신)추가',
'Append/Replace' => '추가/변경',
'Append' => '추가',
'Replace' => '변경',
@@ -890,7 +890,7 @@ return array(
'%s attached a new file to the task %s' => '%sì´ ìƒˆë¡œìš´ 파ì¼ì„ í• ì¼ %sì— ì¶”ê°€í–ˆìŠµë‹ˆë‹¤',
'Link type' => 'ë§í¬ 형ì‹',
'Assign automatically a category based on a link' => 'ë§í¬ 기반 ìžë™ 카테고리 할당',
- // 'BAM - Konvertible Mark' => '',
+ 'BAM - Konvertible Mark' => 'BAM - 보스니아 마르카',
'Assignee Username' => '담당ìžì˜ 사용ìžì´ë¦„',
'Assignee Name' => 'ë‹¹ìž¥ìž ì´ë¦„',
'Groups' => '그룹',
@@ -916,7 +916,7 @@ return array(
'Project Member' => '프로ì íŠ¸ 멤버',
'Project Viewer' => '프로ì íŠ¸ ë·°ì–´',
'Your account is locked for %d minutes' => '%d분 ë™ì•ˆ ê³„ì •ì´ ìž ê¹ë‹ˆë‹¤',
- // 'Invalid captcha' => '',
+ 'Invalid captcha' => 'ìž˜ëª»ëœ ë³´ì•ˆ 문ìž',
'The name must be unique' => 'ì´ë¦„ì€ ìœ ì¼í•´ì•¼ 합니다',
'View all groups' => '모든그룹보기',
'There is no user available.' => '가능한 사용ìžê°€ 없습니다',
@@ -950,14 +950,14 @@ return array(
'Estimated Time' => 'ì˜ˆìƒ ì‹œê°„',
'Actual Time' => '실제 시간',
'Estimated vs actual time' => 'ì˜ˆìƒ vs 실제 시간',
- // 'RUB - Russian Ruble' => '',
+ 'RUB - Russian Ruble' => 'RUB - 러시아 루블',
'Assign the task to the person who does the action when the column is changed' => 'ì»¬ëŸ¼ì´ ë³€ê²½ë˜ë©´ 액션하지 않는 사람ì—게 í• ì¼ì„ 할당합니다',
'Close a task in a specific column' => 'ìƒì„¸ ì»¬ëŸ¼ì˜ í• ì¼ì„ 종료합니다',
'Time-based One-time Password Algorithm' => 'ì‹œê°„ì— ê¸°ë°˜í•œ 1회용 패스워드 알고리즘',
'Two-Factor Provider: ' => 'ì´ì¤‘ ì¸ì¦: ',
'Disable two-factor authentication' => 'ì´ì¤‘ ì¸ì¦ 비활성화',
'Enable two-factor authentication' => 'ì´ì¤‘ ì¸ì¦ 활성화',
- // 'There is no integration registered at the moment.' => '',
+ 'There is no integration registered at the moment.' => '현재 등ë¡ëœ í†µí•©ì´ ì—†ìŠµë‹ˆë‹¤.',
'Password Reset for Kanboard' => 'Kanboardì˜ ë¹„ë°€ë²ˆí˜¸ 초기화',
'Forgot password?' => '비밀번호 찾기',
'Enable "Forget Password"' => '"비밀번호 분실" 활성화',
@@ -977,9 +977,9 @@ return array(
'No plugin has registered a project notification method. You can still configure individual notifications in your user profile.' => '프로ì íŠ¸ 알림 방법으로 플러그ì¸ì´ 등ë¡ë˜ì§€ 않았습니다. ê°ê°ì˜ ì•Œë¦¼ì„ í”„ë¡œíŒŒì¼ì—ì„œ 설정하실 수 있습니다',
'My dashboard' => '대시보드',
'My profile' => '프로필',
- 'Project owner: ' => '프로ì íŠ¸ 소유ìž',
+ 'Project owner: ' => '프로ì íŠ¸ 소유ìž:',
'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => '프로ì íŠ¸ 구분ìžëŠ” ì„ íƒì‚¬í•­ì´ë©°, 숫ìžì™€ 문ìžë§Œ 가능합니다. 예: MYPROJECT.',
- // 'Project owner' => '',
+ 'Project owner' => '프로ì íŠ¸ 소유ìž',
'Those dates are useful for the project Gantt chart.' => 'ì´ ë‚ ì§œëŠ” 프로ì íŠ¸ 간트 ì°¨íŠ¸ì— ì‚¬ìš©ë©ë‹ˆë‹¤',
'Private projects do not have users and groups management.' => '비밀 프로ì íŠ¸ëŠ” 사용ìžë‚˜ 관리 ê·¸ë£¹ì´ ì†Œìœ í•˜ì§€ 않습니다',
'There is no project member.' => '프로ì íŠ¸ 맴버가 없습니다',
@@ -995,7 +995,7 @@ return array(
'Duration in days' => '기간',
'Send email when there is no activity on a task' => '활ë™ì´ 없는 í• ì¼ì„ ì´ë©”ì¼ë¡œ 보냅니다',
'Unable to fetch link information.' => 'ë§í¬ ì •ë³´ 가져오기 비활성화',
- // 'Daily background job for tasks' => '',
+ 'Daily background job for tasks' => 'í• ì¼ì˜ ì¼ì¼ ë°°ê²½ ìž‘ì—… ',
'Auto' => 'ìžë™',
'Related' => 'ì—°ê´€ëœ',
'Attachment' => '첨부',
@@ -1010,7 +1010,7 @@ return array(
'Edit external link' => '외부 ë§í¬ 수정',
'External link' => '외부 ë§í¬',
'Copy and paste your link here...' => 'ì—¬ê¸°ì— ë§í¬ë¥¼ 복사/붙여넣기',
- // 'URL' => '',
+ 'URL' => 'ì¸í„°ë„· 주소',
'Internal links' => '내부 ë§í¬',
'Assign to me' => '나ì—게 할당',
'Me' => '나',
@@ -1047,9 +1047,9 @@ return array(
'Do you really want to remove this custom filter: "%s"?' => 'ì •ì˜ í•„í„°ë¥¼ 삭제하시겠습니까: "%s"?',
'Remove a custom filter' => 'ì •ì˜ í•„í„° ì‚­ì œ',
'User activated successfully.' => '사용ìžê°€ 성공ì ìœ¼ë¡œ 활성화ë˜ì—ˆìŠµë‹ˆë‹¤',
- // 'Unable to enable this user.' => '',
+ 'Unable to enable this user.' => 'ì´ ì‚¬ìš©ìžë¥¼ 활성화할 수 없습니다.',
'User disabled successfully.' => '사용ìžê°€ 성공ì ìœ¼ë¡œ 비활성화ë˜ì—ˆìŠµë‹ˆë‹¤',
- // 'Unable to disable this user.' => '',
+ 'Unable to disable this user.' => 'ì´ ì‚¬ìš©ìžë¥¼ 비활성화할 수 없습니다.',
'All files have been uploaded successfully.' => '모든 파ì¼ì´ 성공ì ìœ¼ë¡œ 업로드ë˜ì—ˆìŠµë‹ˆë‹¤',
'View uploaded files' => '업로드 íŒŒì¼ ë³´ê¸°',
'The maximum allowed file size is %sB.' => '업로드 파ì¼ì˜ 최대 í¬ê¸°ëŠ” %sB 입니다',
@@ -1093,7 +1093,7 @@ return array(
'Local File' => '로컬 파ì¼',
'Configuration' => '구성',
'PHP version:' => 'PHP 버전:',
- // 'PHP SAPI:' => '',
+ 'PHP SAPI:' => 'PHP SAPI:',
'OS version:' => 'ìš´ì˜ì²´ì œ 버전:',
'Database version:' => 'ë°ì´í„°ë² ì´ìŠ¤ 버전:',
'Browser:' => '브ë¼ìš°ì €:',
@@ -1140,7 +1140,7 @@ return array(
'Unable to open plugin archive.' => 'í”ŒëŸ¬ê·¸ì¸ ì•„ì¹´ì´ë¸Œë¥¼ 열수 없습니다.',
'There is no file in the plugin archive.' => 'í”ŒëŸ¬ê·¸ì¸ ì•„ì¹´ì´ë¸Œì— 파ì¼ì´ 존재하지 않습니다.',
'Create tasks in bulk' => 'ëŒ€ëŸ‰ì˜ í• ì¼ ë§Œë“¤ê¸°',
- // 'Your Kanboard instance is not configured to install plugins from the user interface.' => '',
+ 'Your Kanboard instance is not configured to install plugins from the user interface.' => '칸보드 ì¸ìŠ¤í„´ìŠ¤ê°€ ì‚¬ìš©ìž ì¸í„°íŽ˜ì´ìŠ¤ì—ì„œ 플러그ì¸ì„ 설치하ë„ë¡ êµ¬ì„±ë˜ì§€ 않았습니다',
'There is no plugin available.' => '사용 가능한 플러그ì¸ì´ 없습니다.',
'Install' => '설치',
'Update' => '갱신',
@@ -1212,70 +1212,79 @@ return array(
'Notifications for %s' => '%sì˜ ì•Œë¦¼',
'Subtasks export' => 'ì„œë¸Œí• ì¼ ë‚´ë³´ë‚´ê¸°',
'Tasks exportation' => 'í• ì¼ ë‚´ë³´ë‚´ê¸°',
- // 'Assign a color when the task is moved to a specific swimlane' => '',
- // 'Assign a priority when the task is moved to a specific swimlane' => '',
- // 'User unlocked successfully.' => '',
- // 'Unable to unlock the user.' => '',
- // 'Move a task to another swimlane' => '',
- // 'Creator Name' => '',
- // 'Time spent and estimated' => '',
- // 'Move position' => '',
- // 'Move task to another position on the board' => '',
- // 'Insert before this task' => '',
- // 'Insert after this task' => '',
- // 'Unlock this user' => '',
- // 'Custom Project Roles' => '',
- // 'Add a new custom role' => '',
- // 'Restrictions for the role "%s"' => '',
- // 'Add a new project restriction' => '',
- // 'Add a new drag and drop restriction' => '',
- // 'Add a new column restriction' => '',
- // 'Edit this role' => '',
- // 'Remove this role' => '',
- // 'There is no restriction for this role.' => '',
- // 'Only moving task between those columns is permitted' => '',
- // 'Close a task in a specific column when not moved during a given period' => '',
- // 'Edit columns' => '',
- // 'The column restriction has been created successfully.' => '',
- // 'Unable to create this column restriction.' => '',
- // 'Column restriction removed successfully.' => '',
- // 'Unable to remove this restriction.' => '',
- // 'Your custom project role has been created successfully.' => '',
- // 'Unable to create custom project role.' => '',
- // 'Your custom project role has been updated successfully.' => '',
- // 'Unable to update custom project role.' => '',
- // 'Custom project role removed successfully.' => '',
- // 'Unable to remove this project role.' => '',
- // 'The project restriction has been created successfully.' => '',
- // 'Unable to create this project restriction.' => '',
- // 'Project restriction removed successfully.' => '',
- // 'You cannot create tasks in this column.' => '',
- // 'Task creation is permitted for this column' => '',
- // 'Closing or opening a task is permitted for this column' => '',
- // 'Task creation is blocked for this column' => '',
- // 'Closing or opening a task is blocked for this column' => '',
- // 'Task creation is not permitted' => '',
- // 'Closing or opening a task is not permitted' => '',
- // 'New drag and drop restriction for the role "%s"' => '',
- // 'People belonging to this role will be able to move tasks only between the source and the destination column.' => '',
- // 'Remove a column restriction' => '',
- // 'Do you really want to remove this column restriction: "%s" to "%s"?' => '',
- // 'New column restriction for the role "%s"' => '',
- // 'Rule' => '',
- // 'Do you really want to remove this column restriction?' => '',
- // 'Custom roles' => '',
- // 'New custom project role' => '',
- // 'Edit custom project role' => '',
- // 'Remove a custom role' => '',
- // 'Do you really want to remove this custom role: "%s"? All people assigned to this role will become project member.' => '',
- // 'There is no custom role for this project.' => '',
- // 'New project restriction for the role "%s"' => '',
- // 'Restriction' => '',
- // 'Remove a project restriction' => '',
- // 'Do you really want to remove this project restriction: "%s"?' => '',
- // 'Duplicate to multiple projects' => '',
- // 'This field is required' => '',
- // 'Moving a task is not permitted' => '',
- // 'This value must be in the range %d to %d' => '',
- // 'You are not allowed to move this task.' => '',
+ 'Assign a color when the task is moved to a specific swimlane' => 'í• ì¼ì´ 특정 스웜ë¼ì¸ìœ¼ë¡œ 옮겨질 ë•Œ ìƒ‰ìƒ ì§€ì •',
+ 'Assign a priority when the task is moved to a specific swimlane' => 'í• ì¼ì´ 특정 스웜ë¼ì¸ìœ¼ë¡œ 옮겨질 ë•Œ 우선순위 지정',
+ 'User unlocked successfully.' => 'ì‚¬ìš©ìž ìž ê¸ˆ 성공',
+ 'Unable to unlock the user.' => 'ì‚¬ìš©ìž í•´ì œ 성공',
+ 'Move a task to another swimlane' => '다른 스웜ë¼ì¸ìœ¼ë¡œ í• ì¼ ì´ë™',
+ 'Creator Name' => 'ìƒì„±ìž ì´ë¦„',
+ 'Time spent and estimated' => '소요시간과 예ìƒì‹œê°„',
+ 'Move position' => 'ì´ë™ 위치',
+ 'Move task to another position on the board' => 'í• ì¼ì„ ë³´ë“œì˜ ë‹¤ë¥¸ 위치로 ì´ë™',
+ 'Insert before this task' => 'ì´ í• ì¼ ì´ì „ì— ì‚½ìž…',
+ 'Insert after this task' => 'ì´ í• ì¼ ì´í›„ì— ì‚½ìž…',
+ 'Unlock this user' => 'ì‚¬ìš©ìž ìž ê¸ˆ',
+ 'Custom Project Roles' => 'ì •ì˜ í”„ë¡œì íŠ¸ 규칙',
+ 'Add a new custom role' => '새로운 ì •ì˜ ê·œì¹™ 추가',
+ 'Restrictions for the role "%s"' => '"%s" ì—­í• ì˜ ì œì•½',
+ 'Add a new project restriction' => '새로운 프로ì íŠ¸ 제약 추가',
+ 'Add a new drag and drop restriction' => '새로운 드래그 앤 드롭 제약 추가',
+ 'Add a new column restriction' => '새로운 칼럼 제약 추가',
+ 'Edit this role' => '역할 수정',
+ 'Remove this role' => '역할 삭제',
+ 'There is no restriction for this role.' => 'ì—­í• ì— ëŒ€í•œ ì œì•½ì´ ì—†ìŠµë‹ˆë‹¤.',
+ 'Only moving task between those columns is permitted' => '칼럼간 ì´ë™ë§Œ 허용ë©ë‹ˆë‹¤.',
+ 'Close a task in a specific column when not moved during a given period' => '특정 기간ë™ì•ˆ ì´ë™í•˜ì§€ ì•Šì€ íŠ¹ì • ì¹¼ëŸ¼ì˜ í• ì¼ ë§ˆì¹˜ê¸°',
+ 'Edit columns' => '칼럼 수정',
+ 'The column restriction has been created successfully.' => '칼럼 ì œì•½ì´ ìƒì„±ë˜ì—ˆìŠµë‹ˆë‹¤.',
+ 'Unable to create this column restriction.' => '칼럼 ì œì•½ì„ ìƒì„±í•  수 없습니다.',
+ 'Column restriction removed successfully.' => '칼럼 ì œì•½ì´ ì‚­ì œë˜ì—ˆìŠµë‹ˆë‹¤.',
+ 'Unable to remove this restriction.' => '칼럼 ì œì•½ì„ ì‚­ì œí•  수 없습니다.',
+ 'Your custom project role has been created successfully.' => 'ì •ì˜ í”„ë¡œì íŠ¸ ì—­í• ì´ ìƒì„±ë˜ì—ˆìŠµë‹ˆë‹¤.',
+ 'Unable to create custom project role.' => 'ì •ì˜ í”„ë¡œì íŠ¸ ì—­í• ì„ ìƒì„±í•  수 없습니다.',
+ 'Your custom project role has been updated successfully.' => 'ì •ì˜ í”„ë¡œì íŠ¸ ì—­í• ì´ ìˆ˜ì •ë˜ì—ˆìŠµë‹ˆë‹¤.',
+ 'Unable to update custom project role.' => 'ì •ì˜ í”„ë¡œì íŠ¸ ì—­í• ì„ ìˆ˜ì •í•  수 없습니다.',
+ 'Custom project role removed successfully.' => 'ì •ì˜ í”„ë¡œì íŠ¸ ì—­í• ì´ ì‚­ì œë˜ì—ˆìŠµë‹ˆë‹¤.',
+ 'Unable to remove this project role.' => 'ì •ì˜ í”„ë¡œì íŠ¸ ì—­í• ì„ ì‚­ì œí•  수 없습니다.',
+ 'The project restriction has been created successfully.' => '프로ì íŠ¸ ì œì•½ì´ ìƒì„±ë˜ì—ˆìŠµë‹ˆë‹¤.',
+ 'Unable to create this project restriction.' => '프로ì íŠ¸ ì œì•½ì„ ìƒì„±í•  수 없습니다.',
+ 'Project restriction removed successfully.' => '프로ì íŠ¸ ì œì•½ì„ ì‚­ì œí•˜ì˜€ìŠµë‹ˆë‹¤.',
+ 'You cannot create tasks in this column.' => 'ì´ ì¹¼ëŸ¼ì˜ í• ì¼ì„ ìƒì„±í•  수 없습니다.',
+ 'Task creation is permitted for this column' => 'ì´ ì¹¼ëŸ¼ì˜ í• ì¼ ìƒì„±ì´ 허가ë˜ì—ˆìŠµë‹ˆë‹¤.',
+ 'Closing or opening a task is permitted for this column' => 'ì´ ì¹¼ëŸ¼ì˜ í• ì¼ ì—´ê¸° í˜¹ì€ ë‹«ê¸°ê°€ 허가ë˜ì—ˆìŠµë‹ˆë‹¤.',
+ 'Task creation is blocked for this column' => 'ì´ ì¹¼ëŸ¼ì˜ í• ì¼ ìƒì„±ì´ 거부ë˜ì—ˆìŠµë‹ˆë‹¤.',
+ 'Closing or opening a task is blocked for this column' => 'ì´ ì¹¼ëŸ¼ì˜ í• ì¼ ì—´ê¸° í˜¹ì€ ë‹«ê¸°ê°€ 거부ë˜ì—ˆìŠµë‹ˆë‹¤.',
+ 'Task creation is not permitted' => 'í• ì¼ ìƒì„±ì´ 거부ë˜ì—ˆìŠµë‹ˆë‹¤.',
+ 'Closing or opening a task is not permitted' => 'í• ì¼ ì—´ê¸° í˜¹ì€ ë‹«ê¸°ê°€ 거부ë˜ì—ˆìŠµë‹ˆë‹¤.',
+ 'New drag and drop restriction for the role "%s"' => '"%s" ì—­í• ì˜ ìƒˆë¡œìš´ 드래그 앤 드롭 제약',
+ 'People belonging to this role will be able to move tasks only between the source and the destination column.' => 'ì´ ì—­í• ì— ì†í•œ 사용ìžëŠ” ì›ë³¸ ë° ëŒ€ìƒ ì¹¼ëŸ¼ 사ì´ì—서만 í• ì¼ì„ ì´ë™í•  수 있습니다',
+ 'Remove a column restriction' => '칼럼 제약 삭제',
+ 'Do you really want to remove this column restriction: "%s" to "%s"?' => '칼럼 ì œì•½ì„ "%s" ì—ì„œ "%s"ë¡œ ì´ë™í•˜ì‹œê² ìŠµë‹ˆê¹Œ?',
+ 'New column restriction for the role "%s"' => '"%s" ì—­í• ì˜ ìƒˆë¡œìš´ 칼럼 제약',
+ 'Rule' => 'ì—­í• ',
+ 'Do you really want to remove this column restriction?' => '칼럼 ì œì•½ì„ ì‚­ì œí•˜ì‹œê² ìŠµë‹ˆê¹Œ?',
+ 'Custom roles' => 'ì •ì˜ ì—­í• ',
+ 'New custom project role' => '새로운 ì •ì˜ í”„ë¡œì íŠ¸ ì—­í• ',
+ 'Edit custom project role' => 'ì •ì˜ í”„ë¡œì íŠ¸ ì—­í•  수정',
+ 'Remove a custom role' => 'ì •ì˜ ì—­í•  ì‚­ì œ',
+ 'Do you really want to remove this custom role: "%s"? All people assigned to this role will become project member.' => '"%s" ì •ì˜ ì—­í• ì„ ì‚­ì œí•˜ì‹œê² ìŠµë‹ˆê¹Œ? ì´ ì—­í• ì— í• ë‹¹ ëœ ëª¨ë“  ì‚¬ëžŒë“¤ì´ í”„ë¡œì íŠ¸ 멤버가ë©ë‹ˆë‹¤.',
+ 'There is no custom role for this project.' => 'ì´ í”„ë¡œì íŠ¸ì—는 ì •ì˜ ì—­í• ì´ ì—†ìŠµë‹ˆë‹¤.',
+ 'New project restriction for the role "%s"' => '"%s" ì—­í• ì˜ ìƒˆë¡œìš´ 프로ì íŠ¸ 제약',
+ 'Restriction' => '제약',
+ 'Remove a project restriction' => '프로ì íŠ¸ 제약 ì‚­ì œ',
+ 'Do you really want to remove this project restriction: "%s"?' => '"%s" 프로ì íŠ¸ ì œì•½ì„ ì‚­ì œí•˜ì‹œê² ìŠµë‹ˆê¹Œ?',
+ 'Duplicate to multiple projects' => 'ë‹¤ìˆ˜ì˜ í”„ë¡œì íŠ¸ 복제',
+ 'This field is required' => 'ì´ í•„ë“œëŠ” 필수 항목입니다.',
+ 'Moving a task is not permitted' => 'í• ì¼ ì´ë™ì´ 거부ë˜ì—ˆìŠµë‹ˆë‹¤.',
+ 'This value must be in the range %d to %d' => 'ê°’ì˜ ë²”ìœ„ëŠ” %d 부터 %d 까지 입니다.',
+ 'You are not allowed to move this task.' => 'ë‹¹ì‹ ì€ í• ì¼ ì´ë™ì´ 거부ë˜ì—ˆìŠµë‹ˆë‹¤.',
+ // 'API User Access' => '',
+ // 'Preview' => '',
+ // 'Write' => '',
+ // 'Write your text in Markdown' => '',
+ // 'New External Task: %s' => '',
+ // 'No personal API access token registered.' => '',
+ // 'Your personal API access token is "%s"' => '',
+ // 'Remove your token' => '',
+ // 'Generate a new token' => '',
);
diff --git a/app/Locale/my_MY/translations.php b/app/Locale/my_MY/translations.php
index 048d8b4b..be335dec 100644
--- a/app/Locale/my_MY/translations.php
+++ b/app/Locale/my_MY/translations.php
@@ -1278,4 +1278,13 @@ return array(
// 'Moving a task is not permitted' => '',
// 'This value must be in the range %d to %d' => '',
// 'You are not allowed to move this task.' => '',
+ // 'API User Access' => '',
+ // 'Preview' => '',
+ // 'Write' => '',
+ // 'Write your text in Markdown' => '',
+ // 'New External Task: %s' => '',
+ // 'No personal API access token registered.' => '',
+ // 'Your personal API access token is "%s"' => '',
+ // 'Remove your token' => '',
+ // 'Generate a new token' => '',
);
diff --git a/app/Locale/nb_NO/translations.php b/app/Locale/nb_NO/translations.php
index 0d2a340d..6b49545c 100644
--- a/app/Locale/nb_NO/translations.php
+++ b/app/Locale/nb_NO/translations.php
@@ -1278,4 +1278,13 @@ return array(
// 'Moving a task is not permitted' => '',
// 'This value must be in the range %d to %d' => '',
// 'You are not allowed to move this task.' => '',
+ // 'API User Access' => '',
+ // 'Preview' => '',
+ // 'Write' => '',
+ // 'Write your text in Markdown' => '',
+ // 'New External Task: %s' => '',
+ // 'No personal API access token registered.' => '',
+ // 'Your personal API access token is "%s"' => '',
+ // 'Remove your token' => '',
+ // 'Generate a new token' => '',
);
diff --git a/app/Locale/nl_NL/translations.php b/app/Locale/nl_NL/translations.php
index e1745c14..44434a4e 100644
--- a/app/Locale/nl_NL/translations.php
+++ b/app/Locale/nl_NL/translations.php
@@ -1278,4 +1278,13 @@ return array(
// 'Moving a task is not permitted' => '',
// 'This value must be in the range %d to %d' => '',
// 'You are not allowed to move this task.' => '',
+ // 'API User Access' => '',
+ // 'Preview' => '',
+ // 'Write' => '',
+ // 'Write your text in Markdown' => '',
+ // 'New External Task: %s' => '',
+ // 'No personal API access token registered.' => '',
+ // 'Your personal API access token is "%s"' => '',
+ // 'Remove your token' => '',
+ // 'Generate a new token' => '',
);
diff --git a/app/Locale/pl_PL/translations.php b/app/Locale/pl_PL/translations.php
index 164abe0c..51c0fef8 100644
--- a/app/Locale/pl_PL/translations.php
+++ b/app/Locale/pl_PL/translations.php
@@ -1278,4 +1278,13 @@ return array(
// 'Moving a task is not permitted' => '',
// 'This value must be in the range %d to %d' => '',
// 'You are not allowed to move this task.' => '',
+ // 'API User Access' => '',
+ // 'Preview' => '',
+ // 'Write' => '',
+ // 'Write your text in Markdown' => '',
+ // 'New External Task: %s' => '',
+ // 'No personal API access token registered.' => '',
+ // 'Your personal API access token is "%s"' => '',
+ // 'Remove your token' => '',
+ // 'Generate a new token' => '',
);
diff --git a/app/Locale/pt_BR/translations.php b/app/Locale/pt_BR/translations.php
index 637de30e..c0fa2387 100644
--- a/app/Locale/pt_BR/translations.php
+++ b/app/Locale/pt_BR/translations.php
@@ -1278,4 +1278,13 @@ return array(
'Moving a task is not permitted' => 'Mover uma tarefa não é permitido',
'This value must be in the range %d to %d' => 'Este valor precisa estar no intervalo %d até %d',
// 'You are not allowed to move this task.' => '',
+ // 'API User Access' => '',
+ // 'Preview' => '',
+ // 'Write' => '',
+ // 'Write your text in Markdown' => '',
+ // 'New External Task: %s' => '',
+ // 'No personal API access token registered.' => '',
+ // 'Your personal API access token is "%s"' => '',
+ // 'Remove your token' => '',
+ // 'Generate a new token' => '',
);
diff --git a/app/Locale/pt_PT/translations.php b/app/Locale/pt_PT/translations.php
index 3b8975d9..47763d30 100644
--- a/app/Locale/pt_PT/translations.php
+++ b/app/Locale/pt_PT/translations.php
@@ -1278,4 +1278,13 @@ return array(
'Moving a task is not permitted' => 'Não é permitido mover uma tarefa',
'This value must be in the range %d to %d' => 'Este valor deve estar entre %d e %d',
'You are not allowed to move this task.' => 'Não lhe é permitido mover esta tarefa.',
+ // 'API User Access' => '',
+ // 'Preview' => '',
+ // 'Write' => '',
+ // 'Write your text in Markdown' => '',
+ // 'New External Task: %s' => '',
+ // 'No personal API access token registered.' => '',
+ // 'Your personal API access token is "%s"' => '',
+ // 'Remove your token' => '',
+ // 'Generate a new token' => '',
);
diff --git a/app/Locale/ru_RU/translations.php b/app/Locale/ru_RU/translations.php
index 1e5c02c2..4d821f6a 100644
--- a/app/Locale/ru_RU/translations.php
+++ b/app/Locale/ru_RU/translations.php
@@ -1278,4 +1278,13 @@ return array(
'Moving a task is not permitted' => 'Перемещение задачи не разрешено',
'This value must be in the range %d to %d' => 'Значение должно находитьÑÑ Ð² диапазоне от %d до %d',
// 'You are not allowed to move this task.' => '',
+ // 'API User Access' => '',
+ // 'Preview' => '',
+ // 'Write' => '',
+ // 'Write your text in Markdown' => '',
+ // 'New External Task: %s' => '',
+ // 'No personal API access token registered.' => '',
+ // 'Your personal API access token is "%s"' => '',
+ // 'Remove your token' => '',
+ // 'Generate a new token' => '',
);
diff --git a/app/Locale/sr_Latn_RS/translations.php b/app/Locale/sr_Latn_RS/translations.php
index 2f061260..470e3390 100644
--- a/app/Locale/sr_Latn_RS/translations.php
+++ b/app/Locale/sr_Latn_RS/translations.php
@@ -1278,4 +1278,13 @@ return array(
// 'Moving a task is not permitted' => '',
// 'This value must be in the range %d to %d' => '',
// 'You are not allowed to move this task.' => '',
+ // 'API User Access' => '',
+ // 'Preview' => '',
+ // 'Write' => '',
+ // 'Write your text in Markdown' => '',
+ // 'New External Task: %s' => '',
+ // 'No personal API access token registered.' => '',
+ // 'Your personal API access token is "%s"' => '',
+ // 'Remove your token' => '',
+ // 'Generate a new token' => '',
);
diff --git a/app/Locale/sv_SE/translations.php b/app/Locale/sv_SE/translations.php
index f32728e7..2ec4fa82 100644
--- a/app/Locale/sv_SE/translations.php
+++ b/app/Locale/sv_SE/translations.php
@@ -1278,4 +1278,13 @@ return array(
// 'Moving a task is not permitted' => '',
// 'This value must be in the range %d to %d' => '',
// 'You are not allowed to move this task.' => '',
+ // 'API User Access' => '',
+ // 'Preview' => '',
+ // 'Write' => '',
+ // 'Write your text in Markdown' => '',
+ // 'New External Task: %s' => '',
+ // 'No personal API access token registered.' => '',
+ // 'Your personal API access token is "%s"' => '',
+ // 'Remove your token' => '',
+ // 'Generate a new token' => '',
);
diff --git a/app/Locale/th_TH/translations.php b/app/Locale/th_TH/translations.php
index 4025714a..5e0912fc 100644
--- a/app/Locale/th_TH/translations.php
+++ b/app/Locale/th_TH/translations.php
@@ -1278,4 +1278,13 @@ return array(
// 'Moving a task is not permitted' => '',
// 'This value must be in the range %d to %d' => '',
// 'You are not allowed to move this task.' => '',
+ // 'API User Access' => '',
+ // 'Preview' => '',
+ // 'Write' => '',
+ // 'Write your text in Markdown' => '',
+ // 'New External Task: %s' => '',
+ // 'No personal API access token registered.' => '',
+ // 'Your personal API access token is "%s"' => '',
+ // 'Remove your token' => '',
+ // 'Generate a new token' => '',
);
diff --git a/app/Locale/tr_TR/translations.php b/app/Locale/tr_TR/translations.php
index 24399891..1a648bbf 100644
--- a/app/Locale/tr_TR/translations.php
+++ b/app/Locale/tr_TR/translations.php
@@ -1278,4 +1278,13 @@ return array(
'Moving a task is not permitted' => 'Görev taşımaya izin verilmemiş',
'This value must be in the range %d to %d' => 'Bu değer şu aralıkta olmalı: "%d" "%d"',
'You are not allowed to move this task.' => 'Bu görevi taşımaya izniniz yok.',
+ // 'API User Access' => '',
+ // 'Preview' => '',
+ // 'Write' => '',
+ // 'Write your text in Markdown' => '',
+ // 'New External Task: %s' => '',
+ // 'No personal API access token registered.' => '',
+ // 'Your personal API access token is "%s"' => '',
+ // 'Remove your token' => '',
+ // 'Generate a new token' => '',
);
diff --git a/app/Locale/zh_CN/translations.php b/app/Locale/zh_CN/translations.php
index e27a8a56..c87adbec 100644
--- a/app/Locale/zh_CN/translations.php
+++ b/app/Locale/zh_CN/translations.php
@@ -1278,4 +1278,13 @@ return array(
'Moving a task is not permitted' => 'ç¦æ­¢ç§»åŠ¨ä»»åŠ¡',
'This value must be in the range %d to %d' => '输入值必须在%d到%d之间',
'You are not allowed to move this task.' => 'ä½ ä¸èƒ½ç§»åŠ¨æ­¤ä»»åŠ¡',
+ // 'API User Access' => '',
+ // 'Preview' => '',
+ // 'Write' => '',
+ // 'Write your text in Markdown' => '',
+ // 'New External Task: %s' => '',
+ // 'No personal API access token registered.' => '',
+ // 'Your personal API access token is "%s"' => '',
+ // 'Remove your token' => '',
+ // 'Generate a new token' => '',
);
diff --git a/app/Model/ProjectPermissionModel.php b/app/Model/ProjectPermissionModel.php
index 25b6a382..dabd406c 100644
--- a/app/Model/ProjectPermissionModel.php
+++ b/app/Model/ProjectPermissionModel.php
@@ -62,17 +62,33 @@ class ProjectPermissionModel extends Base
->withFilter(new ProjectUserRoleProjectFilter($project_id))
->withFilter(new ProjectUserRoleUsernameFilter($input))
->getQuery()
- ->findAllByColumn('username');
+ ->columns(
+ UserModel::TABLE.'.id',
+ UserModel::TABLE.'.username',
+ UserModel::TABLE.'.name',
+ UserModel::TABLE.'.email',
+ UserModel::TABLE.'.avatar_path'
+ )
+ ->findAll();
$groupMembers = $this->projectGroupRoleQuery
->withFilter(new ProjectGroupRoleProjectFilter($project_id))
->withFilter(new ProjectGroupRoleUsernameFilter($input))
->getQuery()
- ->findAllByColumn('username');
+ ->columns(
+ UserModel::TABLE.'.id',
+ UserModel::TABLE.'.username',
+ UserModel::TABLE.'.name',
+ UserModel::TABLE.'.email',
+ UserModel::TABLE.'.avatar_path'
+ )
+ ->findAll();
- $members = array_unique(array_merge($userMembers, $groupMembers));
+ $userMembers = array_column_index_unique($userMembers, 'username');
+ $groupMembers = array_column_index_unique($groupMembers, 'username');
+ $members = array_merge($userMembers, $groupMembers);
- sort($members);
+ ksort($members);
return $members;
}
diff --git a/app/Model/UserMentionModel.php b/app/Model/UserMentionModel.php
deleted file mode 100644
index cdb9949e..00000000
--- a/app/Model/UserMentionModel.php
+++ /dev/null
@@ -1,62 +0,0 @@
-<?php
-
-namespace Kanboard\Model;
-
-use Kanboard\Core\Base;
-use Kanboard\Event\GenericEvent;
-
-/**
- * User Mention
- *
- * @package Kanboard\Model
- * @author Frederic Guillot
- */
-class UserMentionModel extends Base
-{
- /**
- * Get list of mentioned users
- *
- * @access public
- * @param string $content
- * @return array
- */
- public function getMentionedUsers($content)
- {
- $users = array();
-
- if (preg_match_all('/@([^\s]+)/', $content, $matches)) {
- $users = $this->db->table(UserModel::TABLE)
- ->columns('id', 'username', 'name', 'email', 'language')
- ->eq('notifications_enabled', 1)
- ->neq('id', $this->userSession->getId())
- ->in('username', array_unique($matches[1]))
- ->findAll();
- }
-
- return $users;
- }
-
- /**
- * Fire events for user mentions
- *
- * @access public
- * @param string $content
- * @param string $eventName
- * @param GenericEvent $event
- */
- public function fireEvents($content, $eventName, GenericEvent $event)
- {
- if (empty($event['project_id'])) {
- $event['project_id'] = $this->taskFinderModel->getProjectId($event['task_id']);
- }
-
- $users = $this->getMentionedUsers($content);
-
- foreach ($users as $user) {
- if ($this->projectPermissionModel->isMember($event['project_id'], $user['id'])) {
- $event['mention'] = $user;
- $this->dispatcher->dispatch($eventName, $event);
- }
- }
- }
-}
diff --git a/app/Schema/Mysql.php b/app/Schema/Mysql.php
index b50164ca..fac8688a 100644
--- a/app/Schema/Mysql.php
+++ b/app/Schema/Mysql.php
@@ -6,7 +6,17 @@ use PDO;
use Kanboard\Core\Security\Token;
use Kanboard\Core\Security\Role;
-const VERSION = 116;
+const VERSION = 118;
+
+function version_118(PDO $pdo)
+{
+ $pdo->exec('ALTER TABLE `users` ADD COLUMN `api_access_token` VARCHAR(255) DEFAULT NULL');
+}
+
+function version_117(PDO $pdo)
+{
+ $pdo->exec("ALTER TABLE `settings` MODIFY `value` TEXT");
+}
function version_116(PDO $pdo)
{
diff --git a/app/Schema/Postgres.php b/app/Schema/Postgres.php
index 83926f19..32a7a744 100644
--- a/app/Schema/Postgres.php
+++ b/app/Schema/Postgres.php
@@ -6,7 +6,17 @@ use PDO;
use Kanboard\Core\Security\Token;
use Kanboard\Core\Security\Role;
-const VERSION = 95;
+const VERSION = 97;
+
+function version_97(PDO $pdo)
+{
+ $pdo->exec('ALTER TABLE "users" ADD COLUMN api_access_token VARCHAR(255) DEFAULT NULL');
+}
+
+function version_96(PDO $pdo)
+{
+ $pdo->exec('ALTER TABLE "settings" ALTER COLUMN "value" TYPE TEXT');
+}
function version_95(PDO $pdo)
{
diff --git a/app/Schema/Sql/mysql.sql b/app/Schema/Sql/mysql.sql
index 8d494dcf..0ee88d88 100644
--- a/app/Schema/Sql/mysql.sql
+++ b/app/Schema/Sql/mysql.sql
@@ -35,6 +35,44 @@ CREATE TABLE `actions` (
CONSTRAINT `actions_ibfk_1` FOREIGN KEY (`project_id`) REFERENCES `projects` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
+DROP TABLE IF EXISTS `column_has_move_restrictions`;
+/*!40101 SET @saved_cs_client = @@character_set_client */;
+/*!40101 SET character_set_client = utf8 */;
+CREATE TABLE `column_has_move_restrictions` (
+ `restriction_id` int(11) NOT NULL AUTO_INCREMENT,
+ `project_id` int(11) NOT NULL,
+ `role_id` int(11) NOT NULL,
+ `src_column_id` int(11) NOT NULL,
+ `dst_column_id` int(11) NOT NULL,
+ PRIMARY KEY (`restriction_id`),
+ UNIQUE KEY `role_id` (`role_id`,`src_column_id`,`dst_column_id`),
+ KEY `project_id` (`project_id`),
+ KEY `src_column_id` (`src_column_id`),
+ KEY `dst_column_id` (`dst_column_id`),
+ CONSTRAINT `column_has_move_restrictions_ibfk_1` FOREIGN KEY (`project_id`) REFERENCES `projects` (`id`) ON DELETE CASCADE,
+ CONSTRAINT `column_has_move_restrictions_ibfk_2` FOREIGN KEY (`role_id`) REFERENCES `project_has_roles` (`role_id`) ON DELETE CASCADE,
+ CONSTRAINT `column_has_move_restrictions_ibfk_3` FOREIGN KEY (`src_column_id`) REFERENCES `columns` (`id`) ON DELETE CASCADE,
+ CONSTRAINT `column_has_move_restrictions_ibfk_4` FOREIGN KEY (`dst_column_id`) REFERENCES `columns` (`id`) ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+/*!40101 SET character_set_client = @saved_cs_client */;
+DROP TABLE IF EXISTS `column_has_restrictions`;
+/*!40101 SET @saved_cs_client = @@character_set_client */;
+/*!40101 SET character_set_client = utf8 */;
+CREATE TABLE `column_has_restrictions` (
+ `restriction_id` int(11) NOT NULL AUTO_INCREMENT,
+ `project_id` int(11) NOT NULL,
+ `role_id` int(11) NOT NULL,
+ `column_id` int(11) NOT NULL,
+ `rule` varchar(255) NOT NULL,
+ PRIMARY KEY (`restriction_id`),
+ UNIQUE KEY `role_id` (`role_id`,`column_id`,`rule`),
+ KEY `project_id` (`project_id`),
+ KEY `column_id` (`column_id`),
+ CONSTRAINT `column_has_restrictions_ibfk_1` FOREIGN KEY (`project_id`) REFERENCES `projects` (`id`) ON DELETE CASCADE,
+ CONSTRAINT `column_has_restrictions_ibfk_2` FOREIGN KEY (`role_id`) REFERENCES `project_has_roles` (`role_id`) ON DELETE CASCADE,
+ CONSTRAINT `column_has_restrictions_ibfk_3` FOREIGN KEY (`column_id`) REFERENCES `columns` (`id`) ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `columns`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
@@ -260,7 +298,7 @@ DROP TABLE IF EXISTS `project_has_groups`;
CREATE TABLE `project_has_groups` (
`group_id` int(11) NOT NULL,
`project_id` int(11) NOT NULL,
- `role` varchar(25) NOT NULL,
+ `role` varchar(255) NOT NULL,
UNIQUE KEY `group_id` (`group_id`,`project_id`),
KEY `project_id` (`project_id`),
CONSTRAINT `project_has_groups_ibfk_1` FOREIGN KEY (`group_id`) REFERENCES `groups` (`id`) ON DELETE CASCADE,
@@ -292,19 +330,46 @@ CREATE TABLE `project_has_notification_types` (
CONSTRAINT `project_has_notification_types_ibfk_1` FOREIGN KEY (`project_id`) REFERENCES `projects` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
+DROP TABLE IF EXISTS `project_has_roles`;
+/*!40101 SET @saved_cs_client = @@character_set_client */;
+/*!40101 SET character_set_client = utf8 */;
+CREATE TABLE `project_has_roles` (
+ `role_id` int(11) NOT NULL AUTO_INCREMENT,
+ `role` varchar(255) NOT NULL,
+ `project_id` int(11) NOT NULL,
+ PRIMARY KEY (`role_id`),
+ UNIQUE KEY `project_id` (`project_id`,`role`),
+ CONSTRAINT `project_has_roles_ibfk_1` FOREIGN KEY (`project_id`) REFERENCES `projects` (`id`) ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `project_has_users`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `project_has_users` (
`project_id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
- `role` varchar(25) NOT NULL DEFAULT 'project-viewer',
+ `role` varchar(255) NOT NULL,
UNIQUE KEY `idx_project_user` (`project_id`,`user_id`),
KEY `user_id` (`user_id`),
CONSTRAINT `project_has_users_ibfk_1` FOREIGN KEY (`project_id`) REFERENCES `projects` (`id`) ON DELETE CASCADE,
CONSTRAINT `project_has_users_ibfk_2` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
+DROP TABLE IF EXISTS `project_role_has_restrictions`;
+/*!40101 SET @saved_cs_client = @@character_set_client */;
+/*!40101 SET character_set_client = utf8 */;
+CREATE TABLE `project_role_has_restrictions` (
+ `restriction_id` int(11) NOT NULL AUTO_INCREMENT,
+ `project_id` int(11) NOT NULL,
+ `role_id` int(11) NOT NULL,
+ `rule` varchar(255) NOT NULL,
+ PRIMARY KEY (`restriction_id`),
+ UNIQUE KEY `role_id` (`role_id`,`rule`),
+ KEY `project_id` (`project_id`),
+ CONSTRAINT `project_role_has_restrictions_ibfk_1` FOREIGN KEY (`project_id`) REFERENCES `projects` (`id`) ON DELETE CASCADE,
+ CONSTRAINT `project_role_has_restrictions_ibfk_2` FOREIGN KEY (`role_id`) REFERENCES `project_has_roles` (`role_id`) ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `projects`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
@@ -359,7 +424,7 @@ DROP TABLE IF EXISTS `settings`;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `settings` (
`option` varchar(100) NOT NULL,
- `value` varchar(255) DEFAULT '',
+ `value` text,
`changed_by` int(11) NOT NULL DEFAULT '0',
`changed_on` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`option`)
@@ -537,6 +602,8 @@ CREATE TABLE `tasks` (
`recurrence_parent` int(11) DEFAULT NULL,
`recurrence_child` int(11) DEFAULT NULL,
`priority` int(11) DEFAULT '0',
+ `external_provider` varchar(255) DEFAULT NULL,
+ `external_uri` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_task_active` (`is_active`),
KEY `column_id` (`column_id`),
@@ -648,6 +715,7 @@ CREATE TABLE `users` (
`role` varchar(25) NOT NULL DEFAULT 'app-user',
`is_active` tinyint(1) DEFAULT '1',
`avatar_path` varchar(255) DEFAULT NULL,
+ `api_access_token` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `users_username_idx` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
@@ -671,7 +739,7 @@ CREATE TABLE `users` (
LOCK TABLES `settings` WRITE;
/*!40000 ALTER TABLE `settings` DISABLE KEYS */;
-INSERT INTO `settings` VALUES ('api_token','4064ef3d26efa9a0ff78fa7067d8bb9d99323455128edd89e9dc7c53ed76',0,0),('application_currency','USD',0,0),('application_date_format','m/d/Y',0,0),('application_language','en_US',0,0),('application_stylesheet','',0,0),('application_timezone','UTC',0,0),('application_url','',0,0),('board_columns','',0,0),('board_highlight_period','172800',0,0),('board_private_refresh_interval','10',0,0),('board_public_refresh_interval','60',0,0),('calendar_project_tasks','date_started',0,0),('calendar_user_subtasks_time_tracking','0',0,0),('calendar_user_tasks','date_started',0,0),('cfd_include_closed_tasks','1',0,0),('default_color','yellow',0,0),('integration_gravatar','0',0,0),('password_reset','1',0,0),('project_categories','',0,0),('subtask_restriction','0',0,0),('subtask_time_tracking','1',0,0),('webhook_token','c8f53c0bcd8aead902ad04f180ffafd7889b9c0062c2d510e2297ef543b8',0,0),('webhook_url','',0,0);
+INSERT INTO `settings` VALUES ('api_token','f149956cb60c88d01123a28964fc035b1ce4513be454f2a85fe6b4ca3758',0,0),('application_currency','USD',0,0),('application_date_format','m/d/Y',0,0),('application_language','en_US',0,0),('application_stylesheet','',0,0),('application_timezone','UTC',0,0),('application_url','',0,0),('board_columns','',0,0),('board_highlight_period','172800',0,0),('board_private_refresh_interval','10',0,0),('board_public_refresh_interval','60',0,0),('calendar_project_tasks','date_started',0,0),('calendar_user_subtasks_time_tracking','0',0,0),('calendar_user_tasks','date_started',0,0),('cfd_include_closed_tasks','1',0,0),('default_color','yellow',0,0),('integration_gravatar','0',0,0),('password_reset','1',0,0),('project_categories','',0,0),('subtask_restriction','0',0,0),('subtask_time_tracking','1',0,0),('webhook_token','47d1d896b6612234c7543eb3f3a09a0a669f77a079d13ad3d810ccb79896',0,0),('webhook_url','',0,0);
/*!40000 ALTER TABLE `settings` ENABLE KEYS */;
UNLOCK TABLES;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
@@ -700,4 +768,4 @@ UNLOCK TABLES;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
-INSERT INTO users (username, password, role) VALUES ('admin', '$2y$10$yUJ9QnhG.f47yO.YvWKo3eMAHULukpluDNTOF9.Z7QQg0vOfFRB6u', 'app-admin');INSERT INTO schema_version VALUES ('112');
+INSERT INTO users (username, password, role) VALUES ('admin', '$2y$10$R1zYk04d96KcHRpd9.r5I.5I6mgKIgUdsaISZYmaDLPIJCUO0FFJG', 'app-admin');INSERT INTO schema_version VALUES ('118');
diff --git a/app/Schema/Sql/postgres.sql b/app/Schema/Sql/postgres.sql
index 0add9c91..578b0c75 100644
--- a/app/Schema/Sql/postgres.sql
+++ b/app/Schema/Sql/postgres.sql
@@ -2,8 +2,8 @@
-- PostgreSQL database dump
--
--- Dumped from database version 9.5.2
--- Dumped by pg_dump version 9.5.2
+-- Dumped from database version 9.6.1
+-- Dumped by pg_dump version 9.6.1
SET statement_timeout = 0;
SET lock_timeout = 0;
@@ -89,6 +89,70 @@ ALTER SEQUENCE "actions_id_seq" OWNED BY "actions"."id";
--
+-- Name: column_has_move_restrictions; Type: TABLE; Schema: public; Owner: -
+--
+
+CREATE TABLE "column_has_move_restrictions" (
+ "restriction_id" integer NOT NULL,
+ "project_id" integer NOT NULL,
+ "role_id" integer NOT NULL,
+ "src_column_id" integer NOT NULL,
+ "dst_column_id" integer NOT NULL
+);
+
+
+--
+-- Name: column_has_move_restrictions_restriction_id_seq; Type: SEQUENCE; Schema: public; Owner: -
+--
+
+CREATE SEQUENCE "column_has_move_restrictions_restriction_id_seq"
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1;
+
+
+--
+-- Name: column_has_move_restrictions_restriction_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
+--
+
+ALTER SEQUENCE "column_has_move_restrictions_restriction_id_seq" OWNED BY "column_has_move_restrictions"."restriction_id";
+
+
+--
+-- Name: column_has_restrictions; Type: TABLE; Schema: public; Owner: -
+--
+
+CREATE TABLE "column_has_restrictions" (
+ "restriction_id" integer NOT NULL,
+ "project_id" integer NOT NULL,
+ "role_id" integer NOT NULL,
+ "column_id" integer NOT NULL,
+ "rule" character varying(255) NOT NULL
+);
+
+
+--
+-- Name: column_has_restrictions_restriction_id_seq; Type: SEQUENCE; Schema: public; Owner: -
+--
+
+CREATE SEQUENCE "column_has_restrictions_restriction_id_seq"
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1;
+
+
+--
+-- Name: column_has_restrictions_restriction_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
+--
+
+ALTER SEQUENCE "column_has_restrictions_restriction_id_seq" OWNED BY "column_has_restrictions"."restriction_id";
+
+
+--
-- Name: columns; Type: TABLE; Schema: public; Owner: -
--
@@ -499,7 +563,7 @@ ALTER SEQUENCE "project_has_files_id_seq" OWNED BY "project_has_files"."id";
CREATE TABLE "project_has_groups" (
"group_id" integer NOT NULL,
"project_id" integer NOT NULL,
- "role" character varying(25) NOT NULL
+ "role" character varying(255) NOT NULL
);
@@ -547,17 +611,78 @@ ALTER SEQUENCE "project_has_notification_types_id_seq" OWNED BY "project_has_not
--
+-- Name: project_has_roles; Type: TABLE; Schema: public; Owner: -
+--
+
+CREATE TABLE "project_has_roles" (
+ "role_id" integer NOT NULL,
+ "role" character varying(255) NOT NULL,
+ "project_id" integer NOT NULL
+);
+
+
+--
+-- Name: project_has_roles_role_id_seq; Type: SEQUENCE; Schema: public; Owner: -
+--
+
+CREATE SEQUENCE "project_has_roles_role_id_seq"
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1;
+
+
+--
+-- Name: project_has_roles_role_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
+--
+
+ALTER SEQUENCE "project_has_roles_role_id_seq" OWNED BY "project_has_roles"."role_id";
+
+
+--
-- Name: project_has_users; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE "project_has_users" (
"project_id" integer NOT NULL,
"user_id" integer NOT NULL,
- "role" character varying(25) DEFAULT 'project-viewer'::character varying NOT NULL
+ "role" character varying(255) DEFAULT 'project-viewer'::character varying NOT NULL
+);
+
+
+--
+-- Name: project_role_has_restrictions; Type: TABLE; Schema: public; Owner: -
+--
+
+CREATE TABLE "project_role_has_restrictions" (
+ "restriction_id" integer NOT NULL,
+ "project_id" integer NOT NULL,
+ "role_id" integer NOT NULL,
+ "rule" character varying(255) NOT NULL
);
--
+-- Name: project_role_has_restrictions_restriction_id_seq; Type: SEQUENCE; Schema: public; Owner: -
+--
+
+CREATE SEQUENCE "project_role_has_restrictions_restriction_id_seq"
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1;
+
+
+--
+-- Name: project_role_has_restrictions_restriction_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
+--
+
+ALTER SEQUENCE "project_role_has_restrictions_restriction_id_seq" OWNED BY "project_role_has_restrictions"."restriction_id";
+
+
+--
-- Name: projects; Type: TABLE; Schema: public; Owner: -
--
@@ -652,7 +777,7 @@ CREATE TABLE "schema_version" (
CREATE TABLE "settings" (
"option" character varying(100) NOT NULL,
- "value" character varying(255) DEFAULT ''::character varying,
+ "value" "text" DEFAULT ''::character varying,
"changed_by" integer DEFAULT 0 NOT NULL,
"changed_on" integer DEFAULT 0 NOT NULL
);
@@ -948,7 +1073,9 @@ CREATE TABLE "tasks" (
"recurrence_basedate" integer DEFAULT 0 NOT NULL,
"recurrence_parent" integer,
"recurrence_child" integer,
- "priority" integer DEFAULT 0
+ "priority" integer DEFAULT 0,
+ "external_provider" character varying(255),
+ "external_uri" character varying(255)
);
@@ -1117,7 +1244,8 @@ CREATE TABLE "users" (
"gitlab_id" integer,
"role" character varying(25) DEFAULT 'app-user'::character varying NOT NULL,
"is_active" boolean DEFAULT true,
- "avatar_path" character varying(255)
+ "avatar_path" character varying(255),
+ "api_access_token" character varying(255) DEFAULT NULL::character varying
);
@@ -1141,203 +1269,231 @@ ALTER SEQUENCE "users_id_seq" OWNED BY "users"."id";
--
--- Name: id; Type: DEFAULT; Schema: public; Owner: -
+-- Name: action_has_params id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY "action_has_params" ALTER COLUMN "id" SET DEFAULT "nextval"('"action_has_params_id_seq"'::"regclass");
--
--- Name: id; Type: DEFAULT; Schema: public; Owner: -
+-- Name: actions id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY "actions" ALTER COLUMN "id" SET DEFAULT "nextval"('"actions_id_seq"'::"regclass");
--
--- Name: id; Type: DEFAULT; Schema: public; Owner: -
+-- Name: column_has_move_restrictions restriction_id; Type: DEFAULT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY "column_has_move_restrictions" ALTER COLUMN "restriction_id" SET DEFAULT "nextval"('"column_has_move_restrictions_restriction_id_seq"'::"regclass");
+
+
+--
+-- Name: column_has_restrictions restriction_id; Type: DEFAULT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY "column_has_restrictions" ALTER COLUMN "restriction_id" SET DEFAULT "nextval"('"column_has_restrictions_restriction_id_seq"'::"regclass");
+
+
+--
+-- Name: columns id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY "columns" ALTER COLUMN "id" SET DEFAULT "nextval"('"columns_id_seq"'::"regclass");
--
--- Name: id; Type: DEFAULT; Schema: public; Owner: -
+-- Name: comments id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY "comments" ALTER COLUMN "id" SET DEFAULT "nextval"('"comments_id_seq"'::"regclass");
--
--- Name: id; Type: DEFAULT; Schema: public; Owner: -
+-- Name: custom_filters id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY "custom_filters" ALTER COLUMN "id" SET DEFAULT "nextval"('"custom_filters_id_seq"'::"regclass");
--
--- Name: id; Type: DEFAULT; Schema: public; Owner: -
+-- Name: groups id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY "groups" ALTER COLUMN "id" SET DEFAULT "nextval"('"groups_id_seq"'::"regclass");
--
--- Name: id; Type: DEFAULT; Schema: public; Owner: -
+-- Name: last_logins id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY "last_logins" ALTER COLUMN "id" SET DEFAULT "nextval"('"last_logins_id_seq"'::"regclass");
--
--- Name: id; Type: DEFAULT; Schema: public; Owner: -
+-- Name: links id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY "links" ALTER COLUMN "id" SET DEFAULT "nextval"('"links_id_seq"'::"regclass");
--
--- Name: id; Type: DEFAULT; Schema: public; Owner: -
+-- Name: project_activities id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY "project_activities" ALTER COLUMN "id" SET DEFAULT "nextval"('"project_activities_id_seq"'::"regclass");
--
--- Name: id; Type: DEFAULT; Schema: public; Owner: -
+-- Name: project_daily_column_stats id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY "project_daily_column_stats" ALTER COLUMN "id" SET DEFAULT "nextval"('"project_daily_summaries_id_seq"'::"regclass");
--
--- Name: id; Type: DEFAULT; Schema: public; Owner: -
+-- Name: project_daily_stats id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY "project_daily_stats" ALTER COLUMN "id" SET DEFAULT "nextval"('"project_daily_stats_id_seq"'::"regclass");
--
--- Name: id; Type: DEFAULT; Schema: public; Owner: -
+-- Name: project_has_categories id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY "project_has_categories" ALTER COLUMN "id" SET DEFAULT "nextval"('"project_has_categories_id_seq"'::"regclass");
--
--- Name: id; Type: DEFAULT; Schema: public; Owner: -
+-- Name: project_has_files id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY "project_has_files" ALTER COLUMN "id" SET DEFAULT "nextval"('"project_has_files_id_seq"'::"regclass");
--
--- Name: id; Type: DEFAULT; Schema: public; Owner: -
+-- Name: project_has_notification_types id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY "project_has_notification_types" ALTER COLUMN "id" SET DEFAULT "nextval"('"project_has_notification_types_id_seq"'::"regclass");
--
--- Name: id; Type: DEFAULT; Schema: public; Owner: -
+-- Name: project_has_roles role_id; Type: DEFAULT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY "project_has_roles" ALTER COLUMN "role_id" SET DEFAULT "nextval"('"project_has_roles_role_id_seq"'::"regclass");
+
+
+--
+-- Name: project_role_has_restrictions restriction_id; Type: DEFAULT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY "project_role_has_restrictions" ALTER COLUMN "restriction_id" SET DEFAULT "nextval"('"project_role_has_restrictions_restriction_id_seq"'::"regclass");
+
+
+--
+-- Name: projects id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY "projects" ALTER COLUMN "id" SET DEFAULT "nextval"('"projects_id_seq"'::"regclass");
--
--- Name: id; Type: DEFAULT; Schema: public; Owner: -
+-- Name: remember_me id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY "remember_me" ALTER COLUMN "id" SET DEFAULT "nextval"('"remember_me_id_seq"'::"regclass");
--
--- Name: id; Type: DEFAULT; Schema: public; Owner: -
+-- Name: subtask_time_tracking id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY "subtask_time_tracking" ALTER COLUMN "id" SET DEFAULT "nextval"('"subtask_time_tracking_id_seq"'::"regclass");
--
--- Name: id; Type: DEFAULT; Schema: public; Owner: -
+-- Name: subtasks id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY "subtasks" ALTER COLUMN "id" SET DEFAULT "nextval"('"task_has_subtasks_id_seq"'::"regclass");
--
--- Name: id; Type: DEFAULT; Schema: public; Owner: -
+-- Name: swimlanes id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY "swimlanes" ALTER COLUMN "id" SET DEFAULT "nextval"('"swimlanes_id_seq"'::"regclass");
--
--- Name: id; Type: DEFAULT; Schema: public; Owner: -
+-- Name: tags id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY "tags" ALTER COLUMN "id" SET DEFAULT "nextval"('"tags_id_seq"'::"regclass");
--
--- Name: id; Type: DEFAULT; Schema: public; Owner: -
+-- Name: task_has_external_links id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY "task_has_external_links" ALTER COLUMN "id" SET DEFAULT "nextval"('"task_has_external_links_id_seq"'::"regclass");
--
--- Name: id; Type: DEFAULT; Schema: public; Owner: -
+-- Name: task_has_files id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY "task_has_files" ALTER COLUMN "id" SET DEFAULT "nextval"('"task_has_files_id_seq"'::"regclass");
--
--- Name: id; Type: DEFAULT; Schema: public; Owner: -
+-- Name: task_has_links id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY "task_has_links" ALTER COLUMN "id" SET DEFAULT "nextval"('"task_has_links_id_seq"'::"regclass");
--
--- Name: id; Type: DEFAULT; Schema: public; Owner: -
+-- Name: tasks id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY "tasks" ALTER COLUMN "id" SET DEFAULT "nextval"('"tasks_id_seq"'::"regclass");
--
--- Name: id; Type: DEFAULT; Schema: public; Owner: -
+-- Name: transitions id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY "transitions" ALTER COLUMN "id" SET DEFAULT "nextval"('"transitions_id_seq"'::"regclass");
--
--- Name: id; Type: DEFAULT; Schema: public; Owner: -
+-- Name: user_has_notification_types id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY "user_has_notification_types" ALTER COLUMN "id" SET DEFAULT "nextval"('"user_has_notification_types_id_seq"'::"regclass");
--
--- Name: id; Type: DEFAULT; Schema: public; Owner: -
+-- Name: user_has_unread_notifications id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY "user_has_unread_notifications" ALTER COLUMN "id" SET DEFAULT "nextval"('"user_has_unread_notifications_id_seq"'::"regclass");
--
--- Name: id; Type: DEFAULT; Schema: public; Owner: -
+-- Name: users id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY "users" ALTER COLUMN "id" SET DEFAULT "nextval"('"users_id_seq"'::"regclass");
--
--- Name: action_has_params_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+-- Name: action_has_params action_has_params_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "action_has_params"
@@ -1345,7 +1501,7 @@ ALTER TABLE ONLY "action_has_params"
--
--- Name: actions_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+-- Name: actions actions_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "actions"
@@ -1353,7 +1509,39 @@ ALTER TABLE ONLY "actions"
--
--- Name: columns_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+-- Name: column_has_move_restrictions column_has_move_restrictions_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY "column_has_move_restrictions"
+ ADD CONSTRAINT "column_has_move_restrictions_pkey" PRIMARY KEY ("restriction_id");
+
+
+--
+-- Name: column_has_move_restrictions column_has_move_restrictions_role_id_src_column_id_dst_colu_key; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY "column_has_move_restrictions"
+ ADD CONSTRAINT "column_has_move_restrictions_role_id_src_column_id_dst_colu_key" UNIQUE ("role_id", "src_column_id", "dst_column_id");
+
+
+--
+-- Name: column_has_restrictions column_has_restrictions_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY "column_has_restrictions"
+ ADD CONSTRAINT "column_has_restrictions_pkey" PRIMARY KEY ("restriction_id");
+
+
+--
+-- Name: column_has_restrictions column_has_restrictions_role_id_column_id_rule_key; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY "column_has_restrictions"
+ ADD CONSTRAINT "column_has_restrictions_role_id_column_id_rule_key" UNIQUE ("role_id", "column_id", "rule");
+
+
+--
+-- Name: columns columns_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "columns"
@@ -1361,7 +1549,7 @@ ALTER TABLE ONLY "columns"
--
--- Name: columns_title_project_id_key; Type: CONSTRAINT; Schema: public; Owner: -
+-- Name: columns columns_title_project_id_key; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "columns"
@@ -1369,7 +1557,7 @@ ALTER TABLE ONLY "columns"
--
--- Name: comments_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+-- Name: comments comments_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "comments"
@@ -1377,7 +1565,7 @@ ALTER TABLE ONLY "comments"
--
--- Name: currencies_currency_key; Type: CONSTRAINT; Schema: public; Owner: -
+-- Name: currencies currencies_currency_key; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "currencies"
@@ -1385,7 +1573,7 @@ ALTER TABLE ONLY "currencies"
--
--- Name: custom_filters_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+-- Name: custom_filters custom_filters_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "custom_filters"
@@ -1393,7 +1581,7 @@ ALTER TABLE ONLY "custom_filters"
--
--- Name: group_has_users_group_id_user_id_key; Type: CONSTRAINT; Schema: public; Owner: -
+-- Name: group_has_users group_has_users_group_id_user_id_key; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "group_has_users"
@@ -1401,7 +1589,7 @@ ALTER TABLE ONLY "group_has_users"
--
--- Name: groups_name_key; Type: CONSTRAINT; Schema: public; Owner: -
+-- Name: groups groups_name_key; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "groups"
@@ -1409,7 +1597,7 @@ ALTER TABLE ONLY "groups"
--
--- Name: groups_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+-- Name: groups groups_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "groups"
@@ -1417,7 +1605,7 @@ ALTER TABLE ONLY "groups"
--
--- Name: last_logins_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+-- Name: last_logins last_logins_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "last_logins"
@@ -1425,7 +1613,7 @@ ALTER TABLE ONLY "last_logins"
--
--- Name: links_label_key; Type: CONSTRAINT; Schema: public; Owner: -
+-- Name: links links_label_key; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "links"
@@ -1433,7 +1621,7 @@ ALTER TABLE ONLY "links"
--
--- Name: links_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+-- Name: links links_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "links"
@@ -1441,7 +1629,7 @@ ALTER TABLE ONLY "links"
--
--- Name: password_reset_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+-- Name: password_reset password_reset_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "password_reset"
@@ -1449,7 +1637,7 @@ ALTER TABLE ONLY "password_reset"
--
--- Name: plugin_schema_versions_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+-- Name: plugin_schema_versions plugin_schema_versions_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "plugin_schema_versions"
@@ -1457,7 +1645,7 @@ ALTER TABLE ONLY "plugin_schema_versions"
--
--- Name: project_activities_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+-- Name: project_activities project_activities_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "project_activities"
@@ -1465,7 +1653,7 @@ ALTER TABLE ONLY "project_activities"
--
--- Name: project_daily_stats_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+-- Name: project_daily_stats project_daily_stats_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "project_daily_stats"
@@ -1473,7 +1661,7 @@ ALTER TABLE ONLY "project_daily_stats"
--
--- Name: project_daily_summaries_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+-- Name: project_daily_column_stats project_daily_summaries_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "project_daily_column_stats"
@@ -1481,7 +1669,7 @@ ALTER TABLE ONLY "project_daily_column_stats"
--
--- Name: project_has_categories_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+-- Name: project_has_categories project_has_categories_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "project_has_categories"
@@ -1489,7 +1677,7 @@ ALTER TABLE ONLY "project_has_categories"
--
--- Name: project_has_categories_project_id_name_key; Type: CONSTRAINT; Schema: public; Owner: -
+-- Name: project_has_categories project_has_categories_project_id_name_key; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "project_has_categories"
@@ -1497,7 +1685,7 @@ ALTER TABLE ONLY "project_has_categories"
--
--- Name: project_has_files_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+-- Name: project_has_files project_has_files_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "project_has_files"
@@ -1505,7 +1693,7 @@ ALTER TABLE ONLY "project_has_files"
--
--- Name: project_has_groups_group_id_project_id_key; Type: CONSTRAINT; Schema: public; Owner: -
+-- Name: project_has_groups project_has_groups_group_id_project_id_key; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "project_has_groups"
@@ -1513,7 +1701,7 @@ ALTER TABLE ONLY "project_has_groups"
--
--- Name: project_has_metadata_project_id_name_key; Type: CONSTRAINT; Schema: public; Owner: -
+-- Name: project_has_metadata project_has_metadata_project_id_name_key; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "project_has_metadata"
@@ -1521,7 +1709,7 @@ ALTER TABLE ONLY "project_has_metadata"
--
--- Name: project_has_notification_types_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+-- Name: project_has_notification_types project_has_notification_types_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "project_has_notification_types"
@@ -1529,7 +1717,7 @@ ALTER TABLE ONLY "project_has_notification_types"
--
--- Name: project_has_notification_types_project_id_notification_type_key; Type: CONSTRAINT; Schema: public; Owner: -
+-- Name: project_has_notification_types project_has_notification_types_project_id_notification_type_key; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "project_has_notification_types"
@@ -1537,7 +1725,23 @@ ALTER TABLE ONLY "project_has_notification_types"
--
--- Name: project_has_users_project_id_user_id_key; Type: CONSTRAINT; Schema: public; Owner: -
+-- Name: project_has_roles project_has_roles_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY "project_has_roles"
+ ADD CONSTRAINT "project_has_roles_pkey" PRIMARY KEY ("role_id");
+
+
+--
+-- Name: project_has_roles project_has_roles_project_id_role_key; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY "project_has_roles"
+ ADD CONSTRAINT "project_has_roles_project_id_role_key" UNIQUE ("project_id", "role");
+
+
+--
+-- Name: project_has_users project_has_users_project_id_user_id_key; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "project_has_users"
@@ -1545,7 +1749,23 @@ ALTER TABLE ONLY "project_has_users"
--
--- Name: projects_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+-- Name: project_role_has_restrictions project_role_has_restrictions_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY "project_role_has_restrictions"
+ ADD CONSTRAINT "project_role_has_restrictions_pkey" PRIMARY KEY ("restriction_id");
+
+
+--
+-- Name: project_role_has_restrictions project_role_has_restrictions_role_id_rule_key; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY "project_role_has_restrictions"
+ ADD CONSTRAINT "project_role_has_restrictions_role_id_rule_key" UNIQUE ("role_id", "rule");
+
+
+--
+-- Name: projects projects_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "projects"
@@ -1553,7 +1773,7 @@ ALTER TABLE ONLY "projects"
--
--- Name: remember_me_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+-- Name: remember_me remember_me_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "remember_me"
@@ -1561,7 +1781,7 @@ ALTER TABLE ONLY "remember_me"
--
--- Name: settings_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+-- Name: settings settings_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "settings"
@@ -1569,7 +1789,7 @@ ALTER TABLE ONLY "settings"
--
--- Name: subtask_time_tracking_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+-- Name: subtask_time_tracking subtask_time_tracking_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "subtask_time_tracking"
@@ -1577,7 +1797,7 @@ ALTER TABLE ONLY "subtask_time_tracking"
--
--- Name: swimlanes_name_project_id_key; Type: CONSTRAINT; Schema: public; Owner: -
+-- Name: swimlanes swimlanes_name_project_id_key; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "swimlanes"
@@ -1585,7 +1805,7 @@ ALTER TABLE ONLY "swimlanes"
--
--- Name: swimlanes_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+-- Name: swimlanes swimlanes_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "swimlanes"
@@ -1593,7 +1813,7 @@ ALTER TABLE ONLY "swimlanes"
--
--- Name: tags_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+-- Name: tags tags_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "tags"
@@ -1601,7 +1821,7 @@ ALTER TABLE ONLY "tags"
--
--- Name: tags_project_id_name_key; Type: CONSTRAINT; Schema: public; Owner: -
+-- Name: tags tags_project_id_name_key; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "tags"
@@ -1609,7 +1829,7 @@ ALTER TABLE ONLY "tags"
--
--- Name: task_has_external_links_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+-- Name: task_has_external_links task_has_external_links_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "task_has_external_links"
@@ -1617,7 +1837,7 @@ ALTER TABLE ONLY "task_has_external_links"
--
--- Name: task_has_files_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+-- Name: task_has_files task_has_files_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "task_has_files"
@@ -1625,7 +1845,7 @@ ALTER TABLE ONLY "task_has_files"
--
--- Name: task_has_links_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+-- Name: task_has_links task_has_links_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "task_has_links"
@@ -1633,7 +1853,7 @@ ALTER TABLE ONLY "task_has_links"
--
--- Name: task_has_metadata_task_id_name_key; Type: CONSTRAINT; Schema: public; Owner: -
+-- Name: task_has_metadata task_has_metadata_task_id_name_key; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "task_has_metadata"
@@ -1641,7 +1861,7 @@ ALTER TABLE ONLY "task_has_metadata"
--
--- Name: task_has_subtasks_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+-- Name: subtasks task_has_subtasks_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "subtasks"
@@ -1649,7 +1869,7 @@ ALTER TABLE ONLY "subtasks"
--
--- Name: task_has_tags_tag_id_task_id_key; Type: CONSTRAINT; Schema: public; Owner: -
+-- Name: task_has_tags task_has_tags_tag_id_task_id_key; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "task_has_tags"
@@ -1657,7 +1877,7 @@ ALTER TABLE ONLY "task_has_tags"
--
--- Name: tasks_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+-- Name: tasks tasks_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "tasks"
@@ -1665,7 +1885,7 @@ ALTER TABLE ONLY "tasks"
--
--- Name: transitions_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+-- Name: transitions transitions_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "transitions"
@@ -1673,7 +1893,7 @@ ALTER TABLE ONLY "transitions"
--
--- Name: user_has_metadata_user_id_name_key; Type: CONSTRAINT; Schema: public; Owner: -
+-- Name: user_has_metadata user_has_metadata_user_id_name_key; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "user_has_metadata"
@@ -1681,7 +1901,7 @@ ALTER TABLE ONLY "user_has_metadata"
--
--- Name: user_has_notification_types_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+-- Name: user_has_notification_types user_has_notification_types_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "user_has_notification_types"
@@ -1689,7 +1909,7 @@ ALTER TABLE ONLY "user_has_notification_types"
--
--- Name: user_has_notifications_project_id_user_id_key; Type: CONSTRAINT; Schema: public; Owner: -
+-- Name: user_has_notifications user_has_notifications_project_id_user_id_key; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "user_has_notifications"
@@ -1697,7 +1917,7 @@ ALTER TABLE ONLY "user_has_notifications"
--
--- Name: user_has_unread_notifications_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+-- Name: user_has_unread_notifications user_has_unread_notifications_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "user_has_unread_notifications"
@@ -1705,7 +1925,7 @@ ALTER TABLE ONLY "user_has_unread_notifications"
--
--- Name: users_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+-- Name: users users_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "users"
@@ -1839,7 +2059,7 @@ CREATE UNIQUE INDEX "users_username_idx" ON "users" USING "btree" ("username");
--
--- Name: action_has_params_action_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+-- Name: action_has_params action_has_params_action_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "action_has_params"
@@ -1847,7 +2067,7 @@ ALTER TABLE ONLY "action_has_params"
--
--- Name: actions_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+-- Name: actions actions_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "actions"
@@ -1855,7 +2075,63 @@ ALTER TABLE ONLY "actions"
--
--- Name: columns_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+-- Name: column_has_move_restrictions column_has_move_restrictions_dst_column_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY "column_has_move_restrictions"
+ ADD CONSTRAINT "column_has_move_restrictions_dst_column_id_fkey" FOREIGN KEY ("dst_column_id") REFERENCES "columns"("id") ON DELETE CASCADE;
+
+
+--
+-- Name: column_has_move_restrictions column_has_move_restrictions_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY "column_has_move_restrictions"
+ ADD CONSTRAINT "column_has_move_restrictions_project_id_fkey" FOREIGN KEY ("project_id") REFERENCES "projects"("id") ON DELETE CASCADE;
+
+
+--
+-- Name: column_has_move_restrictions column_has_move_restrictions_role_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY "column_has_move_restrictions"
+ ADD CONSTRAINT "column_has_move_restrictions_role_id_fkey" FOREIGN KEY ("role_id") REFERENCES "project_has_roles"("role_id") ON DELETE CASCADE;
+
+
+--
+-- Name: column_has_move_restrictions column_has_move_restrictions_src_column_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY "column_has_move_restrictions"
+ ADD CONSTRAINT "column_has_move_restrictions_src_column_id_fkey" FOREIGN KEY ("src_column_id") REFERENCES "columns"("id") ON DELETE CASCADE;
+
+
+--
+-- Name: column_has_restrictions column_has_restrictions_column_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY "column_has_restrictions"
+ ADD CONSTRAINT "column_has_restrictions_column_id_fkey" FOREIGN KEY ("column_id") REFERENCES "columns"("id") ON DELETE CASCADE;
+
+
+--
+-- Name: column_has_restrictions column_has_restrictions_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY "column_has_restrictions"
+ ADD CONSTRAINT "column_has_restrictions_project_id_fkey" FOREIGN KEY ("project_id") REFERENCES "projects"("id") ON DELETE CASCADE;
+
+
+--
+-- Name: column_has_restrictions column_has_restrictions_role_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY "column_has_restrictions"
+ ADD CONSTRAINT "column_has_restrictions_role_id_fkey" FOREIGN KEY ("role_id") REFERENCES "project_has_roles"("role_id") ON DELETE CASCADE;
+
+
+--
+-- Name: columns columns_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "columns"
@@ -1863,7 +2139,7 @@ ALTER TABLE ONLY "columns"
--
--- Name: comments_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+-- Name: comments comments_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "comments"
@@ -1871,7 +2147,7 @@ ALTER TABLE ONLY "comments"
--
--- Name: group_has_users_group_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+-- Name: group_has_users group_has_users_group_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "group_has_users"
@@ -1879,7 +2155,7 @@ ALTER TABLE ONLY "group_has_users"
--
--- Name: group_has_users_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+-- Name: group_has_users group_has_users_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "group_has_users"
@@ -1887,7 +2163,7 @@ ALTER TABLE ONLY "group_has_users"
--
--- Name: last_logins_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+-- Name: last_logins last_logins_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "last_logins"
@@ -1895,7 +2171,7 @@ ALTER TABLE ONLY "last_logins"
--
--- Name: password_reset_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+-- Name: password_reset password_reset_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "password_reset"
@@ -1903,7 +2179,7 @@ ALTER TABLE ONLY "password_reset"
--
--- Name: project_activities_creator_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+-- Name: project_activities project_activities_creator_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "project_activities"
@@ -1911,7 +2187,7 @@ ALTER TABLE ONLY "project_activities"
--
--- Name: project_activities_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+-- Name: project_activities project_activities_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "project_activities"
@@ -1919,7 +2195,7 @@ ALTER TABLE ONLY "project_activities"
--
--- Name: project_activities_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+-- Name: project_activities project_activities_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "project_activities"
@@ -1927,7 +2203,7 @@ ALTER TABLE ONLY "project_activities"
--
--- Name: project_daily_stats_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+-- Name: project_daily_stats project_daily_stats_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "project_daily_stats"
@@ -1935,7 +2211,7 @@ ALTER TABLE ONLY "project_daily_stats"
--
--- Name: project_daily_summaries_column_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+-- Name: project_daily_column_stats project_daily_summaries_column_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "project_daily_column_stats"
@@ -1943,7 +2219,7 @@ ALTER TABLE ONLY "project_daily_column_stats"
--
--- Name: project_daily_summaries_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+-- Name: project_daily_column_stats project_daily_summaries_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "project_daily_column_stats"
@@ -1951,7 +2227,7 @@ ALTER TABLE ONLY "project_daily_column_stats"
--
--- Name: project_has_categories_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+-- Name: project_has_categories project_has_categories_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "project_has_categories"
@@ -1959,7 +2235,7 @@ ALTER TABLE ONLY "project_has_categories"
--
--- Name: project_has_files_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+-- Name: project_has_files project_has_files_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "project_has_files"
@@ -1967,7 +2243,7 @@ ALTER TABLE ONLY "project_has_files"
--
--- Name: project_has_groups_group_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+-- Name: project_has_groups project_has_groups_group_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "project_has_groups"
@@ -1975,7 +2251,7 @@ ALTER TABLE ONLY "project_has_groups"
--
--- Name: project_has_groups_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+-- Name: project_has_groups project_has_groups_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "project_has_groups"
@@ -1983,7 +2259,7 @@ ALTER TABLE ONLY "project_has_groups"
--
--- Name: project_has_metadata_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+-- Name: project_has_metadata project_has_metadata_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "project_has_metadata"
@@ -1991,7 +2267,7 @@ ALTER TABLE ONLY "project_has_metadata"
--
--- Name: project_has_notification_types_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+-- Name: project_has_notification_types project_has_notification_types_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "project_has_notification_types"
@@ -1999,7 +2275,15 @@ ALTER TABLE ONLY "project_has_notification_types"
--
--- Name: project_has_users_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+-- Name: project_has_roles project_has_roles_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY "project_has_roles"
+ ADD CONSTRAINT "project_has_roles_project_id_fkey" FOREIGN KEY ("project_id") REFERENCES "projects"("id") ON DELETE CASCADE;
+
+
+--
+-- Name: project_has_users project_has_users_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "project_has_users"
@@ -2007,7 +2291,7 @@ ALTER TABLE ONLY "project_has_users"
--
--- Name: project_has_users_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+-- Name: project_has_users project_has_users_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "project_has_users"
@@ -2015,7 +2299,23 @@ ALTER TABLE ONLY "project_has_users"
--
--- Name: remember_me_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+-- Name: project_role_has_restrictions project_role_has_restrictions_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY "project_role_has_restrictions"
+ ADD CONSTRAINT "project_role_has_restrictions_project_id_fkey" FOREIGN KEY ("project_id") REFERENCES "projects"("id") ON DELETE CASCADE;
+
+
+--
+-- Name: project_role_has_restrictions project_role_has_restrictions_role_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY "project_role_has_restrictions"
+ ADD CONSTRAINT "project_role_has_restrictions_role_id_fkey" FOREIGN KEY ("role_id") REFERENCES "project_has_roles"("role_id") ON DELETE CASCADE;
+
+
+--
+-- Name: remember_me remember_me_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "remember_me"
@@ -2023,7 +2323,7 @@ ALTER TABLE ONLY "remember_me"
--
--- Name: subtask_time_tracking_subtask_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+-- Name: subtask_time_tracking subtask_time_tracking_subtask_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "subtask_time_tracking"
@@ -2031,7 +2331,7 @@ ALTER TABLE ONLY "subtask_time_tracking"
--
--- Name: subtask_time_tracking_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+-- Name: subtask_time_tracking subtask_time_tracking_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "subtask_time_tracking"
@@ -2039,7 +2339,7 @@ ALTER TABLE ONLY "subtask_time_tracking"
--
--- Name: swimlanes_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+-- Name: swimlanes swimlanes_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "swimlanes"
@@ -2047,7 +2347,7 @@ ALTER TABLE ONLY "swimlanes"
--
--- Name: task_has_external_links_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+-- Name: task_has_external_links task_has_external_links_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "task_has_external_links"
@@ -2055,7 +2355,7 @@ ALTER TABLE ONLY "task_has_external_links"
--
--- Name: task_has_files_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+-- Name: task_has_files task_has_files_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "task_has_files"
@@ -2063,7 +2363,7 @@ ALTER TABLE ONLY "task_has_files"
--
--- Name: task_has_links_link_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+-- Name: task_has_links task_has_links_link_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "task_has_links"
@@ -2071,7 +2371,7 @@ ALTER TABLE ONLY "task_has_links"
--
--- Name: task_has_links_opposite_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+-- Name: task_has_links task_has_links_opposite_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "task_has_links"
@@ -2079,7 +2379,7 @@ ALTER TABLE ONLY "task_has_links"
--
--- Name: task_has_links_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+-- Name: task_has_links task_has_links_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "task_has_links"
@@ -2087,7 +2387,7 @@ ALTER TABLE ONLY "task_has_links"
--
--- Name: task_has_metadata_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+-- Name: task_has_metadata task_has_metadata_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "task_has_metadata"
@@ -2095,7 +2395,7 @@ ALTER TABLE ONLY "task_has_metadata"
--
--- Name: task_has_subtasks_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+-- Name: subtasks task_has_subtasks_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "subtasks"
@@ -2103,7 +2403,7 @@ ALTER TABLE ONLY "subtasks"
--
--- Name: task_has_tags_tag_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+-- Name: task_has_tags task_has_tags_tag_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "task_has_tags"
@@ -2111,7 +2411,7 @@ ALTER TABLE ONLY "task_has_tags"
--
--- Name: task_has_tags_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+-- Name: task_has_tags task_has_tags_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "task_has_tags"
@@ -2119,7 +2419,7 @@ ALTER TABLE ONLY "task_has_tags"
--
--- Name: tasks_column_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+-- Name: tasks tasks_column_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "tasks"
@@ -2127,7 +2427,7 @@ ALTER TABLE ONLY "tasks"
--
--- Name: tasks_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+-- Name: tasks tasks_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "tasks"
@@ -2135,7 +2435,7 @@ ALTER TABLE ONLY "tasks"
--
--- Name: transitions_dst_column_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+-- Name: transitions transitions_dst_column_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "transitions"
@@ -2143,7 +2443,7 @@ ALTER TABLE ONLY "transitions"
--
--- Name: transitions_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+-- Name: transitions transitions_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "transitions"
@@ -2151,7 +2451,7 @@ ALTER TABLE ONLY "transitions"
--
--- Name: transitions_src_column_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+-- Name: transitions transitions_src_column_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "transitions"
@@ -2159,7 +2459,7 @@ ALTER TABLE ONLY "transitions"
--
--- Name: transitions_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+-- Name: transitions transitions_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "transitions"
@@ -2167,7 +2467,7 @@ ALTER TABLE ONLY "transitions"
--
--- Name: transitions_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+-- Name: transitions transitions_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "transitions"
@@ -2175,7 +2475,7 @@ ALTER TABLE ONLY "transitions"
--
--- Name: user_has_metadata_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+-- Name: user_has_metadata user_has_metadata_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "user_has_metadata"
@@ -2183,7 +2483,7 @@ ALTER TABLE ONLY "user_has_metadata"
--
--- Name: user_has_notification_types_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+-- Name: user_has_notification_types user_has_notification_types_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "user_has_notification_types"
@@ -2191,7 +2491,7 @@ ALTER TABLE ONLY "user_has_notification_types"
--
--- Name: user_has_notifications_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+-- Name: user_has_notifications user_has_notifications_project_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "user_has_notifications"
@@ -2199,7 +2499,7 @@ ALTER TABLE ONLY "user_has_notifications"
--
--- Name: user_has_notifications_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+-- Name: user_has_notifications user_has_notifications_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "user_has_notifications"
@@ -2207,7 +2507,7 @@ ALTER TABLE ONLY "user_has_notifications"
--
--- Name: user_has_unread_notifications_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+-- Name: user_has_unread_notifications user_has_unread_notifications_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY "user_has_unread_notifications"
@@ -2222,8 +2522,8 @@ ALTER TABLE ONLY "user_has_unread_notifications"
-- PostgreSQL database dump
--
--- Dumped from database version 9.5.2
--- Dumped by pg_dump version 9.5.2
+-- Dumped from database version 9.6.1
+-- Dumped by pg_dump version 9.6.1
SET statement_timeout = 0;
SET lock_timeout = 0;
@@ -2243,8 +2543,8 @@ INSERT INTO settings (option, value, changed_by, changed_on) VALUES ('board_high
INSERT INTO settings (option, value, changed_by, changed_on) VALUES ('board_public_refresh_interval', '60', 0, 0);
INSERT INTO settings (option, value, changed_by, changed_on) VALUES ('board_private_refresh_interval', '10', 0, 0);
INSERT INTO settings (option, value, changed_by, changed_on) VALUES ('board_columns', '', 0, 0);
-INSERT INTO settings (option, value, changed_by, changed_on) VALUES ('webhook_token', 'c9a7c2a4523f1724b2ca047c5685f8e2b26bba47eb69baf4f22d5d50d837', 0, 0);
-INSERT INTO settings (option, value, changed_by, changed_on) VALUES ('api_token', 'c57a6cb1789269547b616454e4e2f06d3de0514f83baf8fa5b5a8af44a08', 0, 0);
+INSERT INTO settings (option, value, changed_by, changed_on) VALUES ('webhook_token', 'b64911d9b61ea71adada348105281e16470e268fce7cb9bf1895958d4bbc', 0, 0);
+INSERT INTO settings (option, value, changed_by, changed_on) VALUES ('api_token', 'f63bd25c2e952d78b70f178fd96b4207ef29315ca73d308af37c02d8d51f', 0, 0);
INSERT INTO settings (option, value, changed_by, changed_on) VALUES ('application_language', 'en_US', 0, 0);
INSERT INTO settings (option, value, changed_by, changed_on) VALUES ('application_timezone', 'UTC', 0, 0);
INSERT INTO settings (option, value, changed_by, changed_on) VALUES ('application_url', '', 0, 0);
@@ -2272,8 +2572,8 @@ INSERT INTO settings (option, value, changed_by, changed_on) VALUES ('password_r
-- PostgreSQL database dump
--
--- Dumped from database version 9.5.2
--- Dumped by pg_dump version 9.5.2
+-- Dumped from database version 9.6.1
+-- Dumped by pg_dump version 9.6.1
SET statement_timeout = 0;
SET lock_timeout = 0;
@@ -2313,4 +2613,4 @@ SELECT pg_catalog.setval('links_id_seq', 11, true);
-- PostgreSQL database dump complete
--
-INSERT INTO users (username, password, role) VALUES ('admin', '$2y$10$yUJ9QnhG.f47yO.YvWKo3eMAHULukpluDNTOF9.Z7QQg0vOfFRB6u', 'app-admin');INSERT INTO schema_version VALUES ('91');
+INSERT INTO users (username, password, role) VALUES ('admin', '$2y$10$0.8BJyhOEBHGqfwD3nIJHuxObqTlZGJ/KRNDVHfSu7RGd42rEbSa.', 'app-admin');INSERT INTO schema_version VALUES ('97');
diff --git a/app/Schema/Sqlite.php b/app/Schema/Sqlite.php
index edf6ce63..11dcd537 100644
--- a/app/Schema/Sqlite.php
+++ b/app/Schema/Sqlite.php
@@ -6,7 +6,12 @@ use Kanboard\Core\Security\Token;
use Kanboard\Core\Security\Role;
use PDO;
-const VERSION = 107;
+const VERSION = 108;
+
+function version_108(PDO $pdo)
+{
+ $pdo->exec('ALTER TABLE users ADD COLUMN api_access_token VARCHAR(255) DEFAULT NULL');
+}
function version_107(PDO $pdo)
{
diff --git a/app/ServiceProvider/AuthenticationProvider.php b/app/ServiceProvider/AuthenticationProvider.php
index adff1e63..c2dad0e6 100644
--- a/app/ServiceProvider/AuthenticationProvider.php
+++ b/app/ServiceProvider/AuthenticationProvider.php
@@ -2,6 +2,7 @@
namespace Kanboard\ServiceProvider;
+use Kanboard\Auth\ApiAccessTokenAuth;
use Pimple\Container;
use Pimple\ServiceProviderInterface;
use Kanboard\Core\Security\AuthenticationManager;
@@ -44,6 +45,8 @@ class AuthenticationProvider implements ServiceProviderInterface
$container['authenticationManager']->register(new LdapAuth($container));
}
+ $container['authenticationManager']->register(new ApiAccessTokenAuth($container));
+
$container['projectAccessMap'] = $this->getProjectAccessMap();
$container['applicationAccessMap'] = $this->getApplicationAccessMap();
$container['apiAccessMap'] = $this->getApiAccessMap();
diff --git a/app/ServiceProvider/ClassProvider.php b/app/ServiceProvider/ClassProvider.php
index c5bf0678..8d471b79 100644
--- a/app/ServiceProvider/ClassProvider.php
+++ b/app/ServiceProvider/ClassProvider.php
@@ -91,7 +91,6 @@ class ClassProvider implements ServiceProviderInterface
'TransitionModel',
'UserModel',
'UserLockingModel',
- 'UserMentionModel',
'UserNotificationModel',
'UserNotificationFilterModel',
'UserUnreadNotificationModel',
diff --git a/app/ServiceProvider/CommandProvider.php b/app/ServiceProvider/CommandProvider.php
index 55c2712b..c9abb294 100644
--- a/app/ServiceProvider/CommandProvider.php
+++ b/app/ServiceProvider/CommandProvider.php
@@ -3,6 +3,8 @@
namespace Kanboard\ServiceProvider;
use Kanboard\Console\CronjobCommand;
+use Kanboard\Console\DatabaseMigrationCommand;
+use Kanboard\Console\DatabaseVersionCommand;
use Kanboard\Console\LocaleComparatorCommand;
use Kanboard\Console\LocaleSyncCommand;
use Kanboard\Console\PluginInstallCommand;
@@ -55,6 +57,8 @@ class CommandProvider implements ServiceProviderInterface
$application->add(new PluginUpgradeCommand($container));
$application->add(new PluginInstallCommand($container));
$application->add(new PluginUninstallCommand($container));
+ $application->add(new DatabaseMigrationCommand($container));
+ $application->add(new DatabaseVersionCommand($container));
$container['cli'] = $application;
return $container;
diff --git a/app/ServiceProvider/DatabaseProvider.php b/app/ServiceProvider/DatabaseProvider.php
index a3f57457..9998ac43 100644
--- a/app/ServiceProvider/DatabaseProvider.php
+++ b/app/ServiceProvider/DatabaseProvider.php
@@ -27,6 +27,10 @@ class DatabaseProvider implements ServiceProviderInterface
{
$container['db'] = $this->getInstance();
+ if (DB_RUN_MIGRATIONS) {
+ self::runMigrations($container['db']);
+ }
+
if (DEBUG) {
$container['db']->getStatementHandler()
->withLogging()
@@ -38,7 +42,7 @@ class DatabaseProvider implements ServiceProviderInterface
}
/**
- * Setup the database driver and execute schema migration
+ * Setup the database driver
*
* @access public
* @return \PicoDb\Database
@@ -59,12 +63,39 @@ class DatabaseProvider implements ServiceProviderInterface
throw new LogicException('Database driver not supported');
}
- if ($db->schema()->check(\Schema\VERSION)) {
- return $db;
- } else {
+ return $db;
+ }
+
+ /**
+ * Get current database version
+ *
+ * @static
+ * @access public
+ * @param Database $db
+ * @return int
+ */
+ public static function getSchemaVersion(Database $db)
+ {
+ return $db->getDriver()->getSchemaVersion();
+ }
+
+ /**
+ * Execute database migrations
+ *
+ * @static
+ * @access public
+ * @throws RuntimeException
+ * @param Database $db
+ * @return bool
+ */
+ public static function runMigrations(Database $db)
+ {
+ if (! $db->schema()->check(\Schema\VERSION)) {
$messages = $db->getLogMessages();
throw new RuntimeException('Unable to run SQL migrations: '.implode(', ', $messages).' (You may have to fix it manually)');
}
+
+ return true;
}
/**
@@ -79,7 +110,7 @@ class DatabaseProvider implements ServiceProviderInterface
return new Database(array(
'driver' => 'sqlite',
- 'filename' => DB_FILENAME
+ 'filename' => DB_FILENAME,
));
}
diff --git a/app/ServiceProvider/JobProvider.php b/app/ServiceProvider/JobProvider.php
index 2194b11c..4e5e0f1a 100644
--- a/app/ServiceProvider/JobProvider.php
+++ b/app/ServiceProvider/JobProvider.php
@@ -10,6 +10,7 @@ use Kanboard\Job\SubtaskEventJob;
use Kanboard\Job\TaskEventJob;
use Kanboard\Job\TaskFileEventJob;
use Kanboard\Job\TaskLinkEventJob;
+use Kanboard\Job\UserMentionJob;
use Pimple\Container;
use Pimple\ServiceProviderInterface;
@@ -62,6 +63,10 @@ class JobProvider implements ServiceProviderInterface
return new ProjectMetricJob($c);
});
+ $container['userMentionJob'] = $container->factory(function ($c) {
+ return new UserMentionJob($c);
+ });
+
return $container;
}
}
diff --git a/app/ServiceProvider/RouteProvider.php b/app/ServiceProvider/RouteProvider.php
index 0d1a7931..52687647 100644
--- a/app/ServiceProvider/RouteProvider.php
+++ b/app/ServiceProvider/RouteProvider.php
@@ -158,6 +158,7 @@ class RouteProvider implements ServiceProviderInterface
$container['route']->addRoute('user/:user_id/authentication', 'UserCredentialController', 'changeAuthentication');
$container['route']->addRoute('user/:user_id/2fa', 'TwoFactorController', 'index');
$container['route']->addRoute('user/:user_id/avatar', 'AvatarFileController', 'show');
+ $container['route']->addRoute('user/:user_id/api', 'UserApiAccessController', 'show');
// Groups
$container['route']->addRoute('groups', 'GroupListController', 'index');
diff --git a/app/Subscriber/NotificationSubscriber.php b/app/Subscriber/NotificationSubscriber.php
index 7cc68b26..ad16685b 100644
--- a/app/Subscriber/NotificationSubscriber.php
+++ b/app/Subscriber/NotificationSubscriber.php
@@ -15,25 +15,25 @@ class NotificationSubscriber extends BaseSubscriber implements EventSubscriberIn
public static function getSubscribedEvents()
{
return array(
- TaskModel::EVENT_USER_MENTION => 'handleEvent',
- TaskModel::EVENT_CREATE => 'handleEvent',
- TaskModel::EVENT_UPDATE => 'handleEvent',
- TaskModel::EVENT_CLOSE => 'handleEvent',
- TaskModel::EVENT_OPEN => 'handleEvent',
- TaskModel::EVENT_MOVE_COLUMN => 'handleEvent',
- TaskModel::EVENT_MOVE_POSITION => 'handleEvent',
- TaskModel::EVENT_MOVE_SWIMLANE => 'handleEvent',
- TaskModel::EVENT_ASSIGNEE_CHANGE => 'handleEvent',
- SubtaskModel::EVENT_CREATE => 'handleEvent',
- SubtaskModel::EVENT_UPDATE => 'handleEvent',
- SubtaskModel::EVENT_DELETE => 'handleEvent',
- CommentModel::EVENT_CREATE => 'handleEvent',
- CommentModel::EVENT_UPDATE => 'handleEvent',
- CommentModel::EVENT_DELETE => 'handleEvent',
- CommentModel::EVENT_USER_MENTION => 'handleEvent',
- TaskFileModel::EVENT_CREATE => 'handleEvent',
- TaskLinkModel::EVENT_CREATE_UPDATE => 'handleEvent',
- TaskLinkModel::EVENT_DELETE => 'handleEvent',
+ TaskModel::EVENT_USER_MENTION => 'handleEvent',
+ TaskModel::EVENT_CREATE => 'handleEvent',
+ TaskModel::EVENT_UPDATE => 'handleEvent',
+ TaskModel::EVENT_CLOSE => 'handleEvent',
+ TaskModel::EVENT_OPEN => 'handleEvent',
+ TaskModel::EVENT_MOVE_COLUMN => 'handleEvent',
+ TaskModel::EVENT_MOVE_POSITION => 'handleEvent',
+ TaskModel::EVENT_MOVE_SWIMLANE => 'handleEvent',
+ TaskModel::EVENT_ASSIGNEE_CHANGE => 'handleEvent',
+ SubtaskModel::EVENT_CREATE => 'handleEvent',
+ SubtaskModel::EVENT_UPDATE => 'handleEvent',
+ SubtaskModel::EVENT_DELETE => 'handleEvent',
+ CommentModel::EVENT_CREATE => 'handleEvent',
+ CommentModel::EVENT_UPDATE => 'handleEvent',
+ CommentModel::EVENT_DELETE => 'handleEvent',
+ CommentModel::EVENT_USER_MENTION => 'handleEvent',
+ TaskFileModel::EVENT_CREATE => 'handleEvent',
+ TaskLinkModel::EVENT_CREATE_UPDATE => 'handleEvent',
+ TaskLinkModel::EVENT_DELETE => 'handleEvent',
);
}
diff --git a/app/Template/category/edit.php b/app/Template/category/edit.php
index 72fd40de..d8ca313d 100644
--- a/app/Template/category/edit.php
+++ b/app/Template/category/edit.php
@@ -10,10 +10,10 @@
<?= $this->form->hidden('project_id', $values) ?>
<?= $this->form->label(t('Category Name'), 'name') ?>
- <?= $this->form->text('name', $values, $errors, array('autofocus', 'required', 'maxlength="50"')) ?>
+ <?= $this->form->text('name', $values, $errors, array('autofocus', 'required', 'maxlength="50"', 'tabindex="1"')) ?>
<?= $this->form->label(t('Description'), 'description') ?>
- <?= $this->form->textEditor('description', $values, $errors) ?>
+ <?= $this->form->textEditor('description', $values, $errors, array('tabindex' => 2)) ?>
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
diff --git a/app/Template/category/index.php b/app/Template/category/index.php
index ac60d9a8..336b79a2 100644
--- a/app/Template/category/index.php
+++ b/app/Template/category/index.php
@@ -15,9 +15,11 @@
<a href="#" class="dropdown-menu dropdown-menu-link-icon"><i class="fa fa-cog fa-fw"></i><i class="fa fa-caret-down"></i></a>
<ul>
<li>
+ <i class="fa fa-pencil-square-o fa-fw" aria-hidden="true"></i>
<?= $this->url->link(t('Edit'), 'CategoryController', 'edit', array('project_id' => $project['id'], 'category_id' => $category_id), false, 'popover') ?>
</li>
<li>
+ <i class="fa fa-trash-o fa-fw" aria-hidden="true"></i>
<?= $this->url->link(t('Remove'), 'CategoryController', 'confirm', array('project_id' => $project['id'], 'category_id' => $category_id), false, 'popover') ?>
</li>
</ul>
diff --git a/app/Template/column/create.php b/app/Template/column/create.php
index 71c94062..f4cded52 100644
--- a/app/Template/column/create.php
+++ b/app/Template/column/create.php
@@ -8,18 +8,18 @@
<?= $this->form->hidden('project_id', $values) ?>
<?= $this->form->label(t('Title'), 'title') ?>
- <?= $this->form->text('title', $values, $errors, array('autofocus', 'required', 'maxlength="50"')) ?>
+ <?= $this->form->text('title', $values, $errors, array('autofocus', 'required', 'maxlength="50"', 'tabindex="1"')) ?>
<?= $this->form->label(t('Task limit'), 'task_limit') ?>
- <?= $this->form->number('task_limit', $values, $errors) ?>
+ <?= $this->form->number('task_limit', $values, $errors, array('tabindex="2"')) ?>
- <?= $this->form->checkbox('hide_in_dashboard', t('Hide tasks in this column in the dashboard'), 1) ?>
+ <?= $this->form->checkbox('hide_in_dashboard', t('Hide tasks in this column in the dashboard'), 1, false, '', array('tabindex' => 3)) ?>
<?= $this->form->label(t('Description'), 'description') ?>
- <?= $this->form->textEditor('description', $values, $errors) ?>
+ <?= $this->form->textEditor('description', $values, $errors, array('tabindex' => 4)) ?>
<div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
+ <button type="submit" class="btn btn-blue" tabindex="5"><?= t('Save') ?></button>
<?= t('or') ?>
<?= $this->url->link(t('cancel'), 'column', 'index', array('project_id' => $project['id']), false, 'close-popover') ?>
</div>
diff --git a/app/Template/comments/show.php b/app/Template/comments/show.php
index 5c6d8e20..dfc13821 100644
--- a/app/Template/comments/show.php
+++ b/app/Template/comments/show.php
@@ -26,6 +26,7 @@
'values' => array(
'user_id' => $this->user->getId(),
'task_id' => $task['id'],
+ 'project_id' => $task['project_id'],
),
'errors' => array(),
'task' => $task,
diff --git a/app/Template/notification/comment_create.php b/app/Template/notification/comment_create.php
index fefc8ba1..41262a7e 100644
--- a/app/Template/notification/comment_create.php
+++ b/app/Template/notification/comment_create.php
@@ -6,6 +6,6 @@
<h3><?= t('New comment') ?></h3>
<?php endif ?>
-<?= $this->text->markdown($comment['comment']) ?>
+<?= $this->text->markdown($comment['comment'], true) ?>
<?= $this->render('notification/footer', array('task' => $task, 'application_url' => $application_url)) ?> \ No newline at end of file
diff --git a/app/Template/notification/comment_delete.php b/app/Template/notification/comment_delete.php
index 928623ec..14babbd9 100644
--- a/app/Template/notification/comment_delete.php
+++ b/app/Template/notification/comment_delete.php
@@ -2,6 +2,6 @@
<h3><?= t('Comment removed') ?></h3>
-<?= $this->text->markdown($comment['comment']) ?>
+<?= $this->text->markdown($comment['comment'], true) ?>
<?= $this->render('notification/footer', array('task' => $task, 'application_url' => $application_url)) ?>
diff --git a/app/Template/notification/comment_update.php b/app/Template/notification/comment_update.php
index 2477d8b3..f1cffae6 100644
--- a/app/Template/notification/comment_update.php
+++ b/app/Template/notification/comment_update.php
@@ -2,6 +2,6 @@
<h3><?= t('Comment updated') ?></h3>
-<?= $this->text->markdown($comment['comment']) ?>
+<?= $this->text->markdown($comment['comment'], true) ?>
<?= $this->render('notification/footer', array('task' => $task, 'application_url' => $application_url)) ?> \ No newline at end of file
diff --git a/app/Template/notification/comment_user_mention.php b/app/Template/notification/comment_user_mention.php
index 372183df..0990e7ab 100644
--- a/app/Template/notification/comment_user_mention.php
+++ b/app/Template/notification/comment_user_mention.php
@@ -2,6 +2,6 @@
<p><?= $this->text->e($task['title']) ?></p>
-<?= $this->text->markdown($comment['comment']) ?>
+<?= $this->text->markdown($comment['comment'], true) ?>
<?= $this->render('notification/footer', array('task' => $task, 'application_url' => $application_url)) ?> \ No newline at end of file
diff --git a/app/Template/notification/task_assignee_change.php b/app/Template/notification/task_assignee_change.php
index 53f7c5c1..f075fdbf 100644
--- a/app/Template/notification/task_assignee_change.php
+++ b/app/Template/notification/task_assignee_change.php
@@ -14,7 +14,7 @@
<?php if (! empty($task['description'])): ?>
<h2><?= t('Description') ?></h2>
- <?= $this->text->markdown($task['description']) ?: t('There is no description.') ?>
+ <?= $this->text->markdown($task['description'], true) ?: t('There is no description.') ?>
<?php endif ?>
<?= $this->render('notification/footer', array('task' => $task, 'application_url' => $application_url)) ?> \ No newline at end of file
diff --git a/app/Template/notification/task_create.php b/app/Template/notification/task_create.php
index 3cd68ac0..3439e357 100644
--- a/app/Template/notification/task_create.php
+++ b/app/Template/notification/task_create.php
@@ -37,7 +37,7 @@
<?php if (! empty($task['description'])): ?>
<h2><?= t('Description') ?></h2>
- <?= $this->text->markdown($task['description']) ?>
+ <?= $this->text->markdown($task['description'], true) ?>
<?php endif ?>
<?= $this->render('notification/footer', array('task' => $task, 'application_url' => $application_url)) ?> \ No newline at end of file
diff --git a/app/Template/notification/task_update.php b/app/Template/notification/task_update.php
index 8adb2553..9abe8e0a 100644
--- a/app/Template/notification/task_update.php
+++ b/app/Template/notification/task_update.php
@@ -1,4 +1,4 @@
<h2><?= $this->text->e($task['title']) ?> (#<?= $task['id'] ?>)</h2>
-<?= $this->render('task/changes', array('changes' => $changes, 'task' => $task)) ?>
+<?= $this->render('task/changes', array('changes' => $changes, 'task' => $task, 'public' => true)) ?>
<?= $this->render('notification/footer', array('task' => $task, 'application_url' => $application_url)) ?> \ No newline at end of file
diff --git a/app/Template/notification/task_user_mention.php b/app/Template/notification/task_user_mention.php
index 3d8c8e95..71ad348b 100644
--- a/app/Template/notification/task_user_mention.php
+++ b/app/Template/notification/task_user_mention.php
@@ -2,6 +2,6 @@
<p><?= $this->text->e($task['title']) ?></p>
<h2><?= t('Description') ?></h2>
-<?= $this->text->markdown($task['description']) ?>
+<?= $this->text->markdown($task['description'], true) ?>
<?= $this->render('notification/footer', array('task' => $task, 'application_url' => $application_url)) ?> \ No newline at end of file
diff --git a/app/Template/swimlane/create.php b/app/Template/swimlane/create.php
index 0eb25411..207b526c 100644
--- a/app/Template/swimlane/create.php
+++ b/app/Template/swimlane/create.php
@@ -7,13 +7,13 @@
<?= $this->form->hidden('project_id', $values) ?>
<?= $this->form->label(t('Name'), 'name') ?>
- <?= $this->form->text('name', $values, $errors, array('autofocus', 'required', 'maxlength="50"')) ?>
+ <?= $this->form->text('name', $values, $errors, array('autofocus', 'required', 'maxlength="50"', 'tabindex="1"')) ?>
<?= $this->form->label(t('Description'), 'description') ?>
- <?= $this->form->textEditor('description', $values, $errors) ?>
+ <?= $this->form->textEditor('description', $values, $errors, array('tabindex' => 2)) ?>
<div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
+ <button type="submit" class="btn btn-blue" tabindex="3"><?= t('Save') ?></button>
<?= t('or') ?>
<?= $this->url->link(t('cancel'), 'SwimlaneController', 'index', array('project_id' => $project['id']), false, 'close-popover') ?>
</div>
diff --git a/app/Template/swimlane/edit.php b/app/Template/swimlane/edit.php
index 2cbabb60..d225b345 100644
--- a/app/Template/swimlane/edit.php
+++ b/app/Template/swimlane/edit.php
@@ -10,13 +10,13 @@
<?= $this->form->hidden('project_id', $values) ?>
<?= $this->form->label(t('Name'), 'name') ?>
- <?= $this->form->text('name', $values, $errors, array('autofocus', 'required', 'maxlength="50"')) ?>
+ <?= $this->form->text('name', $values, $errors, array('autofocus', 'required', 'maxlength="50"', 'tabindex="1"')) ?>
<?= $this->form->label(t('Description'), 'description') ?>
- <?= $this->form->textEditor('description', $values, $errors) ?>
+ <?= $this->form->textEditor('description', $values, $errors, array('tabindex' => 2)) ?>
<div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
+ <button type="submit" class="btn btn-blue" tabindex="3"><?= t('Save') ?></button>
<?= t('or') ?>
<?= $this->url->link(t('cancel'), 'SwimlaneController', 'index', array('project_id' => $project['id']), false, 'close-popover') ?>
</div>
diff --git a/app/Template/swimlane/edit_default.php b/app/Template/swimlane/edit_default.php
index f271c513..8a0c0a15 100644
--- a/app/Template/swimlane/edit_default.php
+++ b/app/Template/swimlane/edit_default.php
@@ -6,7 +6,7 @@
<?= $this->form->hidden('id', $values) ?>
<?= $this->form->label(t('Name'), 'default_swimlane') ?>
- <?= $this->form->text('default_swimlane', $values, $errors, array('required', 'maxlength="50"')) ?>
+ <?= $this->form->text('default_swimlane', $values, $errors, array('autofocus', 'required', 'maxlength="50"')) ?>
<?= $this->form->checkbox('show_default_swimlane', t('Show default swimlane'), 1, $values['show_default_swimlane'] == 1) ?>
diff --git a/app/Template/swimlane/table.php b/app/Template/swimlane/table.php
index cefef9de..81daed01 100644
--- a/app/Template/swimlane/table.php
+++ b/app/Template/swimlane/table.php
@@ -20,12 +20,15 @@
<a href="#" class="dropdown-menu dropdown-menu-link-icon"><i class="fa fa-cog fa-fw"></i><i class="fa fa-caret-down"></i></a>
<ul>
<li>
+ <i class="fa fa-pencil-square-o fa-fw" aria-hidden="true"></i>
<?= $this->url->link(t('Edit'), 'SwimlaneController', 'editDefault', array('project_id' => $project['id']), false, 'popover') ?>
</li>
<li>
<?php if ($default_swimlane['show_default_swimlane'] == 1): ?>
+ <i class="fa fa-toggle-off fa-fw" aria-hidden="true"></i>
<?= $this->url->link(t('Disable'), 'SwimlaneController', 'disableDefault', array('project_id' => $project['id']), true) ?>
<?php else: ?>
+ <i class="fa fa-toggle-on fa-fw" aria-hidden="true"></i>
<?= $this->url->link(t('Enable'), 'SwimlaneController', 'enableDefault', array('project_id' => $project['id']), true) ?>
<?php endif ?>
</li>
@@ -55,16 +58,20 @@
<a href="#" class="dropdown-menu dropdown-menu-link-icon"><i class="fa fa-cog fa-fw"></i><i class="fa fa-caret-down"></i></a>
<ul>
<li>
+ <i class="fa fa-pencil-square-o fa-fw" aria-hidden="true"></i>
<?= $this->url->link(t('Edit'), 'SwimlaneController', 'edit', array('project_id' => $project['id'], 'swimlane_id' => $swimlane['id']), false, 'popover') ?>
</li>
<li>
<?php if ($swimlane['is_active']): ?>
+ <i class="fa fa-toggle-off fa-fw" aria-hidden="true"></i>
<?= $this->url->link(t('Disable'), 'SwimlaneController', 'disable', array('project_id' => $project['id'], 'swimlane_id' => $swimlane['id']), true) ?>
<?php else: ?>
+ <i class="fa fa-toggle-on fa-fw" aria-hidden="true"></i>
<?= $this->url->link(t('Enable'), 'SwimlaneController', 'enable', array('project_id' => $project['id'], 'swimlane_id' => $swimlane['id']), true) ?>
<?php endif ?>
</li>
<li>
+ <i class="fa fa-trash-o fa-fw" aria-hidden="true"></i>
<?= $this->url->link(t('Remove'), 'SwimlaneController', 'confirm', array('project_id' => $project['id'], 'swimlane_id' => $swimlane['id']), false, 'popover') ?>
</li>
</ul>
diff --git a/app/Template/task/changes.php b/app/Template/task/changes.php
index 9d36f09f..2c2bf267 100644
--- a/app/Template/task/changes.php
+++ b/app/Template/task/changes.php
@@ -69,6 +69,10 @@
<?php if (! empty($changes['description'])): ?>
<p><strong><?= t('The description has been modified:') ?></strong></p>
- <div class="markdown"><?= $this->text->markdown($task['description']) ?></div>
+ <?php if (isset($public)): ?>
+ <div class="markdown"><?= $this->text->markdown($task['description'], true) ?></div>
+ <?php else: ?>
+ <div class="markdown"><?= $this->text->markdown($task['description']) ?></div>
+ <?php endif ?>
<?php endif ?>
<?php endif ?> \ No newline at end of file
diff --git a/app/Template/task_move_position/show.php b/app/Template/task_move_position/show.php
index c1a02484..91241016 100644
--- a/app/Template/task_move_position/show.php
+++ b/app/Template/task_move_position/show.php
@@ -2,45 +2,22 @@
<h2><?= t('Move task to another position on the board') ?></h2>
</div>
-<script type="x/template" id="template-task-move-position">
- <?= $this->form->label(t('Swimlane'), 'swimlane') ?>
- <select v-model="swimlaneId" @change="onChangeSwimlane()" id="form-swimlane">
- <option v-for="swimlane in board" v-bind:value="swimlane.id">
- {{ swimlane.name }}
- </option>
- </select>
+<form>
- <div v-if="columns.length > 0">
- <?= $this->form->label(t('Column'), 'column') ?>
- <select v-model="columnId" @change="onChangeColumn()" id="form-column">
- <option v-for="column in columns" v-bind:value="column.id">
- {{ column.title }}
- </option>
- </select>
- </div>
+<?= $this->app->component('task-move-position', array(
+ 'saveUrl' => $this->url->href('TaskMovePositionController', 'save', array('task_id' => $task['id'], 'project_id' => $task['project_id'])),
+ 'board' => $board,
+ 'swimlaneLabel' => t('Swimlane'),
+ 'columnLabel' => t('Column'),
+ 'positionLabel' => t('Position'),
+ 'beforeLabel' => t('Insert before this task'),
+ 'afterLabel' => t('Insert after this task'),
+)) ?>
- <div v-if="tasks.length > 0">
- <?= $this->form->label(t('Position'), 'position') ?>
- <select v-model="position" id="form-position">
- <option v-for="task in tasks" v-bind:value="task.position">#{{ task.id }} - {{ task.title }}</option>
- </select>
- <label><input type="radio" value="before" v-model="positionChoice"><?= t('Insert before this task') ?></label>
- <label><input type="radio" value="after" v-model="positionChoice"><?= t('Insert after this task') ?></label>
- </div>
+<?= $this->app->component('submit-cancel', array(
+ 'submitLabel' => t('Save'),
+ 'orLabel' => t('or'),
+ 'cancelLabel' => t('cancel'),
+)) ?>
- <div v-if="errorMessage">
- <div class="alert alert-error">{{ errorMessage }}</div>
- </div>
-
- <submit-cancel
- label-button="<?= t('Save') ?>"
- label-or="<?= t('or') ?>"
- label-cancel="<?= t('cancel') ?>"
- :callback="onSubmit">
- </submit-cancel>
-</script>
-
-<task-move-position
- save-url="<?= $this->url->href('TaskMovePositionController', 'save', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"
- :board='<?= json_encode($board, JSON_HEX_APOS) ?>'
-></task-move-position>
+</form>
diff --git a/app/Template/user_api_access/show.php b/app/Template/user_api_access/show.php
new file mode 100644
index 00000000..3d58e0d5
--- /dev/null
+++ b/app/Template/user_api_access/show.php
@@ -0,0 +1,17 @@
+<div class="page-header">
+ <h2><?= t('API User Access') ?></h2>
+</div>
+
+<p class="alert">
+ <?php if (empty($user['api_access_token'])): ?>
+ <?= t('No personal API access token registered.') ?>
+ <?php else: ?>
+ <?= t('Your personal API access token is "%s"', $user['api_access_token']) ?>
+ <?php endif ?>
+</p>
+
+<?php if (! empty($user['api_access_token'])): ?>
+ <?= $this->url->link(t('Remove your token'), 'UserApiAccessController', 'remove', array('user_id' => $user['id']), true, 'btn btn-red') ?>
+<?php endif ?>
+
+<?= $this->url->link(t('Generate a new token'), 'UserApiAccessController', 'generate', array('user_id' => $user['id']), true, 'btn btn-blue') ?>
diff --git a/app/Template/user_view/sidebar.php b/app/Template/user_view/sidebar.php
index a80daefa..ef494e42 100644
--- a/app/Template/user_view/sidebar.php
+++ b/app/Template/user_view/sidebar.php
@@ -90,6 +90,11 @@
<?= $this->url->link(t('Integrations'), 'UserViewController', 'integrations', array('user_id' => $user['id'])) ?>
</li>
<?php endif ?>
+ <?php if ($this->user->hasAccess('UserApiAccessController', 'show')): ?>
+ <li <?= $this->app->checkMenuSelection('UserApiAccessController', 'show') ?>>
+ <?= $this->url->link(t('API'), 'UserApiAccessController', 'show', array('user_id' => $user['id'])) ?>
+ </li>
+ <?php endif ?>
<?php endif ?>
<?php if ($this->user->hasAccess('UserCredentialController', 'changeAuthentication')): ?>
diff --git a/app/constants.php b/app/constants.php
index 3adb0835..ba14cde6 100644
--- a/app/constants.php
+++ b/app/constants.php
@@ -35,6 +35,9 @@ defined('LOG_FILE') or define('LOG_FILE', DATA_DIR.DIRECTORY_SEPARATOR.'debug.lo
// Application version
defined('APP_VERSION') or define('APP_VERSION', build_app_version('$Format:%d$', '$Format:%H$'));
+// Run automatically database migrations
+defined('DB_RUN_MIGRATIONS') or define('DB_RUN_MIGRATIONS', true);
+
// Database driver: sqlite, mysql or postgres
defined('DB_DRIVER') or define('DB_DRIVER', 'sqlite');
diff --git a/app/functions.php b/app/functions.php
index 8f0d482c..e732f308 100644
--- a/app/functions.php
+++ b/app/functions.php
@@ -53,6 +53,37 @@ function array_column_index(array &$input, $column)
}
/**
+ * Create indexed array from a list of dict with unique values
+ *
+ * $input = [
+ * ['k1' => 1, 'k2' => 2], ['k1' => 3, 'k2' => 4], ['k1' => 1, 'k2' => 5]
+ * ]
+ *
+ * array_column_index_unique($input, 'k1') will returns:
+ *
+ * [
+ * 1 => ['k1' => 1, 'k2' => 2],
+ * 3 => ['k1' => 3, 'k2' => 4],
+ * ]
+ *
+ * @param array $input
+ * @param string $column
+ * @return array
+ */
+function array_column_index_unique(array &$input, $column)
+{
+ $result = array();
+
+ foreach ($input as &$row) {
+ if (isset($row[$column]) && ! isset($result[$row[$column]])) {
+ $result[$row[$column]] = $row;
+ }
+ }
+
+ return $result;
+}
+
+/**
* Sum all values from a single column in the input array
*
* $input = [
diff --git a/assets/css/app.min.css b/assets/css/app.min.css
index a861f4bd..0ef8f1c9 100644
--- a/assets/css/app.min.css
+++ b/assets/css/app.min.css
@@ -1 +1 @@
-h1,li,ul,ol,table,tr,td,th,p,blockquote,body{margin:0;padding:0;font-size:100%}body{margin-left:10px;margin-right:10px;padding-bottom:10px;color:#333;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;text-rendering:optimizeLegibility}small{font-size:0.8em}hr{border:0;height:0;border-top:1px solid rgba(0,0,0,0.1);border-bottom:1px solid rgba(255,255,255,0.3)}.pull-right{text-align:right}ul.no-bullet li{list-style-type:none;margin-left:0}.chosen-select{min-height:27px}#app-loading-icon{position:fixed;right:3px;bottom:3px}.assign-me{vertical-align:bottom}a{color:#36c;border:none}a:focus{outline:0;color:#DF5353;text-decoration:none}a:hover{color:#333;text-decoration:none}h1,h2,h3{font-weight:normal;color:#333}h1{font-size:1.5em}h2{font-size:1.4em;margin-bottom:10px}h3{margin-top:10px;font-size:1.2em}table{width:100%;border-collapse:collapse;border-spacing:0;margin-bottom:20px}table.table-fixed{table-layout:fixed;white-space:nowrap}table.table-fixed th{overflow:hidden}table.table-fixed td{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}table.table-small{font-size:0.8em}table.table-striped tr:nth-child(odd){background:#fefefe}@media (max-width: 768px){table.table-scrolling{overflow-x:auto;display:inline-block;vertical-align:top;max-width:100%;white-space:nowrap}}table th{text-align:left;padding:0.5em 3px;border:1px solid #eee;background:#fbfbfb}table th a{text-decoration:none;color:#333}table th a:focus,table th a:hover{text-decoration:underline}table td{border:1px solid #eee;padding:0.5em 3px;vertical-align:top}table td li{margin-left:20px}.column-1{width:1%}.column-2{width:2%}.column-3{width:3%}.column-4{width:4%}.column-5{width:5%}.column-6{width:6%}.column-7{width:7%}.column-8{width:8%}.column-9{width:9%}.column-10{width:10%}.column-11{width:11%}.column-12{width:12%}.column-13{width:13%}.column-14{width:14%}.column-15{width:15%}.column-16{width:16%}.column-17{width:17%}.column-18{width:18%}.column-19{width:19%}.column-20{width:20%}.column-21{width:21%}.column-22{width:22%}.column-23{width:23%}.column-24{width:24%}.column-25{width:25%}.column-26{width:26%}.column-27{width:27%}.column-28{width:28%}.column-29{width:29%}.column-30{width:30%}.column-31{width:31%}.column-32{width:32%}.column-33{width:33%}.column-34{width:34%}.column-35{width:35%}.column-36{width:36%}.column-37{width:37%}.column-38{width:38%}.column-39{width:39%}.column-40{width:40%}.column-41{width:41%}.column-42{width:42%}.column-43{width:43%}.column-44{width:44%}.column-45{width:45%}.column-46{width:46%}.column-47{width:47%}.column-48{width:48%}.column-49{width:49%}.column-50{width:50%}.column-51{width:51%}.column-52{width:52%}.column-53{width:53%}.column-54{width:54%}.column-55{width:55%}.column-56{width:56%}.column-57{width:57%}.column-58{width:58%}.column-59{width:59%}.column-60{width:60%}.column-61{width:61%}.column-62{width:62%}.column-63{width:63%}.column-64{width:64%}.column-65{width:65%}.column-66{width:66%}.column-67{width:67%}.column-68{width:68%}.column-69{width:69%}.column-70{width:70%}.column-71{width:71%}.column-72{width:72%}.column-73{width:73%}.column-74{width:74%}.column-75{width:75%}.column-76{width:76%}.column-77{width:77%}.column-78{width:78%}.column-79{width:79%}.column-80{width:80%}.column-81{width:81%}.column-82{width:82%}.column-83{width:83%}.column-84{width:84%}.column-85{width:85%}.column-86{width:86%}.column-87{width:87%}.column-88{width:88%}.column-89{width:89%}.column-90{width:90%}.column-91{width:91%}.column-92{width:92%}.column-93{width:93%}.column-94{width:94%}.column-95{width:95%}.column-96{width:96%}.column-97{width:97%}.column-98{width:98%}.column-99{width:99%}.column-100{width:100%}.draggable-row-handle{cursor:move;color:#dedede}.draggable-row-handle:hover{color:#333}tr.draggable-item-selected{background:#fff;border:2px solid #666;box-shadow:4px 2px 10px -4px rgba(0,0,0,0.55)}tr.draggable-item-selected td{border-top:none;border-bottom:none}tr.draggable-item-selected td:first-child{border-left:none}tr.draggable-item-selected td:last-child{border-right:none}.table-stripped tr.draggable-item-hover,.table-stripped tr.draggable-item-hover{background:#FEFFF2}form{margin-bottom:20px}label{cursor:pointer;display:block;margin-top:10px}input[type="number"],input[type="date"],input[type="email"],input[type="password"],input[type="text"]:not(.input-addon-field){color:#999;border:1px solid #ccc;width:300px;max-width:95%;font-size:1em;height:25px;padding-bottom:0;font-family:sans-serif;margin-top:10px;-webkit-appearance:none;-moz-appearance:none}input[type="number"]::-webkit-input-placeholder,input[type="date"]::-webkit-input-placeholder,input[type="email"]::-webkit-input-placeholder,input[type="password"]::-webkit-input-placeholder,input[type="text"]:not(.input-addon-field)::-webkit-input-placeholder{color:#dedede}input[type="number"]::-moz-placeholder,input[type="date"]::-moz-placeholder,input[type="email"]::-moz-placeholder,input[type="password"]::-moz-placeholder,input[type="text"]:not(.input-addon-field)::-moz-placeholder{color:#dedede}input[type="number"]:-ms-input-placeholder,input[type="date"]:-ms-input-placeholder,input[type="email"]:-ms-input-placeholder,input[type="password"]:-ms-input-placeholder,input[type="text"]:not(.input-addon-field):-ms-input-placeholder{color:#dedede}input[type="number"]:focus,input[type="date"]:focus,input[type="email"]:focus,input[type="password"]:focus,input[type="text"]:focus{color:#000;border-color:rgba(82,168,236,0.8);outline:0;box-shadow:0 0 8px rgba(82,168,236,0.6)}input[type="number"]{width:70px}input[type="text"]:not(.input-addon-field).form-numeric{width:70px}input[type="text"]:not(.input-addon-field).form-datetime,input[type="text"]:not(.input-addon-field).form-date{width:150px}input[type="text"]:not(.input-addon-field).form-input-large{width:400px}input[type="text"]:not(.input-addon-field).form-input-small{width:150px}textarea:focus{color:#000;border-color:rgba(82,168,236,0.8);outline:0;box-shadow:0 0 8px rgba(82,168,236,0.6)}textarea{padding:3px;border:1px solid #ccc;width:400px;max-width:99%;height:200px;font-family:sans-serif;font-size:1em}textarea::-webkit-input-placeholder{color:#dedede}textarea::-moz-placeholder{color:#dedede}textarea:-ms-input-placeholder{color:#dedede}select{font-size:1.0em;max-width:95%}select:focus{outline:0}select[multiple]{width:300px}.tag-autocomplete{width:400px}span.select2-container{margin-top:2px}.form-actions{padding-top:20px;clear:both}.form-required{color:red;padding-left:5px;font-weight:bold}@media (max-width: 480px){.form-required{display:none}}input.form-error,textarea.form-error{border:2px solid #b94a48}input.form-error:focus,textarea.form-error:focus{box-shadow:none;border:2px solid #b94a48}.form-errors{color:#b94a48;list-style-type:none}ul.form-errors li{margin-left:0}.form-help{font-size:0.8em;color:brown;margin-bottom:15px}.form-inline{padding:0;margin:0;border:none}.form-inline label{display:inline}.form-inline input,.form-inline select{margin:0 15px 0 0}.form-inline .form-required{display:none}.form-inline-group{display:inline}.form-columns{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row;-webkit-flex-wrap:wrap;flex-wrap:wrap;-webkit-justify-content:flex-start;justify-content:flex-start}.form-columns .form-column{margin-right:25px;flex-grow:1}.form-login{max-width:350px;margin:8% auto 0}.form-login li{margin-left:25px;line-height:25px}.form-login h2{margin-bottom:30px;font-weight:bold}.reset-password{margin-top:20px}.reset-password a{color:#999}.input-addon{display:flex}.input-addon-field{flex:1;font-size:1em;color:#999;margin:0;-webkit-appearance:none;-moz-appearance:none}.input-addon-item{background-color:rgba(147,128,108,0.1);color:#666;font:inherit;font-weight:normal}@media (max-width: 480px){.input-addon-item .dropdown .fa-caret-down{display:none}}.input-addon-field,.input-addon-item{border:1px solid rgba(147,128,108,0.25);padding:4px 0.75em}.input-addon-field:not(:first-child),.input-addon-item:not(:first-child){border-left:0}.input-addon-field:first-child,.input-addon-item:first-child{border-radius:5px 0 0 5px}.input-addon-field:last-child,.input-addon-item:last-child{border-radius:0 5px 5px 0}.alert{padding:8px 35px 8px 14px;margin-top:5px;margin-bottom:5px;color:#c09853;background-color:#fcf8e3;border:1px solid #fbeed5;border-radius:4px}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-error{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-normal{color:#333;background-color:#f0f0f0;border-color:#ddd}.alert ul{margin-top:10px;margin-bottom:10px}.alert li{margin-left:25px}.alert-fade-out{text-align:center;position:fixed;bottom:0;left:20%;width:60%;padding-top:5px;padding-bottom:5px;margin-bottom:0;border-width:1px 0 0;border-radius:4px 4px 0 0;z-index:9999}a.btn{text-decoration:none}.btn{-webkit-appearance:none;-moz-appearance:none;font-size:1.2em;font-weight:normal;cursor:pointer;display:inline-block;border-radius:2px;padding:3px 10px;margin:0;border:1px solid #ddd;background:#f5f5f5;color:#333}.btn:hover,.btn:focus{border-color:#bbb;background:#fafafa;color:#000}.btn-red{border-color:#b0281a;background:#d14836;color:#fff}.btn-red:hover,.btn-red:focus{border-color:#b0281a;background:#c53727;color:#fff}.btn-blue{border-color:#3079ed;background:#4d90fe;color:#fff}.btn-blue:hover,.btn-blue:focus{border-color:#3079ed;background:#357ae8;color:#fff}.btn:disabled{color:#ccc;border-color:#ccc;background:#f7f7f7}.buttons-header{font-size:0.8em;margin-top:5px;margin-bottom:15px}.tooltip-arrow:after{background:#fff;border:1px solid #aaaaaa;box-shadow:0 0 5px #aaa}div.ui-tooltip{min-width:200px;max-width:600px}.tooltip-arrow{width:20px;height:10px;overflow:hidden;position:absolute}.tooltip-arrow.top{top:-10px}.tooltip-arrow.bottom{bottom:-10px}.tooltip-arrow.align-left{left:10px}.tooltip-arrow.align-right{right:10px}.tooltip-arrow:after{content:"";position:absolute;width:14px;height:14px;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg)}.tooltip-arrow.bottom:after{top:-10px}.tooltip-arrow.top:after{bottom:-10px}.tooltip-arrow.align-left:after{left:0}.tooltip-arrow.align-right:after{right:0}.tooltip-large{width:600px}.ui-tooltip-content .markdown p{margin-bottom:0}.ui-tooltip li{list-style-type:none}.tooltip .fa-info-circle{color:#999}h2 .dropdown ul{display:none}.dropdown{display:inline;position:relative}.dropdown ul{display:none}ul.dropdown-submenu-open{display:block;position:absolute;z-index:1000;min-width:285px;list-style:none;margin:3px 0 0 1px;padding:6px 0;background-color:#fff;border:1px solid #b2b2b2;border-radius:3px;box-shadow:0 1px 3px rgba(0,0,0,0.15)}.dropdown-submenu-open li{display:block;margin:0;padding:8px 10px;font-size:0.9em;border-bottom:1px solid #f8f8f8;cursor:pointer}.dropdown-submenu-open li.no-hover{cursor:default}.dropdown-submenu-open li:last-child{border:none}.dropdown-submenu-open li:not(.no-hover):hover{background:#4078C0;color:#fff}.dropdown-submenu-open li:hover a{color:#fff}.dropdown-submenu-open a{text-decoration:none;color:#333}.dropdown-submenu-open a:focus{text-decoration:underline}.dropdown-menu-link-text,.dropdown-menu-link-icon{color:#333;text-decoration:none}.dropdown-menu-link-text:hover{text-decoration:underline}.accordion-title{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAADCAYAAABS3WWCAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NEQ5RDgxQzc2RjQ5MTFFMjhEMUNENzFGRUMwRjhBRTciIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NEQ5RDgxQzg2RjQ5MTFFMjhEMUNENzFGRUMwRjhBRTciPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo0RDlEODFDNTZGNDkxMUUyOEQxQ0Q3MUZFQzBGOEFFNyIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo0RDlEODFDNjZGNDkxMUUyOEQxQ0Q3MUZFQzBGOEFFNyIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PvXFWFAAAAAYSURBVHjaYvj//z8D0/Pnz/8zgFgAAQYAS5UJscReGMIAAAAASUVORK5CYII=) repeat-x scroll 0 10px}.accordion-title h3{display:inline;padding-right:5px;background:#fff}.accordion-content{margin-top:15px;margin-bottom:25px}.accordion-toggle{color:#333;text-decoration:none}.accordion-toggle:focus{color:#333}.accordion-toggle:hover{color:#999}.accordion-toggle:before{content:"\f0d7"}.accordion-collapsed{margin-bottom:25px}.accordion-collapsed .accordion-toggle:before{content:"\f0da"}.accordion-collapsed .accordion-content{display:none}#main .confirm{max-width:700px}#popover-container{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.9);overflow:auto;z-index:100}#popover-content{position:fixed;width:950px;max-width:95%;max-height:calc(100% - 50px);top:5%;left:50%;transform:translateX(-50%);padding:0 15px 15px;background:#fff;overflow:auto}#popover-content-header{text-align:right}#popover-close-button{color:#333}#popover-close-button:hover{color:#b94a48}.popover-form{margin-bottom:0}.pagination{text-align:center}.pagination-next{margin-left:5px}.pagination-previous{margin-right:5px}header{box-sizing:border-box;display:flex;flex-wrap:wrap;margin-top:5px;margin-bottom:5px;border-bottom:1px solid #dedede}header>*{box-sizing:border-box}header>*{width:1%}header .menus-container{width:10%}@media (min-width: 768px) and (max-width: 1150px){header .menus-container{width:15%}}@media (max-width: 768px){header .menus-container{width:65%;order:2}}header .board-selector-container{width:15%}@media (min-width: 768px) and (max-width: 1150px){header .board-selector-container{width:20%}}@media (max-width: 768px){header .board-selector-container{width:35%;order:1;margin-bottom:5px}}header .title-container{width:75%}@media (min-width: 768px) and (max-width: 1150px){header .title-container{width:65%}}@media (max-width: 768px){header .title-container{width:100%;order:3}}header h1{font-size:1.5em}header h1 .tooltip{opacity:0.3;font-size:0.7em}.web-notification-icon{color:#36c}.web-notification-icon:focus,.web-notification-icon:hover{color:#000}.logo a{opacity:0.5;color:#d40000;text-decoration:none}.logo span{color:#333}.logo a:hover{opacity:0.8;color:#333}.logo a:focus span,.logo a:hover span{color:#d40000}.page-header{margin-bottom:20px}.page-header .dropdown{padding-right:10px}.page-header h2{margin:0;padding:0;font-weight:bold;border-bottom:1px dotted #ccc}.page-header h2 a{color:#333;text-decoration:none}.page-header h2 a:focus,.page-header h2 a:hover{color:#999}.page-header ul{text-align:left;margin-top:5px;display:inline-block}.page-header li{display:inline;padding-right:15px}@media (max-width: 480px){.page-header li{display:block;line-height:1.5em}}.page-header li.active a{color:#333;text-decoration:none;font-weight:bold}.page-header li.active a:hover,.page-header li.active a:focus{text-decoration:underline}.menu-inline{margin-bottom:5px}.menu-inline li{display:inline;padding-right:15px}.menu-inline li .active a{font-weight:bold;color:#000;text-decoration:none}.sidebar-container{box-sizing:border-box;display:flex;flex-wrap:wrap}.sidebar-container>*{box-sizing:border-box}.sidebar-container>*{width:1%}.sidebar-content{padding-left:10px;width:82%}@media (max-width: 480px){.sidebar-content{width:100%}}.sidebar{max-width:240px;min-width:190px;width:18%}@media (max-width: 480px){.sidebar{width:100%;max-width:99%;min-width:0}}.sidebar h2{margin-top:0}.sidebar>ul a{text-decoration:none;color:#999;font-weight:300}.sidebar>ul a:hover{color:#333}.sidebar>ul li{list-style-type:none;line-height:35px;border-bottom:1px dotted #efefef;padding-left:13px}.sidebar>ul li:hover{border-left:5px solid #555;padding-left:8px}.sidebar>ul li.active{border-left:5px solid #333;padding-left:8px}.sidebar>ul li.active a{color:#333;font-weight:bold}.sidebar-icons>ul li{padding-left:0}.sidebar-icons>ul li:hover,.sidebar-icons>ul li.active{padding-left:0;border-left:none}.sidebar>ul li.active a:focus,.sidebar>ul li.active a:hover{color:#555}.sidebar>ul li:last-child{margin-bottom:15px}.avatar img{vertical-align:bottom}.avatar-left{float:left;margin-right:10px}.avatar-inline{display:inline-block;margin-right:3px}.avatar-48 img,.avatar-48 div{border-radius:30px}.avatar-48 .avatar-letter{line-height:48px;width:48px;font-size:25px}.avatar-20 img,.avatar-20 div{border-radius:10px}.avatar-20 .avatar-letter{line-height:20px;width:20px;font-size:11px}.avatar-letter{color:#fff;text-align:center}#file-dropzone,#screenshot-zone{position:relative;border:2px dashed #ccc;width:99%;height:250px;overflow:auto}#file-dropzone-inner,#screenshot-inner{position:absolute;left:0;bottom:48%;width:100%;text-align:center;color:#aaa}#screenshot-zone.screenshot-pasted{border:2px solid #333}#file-list{margin:20px}#file-list li{list-style-type:none;padding-top:8px;padding-bottom:8px;border-bottom:1px dotted #ddd;width:95%}#file-list li.file-error{font-weight:bold;color:#b94a48}.file-thumbnails{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row;-webkit-flex-wrap:wrap;flex-wrap:wrap;-webkit-justify-content:flex-start;justify-content:flex-start}.file-thumbnail{width:250px;border:1px solid #efefef;border-radius:5px;margin-bottom:20px;box-shadow:4px 2px 10px -6px rgba(0,0,0,0.55);margin-right:15px}.file-thumbnail img{border-top-left-radius:5px;border-top-right-radius:5px}.file-thumbnail img:hover{opacity:0.5}.file-thumbnail-content{padding-left:8px;padding-right:8px}.file-thumbnail-title{font-weight:700;font-size:0.9em;color:#555}.file-thumbnail-description{font-size:0.8em;color:#999;margin-top:8px;margin-bottom:5px}.file-viewer{position:relative}.file-viewer img{max-width:95%;max-height:85%;margin-top:10px}.color-picker{width:180px}.color-picker-option{height:25px}.color-picker-square{display:inline-block;width:18px;height:18px;margin-right:5px;border:1px solid #000}.color-picker-label{display:inline-block;vertical-align:bottom;padding-bottom:3px}.filter-box{max-width:800px}.action-menu{color:#333;text-decoration:none}.action-menu:hover,.action-menu:focus{text-decoration:underline}.project-creation-options{max-width:500px;border-left:3px dotted #efefef;margin-top:20px;padding-left:15px;padding-bottom:5px;padding-top:5px}.project-overview-columns{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row;-webkit-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;align-items:center;-webkit-justify-content:center;justify-content:center;margin-bottom:20px;font-size:1.4em}@media (max-width: 480px){.project-overview-columns{display:block}}.project-overview-column{text-align:center;margin-right:3%;margin-top:5px;padding:3px 15px 3px 15px;border:1px dashed #ddd}@media (max-width: 480px){.project-overview-column{text-align:left}}.project-overview-column small{color:#999}.project-overview-column strong{color:#555;display:block}@media (max-width: 480px){.project-overview-column strong{display:inline}}.project-header{box-sizing:border-box;display:flex;flex-wrap:wrap;margin-bottom:8px}.project-header>*{box-sizing:border-box}.project-header>*{width:1%}.project-header .dropdown-component{margin-top:4px;width:5%}@media (min-width: 768px) and (max-width: 1150px){.project-header .dropdown-component{width:8%}}@media (max-width: 768px){.project-header .dropdown-component{width:100%}}.project-header .views-switcher-component{margin-top:4px;width:38%}@media (max-width: 1300px){.project-header .views-switcher-component{width:45%}}@media (min-width: 768px) and (max-width: 1150px){.project-header .views-switcher-component{width:92%}}@media (max-width: 768px){.project-header .views-switcher-component{margin-top:0;width:100%}}.project-header .filter-box-component{margin:0;width:55%}@media (max-width: 1300px){.project-header .filter-box-component{width:50%}}@media (min-width: 768px) and (max-width: 1150px){.project-header .filter-box-component{width:100%;margin-top:10px}.project-header .filter-box-component .filter-box{max-width:100%}}@media (max-width: 768px){.project-header .filter-box-component{width:100%;margin-top:10px}.project-header .filter-box-component .filter-box{max-width:100%}}.project-header .filter-box-component form{margin:0}.views{display:inline-block;margin-right:10px;font-size:0.9em}@media (max-width: 560px){.views{width:100%}}@media (max-width: 768px){.views{margin-top:10px;font-size:1em}}@media (max-width: 480px){.views{margin-top:5px}}.views li{white-space:nowrap;background:#fafafa;border:1px solid #ddd;border-right:none;padding:4px 8px;display:inline}@media (max-width: 560px){.views li{display:block;margin-top:5px;border-radius:5px;border:1px solid #ddd}}.views li.active a{font-weight:bold;color:#000;text-decoration:none}.views li:first-child{border-top-left-radius:5px;border-bottom-left-radius:5px}.views li:last-child{border-right:1px solid #ddd;border-top-right-radius:5px;border-bottom-right-radius:5px}.views a{color:#555;text-decoration:none}.views a:hover{color:#333;text-decoration:underline}.dashboard-project-stats small{margin-right:10px;color:#999}.dashboard-table-link{font-weight:bold;color:#000;text-decoration:none}.dashboard-table-link:focus,.dashboard-table-link:hover{color:#999}.public-board{margin-top:5px}.public-task{max-width:800px;margin:5px auto 0}#board-container{overflow-x:auto}#board{table-layout:fixed;margin-bottom:0}#board th.board-column-header{width:240px}#board td{vertical-align:top}.board-container-compact{overflow-x:initial}@media all and (-ms-high-contrast: active), (-ms-high-contrast: none){.board-container-compact #board{table-layout:auto}}#board th.board-column-header.board-column-compact{width:initial}.board-column-collapsed{display:none}td.board-column-task-collapsed{font-weight:bold;background-color:#fbfbfb}#board th.board-column-header-collapsed{width:28px;min-width:28px;text-align:center;overflow:hidden}.board-rotation-wrapper{position:relative;padding:8px 4px;min-height:150px;overflow:hidden}.board-rotation{white-space:nowrap;-webkit-backface-visibility:hidden;-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg);-webkit-transform-origin:0 100%;-moz-transform-origin:0 100%;-ms-transform-origin:0 100%;transform-origin:0 100%}.board-column-title .dropdown-menu{text-decoration:none}.board-add-icon{float:left;padding:0 5px}.board-add-icon a{text-decoration:none;color:#36c;font-size:1.6em;line-height:70%}.board-add-icon a:focus,.board-add-icon a:hover{text-decoration:none;color:red}.board-column-header-task-count{color:#999;font-weight:normal}a.board-swimlane-toggle{text-decoration:none}a.board-swimlane-toggle:hover,a.board-swimlane-toggle:focus{color:#000;text-decoration:none;border:none}.board-task-list{min-height:60px}.board-task-list-limit{background-color:#DF5353}.draggable-item{cursor:pointer;user-select:none;-webkit-user-select:none;-moz-user-select:none}.draggable-placeholder{border:2px dashed #000;background:#fafafa;height:70px;margin-bottom:10px}div.draggable-item-selected{border:1px solid #000}.task-board-sort-handle{float:left;padding-right:5px}.task-board{position:relative;margin-bottom:4px;border:1px solid #000;padding:2px;word-wrap:break-word;font-size:0.9em}div.task-board-recent{border-width:2px}div.task-board-status-closed{user-select:none;border:1px dotted #555}.task-board a{color:#000;text-decoration:none}.task-board .dropdown-menu{font-weight:bold}.task-board .task-score{font-weight:bold}.task-board-collapsed{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.task-board-title{margin-top:5px;margin-bottom:8px}.task-board-title a:hover{text-decoration:underline}.task-board-saving-state{opacity:0.3}.task-board-saving-icon{position:absolute;margin:auto;width:100%;text-align:center;color:#000}.task-board-category-container{text-align:right;margin-top:8px;margin-bottom:8px}.task-board-category{font-weight:500;color:#000;border:1px solid #555;padding:1px 2px 1px 2px;border-radius:4px}.task-board-category:hover{opacity:0.6}.task-board-avatars{text-align:right;float:right}.task-board-change-assignee{cursor:pointer}.task-board-change-assignee:hover{opacity:0.6}.task-board-icons{font-size:0.8em;text-align:right;margin-top:4px;margin-bottom:2px}.task-board-icons a{opacity:0.5}.task-board-icons span{opacity:0.5;margin-left:2px}.task-board-icons a:hover,.task-board-icons span:hover{opacity:1.0}.flag-milestone{color:green}.task-board-age{display:inline-block}span.task-board-age-total{border:#666 1px solid;padding:1px 3px 1px 3px;border-top-left-radius:3px;border-bottom-left-radius:3px}span.task-board-age-column{border:#666 1px solid;border-left:none;margin-left:-5px;padding:1px 3px 1px 3px;border-top-right-radius:3px;border-bottom-right-radius:3px}.task-board-date{font-weight:bold;color:#000}span.task-board-date-today{opacity:1.0;color:#36c}span.task-board-date-overdue{opacity:1.0;color:#b94a48}.task-tags li{display:inline-block;margin:3px 3px 0 0;padding:1px 3px 1px 3px;color:#333;border:1px solid #333;border-radius:4px}.task-summary-container .task-tags{margin-top:10px}#task-summary{margin-bottom:15px}#task-summary h2{color:#555;font-size:1.6em;margin-top:0;padding-top:0}.task-summary-container{border:2px solid #000;border-radius:8px;padding:15px}.task-summary-columns{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row;-webkit-justify-content:space-between;justify-content:space-between}@media (max-width: 480px){.task-summary-columns{display:block}}.task-summary-column{color:#333}.task-summary-column span{color:#555}.task-summary-column li{line-height:23px}#external-task-view{padding:10px;margin-top:10px;margin-bottom:10px;border:1px dotted #ccc}.task-table .dropdown-menu{color:#000;text-decoration:none;font-weight:bold}.task-table .dropdown-menu:focus,.task-table .dropdown-menu:hover{text-decoration:underline}td.task-table a{color:#000;text-decoration:none}td.task-table a:hover{text-decoration:underline}.comment-sorting{text-align:right}.comment-sorting a{color:#555;font-weight:normal;text-decoration:none}.comment-sorting a:hover{color:#999}.comment{padding:5px;margin-bottom:15px}.comment:hover{background:#fafafa}.comment-title{border-bottom:1px dotted #eee;margin-left:55px;margin-bottom:10px}.comment-date{color:#999;font-weight:200}.comment-actions{font-size:0.8em;margin-left:55px;margin-top:8px}.comment-actions li{display:inline}.comment-actions a{color:#999;text-decoration:none}.comment-actions a:focus,.comment-actions a:hover{color:#333;text-decoration:underline}.comment-content{margin-left:55px}.subtasks-table td{vertical-align:middle}.task-links-table td{vertical-align:middle}.task-links-task-count{color:#999}.task-link-closed{text-decoration:line-through}.text-editor a{font-size:1em;color:#999;text-decoration:none;margin-right:10px}.text-editor a:hover{color:#36c}.text-editor .text-editor-preview-area{border:1px solid #dedede;width:400px;height:200px;overflow:auto;padding:2px}.markdown{line-height:1.4em}.markdown h1{margin-top:5px;margin-bottom:10px;font-weight:bold}.markdown h2{font-weight:bold}.markdown p{margin-bottom:10px}.markdown ol,.markdown ul{margin-left:25px;margin-top:10px;margin-bottom:10px}.markdown pre{background:#fbfbfb;padding:10px;border-radius:5px;border:1px solid #ddd;overflow:auto;color:#555}.markdown blockquote{font-style:italic;border-left:3px solid #ddd;padding-left:10px;margin-bottom:10px;margin-left:20px}.markdown img{display:block;max-width:80%;margin-top:10px}.documentation{margin:0 auto;padding:20px;max-width:850px;background:#fefefe;border:1px solid #ccc;border-radius:5px;color:#555}.documentation img{border:1px solid #333}.documentation h1{text-decoration:none;margin-bottom:30px}.documentation h2{text-decoration:none;border-bottom:1px solid #ccc;margin-bottom:25px}.documentation li{line-height:30px}.listing{border-radius:4px;padding:8px 35px 8px 14px;margin-bottom:20px;border:1px solid #ddd;color:#333;background-color:#fcfcfc;overflow:auto}.listing li{list-style-type:square;margin-left:20px;margin-bottom:3px}.listing ul{margin-top:15px;margin-bottom:15px}.activity-event{margin-bottom:15px;padding:10px}.activity-event:hover{background:#fafafa}.activity-date{margin-left:10px;font-weight:normal;color:#999}.activity-content{margin-left:55px}.activity-title{font-weight:bold;color:#000;border-bottom:1px dotted #efefef}.activity-description{color:#555;margin-top:10px}@media (max-width: 480px){.activity-description{overflow:auto}}.activity-description li{list-style-type:circle}.activity-description ul{margin-top:10px;margin-left:20px}div.ganttview-hzheader-month,div.ganttview-hzheader-day,div.ganttview-vtheader,div.ganttview-vtheader-item-name,div.ganttview-vtheader-series,div.ganttview-grid,div.ganttview-grid-row-cell{float:left}div.ganttview-hzheader-month,div.ganttview-hzheader-day{text-align:center}div.ganttview-grid-row-cell.last,div.ganttview-hzheader-day.last,div.ganttview-hzheader-month.last{border-right:none}div.ganttview{border:1px solid #999}div.ganttview-hzheader-month{width:60px;height:20px;border-right:1px solid #d0d0d0;line-height:20px;overflow:hidden}div.ganttview-hzheader-day{width:20px;height:20px;border-right:1px solid #f0f0f0;border-top:1px solid #d0d0d0;line-height:20px;color:#555}div.ganttview-vtheader{margin-top:41px;width:400px;overflow:hidden;background-color:#fff}div.ganttview-vtheader-item{color:#555}div.ganttview-vtheader-series-name{width:400px;height:31px;line-height:31px;padding-left:3px;border-top:1px solid #d0d0d0;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}div.ganttview-vtheader-series-name a{color:#555;text-decoration:none}div.ganttview-vtheader-series-name a:hover{color:#333;text-decoration:underline}div.ganttview-vtheader-series-name a i{color:#000}div.ganttview-vtheader-series-name a:hover i{color:#555}div.ganttview-slide-container{overflow:auto;border-left:1px solid #999}div.ganttview-grid-row-cell{width:20px;height:31px;border-right:1px solid #f0f0f0;border-top:1px solid #f0f0f0}div.ganttview-grid-row-cell.ganttview-weekend{background-color:#fafafa}div.ganttview-blocks{margin-top:40px}div.ganttview-block-container{height:28px;padding-top:4px}div.ganttview-block{position:relative;height:25px;background-color:#E5ECF9;border:1px solid #c0c0c0;border-radius:3px}.ganttview-block-movable{cursor:move}div.ganttview-block-not-defined{border-color:#000;background-color:#000}div.ganttview-block-text{position:absolute;height:12px;font-size:0.7em;color:#999;padding:2px 3px}div.ganttview-block div.ui-resizable-handle.ui-resizable-s{bottom:-0}.user-mention-link{font-weight:bold;color:#000;text-decoration:none}.user-mention-link:hover{color:#555}
+h1,li,ul,ol,table,tr,td,th,p,blockquote,body{margin:0;padding:0;font-size:100%}body{margin-left:10px;margin-right:10px;padding-bottom:10px;color:#333;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;text-rendering:optimizeLegibility}small{font-size:0.8em}hr{border:0;height:0;border-top:1px solid rgba(0,0,0,0.1);border-bottom:1px solid rgba(255,255,255,0.3)}.pull-right{text-align:right}ul.no-bullet li{list-style-type:none;margin-left:0}.chosen-select{min-height:27px}#app-loading-icon{position:fixed;right:3px;bottom:3px}.assign-me{vertical-align:bottom}a{color:#36c;border:none}a:focus{outline:0;color:#DF5353;text-decoration:none}a:hover{color:#333;text-decoration:none}h1,h2,h3{font-weight:normal;color:#333}h1{font-size:1.5em}h2{font-size:1.4em;margin-bottom:10px}h3{margin-top:10px;font-size:1.2em}table{width:100%;border-collapse:collapse;border-spacing:0;margin-bottom:20px}table.table-fixed{table-layout:fixed;white-space:nowrap}table.table-fixed th{overflow:hidden}table.table-fixed td{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}table.table-small{font-size:0.8em}table.table-striped tr:nth-child(odd){background:#fefefe}@media (max-width: 768px){table.table-scrolling{overflow-x:auto;display:inline-block;vertical-align:top;max-width:100%;white-space:nowrap}}table th{text-align:left;padding:0.5em 3px;border:1px solid #eee;background:#fbfbfb}table th a{text-decoration:none;color:#333}table th a:focus,table th a:hover{text-decoration:underline}table td{border:1px solid #eee;padding:0.5em 3px;vertical-align:top}table td li{margin-left:20px}.column-1{width:1%}.column-2{width:2%}.column-3{width:3%}.column-4{width:4%}.column-5{width:5%}.column-6{width:6%}.column-7{width:7%}.column-8{width:8%}.column-9{width:9%}.column-10{width:10%}.column-11{width:11%}.column-12{width:12%}.column-13{width:13%}.column-14{width:14%}.column-15{width:15%}.column-16{width:16%}.column-17{width:17%}.column-18{width:18%}.column-19{width:19%}.column-20{width:20%}.column-21{width:21%}.column-22{width:22%}.column-23{width:23%}.column-24{width:24%}.column-25{width:25%}.column-26{width:26%}.column-27{width:27%}.column-28{width:28%}.column-29{width:29%}.column-30{width:30%}.column-31{width:31%}.column-32{width:32%}.column-33{width:33%}.column-34{width:34%}.column-35{width:35%}.column-36{width:36%}.column-37{width:37%}.column-38{width:38%}.column-39{width:39%}.column-40{width:40%}.column-41{width:41%}.column-42{width:42%}.column-43{width:43%}.column-44{width:44%}.column-45{width:45%}.column-46{width:46%}.column-47{width:47%}.column-48{width:48%}.column-49{width:49%}.column-50{width:50%}.column-51{width:51%}.column-52{width:52%}.column-53{width:53%}.column-54{width:54%}.column-55{width:55%}.column-56{width:56%}.column-57{width:57%}.column-58{width:58%}.column-59{width:59%}.column-60{width:60%}.column-61{width:61%}.column-62{width:62%}.column-63{width:63%}.column-64{width:64%}.column-65{width:65%}.column-66{width:66%}.column-67{width:67%}.column-68{width:68%}.column-69{width:69%}.column-70{width:70%}.column-71{width:71%}.column-72{width:72%}.column-73{width:73%}.column-74{width:74%}.column-75{width:75%}.column-76{width:76%}.column-77{width:77%}.column-78{width:78%}.column-79{width:79%}.column-80{width:80%}.column-81{width:81%}.column-82{width:82%}.column-83{width:83%}.column-84{width:84%}.column-85{width:85%}.column-86{width:86%}.column-87{width:87%}.column-88{width:88%}.column-89{width:89%}.column-90{width:90%}.column-91{width:91%}.column-92{width:92%}.column-93{width:93%}.column-94{width:94%}.column-95{width:95%}.column-96{width:96%}.column-97{width:97%}.column-98{width:98%}.column-99{width:99%}.column-100{width:100%}.draggable-row-handle{cursor:move;color:#dedede}.draggable-row-handle:hover{color:#333}tr.draggable-item-selected{background:#fff;border:2px solid #666;box-shadow:4px 2px 10px -4px rgba(0,0,0,0.55)}tr.draggable-item-selected td{border-top:none;border-bottom:none}tr.draggable-item-selected td:first-child{border-left:none}tr.draggable-item-selected td:last-child{border-right:none}.table-stripped tr.draggable-item-hover,.table-stripped tr.draggable-item-hover{background:#FEFFF2}form{margin-bottom:20px}label{cursor:pointer;display:block;margin-top:10px}input[type="number"],input[type="date"],input[type="email"],input[type="password"],input[type="text"]:not(.input-addon-field){color:#999;border:1px solid #ccc;width:300px;max-width:95%;font-size:1em;height:25px;padding-bottom:0;font-family:sans-serif;margin-top:10px;-webkit-appearance:none;-moz-appearance:none}input[type="number"]::-webkit-input-placeholder,input[type="date"]::-webkit-input-placeholder,input[type="email"]::-webkit-input-placeholder,input[type="password"]::-webkit-input-placeholder,input[type="text"]:not(.input-addon-field)::-webkit-input-placeholder{color:#dedede}input[type="number"]::-moz-placeholder,input[type="date"]::-moz-placeholder,input[type="email"]::-moz-placeholder,input[type="password"]::-moz-placeholder,input[type="text"]:not(.input-addon-field)::-moz-placeholder{color:#dedede}input[type="number"]:-ms-input-placeholder,input[type="date"]:-ms-input-placeholder,input[type="email"]:-ms-input-placeholder,input[type="password"]:-ms-input-placeholder,input[type="text"]:not(.input-addon-field):-ms-input-placeholder{color:#dedede}input[type="number"]:focus,input[type="date"]:focus,input[type="email"]:focus,input[type="password"]:focus,input[type="text"]:focus{color:#000;border-color:rgba(82,168,236,0.8);outline:0;box-shadow:0 0 8px rgba(82,168,236,0.6)}input[type="number"]{width:70px}input[type="text"]:not(.input-addon-field).form-numeric{width:70px}input[type="text"]:not(.input-addon-field).form-datetime,input[type="text"]:not(.input-addon-field).form-date{width:150px}input[type="text"]:not(.input-addon-field).form-input-large{width:400px}input[type="text"]:not(.input-addon-field).form-input-small{width:150px}textarea:focus{color:#000;border-color:rgba(82,168,236,0.8);outline:0;box-shadow:0 0 8px rgba(82,168,236,0.6)}textarea{padding:3px;border:1px solid #ccc;width:400px;max-width:99%;height:200px;font-family:sans-serif;font-size:1em}textarea::-webkit-input-placeholder{color:#dedede}textarea::-moz-placeholder{color:#dedede}textarea:-ms-input-placeholder{color:#dedede}select{font-size:1.0em;max-width:95%}select:focus{outline:0}select[multiple]{width:300px}.tag-autocomplete{width:400px}span.select2-container{margin-top:2px}.form-actions{padding-top:20px;clear:both}.form-required{color:red;padding-left:5px;font-weight:bold}@media (max-width: 480px){.form-required{display:none}}input.form-error,textarea.form-error{border:2px solid #b94a48}input.form-error:focus,textarea.form-error:focus{box-shadow:none;border:2px solid #b94a48}.form-errors{color:#b94a48;list-style-type:none}ul.form-errors li{margin-left:0}.form-help{font-size:0.8em;color:brown;margin-bottom:15px}.form-inline{padding:0;margin:0;border:none}.form-inline label{display:inline}.form-inline input,.form-inline select{margin:0 15px 0 0}.form-inline .form-required{display:none}.form-inline-group{display:inline}.form-columns{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row;-webkit-flex-wrap:wrap;flex-wrap:wrap;-webkit-justify-content:flex-start;justify-content:flex-start}.form-columns .form-column{margin-right:25px;flex-grow:1}.form-login{max-width:350px;margin:8% auto 0}.form-login li{margin-left:25px;line-height:25px}.form-login h2{margin-bottom:30px;font-weight:bold}.reset-password{margin-top:20px}.reset-password a{color:#999}.input-addon{display:flex}.input-addon-field{flex:1;font-size:1em;color:#999;margin:0;-webkit-appearance:none;-moz-appearance:none}.input-addon-item{background-color:rgba(147,128,108,0.1);color:#666;font:inherit;font-weight:normal}@media (max-width: 480px){.input-addon-item .dropdown .fa-caret-down{display:none}}.input-addon-field,.input-addon-item{border:1px solid rgba(147,128,108,0.25);padding:4px 0.75em}.input-addon-field:not(:first-child),.input-addon-item:not(:first-child){border-left:0}.input-addon-field:first-child,.input-addon-item:first-child{border-radius:5px 0 0 5px}.input-addon-field:last-child,.input-addon-item:last-child{border-radius:0 5px 5px 0}.alert{padding:8px 35px 8px 14px;margin-top:5px;margin-bottom:5px;color:#c09853;background-color:#fcf8e3;border:1px solid #fbeed5;border-radius:4px}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-error{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-normal{color:#333;background-color:#f0f0f0;border-color:#ddd}.alert ul{margin-top:10px;margin-bottom:10px}.alert li{margin-left:25px}.alert-fade-out{text-align:center;position:fixed;bottom:0;left:20%;width:60%;padding-top:5px;padding-bottom:5px;margin-bottom:0;border-width:1px 0 0;border-radius:4px 4px 0 0;z-index:9999;opacity:1;animation:fadeout 5s linear forwards}@keyframes fadeout{0%{opacity:1}100%{opacity:0}}a.btn{text-decoration:none}.btn{-webkit-appearance:none;-moz-appearance:none;font-size:1.2em;font-weight:normal;cursor:pointer;display:inline-block;border-radius:2px;padding:3px 10px;margin:0;border:1px solid #ddd;background:#f5f5f5;color:#333}.btn:hover,.btn:focus{border-color:#bbb;background:#fafafa;color:#000}.btn-red{border-color:#b0281a;background:#d14836;color:#fff}.btn-red:hover,.btn-red:focus{border-color:#b0281a;background:#c53727;color:#fff}.btn-blue{border-color:#3079ed;background:#4d90fe;color:#fff}.btn-blue:hover,.btn-blue:focus{border-color:#3079ed;background:#357ae8;color:#fff}.btn:disabled{color:#ccc;border-color:#ccc;background:#f7f7f7}.buttons-header{font-size:0.8em;margin-top:5px;margin-bottom:15px}.tooltip-arrow:after{background:#fff;border:1px solid #aaaaaa;box-shadow:0 0 5px #aaa}div.ui-tooltip{min-width:200px;max-width:600px}.tooltip-arrow{width:20px;height:10px;overflow:hidden;position:absolute}.tooltip-arrow.top{top:-10px}.tooltip-arrow.bottom{bottom:-10px}.tooltip-arrow.align-left{left:10px}.tooltip-arrow.align-right{right:10px}.tooltip-arrow:after{content:"";position:absolute;width:14px;height:14px;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg)}.tooltip-arrow.bottom:after{top:-10px}.tooltip-arrow.top:after{bottom:-10px}.tooltip-arrow.align-left:after{left:0}.tooltip-arrow.align-right:after{right:0}.tooltip-large{width:600px}.ui-tooltip-content .markdown p{margin-bottom:0}.ui-tooltip li{list-style-type:none}.tooltip .fa-info-circle{color:#999}h2 .dropdown ul{display:none}.dropdown{display:inline;position:relative}.dropdown ul{display:none}ul.dropdown-submenu-open{display:block;position:absolute;z-index:1000;min-width:285px;list-style:none;margin:3px 0 0 1px;padding:6px 0;background-color:#fff;border:1px solid #b2b2b2;border-radius:3px;box-shadow:0 1px 3px rgba(0,0,0,0.15)}.dropdown-submenu-open li{display:block;margin:0;padding:8px 10px;font-size:0.9em;border-bottom:1px solid #f8f8f8;cursor:pointer}.dropdown-submenu-open li.no-hover{cursor:default}.dropdown-submenu-open li:last-child{border:none}.dropdown-submenu-open li:not(.no-hover):hover{background:#4078C0;color:#fff}.dropdown-submenu-open li:hover a{color:#fff}.dropdown-submenu-open a{text-decoration:none;color:#333}.dropdown-submenu-open a:focus{text-decoration:underline}.dropdown-menu-link-text,.dropdown-menu-link-icon{color:#333;text-decoration:none}.dropdown-menu-link-text:hover{text-decoration:underline}.accordion-title{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAADCAYAAABS3WWCAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NEQ5RDgxQzc2RjQ5MTFFMjhEMUNENzFGRUMwRjhBRTciIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NEQ5RDgxQzg2RjQ5MTFFMjhEMUNENzFGRUMwRjhBRTciPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo0RDlEODFDNTZGNDkxMUUyOEQxQ0Q3MUZFQzBGOEFFNyIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo0RDlEODFDNjZGNDkxMUUyOEQxQ0Q3MUZFQzBGOEFFNyIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PvXFWFAAAAAYSURBVHjaYvj//z8D0/Pnz/8zgFgAAQYAS5UJscReGMIAAAAASUVORK5CYII=) repeat-x scroll 0 10px}.accordion-title h3{display:inline;padding-right:5px;background:#fff}.accordion-content{margin-top:15px;margin-bottom:25px}.accordion-toggle{color:#333;text-decoration:none}.accordion-toggle:focus{color:#333}.accordion-toggle:hover{color:#999}.accordion-toggle:before{content:"\f0d7"}.accordion-collapsed{margin-bottom:25px}.accordion-collapsed .accordion-toggle:before{content:"\f0da"}.accordion-collapsed .accordion-content{display:none}#suggest-menu{position:absolute;display:block;z-index:1000;min-width:160px;padding:5px 0;background:#fff;list-style:none;border:1px solid #ccc;border-radius:3px;box-shadow:0 6px 12px rgba(0,0,0,0.175)}.suggest-menu-item{white-space:nowrap;padding:3px 10px;color:#333;font-weight:bold;cursor:pointer}.suggest-menu-item.active{color:#fff;background:#428bca}.suggest-menu-item.active small{color:#fff}.suggest-menu-item small{color:#999;font-weight:normal}#main .confirm{max-width:700px}#popover-container{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.9);overflow:auto;z-index:100}#popover-content{position:fixed;width:950px;max-width:95%;max-height:calc(100% - 50px);top:5%;left:50%;transform:translateX(-50%);padding:0 15px 15px;background:#fff;overflow:auto}#popover-content-header{text-align:right}#popover-close-button{color:#333}#popover-close-button:hover{color:#b94a48}.popover-form{margin-bottom:0}.pagination{text-align:center}.pagination-next{margin-left:5px}.pagination-previous{margin-right:5px}header{box-sizing:border-box;display:flex;flex-wrap:wrap;margin-top:5px;margin-bottom:5px;border-bottom:1px solid #dedede}header>*{box-sizing:border-box}header>*{width:1%}header .menus-container{width:10%}@media (min-width: 768px) and (max-width: 1150px){header .menus-container{width:15%}}@media (max-width: 768px){header .menus-container{width:65%;order:2}}header .board-selector-container{width:15%}@media (min-width: 768px) and (max-width: 1150px){header .board-selector-container{width:20%}}@media (max-width: 768px){header .board-selector-container{width:35%;order:1;margin-bottom:5px}}header .title-container{width:75%}@media (min-width: 768px) and (max-width: 1150px){header .title-container{width:65%}}@media (max-width: 768px){header .title-container{width:100%;order:3}}header h1{font-size:1.5em}header h1 .tooltip{opacity:0.3;font-size:0.7em}.web-notification-icon{color:#36c}.web-notification-icon:focus,.web-notification-icon:hover{color:#000}.logo a{opacity:0.5;color:#d40000;text-decoration:none}.logo span{color:#333}.logo a:hover{opacity:0.8;color:#333}.logo a:focus span,.logo a:hover span{color:#d40000}.page-header{margin-bottom:20px}.page-header .dropdown{padding-right:10px}.page-header h2{margin:0;padding:0;font-weight:bold;border-bottom:1px dotted #ccc}.page-header h2 a{color:#333;text-decoration:none}.page-header h2 a:focus,.page-header h2 a:hover{color:#999}.page-header ul{text-align:left;margin-top:5px;display:inline-block}.page-header li{display:inline;padding-right:15px}@media (max-width: 480px){.page-header li{display:block;line-height:1.5em}}.page-header li.active a{color:#333;text-decoration:none;font-weight:bold}.page-header li.active a:hover,.page-header li.active a:focus{text-decoration:underline}.menu-inline{margin-bottom:5px}.menu-inline li{display:inline;padding-right:15px}.menu-inline li .active a{font-weight:bold;color:#000;text-decoration:none}.sidebar-container{box-sizing:border-box;display:flex;flex-wrap:wrap}.sidebar-container>*{box-sizing:border-box}.sidebar-container>*{width:1%}.sidebar-content{padding-left:10px;width:82%}@media (max-width: 480px){.sidebar-content{width:100%}}.sidebar{max-width:240px;min-width:190px;width:18%}@media (max-width: 480px){.sidebar{width:100%;max-width:99%;min-width:0}}.sidebar h2{margin-top:0}.sidebar>ul a{text-decoration:none;color:#999;font-weight:300}.sidebar>ul a:hover{color:#333}.sidebar>ul li{list-style-type:none;line-height:35px;border-bottom:1px dotted #efefef;padding-left:13px}.sidebar>ul li:hover{border-left:5px solid #555;padding-left:8px}.sidebar>ul li.active{border-left:5px solid #333;padding-left:8px}.sidebar>ul li.active a{color:#333;font-weight:bold}.sidebar-icons>ul li{padding-left:0}.sidebar-icons>ul li:hover,.sidebar-icons>ul li.active{padding-left:0;border-left:none}.sidebar>ul li.active a:focus,.sidebar>ul li.active a:hover{color:#555}.sidebar>ul li:last-child{margin-bottom:15px}.avatar img{vertical-align:bottom}.avatar-left{float:left;margin-right:10px}.avatar-inline{display:inline-block;margin-right:3px}.avatar-48 img,.avatar-48 div{border-radius:30px}.avatar-48 .avatar-letter{line-height:48px;width:48px;font-size:25px}.avatar-20 img,.avatar-20 div{border-radius:10px}.avatar-20 .avatar-letter{line-height:20px;width:20px;font-size:11px}.avatar-letter{color:#fff;text-align:center}#file-dropzone,#screenshot-zone{position:relative;border:2px dashed #ccc;width:99%;height:250px;overflow:auto}#file-dropzone-inner,#screenshot-inner{position:absolute;left:0;bottom:48%;width:100%;text-align:center;color:#aaa}#screenshot-zone.screenshot-pasted{border:2px solid #333}#file-list{margin:20px}#file-list li{list-style-type:none;padding-top:8px;padding-bottom:8px;border-bottom:1px dotted #ddd;width:95%}#file-list li.file-error{font-weight:bold;color:#b94a48}.file-thumbnails{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row;-webkit-flex-wrap:wrap;flex-wrap:wrap;-webkit-justify-content:flex-start;justify-content:flex-start}.file-thumbnail{width:250px;border:1px solid #efefef;border-radius:5px;margin-bottom:20px;box-shadow:4px 2px 10px -6px rgba(0,0,0,0.55);margin-right:15px}.file-thumbnail img{border-top-left-radius:5px;border-top-right-radius:5px}.file-thumbnail img:hover{opacity:0.5}.file-thumbnail-content{padding-left:8px;padding-right:8px}.file-thumbnail-title{font-weight:700;font-size:0.9em;color:#555}.file-thumbnail-description{font-size:0.8em;color:#999;margin-top:8px;margin-bottom:5px}.file-viewer{position:relative}.file-viewer img{max-width:95%;max-height:85%;margin-top:10px}.color-picker{width:180px}.color-picker-option{height:25px}.color-picker-square{display:inline-block;width:18px;height:18px;margin-right:5px;border:1px solid #000}.color-picker-label{display:inline-block;vertical-align:bottom;padding-bottom:3px}.filter-box{max-width:800px}.action-menu{color:#333;text-decoration:none}.action-menu:hover,.action-menu:focus{text-decoration:underline}.project-creation-options{max-width:500px;border-left:3px dotted #efefef;margin-top:20px;padding-left:15px;padding-bottom:5px;padding-top:5px}.project-overview-columns{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row;-webkit-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;align-items:center;-webkit-justify-content:center;justify-content:center;margin-bottom:20px;font-size:1.4em}@media (max-width: 480px){.project-overview-columns{display:block}}.project-overview-column{text-align:center;margin-right:3%;margin-top:5px;padding:3px 15px 3px 15px;border:1px dashed #ddd}@media (max-width: 480px){.project-overview-column{text-align:left}}.project-overview-column small{color:#999}.project-overview-column strong{color:#555;display:block}@media (max-width: 480px){.project-overview-column strong{display:inline}}.project-header{box-sizing:border-box;display:flex;flex-wrap:wrap;margin-bottom:8px}.project-header>*{box-sizing:border-box}.project-header>*{width:1%}.project-header .dropdown-component{margin-top:4px;width:5%}@media (min-width: 768px) and (max-width: 1150px){.project-header .dropdown-component{width:8%}}@media (max-width: 768px){.project-header .dropdown-component{width:100%}}.project-header .views-switcher-component{margin-top:4px;width:38%}@media (max-width: 1300px){.project-header .views-switcher-component{width:45%}}@media (min-width: 768px) and (max-width: 1150px){.project-header .views-switcher-component{width:92%}}@media (max-width: 768px){.project-header .views-switcher-component{margin-top:0;width:100%}}.project-header .filter-box-component{margin:0;width:55%}@media (max-width: 1300px){.project-header .filter-box-component{width:50%}}@media (min-width: 768px) and (max-width: 1150px){.project-header .filter-box-component{width:100%;margin-top:10px}.project-header .filter-box-component .filter-box{max-width:100%}}@media (max-width: 768px){.project-header .filter-box-component{width:100%;margin-top:10px}.project-header .filter-box-component .filter-box{max-width:100%}}.project-header .filter-box-component form{margin:0}.views{display:inline-block;margin-right:10px;font-size:0.9em}@media (max-width: 560px){.views{width:100%}}@media (max-width: 768px){.views{margin-top:10px;font-size:1em}}@media (max-width: 480px){.views{margin-top:5px}}.views li{white-space:nowrap;background:#fafafa;border:1px solid #ddd;border-right:none;padding:4px 8px;display:inline}@media (max-width: 560px){.views li{display:block;margin-top:5px;border-radius:5px;border:1px solid #ddd}}.views li.active a{font-weight:bold;color:#000;text-decoration:none}.views li:first-child{border-top-left-radius:5px;border-bottom-left-radius:5px}.views li:last-child{border-right:1px solid #ddd;border-top-right-radius:5px;border-bottom-right-radius:5px}.views a{color:#555;text-decoration:none}.views a:hover{color:#333;text-decoration:underline}.dashboard-project-stats small{margin-right:10px;color:#999}.dashboard-table-link{font-weight:bold;color:#000;text-decoration:none}.dashboard-table-link:focus,.dashboard-table-link:hover{color:#999}.public-board{margin-top:5px}.public-task{max-width:800px;margin:5px auto 0}#board-container{overflow-x:auto}#board{table-layout:fixed;margin-bottom:0}#board th.board-column-header{width:240px}#board td{vertical-align:top}.board-container-compact{overflow-x:initial}@media all and (-ms-high-contrast: active), (-ms-high-contrast: none){.board-container-compact #board{table-layout:auto}}#board th.board-column-header.board-column-compact{width:initial}.board-column-collapsed{display:none}td.board-column-task-collapsed{font-weight:bold;background-color:#fbfbfb}#board th.board-column-header-collapsed{width:28px;min-width:28px;text-align:center;overflow:hidden}.board-rotation-wrapper{position:relative;padding:8px 4px;min-height:150px;overflow:hidden}.board-rotation{white-space:nowrap;-webkit-backface-visibility:hidden;-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg);-webkit-transform-origin:0 100%;-moz-transform-origin:0 100%;-ms-transform-origin:0 100%;transform-origin:0 100%}.board-column-title .dropdown-menu{text-decoration:none}.board-add-icon{float:left;padding:0 5px}.board-add-icon a{text-decoration:none;color:#36c;font-size:1.6em;line-height:70%}.board-add-icon a:focus,.board-add-icon a:hover{text-decoration:none;color:red}.board-column-header-task-count{color:#999;font-weight:normal}a.board-swimlane-toggle{text-decoration:none}a.board-swimlane-toggle:hover,a.board-swimlane-toggle:focus{color:#000;text-decoration:none;border:none}.board-task-list{min-height:60px}.board-task-list-limit{background-color:#DF5353}.draggable-item{cursor:pointer;user-select:none;-webkit-user-select:none;-moz-user-select:none}.draggable-placeholder{border:2px dashed #000;background:#fafafa;height:70px;margin-bottom:10px}div.draggable-item-selected{border:1px solid #000}.task-board-sort-handle{float:left;padding-right:5px}.task-board{position:relative;margin-bottom:4px;border:1px solid #000;padding:2px;word-wrap:break-word;font-size:0.9em}div.task-board-recent{border-width:2px}div.task-board-status-closed{user-select:none;border:1px dotted #555}.task-board a{color:#000;text-decoration:none}.task-board .dropdown-menu{font-weight:bold}.task-board .task-score{font-weight:bold}.task-board-collapsed{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.task-board-title{margin-top:5px;margin-bottom:8px}.task-board-title a:hover{text-decoration:underline}.task-board-saving-state{opacity:0.3}.task-board-saving-icon{position:absolute;margin:auto;width:100%;text-align:center;color:#000}.task-board-category-container{text-align:right;margin-top:8px;margin-bottom:8px}.task-board-category{font-weight:500;color:#000;border:1px solid #555;padding:1px 2px 1px 2px;border-radius:4px}.task-board-category:hover{opacity:0.6}.task-board-avatars{text-align:right;float:right}.task-board-change-assignee{cursor:pointer}.task-board-change-assignee:hover{opacity:0.6}.task-board-icons{font-size:0.8em;text-align:right;margin-top:4px;margin-bottom:2px}.task-board-icons a{opacity:0.5}.task-board-icons span{opacity:0.5;margin-left:2px}.task-board-icons a:hover,.task-board-icons span:hover{opacity:1.0}.flag-milestone{color:green}.task-board-age{display:inline-block}span.task-board-age-total{border:#666 1px solid;padding:1px 3px 1px 3px;border-top-left-radius:3px;border-bottom-left-radius:3px}span.task-board-age-column{border:#666 1px solid;border-left:none;margin-left:-5px;padding:1px 3px 1px 3px;border-top-right-radius:3px;border-bottom-right-radius:3px}.task-board-date{font-weight:bold;color:#000}span.task-board-date-today{opacity:1.0;color:#36c}span.task-board-date-overdue{opacity:1.0;color:#b94a48}.task-tags li{display:inline-block;margin:3px 3px 0 0;padding:1px 3px 1px 3px;color:#333;border:1px solid #333;border-radius:4px}.task-summary-container .task-tags{margin-top:10px}#task-summary{margin-bottom:15px}#task-summary h2{color:#555;font-size:1.6em;margin-top:0;padding-top:0}.task-summary-container{border:2px solid #000;border-radius:8px;padding:15px}.task-summary-columns{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row;-webkit-justify-content:space-between;justify-content:space-between}@media (max-width: 480px){.task-summary-columns{display:block}}.task-summary-column{color:#333}.task-summary-column span{color:#555}.task-summary-column li{line-height:23px}#external-task-view{padding:10px;margin-top:10px;margin-bottom:10px;border:1px dotted #ccc}.task-table .dropdown-menu{color:#000;text-decoration:none;font-weight:bold}.task-table .dropdown-menu:focus,.task-table .dropdown-menu:hover{text-decoration:underline}td.task-table a{color:#000;text-decoration:none}td.task-table a:hover{text-decoration:underline}.comment-sorting{text-align:right}.comment-sorting a{color:#555;font-weight:normal;text-decoration:none}.comment-sorting a:hover{color:#999}.comment{padding:5px;margin-bottom:15px}.comment:hover{background:#fafafa}.comment-title{border-bottom:1px dotted #eee;margin-left:55px;margin-bottom:10px}.comment-date{color:#999;font-weight:200}.comment-actions{font-size:0.8em;margin-left:55px;margin-top:8px}.comment-actions li{display:inline}.comment-actions a{color:#999;text-decoration:none}.comment-actions a:focus,.comment-actions a:hover{color:#333;text-decoration:underline}.comment-content{margin-left:55px}.subtasks-table td{vertical-align:middle}.task-links-table td{vertical-align:middle}.task-links-task-count{color:#999}.task-link-closed{text-decoration:line-through}.text-editor a{font-size:1em;color:#999;text-decoration:none;margin-right:10px}.text-editor a:hover{color:#36c}.text-editor .text-editor-preview-area{border:1px solid #dedede;width:400px;height:200px;overflow:auto;padding:2px}.markdown{line-height:1.4em}.markdown h1{margin-top:5px;margin-bottom:10px;font-weight:bold}.markdown h2{font-weight:bold}.markdown p{margin-bottom:10px}.markdown ol,.markdown ul{margin-left:25px;margin-top:10px;margin-bottom:10px}.markdown pre{background:#fbfbfb;padding:10px;border-radius:5px;border:1px solid #ddd;overflow:auto;color:#555}.markdown blockquote{font-style:italic;border-left:3px solid #ddd;padding-left:10px;margin-bottom:10px;margin-left:20px}.markdown img{display:block;max-width:80%;margin-top:10px}.documentation{margin:0 auto;padding:20px;max-width:850px;background:#fefefe;border:1px solid #ccc;border-radius:5px;color:#555}.documentation img{border:1px solid #333}.documentation h1{text-decoration:none;margin-bottom:30px}.documentation h2{text-decoration:none;border-bottom:1px solid #ccc;margin-bottom:25px}.documentation li{line-height:30px}.listing{border-radius:4px;padding:8px 35px 8px 14px;margin-bottom:20px;border:1px solid #ddd;color:#333;background-color:#fcfcfc;overflow:auto}.listing li{list-style-type:square;margin-left:20px;margin-bottom:3px}.listing ul{margin-top:15px;margin-bottom:15px}.activity-event{margin-bottom:15px;padding:10px}.activity-event:hover{background:#fafafa}.activity-date{margin-left:10px;font-weight:normal;color:#999}.activity-content{margin-left:55px}.activity-title{font-weight:bold;color:#000;border-bottom:1px dotted #efefef}.activity-description{color:#555;margin-top:10px}@media (max-width: 480px){.activity-description{overflow:auto}}.activity-description li{list-style-type:circle}.activity-description ul{margin-top:10px;margin-left:20px}div.ganttview-hzheader-month,div.ganttview-hzheader-day,div.ganttview-vtheader,div.ganttview-vtheader-item-name,div.ganttview-vtheader-series,div.ganttview-grid,div.ganttview-grid-row-cell{float:left}div.ganttview-hzheader-month,div.ganttview-hzheader-day{text-align:center}div.ganttview-grid-row-cell.last,div.ganttview-hzheader-day.last,div.ganttview-hzheader-month.last{border-right:none}div.ganttview{border:1px solid #999}div.ganttview-hzheader-month{width:60px;height:20px;border-right:1px solid #d0d0d0;line-height:20px;overflow:hidden}div.ganttview-hzheader-day{width:20px;height:20px;border-right:1px solid #f0f0f0;border-top:1px solid #d0d0d0;line-height:20px;color:#555}div.ganttview-vtheader{margin-top:41px;width:400px;overflow:hidden;background-color:#fff}div.ganttview-vtheader-item{color:#555}div.ganttview-vtheader-series-name{width:400px;height:31px;line-height:31px;padding-left:3px;border-top:1px solid #d0d0d0;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}div.ganttview-vtheader-series-name a{color:#555;text-decoration:none}div.ganttview-vtheader-series-name a:hover{color:#333;text-decoration:underline}div.ganttview-vtheader-series-name a i{color:#000}div.ganttview-vtheader-series-name a:hover i{color:#555}div.ganttview-slide-container{overflow:auto;border-left:1px solid #999}div.ganttview-grid-row-cell{width:20px;height:31px;border-right:1px solid #f0f0f0;border-top:1px solid #f0f0f0}div.ganttview-grid-row-cell.ganttview-weekend{background-color:#fafafa}div.ganttview-blocks{margin-top:40px}div.ganttview-block-container{height:28px;padding-top:4px}div.ganttview-block{position:relative;height:25px;background-color:#E5ECF9;border:1px solid #c0c0c0;border-radius:3px}.ganttview-block-movable{cursor:move}div.ganttview-block-not-defined{border-color:#000;background-color:#000}div.ganttview-block-text{position:absolute;height:12px;font-size:0.7em;color:#999;padding:2px 3px}div.ganttview-block div.ui-resizable-handle.ui-resizable-s{bottom:-0}.user-mention-link{font-weight:bold;color:#000;text-decoration:none}.user-mention-link:hover{color:#555}
diff --git a/assets/js/app.min.js b/assets/js/app.min.js
index 576f3971..8b73db8c 100644
--- a/assets/js/app.min.js
+++ b/assets/js/app.min.js
@@ -1,2 +1,2 @@
-"use strict";var Kanboard={},KB={components:{},utils:{}};KB.component=function(t,e){this.components[t]=e},KB.render=function(){for(var t in this.components)for(var e=document.querySelectorAll(".js-"+t),o=0;o<e.length;o++){var a=this.components[t],n=new a(e[o],JSON.parse(e[o].dataset.params));n.render(),e[o].className=e[o].className+"-rendered"}},KB.el=function(t){function e(t){var e="string"==typeof t?document.createElement(t):t;this.attr=function(t,o){return null!==o&&e.setAttribute(t,o),this},this.hide=function(){return e.style.display="none",this},this.show=function(){return e.style.display="block",this},this.toggle=function(){return"none"===e.style.display?this.show():this.hide(),this},this.click=function(t){return e.onclick=function(e){e.preventDefault(),t()},this},this.add=function(t){return e.appendChild(t),this},this.html=function(t){return e.innerHTML=t,this},this.text=function(t){return e.appendChild(document.createTextNode(t)),this},this["for"]=function(t,o){for(var a=0;a<o.length;a++){var n=o[a];if("object"!=typeof n)e.appendChild(KB.el(t).text(n).build());else{var i=KB.el(t);for(var r in n)r in this&&"function"==typeof this[r]?i[r](n[r]):i.attr(r,n[r]);e.appendChild(i.build())}}return this},this.build=function(){return e}}return new e(t)},KB.utils.formatDuration=function(t){return t>=86400?Math.round(t/86400)+"d":t>=3600?Math.round(t/3600)+"h":t>=60?Math.round(t/60)+"m":t+"s"},Kanboard.Accordion=function(t){this.app=t},Kanboard.Accordion.prototype.listen=function(){$(document).on("click",".accordion-toggle",function(t){var e=$(this).parents(".accordion-section");t.preventDefault(),e.hasClass("accordion-collapsed")?(e.find(".accordion-content").show(),e.removeClass("accordion-collapsed")):(e.find(".accordion-content").hide(),e.addClass("accordion-collapsed"))})},Kanboard.App=function(){this.controllers={}},Kanboard.App.prototype.get=function(t){return this.controllers[t]},Kanboard.App.prototype.execute=function(){for(var t in Kanboard)if("App"!==t){var e=new Kanboard[t](this);this.controllers[t]=e,"function"==typeof e.execute&&e.execute(),"function"==typeof e.listen&&e.listen(),"function"==typeof e.focus&&e.focus(),"function"==typeof e.keyboardShortcuts&&e.keyboardShortcuts()}this.focus(),this.chosen(),this.keyboardShortcuts(),this.datePicker(),this.autoComplete(),this.tagAutoComplete()},Kanboard.App.prototype.keyboardShortcuts=function(){var t=this;Mousetrap.bindGlobal("mod+enter",function(){var e=$("form");1==e.length?e.submit():e.length>1&&("INPUT"===document.activeElement.tagName||"TEXTAREA"===document.activeElement.tagName?$(document.activeElement).parents("form").submit():t.get("Popover").isOpen()&&$("#popover-container form").submit())}),Mousetrap.bind("b",function(t){t.preventDefault(),$("#board-selector").trigger("chosen:open")}),Mousetrap.bindGlobal("esc",function(){t.get("Popover").close(),t.get("Dropdown").close()}),Mousetrap.bind("?",function(){t.get("Popover").open($("body").data("keyboard-shortcut-url"))})},Kanboard.App.prototype.focus=function(){$(document).on("focus",".auto-select",function(){$(this).select()}),$(document).on("mouseup",".auto-select",function(t){t.preventDefault()})},Kanboard.App.prototype.chosen=function(){$(".chosen-select").each(function(){var t=$(this).data("search-threshold");void 0===t&&(t=10),$(this).chosen({width:"180px",no_results_text:$(this).data("notfound"),disable_search_threshold:t})}),$(".select-auto-redirect").change(function(){var t=new RegExp($(this).data("redirect-regex"),"g");window.location=$(this).data("redirect-url").replace(t,$(this).val())})},Kanboard.App.prototype.datePicker=function(){var t=$("body"),e=t.data("js-date-format"),o=t.data("js-time-format"),a=t.data("js-lang");$.datepicker.setDefaults($.datepicker.regional[a]),$.timepicker.setDefaults($.timepicker.regional[a]),$(".form-date").datepicker({showOtherMonths:!0,selectOtherMonths:!0,dateFormat:e,constrainInput:!1}),$(".form-datetime").datetimepicker({dateFormat:e,timeFormat:o,constrainInput:!1})},Kanboard.App.prototype.tagAutoComplete=function(){$(".tag-autocomplete").select2({tags:!0})},Kanboard.App.prototype.autoComplete=function(){$(".autocomplete").each(function(){var t=$(this),e=t.data("dst-field"),o=t.data("dst-extra-field");""==$("#form-"+e).val()&&t.parent().find("button[type=submit]").attr("disabled","disabled"),t.autocomplete({source:t.data("search-url"),minLength:1,select:function(a,n){$("input[name="+e+"]").val(n.item.id),o&&$("input[name="+o+"]").val(n.item[o]),t.parent().find("button[type=submit]").removeAttr("disabled")}})})},Kanboard.App.prototype.hasId=function(t){return!!document.getElementById(t)},Kanboard.App.prototype.showLoadingIcon=function(){$("body").append('<span id="app-loading-icon">&nbsp;<i class="fa fa-spinner fa-spin"></i></span>')},Kanboard.App.prototype.hideLoadingIcon=function(){$("#app-loading-icon").remove()},Kanboard.App.prototype.isVisible=function(){var t="";return"undefined"!=typeof document.hidden?t="visibilityState":"undefined"!=typeof document.mozHidden?t="mozVisibilityState":"undefined"!=typeof document.msHidden?t="msVisibilityState":"undefined"!=typeof document.webkitHidden&&(t="webkitVisibilityState"),""==t||"visible"==document[t]},Kanboard.BoardCollapsedMode=function(t){this.app=t},Kanboard.BoardCollapsedMode.prototype.keyboardShortcuts=function(){var t=this;t.app.hasId("board")&&Mousetrap.bind("s",function(){t.toggle()})},Kanboard.BoardCollapsedMode.prototype.toggle=function(){var t=this;this.app.showLoadingIcon(),$.ajax({cache:!1,url:$('.filter-display-mode:not([style="display: none;"]) a').attr("href"),success:function(e){$(".filter-display-mode").toggle(),t.app.get("BoardDragAndDrop").refresh(e)}})},Kanboard.BoardColumnView=function(t){this.app=t},Kanboard.BoardColumnView.prototype.execute=function(){this.app.hasId("board")&&this.render()},Kanboard.BoardColumnView.prototype.listen=function(){var t=this;$(document).on("click",".board-toggle-column-view",function(){t.toggle($(this).data("column-id"))})},Kanboard.BoardColumnView.prototype.onBoardRendered=function(){this.render()},Kanboard.BoardColumnView.prototype.render=function(){var t=this;$(".board-column-header").each(function(){var e=$(this).data("column-id");localStorage.getItem("hidden_column_"+e)&&t.hideColumn(e)})},Kanboard.BoardColumnView.prototype.toggle=function(t){localStorage.getItem("hidden_column_"+t)?this.showColumn(t):this.hideColumn(t)},Kanboard.BoardColumnView.prototype.hideColumn=function(t){$(".board-column-"+t+" .board-column-expanded").hide(),$(".board-column-"+t+" .board-column-collapsed").show(),$(".board-column-header-"+t+" .board-column-expanded").hide(),$(".board-column-header-"+t+" .board-column-collapsed").show(),$(".board-column-header-"+t).each(function(){$(this).removeClass("board-column-compact"),$(this).addClass("board-column-header-collapsed")}),$(".board-column-"+t).each(function(){$(this).addClass("board-column-task-collapsed")}),$(".board-column-"+t+" .board-rotation").each(function(){$(this).css("width",$(".board-column-"+t).height())}),localStorage.setItem("hidden_column_"+t,1)},Kanboard.BoardColumnView.prototype.showColumn=function(t){$(".board-column-"+t+" .board-column-expanded").show(),$(".board-column-"+t+" .board-column-collapsed").hide(),$(".board-column-header-"+t+" .board-column-expanded").show(),$(".board-column-header-"+t+" .board-column-collapsed").hide(),$(".board-column-header-"+t).removeClass("board-column-header-collapsed"),$(".board-column-"+t).removeClass("board-column-task-collapsed"),0==localStorage.getItem("horizontal_scroll")&&$(".board-column-header-"+t).addClass("board-column-compact"),localStorage.removeItem("hidden_column_"+t)},Kanboard.BoardHorizontalScrolling=function(t){this.app=t},Kanboard.BoardHorizontalScrolling.prototype.execute=function(){this.app.hasId("board")&&this.render()},Kanboard.BoardHorizontalScrolling.prototype.listen=function(){var t=this;$(document).on("click",".filter-toggle-scrolling",function(e){e.preventDefault(),t.toggle()})},Kanboard.BoardHorizontalScrolling.prototype.keyboardShortcuts=function(){var t=this;t.app.hasId("board")&&Mousetrap.bind("c",function(){t.toggle()})},Kanboard.BoardHorizontalScrolling.prototype.onBoardRendered=function(){this.render()},Kanboard.BoardHorizontalScrolling.prototype.toggle=function(){var t=localStorage.getItem("horizontal_scroll")||1;localStorage.setItem("horizontal_scroll",0==t?1:0),this.render()},Kanboard.BoardHorizontalScrolling.prototype.render=function(){0==localStorage.getItem("horizontal_scroll")?($(".filter-wide").show(),$(".filter-compact").hide(),$("#board-container").addClass("board-container-compact"),$("#board th:not(.board-column-header-collapsed)").addClass("board-column-compact")):($(".filter-wide").hide(),$(".filter-compact").show(),$("#board-container").removeClass("board-container-compact"),$("#board th").removeClass("board-column-compact"))},Kanboard.BoardPolling=function(t){this.app=t},Kanboard.BoardPolling.prototype.execute=function(){if(this.app.hasId("board")){var t=parseInt($("#board").attr("data-check-interval"));t>0&&window.setInterval(this.check.bind(this),1e3*t)}},Kanboard.BoardPolling.prototype.check=function(){if(this.app.isVisible()&&!this.app.get("BoardDragAndDrop").savingInProgress){var t=this;this.app.showLoadingIcon(),$.ajax({cache:!1,url:$("#board").data("check-url"),statusCode:{200:function(e){t.app.get("BoardDragAndDrop").refresh(e)},304:function(){t.app.hideLoadingIcon()}}})}},Kanboard.BoardTask=function(t){this.app=t},Kanboard.BoardTask.prototype.listen=function(){var t=this;$(document).on("click",".task-board-change-assignee",function(e){e.preventDefault(),e.stopPropagation(),t.app.get("Popover").open($(this).data("url"))}),$(document).on("click",".task-board",function(t){"A"!=t.target.tagName&&"IMG"!=t.target.tagName&&(window.location=$(this).data("task-url"))})},Kanboard.BoardTask.prototype.keyboardShortcuts=function(){var t=this;t.app.hasId("board")&&Mousetrap.bind("n",function(){t.app.get("Popover").open($("#board").data("task-creation-url"))})},Kanboard.Column=function(t){this.app=t},Kanboard.Column.prototype.listen=function(){this.dragAndDrop()},Kanboard.Column.prototype.dragAndDrop=function(){var t=this;$(".draggable-row-handle").mouseenter(function(){$(this).parent().parent().addClass("draggable-item-hover")}).mouseleave(function(){$(this).parent().parent().removeClass("draggable-item-hover")}),$(".columns-table tbody").sortable({forcePlaceholderSize:!0,handle:"td:first i",helper:function(t,e){return e.children().each(function(){$(this).width($(this).width())}),e},stop:function(e,o){var a=o.item;a.removeClass("draggable-item-selected"),t.savePosition(a.data("column-id"),a.index()+1)},start:function(t,e){e.item.addClass("draggable-item-selected")}}).disableSelection()},Kanboard.Column.prototype.savePosition=function(t,e){var o=$(".columns-table").data("save-position-url"),a=this;this.app.showLoadingIcon(),$.ajax({cache:!1,url:o,contentType:"application/json",type:"POST",processData:!1,data:JSON.stringify({column_id:t,position:e}),complete:function(){a.app.hideLoadingIcon()}})},Kanboard.Dropdown=function(t){this.app=t},Kanboard.Dropdown.prototype.listen=function(){var t=this;$(document).on("click",function(){t.close()}),$(document).on("click","#popover-content",function(){t.close()}),$(document).on("click",".dropdown-menu",function(e){e.preventDefault(),e.stopImmediatePropagation(),t.close();var o=$(this).next("ul"),a=$(this).offset();$("body").append(jQuery("<div>",{id:"dropdown"})),o.clone().appendTo("#dropdown");var n=$("#dropdown ul");n.addClass("dropdown-submenu-open");var i=n.outerHeight(),r=n.outerWidth();a.top+i-$(window).scrollTop()<$(window).height()||$(window).scrollTop()+a.top<i?n.css("top",a.top+$(this).height()):n.css("top",a.top-i-5),a.left+r>$(window).width()?n.css("left",a.left-r+$(this).outerWidth()):n.css("left",a.left)}),$(document).on("click",".dropdown-submenu-open li",function(t){$(t.target).is("li")&&$(this).find("a:visible")[0].click()})},Kanboard.Dropdown.prototype.close=function(){$("#dropdown").remove()},Kanboard.Dropdown.prototype.onPopoverOpened=function(){this.close()},Kanboard.FileUpload=function(t){this.app=t,this.files=[],this.currentFile=0},Kanboard.FileUpload.prototype.onPopoverOpened=function(){var t=document.getElementById("file-dropzone"),e=this;t&&(t.ondragover=t.ondragenter=function(t){t.stopPropagation(),t.preventDefault()},t.ondrop=function(t){t.stopPropagation(),t.preventDefault(),e.files=t.dataTransfer.files,e.show(),$("#file-error-max-size").hide()},$(document).on("click","#file-browser",function(t){t.preventDefault(),$("#file-form-element").get(0).click()}),$(document).on("click","#file-upload-button",function(t){t.preventDefault(),e.currentFile=0,e.checkFiles()}),$("#file-form-element").change(function(){e.files=document.getElementById("file-form-element").files,e.show(),$("#file-error-max-size").hide()}))},Kanboard.FileUpload.prototype.show=function(){if($("#file-list").remove(),this.files.length>0){$("#file-upload-button").prop("disabled",!1),$("#file-dropzone-inner").hide();for(var t=jQuery("<ul>",{id:"file-list"}),e=0;e<this.files.length;e++){var o=jQuery("<span>",{id:"file-percentage-"+e}).append("(0%)"),a=jQuery("<progress>",{id:"file-progress-"+e,value:0}),n=jQuery("<li>",{id:"file-label-"+e}).append(a).append("&nbsp;").append(this.files[e].name).append("&nbsp;").append(o);t.append(n)}$("#file-dropzone").append(t)}else $("#file-dropzone-inner").show()},Kanboard.FileUpload.prototype.checkFiles=function(){for(var t=parseInt($("#file-dropzone").data("max-size")),e=0;e<this.files.length;e++)if(this.files[e].size>t)return $("#file-error-max-size").show(),$("#file-label-"+e).addClass("file-error"),void $("#file-upload-button").prop("disabled",!0);this.uploadFiles()},Kanboard.FileUpload.prototype.uploadFiles=function(){this.files.length>0&&this.uploadFile(this.files[this.currentFile])},Kanboard.FileUpload.prototype.uploadFile=function(t){var e=document.getElementById("file-dropzone"),o=e.dataset.url,a=new XMLHttpRequest,n=new FormData;a.upload.addEventListener("progress",this.updateProgress.bind(this)),a.upload.addEventListener("load",this.transferComplete.bind(this)),a.open("POST",o,!0),n.append("files[]",t),a.send(n)},Kanboard.FileUpload.prototype.updateProgress=function(t){t.lengthComputable&&($("#file-progress-"+this.currentFile).val(t.loaded/t.total),$("#file-percentage-"+this.currentFile).text("("+Math.floor(t.loaded/t.total*100)+"%)"))},Kanboard.FileUpload.prototype.transferComplete=function(){if(this.currentFile++,this.currentFile<this.files.length)this.uploadFile(this.files[this.currentFile]);else{var t=$("#file-upload-button");t.prop("disabled",!0),t.parent().hide(),$("#file-done").show()}},Kanboard.Gantt=function(t){this.app=t,this.data=[],this.options={container:"#gantt-chart",showWeekends:!0,allowMoves:!0,allowResizes:!0,cellWidth:21,cellHeight:31,slideWidth:1e3,vHeaderWidth:200}},Kanboard.Gantt.prototype.execute=function(){this.app.hasId("gantt-chart")&&this.show()},Kanboard.Gantt.prototype.saveRecord=function(t){this.app.showLoadingIcon(),$.ajax({cache:!1,url:$(this.options.container).data("save-url"),contentType:"application/json",type:"POST",processData:!1,data:JSON.stringify(t),complete:this.app.hideLoadingIcon.bind(this)})},Kanboard.Gantt.prototype.show=function(){this.data=this.prepareData($(this.options.container).data("records"));var t=Math.floor(this.options.slideWidth/this.options.cellWidth+5),e=this.getDateRange(t),o=e[0],a=e[1],n=$(this.options.container),i=jQuery("<div>",{"class":"ganttview"});i.append(this.renderVerticalHeader()),i.append(this.renderSlider(o,a)),n.append(i),jQuery("div.ganttview-grid-row div.ganttview-grid-row-cell:last-child",n).addClass("last"),jQuery("div.ganttview-hzheader-days div.ganttview-hzheader-day:last-child",n).addClass("last"),jQuery("div.ganttview-hzheader-months div.ganttview-hzheader-month:last-child",n).addClass("last"),$(this.options.container).data("readonly")?(this.options.allowResizes=!1,this.options.allowMoves=!1):(this.listenForBlockResize(o),this.listenForBlockMove(o))},Kanboard.Gantt.prototype.renderVerticalHeader=function(){for(var t=jQuery("<div>",{"class":"ganttview-vtheader"}),e=jQuery("<div>",{"class":"ganttview-vtheader-item"}),o=jQuery("<div>",{"class":"ganttview-vtheader-series"}),a=0;a<this.data.length;a++){var n=jQuery("<span>").append(jQuery("<i>",{"class":"fa fa-info-circle tooltip",title:this.getVerticalHeaderTooltip(this.data[a])})).append("&nbsp;");"task"==this.data[a].type?n.append(jQuery("<a>",{href:this.data[a].link,title:this.data[a].title}).append(this.data[a].title)):n.append(jQuery("<a>",{href:this.data[a].board_link,title:$(this.options.container).data("label-board-link")}).append('<i class="fa fa-th"></i>')).append("&nbsp;").append(jQuery("<a>",{href:this.data[a].gantt_link,title:$(this.options.container).data("label-gantt-link")}).append('<i class="fa fa-sliders"></i>')).append("&nbsp;").append(jQuery("<a>",{href:this.data[a].link}).append(this.data[a].title)),o.append(jQuery("<div>",{"class":"ganttview-vtheader-series-name"}).append(n))}return e.append(o),t.append(e),t},Kanboard.Gantt.prototype.renderSlider=function(t,e){var o=jQuery("<div>",{"class":"ganttview-slide-container"}),a=this.getDates(t,e);return o.append(this.renderHorizontalHeader(a)),o.append(this.renderGrid(a)),o.append(this.addBlockContainers()),this.addBlocks(o,t),o},Kanboard.Gantt.prototype.renderHorizontalHeader=function(t){var e=jQuery("<div>",{"class":"ganttview-hzheader"}),o=jQuery("<div>",{"class":"ganttview-hzheader-months"}),a=jQuery("<div>",{"class":"ganttview-hzheader-days"}),n=0;for(var i in t)for(var r in t[i]){var s=t[i][r].length*this.options.cellWidth;n+=s,o.append(jQuery("<div>",{"class":"ganttview-hzheader-month",css:{width:s-1+"px"}}).append($.datepicker.regional[$("body").data("js-lang")].monthNames[r]+" "+i));for(var d in t[i][r])a.append(jQuery("<div>",{"class":"ganttview-hzheader-day"}).append(t[i][r][d].getDate()))}return o.css("width",n+"px"),a.css("width",n+"px"),e.append(o).append(a),e},Kanboard.Gantt.prototype.renderGrid=function(t){var e=jQuery("<div>",{"class":"ganttview-grid"}),o=jQuery("<div>",{"class":"ganttview-grid-row"});for(var a in t)for(var n in t[a])for(var i in t[a][n]){var r=jQuery("<div>",{"class":"ganttview-grid-row-cell"});this.options.showWeekends&&this.isWeekend(t[a][n][i])&&r.addClass("ganttview-weekend"),o.append(r)}var s=jQuery("div.ganttview-grid-row-cell",o).length*this.options.cellWidth;o.css("width",s+"px"),e.css("width",s+"px");for(var d=0;d<this.data.length;d++)e.append(o.clone());return e},Kanboard.Gantt.prototype.addBlockContainers=function(){for(var t=jQuery("<div>",{"class":"ganttview-blocks"}),e=0;e<this.data.length;e++)t.append(jQuery("<div>",{"class":"ganttview-block-container"}));return t},Kanboard.Gantt.prototype.addBlocks=function(t,e){for(var o=jQuery("div.ganttview-blocks div.ganttview-block-container",t),a=0,n=0;n<this.data.length;n++){var i=this.data[n],r=this.daysBetween(i.start,i.end)+1,s=this.daysBetween(e,i.start),d=jQuery("<div>",{"class":"ganttview-block-text"}),l=jQuery("<div>",{"class":"ganttview-block tooltip"+(this.options.allowMoves?" ganttview-block-movable":""),title:this.getBarTooltip(i),css:{width:r*this.options.cellWidth-9+"px","margin-left":s*this.options.cellWidth+"px"}}).append(d);r>=2&&d.append(i.progress),l.data("record",i),this.setBarColor(l,i),jQuery(o[a]).append(l),a+=1}},Kanboard.Gantt.prototype.getVerticalHeaderTooltip=function(t){var e="";if("task"==t.type)e="<strong>"+t.column_title+"</strong> ("+t.progress+")<br/>"+t.title;else{var o=["project-manager","project-member"];for(var a in o){var n=o[a];if(!jQuery.isEmptyObject(t.users[n])){var i=jQuery("<ul>");for(var r in t.users[n])r&&i.append(jQuery("<li>").append(t.users[n][r]));e+="<p><strong>"+$(this.options.container).data("label-"+n)+"</strong></p>"+i[0].outerHTML}}}return e},Kanboard.Gantt.prototype.getBarTooltip=function(t){var e="";return t.not_defined?e=$(this.options.container).data("label-not-defined"):("task"==t.type&&(e="<strong>"+t.progress+"</strong><br/>"+$(this.options.container).data("label-assignee")+" "+(t.assignee?t.assignee:"")+"<br/>"),e+=$(this.options.container).data("label-start-date")+" "+$.datepicker.formatDate("yy-mm-dd",t.start)+"<br/>",e+=$(this.options.container).data("label-end-date")+" "+$.datepicker.formatDate("yy-mm-dd",t.end)),e},Kanboard.Gantt.prototype.setBarColor=function(t,e){e.not_defined?t.addClass("ganttview-block-not-defined"):(t.css("background-color",e.color.background),t.css("border-color",e.color.border),"0%"!=e.progress&&t.append(jQuery("<div>",{css:{"z-index":0,position:"absolute",top:0,bottom:0,"background-color":e.color.border,width:e.progress,opacity:.4}})))},Kanboard.Gantt.prototype.listenForBlockResize=function(t){var e=this;jQuery("div.ganttview-block",this.options.container).resizable({grid:this.options.cellWidth,handles:"e,w",delay:300,stop:function(){var o=jQuery(this);e.updateDataAndPosition(o,t),e.saveRecord(o.data("record"))}})},Kanboard.Gantt.prototype.listenForBlockMove=function(t){var e=this;jQuery("div.ganttview-block",this.options.container).draggable({axis:"x",delay:300,grid:[this.options.cellWidth,this.options.cellWidth],stop:function(){var o=jQuery(this);e.updateDataAndPosition(o,t),e.saveRecord(o.data("record"))}})},Kanboard.Gantt.prototype.updateDataAndPosition=function(t,e){var o=jQuery("div.ganttview-slide-container",this.options.container),a=o.scrollLeft(),n=t.offset().left-o.offset().left-1+a,i=t.data("record");i.not_defined=!1,this.setBarColor(t,i);var r=Math.round(n/this.options.cellWidth),s=this.addDays(this.cloneDate(e),r);i.start=s;var d=t.outerWidth(),l=Math.round(d/this.options.cellWidth)-1;i.end=this.addDays(this.cloneDate(s),l),"task"===i.type&&l>0&&jQuery("div.ganttview-block-text",t).text(i.progress),t.attr("title",this.getBarTooltip(i)),t.data("record",i),t.css("top","").css("left","").css("position","relative").css("margin-left",n+"px")},Kanboard.Gantt.prototype.getDates=function(t,e){var o=[];o[t.getFullYear()]=[],o[t.getFullYear()][t.getMonth()]=[t];for(var a=t;this.compareDate(a,e)==-1;){var n=this.addDays(this.cloneDate(a),1);o[n.getFullYear()]||(o[n.getFullYear()]=[]),o[n.getFullYear()][n.getMonth()]||(o[n.getFullYear()][n.getMonth()]=[]),o[n.getFullYear()][n.getMonth()].push(n),a=n}return o},Kanboard.Gantt.prototype.prepareData=function(t){for(var e=0;e<t.length;e++){var o=new Date(t[e].start[0],t[e].start[1]-1,t[e].start[2],0,0,0,0);t[e].start=o;var a=new Date(t[e].end[0],t[e].end[1]-1,t[e].end[2],0,0,0,0);t[e].end=a}return t},Kanboard.Gantt.prototype.getDateRange=function(t){for(var e=new Date,o=new Date,a=0;a<this.data.length;a++){var n=new Date;n.setTime(Date.parse(this.data[a].start));var i=new Date;i.setTime(Date.parse(this.data[a].end)),0==a&&(e=n,o=i),1==this.compareDate(e,n)&&(e=n),this.compareDate(o,i)==-1&&(o=i)}return this.daysBetween(e,o)<t&&(o=this.addDays(this.cloneDate(e),t)),e.setDate(e.getDate()-1),[e,o]},Kanboard.Gantt.prototype.daysBetween=function(t,e){if(!t||!e)return 0;for(var o=0,a=this.cloneDate(t);this.compareDate(a,e)==-1;)o+=1,this.addDays(a,1);return o},Kanboard.Gantt.prototype.isWeekend=function(t){return t.getDay()%6==0},Kanboard.Gantt.prototype.cloneDate=function(t){return new Date(t.getTime())},Kanboard.Gantt.prototype.addDays=function(t,e){return t.setDate(t.getDate()+1*e),t},Kanboard.Gantt.prototype.compareDate=function(t,e){if(isNaN(t)||isNaN(e))throw new Error(t+" - "+e);if(t instanceof Date&&e instanceof Date)return t<e?-1:t>e?1:0;throw new TypeError(t+" - "+e)},Kanboard.Notification=function(t){this.app=t},Kanboard.Notification.prototype.execute=function(){$(".alert-fade-out").delay(4e3).fadeOut(800,function(){$(this).remove()})},Kanboard.Popover=function(t){this.app=t},Kanboard.Popover.prototype.listen=function(){var t=this;$(document).on("click",".popover",function(e){t.onClick(e)}),$(document).on("click",".close-popover",function(e){t.close(e)}),$(document).on("click","#popover-close-button",function(e){t.close(e)}),$(document).on("click","#popover-content",function(t){t.stopPropagation()})},Kanboard.Popover.prototype.onClick=function(t){t.preventDefault(),t.stopPropagation();var e=t.currentTarget||t.target,o=e.getAttribute("href");o||(o=e.getAttribute("data-href")),o&&this.open(o)},Kanboard.Popover.prototype.isOpen=function(){return $("#popover-container").size()>0},Kanboard.Popover.prototype.open=function(t){var e=this;e.isOpen()||$.get(t,function(t){$("body").prepend('<div id="popover-container"><div id="popover-content"><div id="popover-content-header"><a href="#" id="popover-close-button"><i class="fa fa-times"></i></a></div>'+t+"</div></div>"),e.executeOnOpenedListeners()})},Kanboard.Popover.prototype.close=function(t){this.isOpen()&&(t&&t.preventDefault(),$("#popover-container").remove(),this.executeOnClosedListeners())},Kanboard.Popover.prototype.ajaxReload=function(t,e,o){var a=e.getResponseHeader("X-Ajax-Redirect");"self"===a?window.location.reload():a&&a.indexOf("#")>-1?window.location=a.split("#")[0]:a?window.location=a:($("#popover-content").html(t),$("#popover-content input[autofocus]").focus(),o.executeOnOpenedListeners())},Kanboard.Popover.prototype.executeOnOpenedListeners=function(){for(var t in this.app.controllers){var e=this.app.get(t);"function"==typeof e.onPopoverOpened&&e.onPopoverOpened()}this.afterOpen()},Kanboard.Popover.prototype.executeOnClosedListeners=function(){for(var t in this.app.controllers){var e=this.app.get(t);"function"==typeof e.onPopoverClosed&&e.onPopoverClosed()}},Kanboard.Popover.prototype.afterOpen=function(){var t=this,e=$("#popover-content .popover-form");e&&e.on("submit",function(o){o.preventDefault(),$.ajax({type:"POST",url:e.attr("action"),data:e.serialize(),success:function(e,o,a){t.ajaxReload(e,a,t)},beforeSend:function(){var t=$('.popover-form button[type="submit"]');t.html('<i class="fa fa-spinner fa-pulse"></i> '+t.html()),t.attr("disabled",!0)}})}),$(document).on("click",".popover-link",function(e){e.preventDefault(),$.ajax({type:"GET",url:$(this).attr("href"),success:function(e,o,a){t.ajaxReload(e,a,t)}})}),$("#popover-content input[autofocus]").each(function(){$(this).focus()}),this.app.datePicker(),this.app.autoComplete(),this.app.tagAutoComplete(),new Vue({el:"#popover-container"}),KB.render()},Kanboard.ProjectCreation=function(t){this.app=t},Kanboard.ProjectCreation.prototype.onPopoverOpened=function(){$("#project-creation-form #form-src_project_id").on("change",function(){var t=$(this).val();0==t?$(".project-creation-options").hide():$(".project-creation-options").show()})},Kanboard.ProjectPermission=function(t){this.app=t},Kanboard.ProjectPermission.prototype.listen=function(){$(".project-change-role").on("change",function(){$.ajax({cache:!1,url:$(this).data("url"),contentType:"application/json",type:"POST",processData:!1,data:JSON.stringify({id:$(this).data("id"),role:$(this).val()})})})},Kanboard.Screenshot=function(t){this.app=t,this.pasteCatcher=null},Kanboard.Screenshot.prototype.onPopoverOpened=function(){this.app.hasId("screenshot-zone")&&this.initialize()},Kanboard.Screenshot.prototype.initialize=function(){this.destroy(),window.Clipboard||(this.pasteCatcher=document.createElement("div"),this.pasteCatcher.id="screenshot-pastezone",this.pasteCatcher.contentEditable="true",this.pasteCatcher.style.opacity=0,this.pasteCatcher.style.position="fixed",this.pasteCatcher.style.top=0,this.pasteCatcher.style.right=0,this.pasteCatcher.style.width=0,document.body.insertBefore(this.pasteCatcher,document.body.firstChild),this.pasteCatcher.focus(),document.addEventListener("click",this.setFocus.bind(this)),document.getElementById("screenshot-zone").addEventListener("click",this.setFocus.bind(this))),window.addEventListener("paste",this.pasteHandler.bind(this))},Kanboard.Screenshot.prototype.destroy=function(){null!=this.pasteCatcher?document.body.removeChild(this.pasteCatcher):document.getElementById("screenshot-pastezone")&&document.body.removeChild(document.getElementById("screenshot-pastezone")),document.removeEventListener("click",this.setFocus.bind(this)),this.pasteCatcher=null},Kanboard.Screenshot.prototype.setFocus=function(){null!==this.pasteCatcher&&this.pasteCatcher.focus()},Kanboard.Screenshot.prototype.pasteHandler=function(t){if(t.clipboardData&&t.clipboardData.items){var e=t.clipboardData.items;if(e)for(var o=0;o<e.length;o++)if(e[o].type.indexOf("image")!==-1){var a=e[o].getAsFile(),n=new FileReader,i=this;n.onload=function(t){i.createImage(t.target.result)},n.readAsDataURL(a)}}else setTimeout(this.checkInput.bind(this),100)},Kanboard.Screenshot.prototype.checkInput=function(){var t=this.pasteCatcher.childNodes[0];t&&"IMG"===t.tagName&&this.createImage(t.src),this.pasteCatcher.innerHTML=""},Kanboard.Screenshot.prototype.createImage=function(t){var e=new Image;e.src=t,e.onload=function(){var e=t.split("base64,"),o=e[1];$("input[name=screenshot]").val(o)};var o=document.getElementById("screenshot-zone");o.innerHTML="",o.className="screenshot-pasted",o.appendChild(e),this.destroy(),this.initialize()},Kanboard.Search=function(t){this.app=t},Kanboard.Search.prototype.focus=function(){$(document).on("focus","#form-search",function(){var t=$("#form-search");if(t[0].setSelectionRange){var e=2*t.val().length;t[0].setSelectionRange(e,e)}})},Kanboard.Search.prototype.listen=function(){$(document).on("click",".filter-helper",function(t){t.preventDefault();var e=$(this).data("filter"),o=$(this).data("append-filter"),a=$(this).data("unique-filter"),n=$("#form-search");if(a){var i=a.substr(0,a.indexOf(":"));e=n.val().replace(new RegExp("("+i+":[#a-z0-9]+)","g"),""),e=e.replace(new RegExp("("+i+':"(.+)")',"g"),""),e=e.trim(),e+=" "+a}else o&&(e=n.val()+" "+o);n.val(e),$("form.search").submit()})},Kanboard.Search.prototype.goToView=function(t){var e=$(t);e.length&&(window.location=e.attr("href"))},Kanboard.Search.prototype.keyboardShortcuts=function(){var t=this;Mousetrap.bind("v o",function(){t.goToView(".view-overview")}),Mousetrap.bind("v b",function(){t.goToView(".view-board")}),Mousetrap.bind("v c",function(){t.goToView(".view-calendar")}),Mousetrap.bind("v l",function(){t.goToView(".view-listing")}),Mousetrap.bind("v g",function(){t.goToView(".view-gantt")}),Mousetrap.bind("f",function(t){t.preventDefault();var e=document.getElementById("form-search");e&&e.focus()}),Mousetrap.bind("r",function(t){t.preventDefault();var e=$(".filter-reset").data("filter"),o=$("#form-search");o.val(e),$("form.search").submit()})},Kanboard.Session=function(t){this.app=t},Kanboard.Session.prototype.execute=function(){window.setInterval(this.checkSession,6e4)},Kanboard.Session.prototype.checkSession=function(){$(".form-login").length||$.ajax({cache:!1,url:$("body").data("status-url"),statusCode:{401:function(){window.location=$("body").data("login-url")}}})},Kanboard.Subtask=function(t){this.app=t},Kanboard.Subtask.prototype.listen=function(){var t=this;this.dragAndDrop(),$(document).on("click",".subtask-toggle-status",function(e){var o=$(this);e.preventDefault(),$.ajax({cache:!1,url:o.attr("href"),success:function(e){o.hasClass("subtask-refresh-table")?$(".subtasks-table").replaceWith(e):o.replaceWith(e),t.dragAndDrop()}})}),$(document).on("click",".subtask-toggle-timer",function(e){var o=$(this);e.preventDefault(),$.ajax({cache:!1,url:o.attr("href"),success:function(e){$(".subtasks-table").replaceWith(e),t.dragAndDrop()}})})},Kanboard.Subtask.prototype.dragAndDrop=function(){var t=this;$(".draggable-row-handle").mouseenter(function(){$(this).parent().parent().addClass("draggable-item-hover")}).mouseleave(function(){$(this).parent().parent().removeClass("draggable-item-hover")}),$(".subtasks-table tbody").sortable({forcePlaceholderSize:!0,handle:"td:first i",helper:function(t,e){return e.children().each(function(){$(this).width($(this).width())}),e},stop:function(e,o){var a=o.item;a.removeClass("draggable-item-selected"),t.savePosition(a.data("subtask-id"),a.index()+1);
-},start:function(t,e){e.item.addClass("draggable-item-selected")}}).disableSelection()},Kanboard.Subtask.prototype.savePosition=function(t,e){var o=$(".subtasks-table").data("save-position-url"),a=this;this.app.showLoadingIcon(),$.ajax({cache:!1,url:o,contentType:"application/json",type:"POST",processData:!1,data:JSON.stringify({subtask_id:t,position:e}),complete:function(){a.app.hideLoadingIcon()}})},Kanboard.Swimlane=function(t){this.app=t},Kanboard.Swimlane.prototype.execute=function(){$(".swimlanes-table").length&&this.dragAndDrop()},Kanboard.Swimlane.prototype.listen=function(){var t=this;$(document).on("click",".board-swimlane-toggle",function(e){e.preventDefault();var o=$(this).data("swimlane-id");t.isCollapsed(o)?t.expand(o):t.collapse(o)})},Kanboard.Swimlane.prototype.onBoardRendered=function(){for(var t=this.getAllCollapsed(),e=0;e<t.length;e++)this.collapse(t[e])},Kanboard.Swimlane.prototype.getStorageKey=function(){return"hidden_swimlanes_"+$("#board").data("project-id")},Kanboard.Swimlane.prototype.expand=function(t){var e=this.getAllCollapsed(),o=e.indexOf(t);o>-1&&e.splice(o,1),localStorage.setItem(this.getStorageKey(),JSON.stringify(e)),$(".board-swimlane-columns-"+t).css("display","table-row"),$(".board-swimlane-tasks-"+t).css("display","table-row"),$(".hide-icon-swimlane-"+t).css("display","inline"),$(".show-icon-swimlane-"+t).css("display","none")},Kanboard.Swimlane.prototype.collapse=function(t){var e=this.getAllCollapsed();e.indexOf(t)<0&&(e.push(t),localStorage.setItem(this.getStorageKey(),JSON.stringify(e))),$(".board-swimlane-columns-"+t+":not(:first-child)").css("display","none"),$(".board-swimlane-tasks-"+t).css("display","none"),$(".hide-icon-swimlane-"+t).css("display","none"),$(".show-icon-swimlane-"+t).css("display","inline")},Kanboard.Swimlane.prototype.isCollapsed=function(t){return this.getAllCollapsed().indexOf(t)>-1},Kanboard.Swimlane.prototype.getAllCollapsed=function(){return JSON.parse(localStorage.getItem(this.getStorageKey()))||[]},Kanboard.Swimlane.prototype.dragAndDrop=function(){var t=this;$(".draggable-row-handle").mouseenter(function(){$(this).parent().parent().addClass("draggable-item-hover")}).mouseleave(function(){$(this).parent().parent().removeClass("draggable-item-hover")}),$(".swimlanes-table tbody").sortable({forcePlaceholderSize:!0,handle:"td:first i",helper:function(t,e){return e.children().each(function(){$(this).width($(this).width())}),e},stop:function(e,o){var a=o.item;a.removeClass("draggable-item-selected"),t.savePosition(a.data("swimlane-id"),a.index()+1)},start:function(t,e){e.item.addClass("draggable-item-selected")}}).disableSelection()},Kanboard.Swimlane.prototype.savePosition=function(t,e){var o=$(".swimlanes-table").data("save-position-url"),a=this;this.app.showLoadingIcon(),$.ajax({cache:!1,url:o,contentType:"application/json",type:"POST",processData:!1,data:JSON.stringify({swimlane_id:t,position:e}),complete:function(){a.app.hideLoadingIcon()}})},Kanboard.Task=function(t){this.app=t},Kanboard.Task.prototype.keyboardShortcuts=function(){var t=$("#task-view"),e=this;this.app.hasId("task-view")&&(Mousetrap.bind("e",function(){e.app.get("Popover").open(t.data("edit-url"))}),Mousetrap.bind("c",function(){e.app.get("Popover").open(t.data("comment-url"))}),Mousetrap.bind("s",function(){e.app.get("Popover").open(t.data("subtask-url"))}),Mousetrap.bind("l",function(){e.app.get("Popover").open(t.data("internal-link-url"))}))},Kanboard.Task.prototype.onPopoverOpened=function(){var t=this,e=0;t.renderColorPicker(),$(document).on("click",".assign-me",function(t){var e=$(this).data("current-id"),o="#"+$(this).data("target-id");t.preventDefault(),$(o+" option[value="+e+"]").length&&$(o).val(e)}),$(document).on("change","select.task-reload-project-destination",function(){if(e>0)$(this).val(e);else{e=$(this).val();var o=$(this).data("redirect").replace(/PROJECT_ID/g,e);$(".loading-icon").show(),$.ajax({type:"GET",url:o,success:function(o,a,n){e=0,$(".loading-icon").hide(),t.app.get("Popover").ajaxReload(o,n,t.app.get("Popover"))}})}})},Kanboard.Task.prototype.renderColorPicker=function(){function t(t){return $('<div class="color-picker-option"><div class="color-picker-square color-'+t.id+'"></div><div class="color-picker-label">'+t.text+"</div></div>")}$(".color-picker").select2({minimumResultsForSearch:1/0,templateResult:t,templateSelection:t})},Kanboard.Tooltip=function(t){this.app=t},Kanboard.Tooltip.prototype.onBoardRendered=function(){this.execute()},Kanboard.Tooltip.prototype.execute=function(){$(".tooltip").tooltip({track:!1,show:!1,hide:!1,position:{my:"left-20 top",at:"center bottom+9",using:function(t,e){$(this).css(t);var o=e.target.left+e.target.width/2-e.element.left-20;$("<div>").addClass("tooltip-arrow").addClass(e.vertical).addClass(o<1?"align-left":"align-right").appendTo(this)}},content:function(){var t=this,e=$(this).attr("data-href");return e?($.get(e,function(e){var o=$(".ui-tooltip:visible");$(".ui-tooltip-content:visible").html(e),o.css({top:"",left:""}),o.children(".tooltip-arrow").remove();var a=$(t).tooltip("option","position");a.of=$(t),o.position(a)}),'<i class="fa fa-spinner fa-spin"></i>'):'<div class="markdown">'+$(this).attr("title")+"</div>"}}).on("mouseenter",function(){var t=this;$(this).tooltip("open"),$(".ui-tooltip").on("mouseleave",function(){$(t).tooltip("close")})}).on("mouseleave focusout",function(t){t.stopImmediatePropagation();var e=this;setTimeout(function(){$(".ui-tooltip:hover").length||$(e).tooltip("close")},100)})},Kanboard.BoardDragAndDrop=function(t){this.app=t,this.savingInProgress=!1},Kanboard.BoardDragAndDrop.prototype.execute=function(){this.app.hasId("board")&&(this.dragAndDrop(),this.executeListeners())},Kanboard.BoardDragAndDrop.prototype.dragAndDrop=function(){var t=this,e=$(".board-task-list"),o={forcePlaceholderSize:!0,tolerance:"pointer",connectWith:".sortable-column",placeholder:"draggable-placeholder",items:".draggable-item",stop:function(e,o){var a=o.item,n=a.attr("data-task-id"),i=a.attr("data-position"),r=a.attr("data-column-id"),s=a.attr("data-swimlane-id"),d=a.parent().attr("data-column-id"),l=a.parent().attr("data-swimlane-id"),c=a.index()+1;a.removeClass("draggable-item-selected"),d==r&&l==s&&c==i||(t.changeTaskState(n),t.save(n,r,d,c,l))},start:function(t,e){e.item.addClass("draggable-item-selected"),e.placeholder.height(e.item.height())}};isMobile.any&&($(".task-board-sort-handle").css("display","inline"),o.handle=".task-board-sort-handle"),e.each(function(){$(this).css("min-height",$(this).parent().height())}),e.sortable(o)},Kanboard.BoardDragAndDrop.prototype.changeTaskState=function(t){var e=$("div[data-task-id="+t+"]");e.addClass("task-board-saving-state"),e.find(".task-board-saving-icon").show()},Kanboard.BoardDragAndDrop.prototype.save=function(t,e,o,a,n){var i=this;i.app.showLoadingIcon(),i.savingInProgress=!0,$.ajax({cache:!1,url:$("#board").data("save-url"),contentType:"application/json",type:"POST",processData:!1,data:JSON.stringify({task_id:t,src_column_id:e,dst_column_id:o,swimlane_id:n,position:a}),success:function(t){i.refresh(t),i.savingInProgress=!1},error:function(){i.app.hideLoadingIcon(),i.savingInProgress=!1},statusCode:{403:function(t){window.alert(t.responseJSON.message),document.location.reload(!0)}}})},Kanboard.BoardDragAndDrop.prototype.refresh=function(t){$("#board-container").replaceWith(t),this.app.hideLoadingIcon(),this.dragAndDrop(),this.executeListeners()},Kanboard.BoardDragAndDrop.prototype.executeListeners=function(){for(var t in this.app.controllers){var e=this.app.get(t);"function"==typeof e.onBoardRendered&&e.onBoardRendered()}},KB.component("calendar",function(t,e){this.render=function(){var o=$(t);o.fullCalendar({locale:$("body").data("js-lang"),editable:!0,eventLimit:!0,defaultView:"month",header:{left:"prev,next today",center:"title",right:"month,agendaWeek,agendaDay"},eventDrop:function(t){$.ajax({cache:!1,url:e.saveUrl,contentType:"application/json",type:"POST",processData:!1,data:JSON.stringify({task_id:t.id,date_due:t.start.format()})})},viewRender:function(){var t=e.checkUrl,a={start:o.fullCalendar("getView").start.format(),end:o.fullCalendar("getView").end.format()};for(var n in a)t+="&"+n+"="+a[n];$.getJSON(t,function(t){o.fullCalendar("removeEvents"),o.fullCalendar("addEventSource",t),o.fullCalendar("rerenderEvents")})}})}}),KB.component("chart-project-avg-time-column",function(t,e){this.render=function(){var o=e.metrics,a=[e.label],n=[];for(var i in o)a.push(o[i].average),n.push(o[i].title);KB.el(t).add(KB.el("div").attr("id","chart").build()),c3.generate({data:{columns:[a],type:"bar"},bar:{width:{ratio:.5}},axis:{x:{type:"category",categories:n},y:{tick:{format:KB.utils.formatDuration}}},legend:{show:!1}})}}),KB.component("chart-project-burndown",function(t,e){this.render=function(){for(var o=e.metrics,a=[[e.labelTotal]],n=[],i=d3.time.format("%Y-%m-%d"),r=d3.time.format(e.dateFormat),s=0;s<o.length;s++)for(var d=0;d<o[s].length;d++)0==s?a.push([o[s][d]]):(a[d+1].push(o[s][d]),d>0&&(void 0==a[0][s]&&a[0].push(0),a[0][s]+=o[s][d]),0==d&&n.push(r(i.parse(o[s][d]))));KB.el(t).add(KB.el("div").attr("id","chart").build()),c3.generate({data:{columns:a},axis:{x:{type:"category",categories:n}}})}}),KB.component("chart-project-cumulative-flow",function(t,e){this.render=function(){for(var o=e.metrics,a=[],n=[],i=[],r=d3.time.format("%Y-%m-%d"),s=d3.time.format(e.dateFormat),d=0;d<o.length;d++)for(var l=0;l<o[d].length;l++)0==d?(a.push([o[d][l]]),l>0&&n.push(o[d][l])):(a[l].push(o[d][l]),0==l&&i.push(s(r.parse(o[d][l]))));KB.el(t).add(KB.el("div").attr("id","chart").build()),c3.generate({data:{columns:a,type:"area-spline",groups:[n]},axis:{x:{type:"category",categories:i}}})}}),KB.component("chart-project-lead-cycle-time",function(t,e){this.render=function(){var o=e.metrics,a=[e.labelCycle],n=[e.labelLead],i=[],r={};r[e.labelCycle]="area",r[e.labelLead]="area-spline";var s={};s[e.labelLead]="#afb42b",s[e.labelCycle]="#4e342e";for(var d=0;d<o.length;d++)a.push(parseInt(o[d].avg_cycle_time)),n.push(parseInt(o[d].avg_lead_time)),i.push(o[d].day);KB.el(t).add(KB.el("div").attr("id","chart").build()),c3.generate({data:{columns:[n,a],types:r,colors:s},axis:{x:{type:"category",categories:i},y:{tick:{format:KB.utils.formatDuration}}}})}}),KB.component("chart-project-task-distribution",function(t,e){this.render=function(){for(var o=[],a=0;a<e.metrics.length;a++)o.push([e.metrics[a].column_title,e.metrics[a].nb_tasks]);KB.el(t).add(KB.el("div").attr("id","chart").build()),c3.generate({data:{columns:o,type:"donut"}})}}),KB.component("chart-project-time-comparison",function(t,e){this.render=function(){var o=[e.labelSpent],a=[e.labelEstimated],n=[];for(var i in e.metrics)o.push(e.metrics[i].time_spent),a.push(e.metrics[i].time_estimated),n.push("open"===i?e.labelOpen:e.labelClosed);KB.el(t).add(KB.el("div").attr("id","chart").build()),c3.generate({data:{columns:[o,a],type:"bar"},bar:{width:{ratio:.2}},axis:{x:{type:"category",categories:n}},legend:{show:!0}})}}),KB.component("chart-project-user-distribution",function(t,e){this.render=function(){for(var o=[],a=0;a<e.metrics.length;a++)o.push([e.metrics[a].user,e.metrics[a].nb_tasks]);KB.el(t).add(KB.el("div").attr("id","chart").build()),c3.generate({data:{columns:o,type:"donut"}})}}),KB.component("chart-task-time-column",function(t,e){this.render=function(){for(var o=e.metrics,a=[e.label],n=[],i=0;i<o.length;i++)a.push(o[i].time_spent),n.push(o[i].title);KB.el(t).add(KB.el("div").attr("id","chart").build()),c3.generate({data:{columns:[a],type:"bar"},bar:{width:{ratio:.5}},axis:{x:{type:"category",categories:n},y:{tick:{format:KB.utils.formatDuration}}},legend:{show:!1}})}}),KB.component("external-task-view",function(t,e){this.render=function(){$.ajax({cache:!1,url:e.url,success:function(e){KB.el(t).html('<div id="external-task-view">'+e+"</div>")}})}}),Vue.component("submit-cancel",{props:["labelButton","labelOr","labelCancel","callback"],template:'<div class="form-actions"><button type="button" class="btn btn-blue" @click="onSubmit" :disabled="isLoading"><span v-show="isLoading"><i class="fa fa-spinner fa-pulse"></i> </span>{{ labelButton }}</button> {{ labelOr }} <a href="#" v-on:click.prevent="onCancel">{{ labelCancel }}</a></div>',data:function(){return{loading:!1}},computed:{isLoading:function(){return this.loading}},methods:{onSubmit:function(){this.loading=!0,this.callback()},onCancel:function(){_KB.get("Popover").close()}},events:{submitCancelled:function(){this.loading=!1}}}),Vue.component("task-move-position",{props:["board","saveUrl"],template:"#template-task-move-position",data:function(){return{swimlaneId:0,columnId:0,position:1,columns:[],tasks:[],positionChoice:"before",errorMessage:""}},ready:function(){this.columns=this.board[0].columns,this.columnId=this.columns[0].id,this.tasks=this.columns[0].tasks,this.errorMessage=""},methods:{onChangeSwimlane:function(){var t=this;this.columnId=0,this.position=1,this.columns=[],this.tasks=[],this.positionChoice="before",this.board.forEach(function(e){e.id===t.swimlaneId&&(t.columns=e.columns,t.tasks=t.columns[0].tasks,t.columnId=t.columns[0].id)})},onChangeColumn:function(){var t=this;this.position=1,this.tasks=[],this.positionChoice="before",this.columns.forEach(function(e){e.id==t.columnId&&(t.tasks=e.tasks,t.tasks.length>0&&(t.position=parseInt(t.tasks[0].position)))})},onSubmit:function(){var t=this;"after"==this.positionChoice&&this.position++,$.ajax({cache:!1,url:this.saveUrl,contentType:"application/json",type:"POST",processData:!1,data:JSON.stringify({column_id:this.columnId,swimlane_id:this.swimlaneId,position:this.position}),statusCode:{200:function(){window.location.reload(!0)},403:function(e){var o=JSON.parse(e.responseText);t.errorMessage=o.message,t.$broadcast("submitCancelled")}}})}}}),KB.component("text-editor",function(t,e){function o(){var t=KB.el("div").attr("class","text-editor-toolbar")["for"]("a",[{href:"#",html:'<i class="fa fa-pencil-square-o fa-fw"></i> '+e.labelWrite,click:function(){n()}}]).build();return m=KB.el("div").attr("class","text-editor-preview-area markdown").build(),KB.el("div").attr("class","text-editor-view-mode").add(t).add(m).hide().build()}function a(){var t=KB.el("div").attr("class","text-editor-toolbar")["for"]("a",[{href:"#",html:'<i class="fa fa-eye fa-fw"></i> '+e.labelPreview,click:function(){n()}},{href:"#",html:'<i class="fa fa-bold fa-fw"></i>',click:function(){s("**")}},{href:"#",html:'<i class="fa fa-italic fa-fw"></i>',click:function(){s("_")}},{href:"#",html:'<i class="fa fa-strikethrough fa-fw"></i>',click:function(){s("~~")}},{href:"#",html:'<i class="fa fa-quote-right fa-fw"></i>',click:function(){l("> ")}},{href:"#",html:'<i class="fa fa-list-ul fa-fw"></i>',click:function(){l("* ")}},{href:"#",html:'<i class="fa fa-code fa-fw"></i>',click:function(){d("```")}}]).build();return u=KB.el("textarea").attr("name",e.name).attr("tabindex",e.tabindex||"-1").attr("required",e.required||!1).attr("autofocus",e.autofocus||null).attr("placeholder",e.placeholder||"").text(e.text).build(),KB.el("div").attr("class","text-editor-write-mode").add(t).add(u).build()}function n(){KB.el(m).html(marked(u.value,{sanitize:!0})),KB.el(h).toggle(),KB.el(f).toggle()}function i(){return u.value.substring(u.selectionStart,u.selectionEnd)}function r(t,e,o,a){return t.substring(0,e)+a+t.substring(o)}function s(t){var e=i();c(t+e+t),p(t)}function d(t){var e=i();c("\n"+t+"\n"+e+"\n"+t),p(t,2)}function l(t){var e=i();if(e.indexOf("\n")===-1)c("\n"+t+e);else{for(var o=e.split("\n"),a=0;a<o.length;a++)o[a].indexOf(t)===-1&&(o[a]=t+o[a]);c(o.join("\n"))}}function c(t){var e=!1;if(b=u.selectionStart,v=u.selectionEnd,u.focus(),document.queryCommandSupported("insertText")&&(e=document.execCommand("insertText",!1,t)),!e){try{document.execCommand("ms-beginUndoUnit")}catch(o){}u.value=r(text,u.selectionStart,u.selectionEnd,t);try{document.execCommand("ms-endUndoUnit")}catch(o){}}}function p(t,e){e=e||0;var o=v+t.length+e;u.setSelectionRange(o,o)}var u,h,f,m,b,v;this.render=function(){f=a(),h=o(),t.appendChild(KB.el("div").attr("class","text-editor").add(h).add(f).build())}});var _KB=null;jQuery(document).ready(function(){_KB=new Kanboard.App,_KB.execute(),KB.render()}); \ No newline at end of file
+!function(){function t(t,a,i){if(!o)throw new Error("textarea-caret-position#getCaretCoordinates should only be called in a browser");var r=i&&i.debug||!1;if(r){var s=document.querySelector("#input-textarea-caret-position-mirror-div");s&&s.parentNode.removeChild(s)}var d=document.createElement("div");d.id="input-textarea-caret-position-mirror-div",document.body.appendChild(d);var l=d.style,c=window.getComputedStyle?getComputedStyle(t):t.currentStyle;l.whiteSpace="pre-wrap","INPUT"!==t.nodeName&&(l.wordWrap="break-word"),l.position="absolute",r||(l.visibility="hidden"),e.forEach(function(t){l[t]=c[t]}),n?t.scrollHeight>parseInt(c.height)&&(l.overflowY="scroll"):l.overflow="hidden",d.textContent=t.value.substring(0,a),"INPUT"===t.nodeName&&(d.textContent=d.textContent.replace(/\s/g," "));var p=document.createElement("span");p.textContent=t.value.substring(a)||".",d.appendChild(p);var u={top:p.offsetTop+parseInt(c.borderTopWidth),left:p.offsetLeft+parseInt(c.borderLeftWidth)};return r?p.style.backgroundColor="#aaa":document.body.removeChild(d),u}var e=["direction","boxSizing","width","height","overflowX","overflowY","borderTopWidth","borderRightWidth","borderBottomWidth","borderLeftWidth","borderStyle","paddingTop","paddingRight","paddingBottom","paddingLeft","fontStyle","fontVariant","fontWeight","fontStretch","fontSize","fontSizeAdjust","lineHeight","fontFamily","textAlign","textTransform","textIndent","textDecoration","letterSpacing","wordSpacing","tabSize","MozTabSize"],o="undefined"!=typeof window,n=o&&null!=window.mozInnerScreenX;"undefined"!=typeof module&&"undefined"!=typeof module.exports?module.exports=t:o&&(window.getCaretCoordinates=t)}(),Element.prototype.matches||(Element.prototype.matches=Element.prototype.matchesSelector||Element.prototype.mozMatchesSelector||Element.prototype.msMatchesSelector||Element.prototype.oMatchesSelector||Element.prototype.webkitMatchesSelector||function(t){for(var e=(this.document||this.ownerDocument).querySelectorAll(t),o=e.length;--o>=0&&e.item(o)!==this;);return o>-1});var KB={components:{},utils:{},html:{},http:{},listeners:{clicks:{},internals:{}}};KB.on=function(t,e){this.listeners.internals.hasOwnProperty(t)||(this.listeners.internals[t]=[]),this.listeners.internals[t].push(e)},KB.trigger=function(t,e){if(this.listeners.internals.hasOwnProperty(t))for(var o=0;o<this.listeners.internals[t].length&&this.listeners.internals[t][o](e);o++);},KB.onClick=function(t,e){this.listeners.clicks[t]=e},KB.listen=function(){function t(t){for(var o in e.listeners.clicks)e.listeners.clicks.hasOwnProperty(o)&&t.target.matches(o)&&(t.preventDefault(),e.listeners.clicks[o](t))}var e=this;document.addEventListener("click",t,!1)},KB.component=function(t,e){this.components[t]=e},KB.getComponent=function(t,e,o){var n=this.components[t];return new n(e,o)},KB.render=function(){for(var t in this.components)for(var e=document.querySelectorAll(".js-"+t),o=0;o<e.length;o++)if(this.components.hasOwnProperty(t)){var n;e[o].dataset.params&&(n=JSON.parse(e[o].dataset.params));var a=KB.getComponent(t,e[o],n);a.render(),e[o].className=e[o].className+"-rendered"}},KB.dom=function(t){function e(t){var e="string"==typeof t?document.createElement(t):t;this.attr=function(t,o){return null!==o&&e.setAttribute(t,o),this},this.data=function(t,o){return 1===arguments.length?e.dataset[t]:(e.dataset[t]=o,this)},this.hide=function(){return e.style.display="none",this},this.show=function(){return e.style.display="block",this},this.toggle=function(){return"none"===e.style.display?this.show():this.hide(),this},this.style=function(t,o){return e.style[t]=o,this},this.on=function(t,o){return e.addEventListener(t,function(t){t.preventDefault(),o(t.target)}),this},this.click=function(t){return this.on("click",t)},this.mouseover=function(t){return this.on("mouseover",t)},this.change=function(t){return this.on("change",t)},this.add=function(t){return e.appendChild(t),this},this.replace=function(t){return e.parentNode.replaceChild(t,e),this},this.html=function(t){return e.innerHTML=t,this},this.text=function(t){return e.appendChild(document.createTextNode(t)),this},this.addClass=function(t){return e.classList.add(t),this},this.removeClass=function(t){return e.classList.remove(t),this},this.toggleClass=function(t){return e.classList.toggle(t),this},this.hasClass=function(t){return e.classList.contains(t)},this.disable=function(){return e.disabled=!0,this},this.enable=function(){return e.disabled=!1,this},this.remove=function(){return e.parentNode.removeChild(e),this},this.parent=function(t){for(;e&&e!==document;e=e.parentNode)if(e.matches(t))return e;return null},this.find=function(t){return e.querySelector(t)},this["for"]=function(t,o){for(var n=0;n<o.length;n++){var a=o[n];if("object"!=typeof a)e.appendChild(KB.dom(t).text(a).build());else{var i=KB.dom(t);for(var r in a)a.hasOwnProperty(r)&&r in this&&"function"==typeof this[r]?i[r](a[r]):i.attr(r,a[r]);e.appendChild(i.build())}}return this},this.build=function(){return e}}return new e(t)},KB.find=function(t){var e=document.querySelector(t);return e?KB.dom(e):null},KB.html.label=function(t,e){return KB.dom("label").attr("for",e).text(t).build()},KB.html.radio=function(t,e,o){return KB.dom("label").add(KB.dom("input").attr("type","radio").attr("name",e).attr("value",o).build()).text(t).build()},KB.html.radios=function(t){var e=KB.dom("div");for(var o in t)t.hasOwnProperty(o)&&e.add(KB.html.radio(o.label,o.name,o.value))},KB.http.request=function(t,e,o,n){function a(t){try{return JSON.parse(t.responseText)}catch(e){return t.responseText}}var i=function(){},r=function(){};this.execute=function(){var s=new XMLHttpRequest;s.open(t,e,!0),s.setRequestHeader("X-Requested-With","XMLHttpRequest");for(var d in o)o.hasOwnProperty(d)&&s.setRequestHeader(d,o[d]);return s.onerror=function(){r()},s.onreadystatechange=function(){if(s.readyState===XMLHttpRequest.DONE){var t=a(s);200===s.status?i(t):r(t)}},s.send(n),this},this.success=function(t){return i=t,this},this.error=function(t){return r=t,this}},KB.http.get=function(t){return new KB.http.request("GET",t).execute()},KB.http.postJson=function(t,e){var o={"Content-Type":"application/json",Accept:"application/json"};return new KB.http.request("POST",t,o,JSON.stringify(e)).execute()},KB.utils.formatDuration=function(t){return t>=86400?Math.round(t/86400)+"d":t>=3600?Math.round(t/3600)+"h":t>=60?Math.round(t/60)+"m":t+"s"},KB.utils.getSelectionPosition=function(t){var e,o;return e=t.value.length<t.selectionStart?t.value.length:t.selectionStart,o=t.selectionStart===t.selectionEnd?e:t.selectionEnd,{selectionStart:e,selectionEnd:o}},KB.onClick(".accordion-toggle",function(t){var e=KB.dom(t.target).parent(".accordion-section");e&&(KB.dom(e).toggleClass("accordion-collapsed"),KB.dom(KB.dom(e).find(".accordion-content")).toggle())}),KB.component("calendar",function(t,e){this.render=function(){var o=$(t);o.fullCalendar({locale:$("body").data("js-lang"),editable:!0,eventLimit:!0,defaultView:"month",header:{left:"prev,next today",center:"title",right:"month,agendaWeek,agendaDay"},eventDrop:function(t){$.ajax({cache:!1,url:e.saveUrl,contentType:"application/json",type:"POST",processData:!1,data:JSON.stringify({task_id:t.id,date_due:t.start.format()})})},viewRender:function(){var t=e.checkUrl,n={start:o.fullCalendar("getView").start.format(),end:o.fullCalendar("getView").end.format()};for(var a in n)t+="&"+a+"="+n[a];$.getJSON(t,function(t){o.fullCalendar("removeEvents"),o.fullCalendar("addEventSource",t),o.fullCalendar("rerenderEvents")})}})}}),KB.component("chart-project-avg-time-column",function(t,e){this.render=function(){var o=e.metrics,n=[e.label],a=[];for(var i in o)n.push(o[i].average),a.push(o[i].title);KB.dom(t).add(KB.dom("div").attr("id","chart").build()),c3.generate({data:{columns:[n],type:"bar"},bar:{width:{ratio:.5}},axis:{x:{type:"category",categories:a},y:{tick:{format:KB.utils.formatDuration}}},legend:{show:!1}})}}),KB.component("chart-project-burndown",function(t,e){this.render=function(){for(var o=e.metrics,n=[[e.labelTotal]],a=[],i=d3.time.format("%Y-%m-%d"),r=d3.time.format(e.dateFormat),s=0;s<o.length;s++)for(var d=0;d<o[s].length;d++)0===s?n.push([o[s][d]]):(n[d+1].push(o[s][d]),d>0&&(void 0===n[0][s]&&n[0].push(0),n[0][s]+=o[s][d]),0===d&&a.push(r(i.parse(o[s][d]))));KB.dom(t).add(KB.dom("div").attr("id","chart").build()),c3.generate({data:{columns:n},axis:{x:{type:"category",categories:a}}})}}),KB.component("chart-project-cumulative-flow",function(t,e){this.render=function(){for(var o=e.metrics,n=[],a=[],i=[],r=d3.time.format("%Y-%m-%d"),s=d3.time.format(e.dateFormat),d=0;d<o.length;d++)for(var l=0;l<o[d].length;l++)0===d?(n.push([o[d][l]]),l>0&&a.push(o[d][l])):(n[l].push(o[d][l]),0===l&&i.push(s(r.parse(o[d][l]))));KB.dom(t).add(KB.dom("div").attr("id","chart").build()),c3.generate({data:{columns:n,type:"area-spline",groups:[a]},axis:{x:{type:"category",categories:i}}})}}),KB.component("chart-project-lead-cycle-time",function(t,e){this.render=function(){var o=e.metrics,n=[e.labelCycle],a=[e.labelLead],i=[],r={};r[e.labelCycle]="area",r[e.labelLead]="area-spline";var s={};s[e.labelLead]="#afb42b",s[e.labelCycle]="#4e342e";for(var d=0;d<o.length;d++)n.push(parseInt(o[d].avg_cycle_time)),a.push(parseInt(o[d].avg_lead_time)),i.push(o[d].day);KB.dom(t).add(KB.dom("div").attr("id","chart").build()),c3.generate({data:{columns:[a,n],types:r,colors:s},axis:{x:{type:"category",categories:i},y:{tick:{format:KB.utils.formatDuration}}}})}}),KB.component("chart-project-task-distribution",function(t,e){this.render=function(){for(var o=[],n=0;n<e.metrics.length;n++)o.push([e.metrics[n].column_title,e.metrics[n].nb_tasks]);KB.dom(t).add(KB.dom("div").attr("id","chart").build()),c3.generate({data:{columns:o,type:"donut"}})}}),KB.component("chart-project-time-comparison",function(t,e){this.render=function(){var o=[e.labelSpent],n=[e.labelEstimated],a=[];for(var i in e.metrics)o.push(e.metrics[i].time_spent),n.push(e.metrics[i].time_estimated),a.push("open"===i?e.labelOpen:e.labelClosed);KB.dom(t).add(KB.dom("div").attr("id","chart").build()),c3.generate({data:{columns:[o,n],type:"bar"},bar:{width:{ratio:.2}},axis:{x:{type:"category",categories:a}},legend:{show:!0}})}}),KB.component("chart-project-user-distribution",function(t,e){this.render=function(){for(var o=[],n=0;n<e.metrics.length;n++)o.push([e.metrics[n].user,e.metrics[n].nb_tasks]);KB.dom(t).add(KB.dom("div").attr("id","chart").build()),c3.generate({data:{columns:o,type:"donut"}})}}),KB.component("chart-task-time-column",function(t,e){this.render=function(){for(var o=e.metrics,n=[e.label],a=[],i=0;i<o.length;i++)n.push(o[i].time_spent),a.push(o[i].title);KB.dom(t).add(KB.dom("div").attr("id","chart").build()),c3.generate({data:{columns:[n],type:"bar"},bar:{width:{ratio:.5}},axis:{x:{type:"category",categories:a},y:{tick:{format:KB.utils.formatDuration}}},legend:{show:!1}})}}),KB.component("external-task-view",function(t,e){this.render=function(){$.ajax({cache:!1,url:e.url,success:function(e){KB.dom(t).html('<div id="external-task-view">'+e+"</div>")}})}}),KB.component("submit-cancel",function(t,e){function o(){r=!0,KB.find("#modal-submit-button").replace(i()),KB.trigger("modal.submit")}function n(){KB.trigger("modal.cancel"),_KB.get("Popover").close()}function a(){r=!1,KB.find("#modal-submit-button").replace(i())}function i(){var t=KB.dom("button").click(o).attr("id","modal-submit-button").attr("type","submit").attr("class","btn btn-blue");return r&&t.disable().add(KB.dom("i").attr("class","fa fa-spinner fa-pulse").build()).text(" "),t.text(e.submitLabel).build()}var r=!1;this.render=function(){KB.on("modal.stop",a);var o=KB.dom("div").attr("class","form-actions").add(i()).text(" "+e.orLabel+" ").add(KB.dom("a").attr("href","#").click(n).text(e.cancelLabel).build()).build();t.appendChild(o)}}),KB.component("suggest-menu",function(t,e){function o(t){switch(t.keyCode){case 27:p();break;case 38:t.preventDefault(),t.stopImmediatePropagation(),l();break;case 40:t.preventDefault(),t.stopImmediatePropagation(),c();break;case 13:t.preventDefault(),t.stopImmediatePropagation(),i()}}function n(){i()}function a(t){KB.dom(t).hasClass("suggest-menu-item")&&(KB.find(".suggest-menu-item.active").removeClass("active"),KB.dom(t).addClass("active"))}function i(){t.focus();var e=KB.find(".suggest-menu-item.active"),o=e.data("value"),n=e.data("trigger"),a=t.value,i=r(t),s=n+o+" ",d=KB.utils.getSelectionPosition(t),l=a.substring(0,d.selectionStart-i.length),c=a.substring(d.selectionEnd),u=l.length+s.length;t.value=l+s+c,t.setSelectionRange(u,u),p()}function r(t){var e=t.value.substring(0,t.selectionEnd).split("\n"),o=e[e.length-1],n=o.split(" ");return n[n.length-1]}function s(){for(var t=[".popover-form","#popover-content","body"],e=0;e<t.length;e++){var o=document.querySelector(t[e]);if(null!==o)return o}return null}function d(){for(var t=document.querySelectorAll(".suggest-menu-item"),e=0;e<t.length;e++)if(KB.dom(t[e]).hasClass("active")){KB.dom(t[e]).removeClass("active");break}return{items:t,index:e}}function l(){var t=d();t.index>0&&(t.index=t.index-1),KB.dom(t.items[t.index]).addClass("active")}function c(){var t=d();t.index<t.items.length-1&&t.index++,KB.dom(t.items[t.index]).addClass("active")}function p(){var t=KB.find("#suggest-menu");null!==t&&t.remove(),document.removeEventListener("keydown",o,!1)}function u(t){var o=r(t),n=h(o,e.triggers);p(),null!==n&&f(n,o.substring(n.length),e.triggers[n])}function h(t,e){for(var o in e)if(e.hasOwnProperty(o)&&0===t.indexOf(o))return o;return null}function f(t,e,o){if("string"==typeof o){var n=new RegExp("SEARCH_TERM","g"),a=o.replace(n,e);KB.http.get(a).success(function(o){m(t,e,o)})}else m(t,e,o)}function m(t,e,o){o=v(e,o),o.length>0&&b(g(t,o))}function v(t,e){var o=[];if(0===t.length)return e;for(var n=0;n<e.length;n++)0===e[n].value.toLowerCase().indexOf(t.toLowerCase())&&o.push(e[n]);return o}function g(t,e){for(var o=[],n=0;n<e.length;n++){var a="suggest-menu-item";0===n&&(a+=" active"),o.push({"class":a,html:e[n].html,"data-value":e[n].value,"data-trigger":t})}return o}function b(e){var i=s(),r=getCaretCoordinates(t,t.selectionEnd),d=r.left+t.offsetLeft-t.scrollLeft,l=r.top+t.offsetTop-t.scrollTop+16;document.addEventListener("keydown",o,!1);var c=KB.dom("ul").attr("id","suggest-menu").click(n).mouseover(a).style("left",d+"px").style("top",l+"px")["for"]("li",e).build();i.appendChild(c)}this.render=function(){t.addEventListener("input",function(){u(this)})}}),KB.component("task-move-position",function(t,e){function o(t){var e=KB.dom(document).find("#"+t);return e?parseInt(e.options[e.selectedIndex].value):null}function n(){var t=o("form-swimlanes");return null===t?e.board[0].id:t}function a(){var t=o("form-columns");return null===t?e.board[0].columns[0].id:t}function i(){var t=o("form-position");return null===t?1:t}function r(){var t=KB.find("input[name=positionChoice]:checked");return t?t.value:"before"}function s(){var t=KB.dom(document).find("#form-columns");KB.dom(t).replace(u());var e=KB.dom(document).find("#form-tasks");KB.dom(e).replace(h())}function d(){var t=KB.dom(document).find("#form-tasks");KB.dom(t).replace(h())}function l(t){KB.trigger("modal.stop"),KB.find("#message-container").replace(KB.dom("div").attr("id","message-container").attr("class","alert alert-error").text(t).build())}function c(){var t=i(),o=r();"after"===o&&t++,KB.find("#message-container").replace(KB.dom("div").attr("id","message-container").build()),KB.http.postJson(e.saveUrl,{column_id:a(),swimlane_id:n(),position:t}).success(function(){window.location.reload(!0)}).error(function(t){t&&l(t.message)})}function p(){var t=[];return e.board.forEach(function(e){t.push({value:e.id,text:e.name})}),KB.dom("select").attr("id","form-swimlanes").change(s)["for"]("option",t).build()}function u(){var t=[],o=n();return e.board.forEach(function(e){o===e.id&&e.columns.forEach(function(e){t.push({value:e.id,text:e.title})})}),KB.dom("select").attr("id","form-columns").change(d)["for"]("option",t).build()}function h(){var t=[],o=n(),i=a(),r=KB.dom("div").attr("id","form-tasks");return e.board.forEach(function(e){o===e.id&&e.columns.forEach(function(e){i===e.id&&e.tasks.forEach(function(e){t.push({value:e.position,text:"#"+e.id+" - "+e.title})})})}),t.length>0&&r.add(KB.html.label(e.positionLabel,"form-position")).add(KB.dom("select").attr("id","form-position")["for"]("option",t).build()).add(KB.html.radio(e.beforeLabel,"positionChoice","before")).add(KB.html.radio(e.afterLabel,"positionChoice","after")),r.build()}this.render=function(){KB.on("modal.submit",c);var o=KB.dom("div").on("submit",c).add(KB.dom("div").attr("id","message-container").build()).add(KB.html.label(e.swimlaneLabel,"form-swimlanes")).add(p()).add(KB.html.label(e.columnLabel,"form-columns")).add(u()).add(h()).build();t.appendChild(o)}}),KB.component("text-editor",function(t,e){function o(){var t=KB.dom("div").attr("class","text-editor-toolbar")["for"]("a",[{href:"#",html:'<i class="fa fa-pencil-square-o fa-fw"></i> '+e.labelWrite,click:function(){a()}}]).build();return m=KB.dom("div").attr("class","text-editor-preview-area markdown").build(),KB.dom("div").attr("class","text-editor-view-mode").add(t).add(m).hide().build()}function n(){var t=KB.dom("div").attr("class","text-editor-toolbar")["for"]("a",[{href:"#",html:'<i class="fa fa-eye fa-fw"></i> '+e.labelPreview,click:function(){a()}},{href:"#",html:'<i class="fa fa-bold fa-fw"></i>',click:function(){s("**")}},{href:"#",html:'<i class="fa fa-italic fa-fw"></i>',click:function(){s("_")}},{href:"#",html:'<i class="fa fa-strikethrough fa-fw"></i>',click:function(){s("~~")}},{href:"#",html:'<i class="fa fa-quote-right fa-fw"></i>',click:function(){l("> ")}},{href:"#",html:'<i class="fa fa-list-ul fa-fw"></i>',click:function(){l("* ")}},{href:"#",html:'<i class="fa fa-code fa-fw"></i>',click:function(){d("```")}}]).build(),o=KB.dom("textarea");return o.attr("name",e.name),e.tabindex&&o.attr("tabindex",e.tabindex),e.required&&o.attr("required","required"),o.text(e.text),e.placeholder&&o.attr("placeholder",e.placeholder),u=o.build(),e.suggestOptions&&KB.getComponent("suggest-menu",u,e.suggestOptions).render(),KB.dom("div").attr("class","text-editor-write-mode").add(t).add(u).build()}function a(){KB.dom(m).html(marked(u.value,{sanitize:!0})),KB.dom(h).toggle(),KB.dom(f).toggle()}function i(){return u.value.substring(u.selectionStart,u.selectionEnd)}function r(t,e,o,n){return t.substring(0,e)+n+t.substring(o)}function s(t){var e=i();c(t+e+t),p(t)}function d(t){var e=i();c("\n"+t+"\n"+e+"\n"+t),p(t,2)}function l(t){var e=i();if(e.indexOf("\n")===-1)c("\n"+t+e);else{for(var o=e.split("\n"),n=0;n<o.length;n++)o[n].indexOf(t)===-1&&(o[n]=t+o[n]);c(o.join("\n"))}p(t,1)}function c(t){u.focus();var e=!1,o=KB.utils.getSelectionPosition(u);if(v=o.selectionStart,g=o.selectionEnd,document.queryCommandSupported("insertText")&&(e=document.execCommand("insertText",!1,t)),!e){try{document.execCommand("ms-beginUndoUnit")}catch(n){}u.value=r(u.value,v,g,t);try{document.execCommand("ms-endUndoUnit")}catch(n){}}}function p(t,e){e=e||0;var o=g+t.length+e;u.setSelectionRange(o,o)}var u,h,f,m,v,g;this.render=function(){f=n(),h=o(),t.appendChild(KB.dom("div").attr("class","text-editor").add(h).add(f).build()),e.autofocus&&u.focus()}}),document.addEventListener("DOMContentLoaded",function(){KB.render(),KB.listen()});var Kanboard={};Kanboard.App=function(){this.controllers={}},Kanboard.App.prototype.get=function(t){return this.controllers[t]},Kanboard.App.prototype.execute=function(){for(var t in Kanboard)if("App"!==t){var e=new Kanboard[t](this);this.controllers[t]=e,"function"==typeof e.execute&&e.execute(),"function"==typeof e.listen&&e.listen(),"function"==typeof e.focus&&e.focus(),"function"==typeof e.keyboardShortcuts&&e.keyboardShortcuts()}this.focus(),this.chosen(),this.keyboardShortcuts(),this.datePicker(),this.autoComplete(),this.tagAutoComplete()},Kanboard.App.prototype.keyboardShortcuts=function(){var t=this;Mousetrap.bindGlobal("mod+enter",function(){var e=$("form");1==e.length?e.submit():e.length>1&&("INPUT"===document.activeElement.tagName||"TEXTAREA"===document.activeElement.tagName?$(document.activeElement).parents("form").submit():t.get("Popover").isOpen()&&$("#popover-container form").submit())}),Mousetrap.bind("b",function(t){t.preventDefault(),$("#board-selector").trigger("chosen:open")}),Mousetrap.bindGlobal("esc",function(){document.getElementById("suggest-menu")||(t.get("Popover").close(),t.get("Dropdown").close())}),Mousetrap.bind("?",function(){t.get("Popover").open($("body").data("keyboard-shortcut-url"))})},Kanboard.App.prototype.focus=function(){$(document).on("focus",".auto-select",function(){$(this).select()}),$(document).on("mouseup",".auto-select",function(t){t.preventDefault()})},Kanboard.App.prototype.chosen=function(){$(".chosen-select").each(function(){var t=$(this).data("search-threshold");void 0===t&&(t=10),$(this).chosen({width:"180px",no_results_text:$(this).data("notfound"),disable_search_threshold:t})}),$(".select-auto-redirect").change(function(){var t=new RegExp($(this).data("redirect-regex"),"g");window.location=$(this).data("redirect-url").replace(t,$(this).val())})},Kanboard.App.prototype.datePicker=function(){var t=$("body"),e=t.data("js-date-format"),o=t.data("js-time-format"),n=t.data("js-lang");$.datepicker.setDefaults($.datepicker.regional[n]),$.timepicker.setDefaults($.timepicker.regional[n]),$(".form-date").datepicker({showOtherMonths:!0,selectOtherMonths:!0,dateFormat:e,constrainInput:!1}),$(".form-datetime").datetimepicker({dateFormat:e,timeFormat:o,constrainInput:!1})},Kanboard.App.prototype.tagAutoComplete=function(){$(".tag-autocomplete").select2({tags:!0})},Kanboard.App.prototype.autoComplete=function(){$(".autocomplete").each(function(){var t=$(this),e=t.data("dst-field"),o=t.data("dst-extra-field");""===$("#form-"+e).val()&&t.parent().find("button[type=submit]").attr("disabled","disabled"),t.autocomplete({source:t.data("search-url"),minLength:1,select:function(n,a){$("input[name="+e+"]").val(a.item.id),o&&$("input[name="+o+"]").val(a.item[o]),t.parent().find("button[type=submit]").removeAttr("disabled")}})})},Kanboard.App.prototype.hasId=function(t){return!!document.getElementById(t)},Kanboard.App.prototype.showLoadingIcon=function(){$("body").append('<span id="app-loading-icon">&nbsp;<i class="fa fa-spinner fa-spin"></i></span>')},Kanboard.App.prototype.hideLoadingIcon=function(){$("#app-loading-icon").remove()},Kanboard.App.prototype.isVisible=function(){var t="";return"undefined"!=typeof document.hidden?t="visibilityState":"undefined"!=typeof document.mozHidden?t="mozVisibilityState":"undefined"!=typeof document.msHidden?t="msVisibilityState":"undefined"!=typeof document.webkitHidden&&(t="webkitVisibilityState"),""===t||"visible"==document[t]},Kanboard.BoardCollapsedMode=function(t){this.app=t},Kanboard.BoardCollapsedMode.prototype.keyboardShortcuts=function(){var t=this;t.app.hasId("board")&&Mousetrap.bind("s",function(){t.toggle()})},Kanboard.BoardCollapsedMode.prototype.toggle=function(){var t=this;this.app.showLoadingIcon(),$.ajax({cache:!1,url:$('.filter-display-mode:not([style="display: none;"]) a').attr("href"),success:function(e){$(".filter-display-mode").toggle(),t.app.get("BoardDragAndDrop").refresh(e)}})},Kanboard.BoardColumnView=function(t){this.app=t},Kanboard.BoardColumnView.prototype.execute=function(){this.app.hasId("board")&&this.render()},Kanboard.BoardColumnView.prototype.listen=function(){var t=this;$(document).on("click",".board-toggle-column-view",function(){t.toggle($(this).data("column-id"))})},Kanboard.BoardColumnView.prototype.onBoardRendered=function(){this.render()},Kanboard.BoardColumnView.prototype.render=function(){var t=this;$(".board-column-header").each(function(){var e=$(this).data("column-id");localStorage.getItem("hidden_column_"+e)&&t.hideColumn(e)})},Kanboard.BoardColumnView.prototype.toggle=function(t){localStorage.getItem("hidden_column_"+t)?this.showColumn(t):this.hideColumn(t)},Kanboard.BoardColumnView.prototype.hideColumn=function(t){$(".board-column-"+t+" .board-column-expanded").hide(),$(".board-column-"+t+" .board-column-collapsed").show(),$(".board-column-header-"+t+" .board-column-expanded").hide(),$(".board-column-header-"+t+" .board-column-collapsed").show(),$(".board-column-header-"+t).each(function(){$(this).removeClass("board-column-compact"),$(this).addClass("board-column-header-collapsed")}),$(".board-column-"+t).each(function(){$(this).addClass("board-column-task-collapsed")}),$(".board-column-"+t+" .board-rotation").each(function(){$(this).css("width",$(".board-column-"+t).height())}),localStorage.setItem("hidden_column_"+t,1)},Kanboard.BoardColumnView.prototype.showColumn=function(t){$(".board-column-"+t+" .board-column-expanded").show(),$(".board-column-"+t+" .board-column-collapsed").hide(),$(".board-column-header-"+t+" .board-column-expanded").show(),$(".board-column-header-"+t+" .board-column-collapsed").hide(),$(".board-column-header-"+t).removeClass("board-column-header-collapsed"),$(".board-column-"+t).removeClass("board-column-task-collapsed"),0==localStorage.getItem("horizontal_scroll")&&$(".board-column-header-"+t).addClass("board-column-compact"),localStorage.removeItem("hidden_column_"+t)},Kanboard.BoardHorizontalScrolling=function(t){this.app=t},Kanboard.BoardHorizontalScrolling.prototype.execute=function(){this.app.hasId("board")&&this.render()},Kanboard.BoardHorizontalScrolling.prototype.listen=function(){var t=this;$(document).on("click",".filter-toggle-scrolling",function(e){e.preventDefault(),t.toggle()})},Kanboard.BoardHorizontalScrolling.prototype.keyboardShortcuts=function(){var t=this;t.app.hasId("board")&&Mousetrap.bind("c",function(){t.toggle()})},Kanboard.BoardHorizontalScrolling.prototype.onBoardRendered=function(){this.render()},Kanboard.BoardHorizontalScrolling.prototype.toggle=function(){var t=localStorage.getItem("horizontal_scroll")||1;localStorage.setItem("horizontal_scroll",0==t?1:0),this.render()},Kanboard.BoardHorizontalScrolling.prototype.render=function(){0==localStorage.getItem("horizontal_scroll")?($(".filter-wide").show(),$(".filter-compact").hide(),$("#board-container").addClass("board-container-compact"),$("#board th:not(.board-column-header-collapsed)").addClass("board-column-compact")):($(".filter-wide").hide(),$(".filter-compact").show(),$("#board-container").removeClass("board-container-compact"),$("#board th").removeClass("board-column-compact"))},Kanboard.BoardPolling=function(t){this.app=t},Kanboard.BoardPolling.prototype.execute=function(){if(this.app.hasId("board")){var t=parseInt($("#board").attr("data-check-interval"));t>0&&window.setInterval(this.check.bind(this),1e3*t)}},Kanboard.BoardPolling.prototype.check=function(){if(this.app.isVisible()&&!this.app.get("BoardDragAndDrop").savingInProgress){var t=this;this.app.showLoadingIcon(),$.ajax({cache:!1,url:$("#board").data("check-url"),statusCode:{200:function(e){t.app.get("BoardDragAndDrop").refresh(e)},304:function(){t.app.hideLoadingIcon()}}})}},Kanboard.BoardTask=function(t){this.app=t},Kanboard.BoardTask.prototype.listen=function(){var t=this;$(document).on("click",".task-board-change-assignee",function(e){e.preventDefault(),e.stopPropagation(),t.app.get("Popover").open($(this).data("url"))}),$(document).on("click",".task-board",function(t){"A"!=t.target.tagName&&"IMG"!=t.target.tagName&&(window.location=$(this).data("task-url"))})},Kanboard.BoardTask.prototype.keyboardShortcuts=function(){var t=this;t.app.hasId("board")&&Mousetrap.bind("n",function(){t.app.get("Popover").open($("#board").data("task-creation-url"))})},Kanboard.Column=function(t){this.app=t},Kanboard.Column.prototype.listen=function(){this.dragAndDrop()},Kanboard.Column.prototype.dragAndDrop=function(){var t=this;$(".draggable-row-handle").mouseenter(function(){$(this).parent().parent().addClass("draggable-item-hover")}).mouseleave(function(){$(this).parent().parent().removeClass("draggable-item-hover")}),$(".columns-table tbody").sortable({forcePlaceholderSize:!0,handle:"td:first i",helper:function(t,e){return e.children().each(function(){$(this).width($(this).width())}),e},stop:function(e,o){var n=o.item;n.removeClass("draggable-item-selected"),t.savePosition(n.data("column-id"),n.index()+1)},start:function(t,e){e.item.addClass("draggable-item-selected")}}).disableSelection()},Kanboard.Column.prototype.savePosition=function(t,e){var o=$(".columns-table").data("save-position-url"),n=this;this.app.showLoadingIcon(),$.ajax({cache:!1,url:o,contentType:"application/json",type:"POST",processData:!1,data:JSON.stringify({column_id:t,position:e}),complete:function(){n.app.hideLoadingIcon()}})},Kanboard.Dropdown=function(t){this.app=t},Kanboard.Dropdown.prototype.listen=function(){var t=this;$(document).on("click",function(){t.close()}),$(document).on("click","#popover-content",function(){t.close()}),$(document).on("click",".dropdown-menu",function(e){e.preventDefault(),e.stopImmediatePropagation(),t.close();var o=$(this).next("ul"),n=$(this).offset();$("body").append(jQuery("<div>",{id:"dropdown"})),o.clone().appendTo("#dropdown");var a=$("#dropdown ul");a.addClass("dropdown-submenu-open");var i=a.outerHeight(),r=a.outerWidth();n.top+i-$(window).scrollTop()<$(window).height()||$(window).scrollTop()+n.top<i?a.css("top",n.top+$(this).height()):a.css("top",n.top-i-5),n.left+r>$(window).width()?a.css("left",n.left-r+$(this).outerWidth()):a.css("left",n.left)}),$(document).on("click",".dropdown-submenu-open li",function(t){$(t.target).is("li")&&$(this).find("a:visible")[0].click()})},Kanboard.Dropdown.prototype.close=function(){$("#dropdown").remove()},Kanboard.Dropdown.prototype.onPopoverOpened=function(){this.close()},Kanboard.FileUpload=function(t){this.app=t,this.files=[],this.currentFile=0},Kanboard.FileUpload.prototype.onPopoverOpened=function(){var t=document.getElementById("file-dropzone"),e=this;t&&(t.ondragover=t.ondragenter=function(t){t.stopPropagation(),t.preventDefault()},t.ondrop=function(t){t.stopPropagation(),t.preventDefault(),e.files=t.dataTransfer.files,e.show(),$("#file-error-max-size").hide()},$(document).on("click","#file-browser",function(t){t.preventDefault(),$("#file-form-element").get(0).click()}),$(document).on("click","#file-upload-button",function(t){t.preventDefault(),e.currentFile=0,e.checkFiles()}),$("#file-form-element").change(function(){e.files=document.getElementById("file-form-element").files,e.show(),$("#file-error-max-size").hide()}))},Kanboard.FileUpload.prototype.show=function(){if($("#file-list").remove(),this.files.length>0){$("#file-upload-button").prop("disabled",!1),$("#file-dropzone-inner").hide();for(var t=jQuery("<ul>",{id:"file-list"}),e=0;e<this.files.length;e++){var o=jQuery("<span>",{id:"file-percentage-"+e}).append("(0%)"),n=jQuery("<progress>",{id:"file-progress-"+e,value:0}),a=jQuery("<li>",{id:"file-label-"+e}).append(n).append("&nbsp;").append(this.files[e].name).append("&nbsp;").append(o);t.append(a)}$("#file-dropzone").append(t)}else $("#file-dropzone-inner").show()},Kanboard.FileUpload.prototype.checkFiles=function(){for(var t=parseInt($("#file-dropzone").data("max-size")),e=0;e<this.files.length;e++)if(this.files[e].size>t)return $("#file-error-max-size").show(),$("#file-label-"+e).addClass("file-error"),void $("#file-upload-button").prop("disabled",!0);this.uploadFiles()},Kanboard.FileUpload.prototype.uploadFiles=function(){this.files.length>0&&this.uploadFile(this.files[this.currentFile])},Kanboard.FileUpload.prototype.uploadFile=function(t){var e=document.getElementById("file-dropzone"),o=e.dataset.url,n=new XMLHttpRequest,a=new FormData;n.upload.addEventListener("progress",this.updateProgress.bind(this)),n.upload.addEventListener("load",this.transferComplete.bind(this)),n.open("POST",o,!0),a.append("files[]",t),n.send(a)},Kanboard.FileUpload.prototype.updateProgress=function(t){t.lengthComputable&&($("#file-progress-"+this.currentFile).val(t.loaded/t.total),
+$("#file-percentage-"+this.currentFile).text("("+Math.floor(t.loaded/t.total*100)+"%)"))},Kanboard.FileUpload.prototype.transferComplete=function(){if(this.currentFile++,this.currentFile<this.files.length)this.uploadFile(this.files[this.currentFile]);else{var t=$("#file-upload-button");t.prop("disabled",!0),t.parent().hide(),$("#file-done").show()}},Kanboard.Gantt=function(t){this.app=t,this.data=[],this.options={container:"#gantt-chart",showWeekends:!0,allowMoves:!0,allowResizes:!0,cellWidth:21,cellHeight:31,slideWidth:1e3,vHeaderWidth:200}},Kanboard.Gantt.prototype.execute=function(){this.app.hasId("gantt-chart")&&this.show()},Kanboard.Gantt.prototype.saveRecord=function(t){this.app.showLoadingIcon(),$.ajax({cache:!1,url:$(this.options.container).data("save-url"),contentType:"application/json",type:"POST",processData:!1,data:JSON.stringify(t),complete:this.app.hideLoadingIcon.bind(this)})},Kanboard.Gantt.prototype.show=function(){this.data=this.prepareData($(this.options.container).data("records"));var t=Math.floor(this.options.slideWidth/this.options.cellWidth+5),e=this.getDateRange(t),o=e[0],n=e[1],a=$(this.options.container),i=jQuery("<div>",{"class":"ganttview"});i.append(this.renderVerticalHeader()),i.append(this.renderSlider(o,n)),a.append(i),jQuery("div.ganttview-grid-row div.ganttview-grid-row-cell:last-child",a).addClass("last"),jQuery("div.ganttview-hzheader-days div.ganttview-hzheader-day:last-child",a).addClass("last"),jQuery("div.ganttview-hzheader-months div.ganttview-hzheader-month:last-child",a).addClass("last"),$(this.options.container).data("readonly")?(this.options.allowResizes=!1,this.options.allowMoves=!1):(this.listenForBlockResize(o),this.listenForBlockMove(o))},Kanboard.Gantt.prototype.renderVerticalHeader=function(){for(var t=jQuery("<div>",{"class":"ganttview-vtheader"}),e=jQuery("<div>",{"class":"ganttview-vtheader-item"}),o=jQuery("<div>",{"class":"ganttview-vtheader-series"}),n=0;n<this.data.length;n++){var a=jQuery("<span>").append(jQuery("<i>",{"class":"fa fa-info-circle tooltip",title:this.getVerticalHeaderTooltip(this.data[n])})).append("&nbsp;");"task"==this.data[n].type?a.append(jQuery("<a>",{href:this.data[n].link,title:this.data[n].title}).append(this.data[n].title)):a.append(jQuery("<a>",{href:this.data[n].board_link,title:$(this.options.container).data("label-board-link")}).append('<i class="fa fa-th"></i>')).append("&nbsp;").append(jQuery("<a>",{href:this.data[n].gantt_link,title:$(this.options.container).data("label-gantt-link")}).append('<i class="fa fa-sliders"></i>')).append("&nbsp;").append(jQuery("<a>",{href:this.data[n].link}).append(this.data[n].title)),o.append(jQuery("<div>",{"class":"ganttview-vtheader-series-name"}).append(a))}return e.append(o),t.append(e),t},Kanboard.Gantt.prototype.renderSlider=function(t,e){var o=jQuery("<div>",{"class":"ganttview-slide-container"}),n=this.getDates(t,e);return o.append(this.renderHorizontalHeader(n)),o.append(this.renderGrid(n)),o.append(this.addBlockContainers()),this.addBlocks(o,t),o},Kanboard.Gantt.prototype.renderHorizontalHeader=function(t){var e=jQuery("<div>",{"class":"ganttview-hzheader"}),o=jQuery("<div>",{"class":"ganttview-hzheader-months"}),n=jQuery("<div>",{"class":"ganttview-hzheader-days"}),a=0;for(var i in t)for(var r in t[i]){var s=t[i][r].length*this.options.cellWidth;a+=s,o.append(jQuery("<div>",{"class":"ganttview-hzheader-month",css:{width:s-1+"px"}}).append($.datepicker.regional[$("body").data("js-lang")].monthNames[r]+" "+i));for(var d in t[i][r])n.append(jQuery("<div>",{"class":"ganttview-hzheader-day"}).append(t[i][r][d].getDate()))}return o.css("width",a+"px"),n.css("width",a+"px"),e.append(o).append(n),e},Kanboard.Gantt.prototype.renderGrid=function(t){var e=jQuery("<div>",{"class":"ganttview-grid"}),o=jQuery("<div>",{"class":"ganttview-grid-row"});for(var n in t)for(var a in t[n])for(var i in t[n][a]){var r=jQuery("<div>",{"class":"ganttview-grid-row-cell"});this.options.showWeekends&&this.isWeekend(t[n][a][i])&&r.addClass("ganttview-weekend"),o.append(r)}var s=jQuery("div.ganttview-grid-row-cell",o).length*this.options.cellWidth;o.css("width",s+"px"),e.css("width",s+"px");for(var d=0;d<this.data.length;d++)e.append(o.clone());return e},Kanboard.Gantt.prototype.addBlockContainers=function(){for(var t=jQuery("<div>",{"class":"ganttview-blocks"}),e=0;e<this.data.length;e++)t.append(jQuery("<div>",{"class":"ganttview-block-container"}));return t},Kanboard.Gantt.prototype.addBlocks=function(t,e){for(var o=jQuery("div.ganttview-blocks div.ganttview-block-container",t),n=0,a=0;a<this.data.length;a++){var i=this.data[a],r=this.daysBetween(i.start,i.end)+1,s=this.daysBetween(e,i.start),d=jQuery("<div>",{"class":"ganttview-block-text"}),l=jQuery("<div>",{"class":"ganttview-block tooltip"+(this.options.allowMoves?" ganttview-block-movable":""),title:this.getBarTooltip(i),css:{width:r*this.options.cellWidth-9+"px","margin-left":s*this.options.cellWidth+"px"}}).append(d);r>=2&&d.append(i.progress),l.data("record",i),this.setBarColor(l,i),jQuery(o[n]).append(l),n+=1}},Kanboard.Gantt.prototype.getVerticalHeaderTooltip=function(t){var e="";if("task"==t.type)e="<strong>"+t.column_title+"</strong> ("+t.progress+")<br/>"+t.title;else{var o=["project-manager","project-member"];for(var n in o){var a=o[n];if(!jQuery.isEmptyObject(t.users[a])){var i=jQuery("<ul>");for(var r in t.users[a])r&&i.append(jQuery("<li>").append(t.users[a][r]));e+="<p><strong>"+$(this.options.container).data("label-"+a)+"</strong></p>"+i[0].outerHTML}}}return e},Kanboard.Gantt.prototype.getBarTooltip=function(t){var e="";return t.not_defined?e=$(this.options.container).data("label-not-defined"):("task"==t.type&&(e="<strong>"+t.progress+"</strong><br/>"+$(this.options.container).data("label-assignee")+" "+(t.assignee?t.assignee:"")+"<br/>"),e+=$(this.options.container).data("label-start-date")+" "+$.datepicker.formatDate("yy-mm-dd",t.start)+"<br/>",e+=$(this.options.container).data("label-end-date")+" "+$.datepicker.formatDate("yy-mm-dd",t.end)),e},Kanboard.Gantt.prototype.setBarColor=function(t,e){e.not_defined?t.addClass("ganttview-block-not-defined"):(t.css("background-color",e.color.background),t.css("border-color",e.color.border),"0%"!=e.progress&&t.append(jQuery("<div>",{css:{"z-index":0,position:"absolute",top:0,bottom:0,"background-color":e.color.border,width:e.progress,opacity:.4}})))},Kanboard.Gantt.prototype.listenForBlockResize=function(t){var e=this;jQuery("div.ganttview-block",this.options.container).resizable({grid:this.options.cellWidth,handles:"e,w",delay:300,stop:function(){var o=jQuery(this);e.updateDataAndPosition(o,t),e.saveRecord(o.data("record"))}})},Kanboard.Gantt.prototype.listenForBlockMove=function(t){var e=this;jQuery("div.ganttview-block",this.options.container).draggable({axis:"x",delay:300,grid:[this.options.cellWidth,this.options.cellWidth],stop:function(){var o=jQuery(this);e.updateDataAndPosition(o,t),e.saveRecord(o.data("record"))}})},Kanboard.Gantt.prototype.updateDataAndPosition=function(t,e){var o=jQuery("div.ganttview-slide-container",this.options.container),n=o.scrollLeft(),a=t.offset().left-o.offset().left-1+n,i=t.data("record");i.not_defined=!1,this.setBarColor(t,i);var r=Math.round(a/this.options.cellWidth),s=this.addDays(this.cloneDate(e),r);i.start=s;var d=t.outerWidth(),l=Math.round(d/this.options.cellWidth)-1;i.end=this.addDays(this.cloneDate(s),l),"task"===i.type&&l>0&&jQuery("div.ganttview-block-text",t).text(i.progress),t.attr("title",this.getBarTooltip(i)),t.data("record",i),t.css("top","").css("left","").css("position","relative").css("margin-left",a+"px")},Kanboard.Gantt.prototype.getDates=function(t,e){var o=[];o[t.getFullYear()]=[],o[t.getFullYear()][t.getMonth()]=[t];for(var n=t;this.compareDate(n,e)==-1;){var a=this.addDays(this.cloneDate(n),1);o[a.getFullYear()]||(o[a.getFullYear()]=[]),o[a.getFullYear()][a.getMonth()]||(o[a.getFullYear()][a.getMonth()]=[]),o[a.getFullYear()][a.getMonth()].push(a),n=a}return o},Kanboard.Gantt.prototype.prepareData=function(t){for(var e=0;e<t.length;e++){var o=new Date(t[e].start[0],t[e].start[1]-1,t[e].start[2],0,0,0,0);t[e].start=o;var n=new Date(t[e].end[0],t[e].end[1]-1,t[e].end[2],0,0,0,0);t[e].end=n}return t},Kanboard.Gantt.prototype.getDateRange=function(t){for(var e=new Date,o=new Date,n=0;n<this.data.length;n++){var a=new Date;a.setTime(Date.parse(this.data[n].start));var i=new Date;i.setTime(Date.parse(this.data[n].end)),0==n&&(e=a,o=i),1==this.compareDate(e,a)&&(e=a),this.compareDate(o,i)==-1&&(o=i)}return this.daysBetween(e,o)<t&&(o=this.addDays(this.cloneDate(e),t)),e.setDate(e.getDate()-1),[e,o]},Kanboard.Gantt.prototype.daysBetween=function(t,e){if(!t||!e)return 0;for(var o=0,n=this.cloneDate(t);this.compareDate(n,e)==-1;)o+=1,this.addDays(n,1);return o},Kanboard.Gantt.prototype.isWeekend=function(t){return t.getDay()%6==0},Kanboard.Gantt.prototype.cloneDate=function(t){return new Date(t.getTime())},Kanboard.Gantt.prototype.addDays=function(t,e){return t.setDate(t.getDate()+1*e),t},Kanboard.Gantt.prototype.compareDate=function(t,e){if(isNaN(t)||isNaN(e))throw new Error(t+" - "+e);if(t instanceof Date&&e instanceof Date)return t<e?-1:t>e?1:0;throw new TypeError(t+" - "+e)},Kanboard.Popover=function(t){this.app=t},Kanboard.Popover.prototype.listen=function(){var t=this;$(document).on("click",".popover",function(e){t.onClick(e)}),$(document).on("click",".close-popover",function(e){t.close(e)}),$(document).on("click","#popover-close-button",function(e){t.close(e)}),$(document).on("click","#popover-content",function(t){t.stopPropagation()})},Kanboard.Popover.prototype.onClick=function(t){t.preventDefault(),t.stopPropagation();var e=t.currentTarget||t.target,o=e.getAttribute("href");o||(o=e.getAttribute("data-href")),o&&this.open(o)},Kanboard.Popover.prototype.isOpen=function(){return $("#popover-container").size()>0},Kanboard.Popover.prototype.open=function(t){var e=this;e.isOpen()||$.get(t,function(t){$("body").prepend('<div id="popover-container"><div id="popover-content"><div id="popover-content-header"><a href="#" id="popover-close-button"><i class="fa fa-times"></i></a></div>'+t+"</div></div>"),e.executeOnOpenedListeners()})},Kanboard.Popover.prototype.close=function(t){this.isOpen()&&(t&&t.preventDefault(),$("#popover-container").remove(),this.executeOnClosedListeners())},Kanboard.Popover.prototype.ajaxReload=function(t,e,o){var n=e.getResponseHeader("X-Ajax-Redirect");"self"===n?window.location.reload():n&&n.indexOf("#")>-1?window.location=n.split("#")[0]:n?window.location=n:($("#popover-content").html(t),$("#popover-content input[autofocus]").focus(),o.executeOnOpenedListeners())},Kanboard.Popover.prototype.executeOnOpenedListeners=function(){for(var t in this.app.controllers){var e=this.app.get(t);"function"==typeof e.onPopoverOpened&&e.onPopoverOpened()}this.afterOpen()},Kanboard.Popover.prototype.executeOnClosedListeners=function(){for(var t in this.app.controllers){var e=this.app.get(t);"function"==typeof e.onPopoverClosed&&e.onPopoverClosed()}},Kanboard.Popover.prototype.afterOpen=function(){var t=this,e=$("#popover-content .popover-form");e&&e.on("submit",function(o){o.preventDefault(),$.ajax({type:"POST",url:e.attr("action"),data:e.serialize(),success:function(e,o,n){t.ajaxReload(e,n,t)},beforeSend:function(){var t=$('.popover-form button[type="submit"]');t.html('<i class="fa fa-spinner fa-pulse"></i> '+t.html()),t.attr("disabled",!0)}})}),$(document).on("click",".popover-link",function(e){e.preventDefault(),$.ajax({type:"GET",url:$(this).attr("href"),success:function(e,o,n){t.ajaxReload(e,n,t)}})}),$("#popover-content input[autofocus]").each(function(){$(this).focus()}),this.app.datePicker(),this.app.autoComplete(),this.app.tagAutoComplete(),KB.render()},Kanboard.ProjectCreation=function(t){this.app=t},Kanboard.ProjectCreation.prototype.onPopoverOpened=function(){$("#project-creation-form #form-src_project_id").on("change",function(){var t=$(this).val();0==t?$(".project-creation-options").hide():$(".project-creation-options").show()})},Kanboard.ProjectPermission=function(t){this.app=t},Kanboard.ProjectPermission.prototype.listen=function(){$(".project-change-role").on("change",function(){$.ajax({cache:!1,url:$(this).data("url"),contentType:"application/json",type:"POST",processData:!1,data:JSON.stringify({id:$(this).data("id"),role:$(this).val()})})})},Kanboard.Screenshot=function(t){this.app=t,this.pasteCatcher=null},Kanboard.Screenshot.prototype.onPopoverOpened=function(){this.app.hasId("screenshot-zone")&&this.initialize()},Kanboard.Screenshot.prototype.initialize=function(){this.destroy(),window.Clipboard||(this.pasteCatcher=document.createElement("div"),this.pasteCatcher.id="screenshot-pastezone",this.pasteCatcher.contentEditable="true",this.pasteCatcher.style.opacity=0,this.pasteCatcher.style.position="fixed",this.pasteCatcher.style.top=0,this.pasteCatcher.style.right=0,this.pasteCatcher.style.width=0,document.body.insertBefore(this.pasteCatcher,document.body.firstChild),this.pasteCatcher.focus(),document.addEventListener("click",this.setFocus.bind(this)),document.getElementById("screenshot-zone").addEventListener("click",this.setFocus.bind(this))),window.addEventListener("paste",this.pasteHandler.bind(this))},Kanboard.Screenshot.prototype.destroy=function(){null!==this.pasteCatcher?document.body.removeChild(this.pasteCatcher):document.getElementById("screenshot-pastezone")&&document.body.removeChild(document.getElementById("screenshot-pastezone")),document.removeEventListener("click",this.setFocus.bind(this)),this.pasteCatcher=null},Kanboard.Screenshot.prototype.setFocus=function(){null!==this.pasteCatcher&&this.pasteCatcher.focus()},Kanboard.Screenshot.prototype.pasteHandler=function(t){if(t.clipboardData&&t.clipboardData.items){var e=t.clipboardData.items;if(e)for(var o=0;o<e.length;o++)if(e[o].type.indexOf("image")!==-1){var n=e[o].getAsFile(),a=new FileReader,i=this;a.onload=function(t){i.createImage(t.target.result)},a.readAsDataURL(n)}}else setTimeout(this.checkInput.bind(this),100)},Kanboard.Screenshot.prototype.checkInput=function(){var t=this.pasteCatcher.childNodes[0];t&&"IMG"===t.tagName&&this.createImage(t.src),this.pasteCatcher.innerHTML=""},Kanboard.Screenshot.prototype.createImage=function(t){var e=new Image;e.src=t,e.onload=function(){var e=t.split("base64,"),o=e[1];$("input[name=screenshot]").val(o)};var o=document.getElementById("screenshot-zone");o.innerHTML="",o.className="screenshot-pasted",o.appendChild(e),this.destroy(),this.initialize()},Kanboard.Search=function(t){this.app=t},Kanboard.Search.prototype.focus=function(){$(document).on("focus","#form-search",function(){var t=$("#form-search");if(t[0].setSelectionRange){var e=2*t.val().length;t[0].setSelectionRange(e,e)}})},Kanboard.Search.prototype.listen=function(){$(document).on("click",".filter-helper",function(t){t.preventDefault();var e=$(this).data("filter"),o=$(this).data("append-filter"),n=$(this).data("unique-filter"),a=$("#form-search");if(n){var i=n.substr(0,n.indexOf(":"));e=a.val().replace(new RegExp("("+i+":[#a-z0-9]+)","g"),""),e=e.replace(new RegExp("("+i+':"(.+)")',"g"),""),e=e.trim(),e+=" "+n}else o&&(e=a.val()+" "+o);a.val(e),$("form.search").submit()})},Kanboard.Search.prototype.goToView=function(t){var e=$(t);e.length&&(window.location=e.attr("href"))},Kanboard.Search.prototype.keyboardShortcuts=function(){var t=this;Mousetrap.bind("v o",function(){t.goToView(".view-overview")}),Mousetrap.bind("v b",function(){t.goToView(".view-board")}),Mousetrap.bind("v c",function(){t.goToView(".view-calendar")}),Mousetrap.bind("v l",function(){t.goToView(".view-listing")}),Mousetrap.bind("v g",function(){t.goToView(".view-gantt")}),Mousetrap.bind("f",function(t){t.preventDefault();var e=document.getElementById("form-search");e&&e.focus()}),Mousetrap.bind("r",function(t){t.preventDefault();var e=$(".filter-reset").data("filter"),o=$("#form-search");o.val(e),$("form.search").submit()})},Kanboard.Session=function(t){this.app=t},Kanboard.Session.prototype.execute=function(){window.setInterval(this.checkSession,6e4)},Kanboard.Session.prototype.checkSession=function(){$(".form-login").length||$.ajax({cache:!1,url:$("body").data("status-url"),statusCode:{401:function(){window.location=$("body").data("login-url")}}})},Kanboard.Subtask=function(t){this.app=t},Kanboard.Subtask.prototype.listen=function(){var t=this;this.dragAndDrop(),$(document).on("click",".subtask-toggle-status",function(e){var o=$(this);e.preventDefault(),$.ajax({cache:!1,url:o.attr("href"),success:function(e){o.hasClass("subtask-refresh-table")?$(".subtasks-table").replaceWith(e):o.replaceWith(e),t.dragAndDrop()}})}),$(document).on("click",".subtask-toggle-timer",function(e){var o=$(this);e.preventDefault(),$.ajax({cache:!1,url:o.attr("href"),success:function(e){$(".subtasks-table").replaceWith(e),t.dragAndDrop()}})})},Kanboard.Subtask.prototype.dragAndDrop=function(){var t=this;$(".draggable-row-handle").mouseenter(function(){$(this).parent().parent().addClass("draggable-item-hover")}).mouseleave(function(){$(this).parent().parent().removeClass("draggable-item-hover")}),$(".subtasks-table tbody").sortable({forcePlaceholderSize:!0,handle:"td:first i",helper:function(t,e){return e.children().each(function(){$(this).width($(this).width())}),e},stop:function(e,o){var n=o.item;n.removeClass("draggable-item-selected"),t.savePosition(n.data("subtask-id"),n.index()+1)},start:function(t,e){e.item.addClass("draggable-item-selected")}}).disableSelection()},Kanboard.Subtask.prototype.savePosition=function(t,e){var o=$(".subtasks-table").data("save-position-url"),n=this;this.app.showLoadingIcon(),$.ajax({cache:!1,url:o,contentType:"application/json",type:"POST",processData:!1,data:JSON.stringify({subtask_id:t,position:e}),complete:function(){n.app.hideLoadingIcon()}})},Kanboard.Swimlane=function(t){this.app=t},Kanboard.Swimlane.prototype.execute=function(){$(".swimlanes-table").length&&this.dragAndDrop()},Kanboard.Swimlane.prototype.listen=function(){var t=this;$(document).on("click",".board-swimlane-toggle",function(e){e.preventDefault();var o=$(this).data("swimlane-id");t.isCollapsed(o)?t.expand(o):t.collapse(o)})},Kanboard.Swimlane.prototype.onBoardRendered=function(){for(var t=this.getAllCollapsed(),e=0;e<t.length;e++)this.collapse(t[e])},Kanboard.Swimlane.prototype.getStorageKey=function(){return"hidden_swimlanes_"+$("#board").data("project-id")},Kanboard.Swimlane.prototype.expand=function(t){var e=this.getAllCollapsed(),o=e.indexOf(t);o>-1&&e.splice(o,1),localStorage.setItem(this.getStorageKey(),JSON.stringify(e)),$(".board-swimlane-columns-"+t).css("display","table-row"),$(".board-swimlane-tasks-"+t).css("display","table-row"),$(".hide-icon-swimlane-"+t).css("display","inline"),$(".show-icon-swimlane-"+t).css("display","none")},Kanboard.Swimlane.prototype.collapse=function(t){var e=this.getAllCollapsed();e.indexOf(t)<0&&(e.push(t),localStorage.setItem(this.getStorageKey(),JSON.stringify(e))),$(".board-swimlane-columns-"+t+":not(:first-child)").css("display","none"),$(".board-swimlane-tasks-"+t).css("display","none"),$(".hide-icon-swimlane-"+t).css("display","none"),$(".show-icon-swimlane-"+t).css("display","inline")},Kanboard.Swimlane.prototype.isCollapsed=function(t){return this.getAllCollapsed().indexOf(t)>-1},Kanboard.Swimlane.prototype.getAllCollapsed=function(){return JSON.parse(localStorage.getItem(this.getStorageKey()))||[]},Kanboard.Swimlane.prototype.dragAndDrop=function(){var t=this;$(".draggable-row-handle").mouseenter(function(){$(this).parent().parent().addClass("draggable-item-hover")}).mouseleave(function(){$(this).parent().parent().removeClass("draggable-item-hover")}),$(".swimlanes-table tbody").sortable({forcePlaceholderSize:!0,handle:"td:first i",helper:function(t,e){return e.children().each(function(){$(this).width($(this).width())}),e},stop:function(e,o){var n=o.item;n.removeClass("draggable-item-selected"),t.savePosition(n.data("swimlane-id"),n.index()+1)},start:function(t,e){e.item.addClass("draggable-item-selected")}}).disableSelection()},Kanboard.Swimlane.prototype.savePosition=function(t,e){var o=$(".swimlanes-table").data("save-position-url"),n=this;this.app.showLoadingIcon(),$.ajax({cache:!1,url:o,contentType:"application/json",type:"POST",processData:!1,data:JSON.stringify({swimlane_id:t,position:e}),complete:function(){n.app.hideLoadingIcon()}})},Kanboard.Task=function(t){this.app=t},Kanboard.Task.prototype.keyboardShortcuts=function(){var t=$("#task-view"),e=this;this.app.hasId("task-view")&&(Mousetrap.bind("e",function(){e.app.get("Popover").open(t.data("edit-url"))}),Mousetrap.bind("c",function(){e.app.get("Popover").open(t.data("comment-url"))}),Mousetrap.bind("s",function(){e.app.get("Popover").open(t.data("subtask-url"))}),Mousetrap.bind("l",function(){e.app.get("Popover").open(t.data("internal-link-url"))}))},Kanboard.Task.prototype.onPopoverOpened=function(){var t=this,e=0;t.renderColorPicker(),$(document).on("click",".assign-me",function(t){var e=$(this).data("current-id"),o="#"+$(this).data("target-id");t.preventDefault(),$(o+" option[value="+e+"]").length&&$(o).val(e)}),$(document).on("change","select.task-reload-project-destination",function(){if(e>0)$(this).val(e);else{e=$(this).val();var o=$(this).data("redirect").replace(/PROJECT_ID/g,e);$(".loading-icon").show(),$.ajax({type:"GET",url:o,success:function(o,n,a){e=0,$(".loading-icon").hide(),t.app.get("Popover").ajaxReload(o,a,t.app.get("Popover"))}})}})},Kanboard.Task.prototype.renderColorPicker=function(){function t(t){return $('<div class="color-picker-option"><div class="color-picker-square color-'+t.id+'"></div><div class="color-picker-label">'+t.text+"</div></div>")}$(".color-picker").select2({minimumResultsForSearch:1/0,templateResult:t,templateSelection:t})},Kanboard.Tooltip=function(t){this.app=t},Kanboard.Tooltip.prototype.onBoardRendered=function(){this.execute()},Kanboard.Tooltip.prototype.execute=function(){$(".tooltip").tooltip({track:!1,show:!1,hide:!1,position:{my:"left-20 top",at:"center bottom+9",using:function(t,e){$(this).css(t);var o=e.target.left+e.target.width/2-e.element.left-20;$("<div>").addClass("tooltip-arrow").addClass(e.vertical).addClass(o<1?"align-left":"align-right").appendTo(this)}},content:function(){var t=this,e=$(this).attr("data-href");return e?($.get(e,function(e){var o=$(".ui-tooltip:visible");$(".ui-tooltip-content:visible").html(e),o.css({top:"",left:""}),o.children(".tooltip-arrow").remove();var n=$(t).tooltip("option","position");n.of=$(t),o.position(n)}),'<i class="fa fa-spinner fa-spin"></i>'):'<div class="markdown">'+$(this).attr("title")+"</div>"}}).on("mouseenter",function(){var t=this;$(this).tooltip("open"),$(".ui-tooltip").on("mouseleave",function(){$(t).tooltip("close")})}).on("mouseleave focusout",function(t){t.stopImmediatePropagation();var e=this;setTimeout(function(){$(".ui-tooltip:hover").length||$(e).tooltip("close")},100)})},Kanboard.BoardDragAndDrop=function(t){this.app=t,this.savingInProgress=!1},Kanboard.BoardDragAndDrop.prototype.execute=function(){this.app.hasId("board")&&(this.dragAndDrop(),this.executeListeners())},Kanboard.BoardDragAndDrop.prototype.dragAndDrop=function(){var t=this,e=$(".board-task-list"),o={forcePlaceholderSize:!0,tolerance:"pointer",connectWith:".sortable-column",placeholder:"draggable-placeholder",items:".draggable-item",stop:function(e,o){var n=o.item,a=n.attr("data-task-id"),i=n.attr("data-position"),r=n.attr("data-column-id"),s=n.attr("data-swimlane-id"),d=n.parent().attr("data-column-id"),l=n.parent().attr("data-swimlane-id"),c=n.index()+1;n.removeClass("draggable-item-selected"),d==r&&l==s&&c==i||(t.changeTaskState(a),t.save(a,r,d,c,l))},start:function(t,e){e.item.addClass("draggable-item-selected"),e.placeholder.height(e.item.height())}};isMobile.any&&($(".task-board-sort-handle").css("display","inline"),o.handle=".task-board-sort-handle"),e.each(function(){$(this).css("min-height",$(this).parent().height())}),e.sortable(o)},Kanboard.BoardDragAndDrop.prototype.changeTaskState=function(t){var e=$("div[data-task-id="+t+"]");e.addClass("task-board-saving-state"),e.find(".task-board-saving-icon").show()},Kanboard.BoardDragAndDrop.prototype.save=function(t,e,o,n,a){var i=this;i.app.showLoadingIcon(),i.savingInProgress=!0,$.ajax({cache:!1,url:$("#board").data("save-url"),contentType:"application/json",type:"POST",processData:!1,data:JSON.stringify({task_id:t,src_column_id:e,dst_column_id:o,swimlane_id:a,position:n}),success:function(t){i.refresh(t),i.savingInProgress=!1},error:function(){i.app.hideLoadingIcon(),i.savingInProgress=!1},statusCode:{403:function(t){window.alert(t.responseJSON.message),document.location.reload(!0)}}})},Kanboard.BoardDragAndDrop.prototype.refresh=function(t){$("#board-container").replaceWith(t),this.app.hideLoadingIcon(),this.dragAndDrop(),this.executeListeners()},Kanboard.BoardDragAndDrop.prototype.executeListeners=function(){for(var t in this.app.controllers){var e=this.app.get(t);"function"==typeof e.onBoardRendered&&e.onBoardRendered()}};var _KB=null;jQuery(document).ready(function(){_KB=new Kanboard.App,_KB.execute()}); \ No newline at end of file
diff --git a/assets/js/components/accordion.js b/assets/js/components/accordion.js
new file mode 100644
index 00000000..4588ccc6
--- /dev/null
+++ b/assets/js/components/accordion.js
@@ -0,0 +1,8 @@
+KB.onClick('.accordion-toggle', function(e) {
+ var section = KB.dom(e.target).parent('.accordion-section');
+
+ if (section) {
+ KB.dom(section).toggleClass('accordion-collapsed');
+ KB.dom(KB.dom(section).find('.accordion-content')).toggle();
+ }
+});
diff --git a/assets/js/components/chart-project-avg-time-column.js b/assets/js/components/chart-project-avg-time-column.js
index 74fe31de..18564367 100644
--- a/assets/js/components/chart-project-avg-time-column.js
+++ b/assets/js/components/chart-project-avg-time-column.js
@@ -10,7 +10,7 @@ KB.component('chart-project-avg-time-column', function (containerElement, option
categories.push(metrics[column_id].title);
}
- KB.el(containerElement).add(KB.el('div').attr('id', 'chart').build());
+ KB.dom(containerElement).add(KB.dom('div').attr('id', 'chart').build());
c3.generate({
data: {
diff --git a/assets/js/components/chart-project-burndown.js b/assets/js/components/chart-project-burndown.js
index 34a01e4a..abcab925 100644
--- a/assets/js/components/chart-project-burndown.js
+++ b/assets/js/components/chart-project-burndown.js
@@ -11,29 +11,28 @@ KB.component('chart-project-burndown', function (containerElement, options) {
for (var j = 0; j < metrics[i].length; j++) {
- if (i == 0) {
+ if (i === 0) {
columns.push([metrics[i][j]]);
- }
- else {
+ } else {
columns[j + 1].push(metrics[i][j]);
if (j > 0) {
- if (columns[0][i] == undefined) {
+ if (columns[0][i] === undefined) {
columns[0].push(0);
}
columns[0][i] += metrics[i][j];
}
- if (j == 0) {
+ if (j === 0) {
categories.push(outputFormat(inputFormat.parse(metrics[i][j])));
}
}
}
}
- KB.el(containerElement).add(KB.el('div').attr('id', 'chart').build());
+ KB.dom(containerElement).add(KB.dom('div').attr('id', 'chart').build());
c3.generate({
data: {
diff --git a/assets/js/components/chart-project-cumulative-flow.js b/assets/js/components/chart-project-cumulative-flow.js
index aa150397..7b258230 100644
--- a/assets/js/components/chart-project-cumulative-flow.js
+++ b/assets/js/components/chart-project-cumulative-flow.js
@@ -12,25 +12,24 @@ KB.component('chart-project-cumulative-flow', function (containerElement, option
for (var j = 0; j < metrics[i].length; j++) {
- if (i == 0) {
+ if (i === 0) {
columns.push([metrics[i][j]]);
if (j > 0) {
groups.push(metrics[i][j]);
}
- }
- else {
+ } else {
columns[j].push(metrics[i][j]);
- if (j == 0) {
+ if (j === 0) {
categories.push(outputFormat(inputFormat.parse(metrics[i][j])));
}
}
}
}
- KB.el(containerElement).add(KB.el('div').attr('id', 'chart').build());
+ KB.dom(containerElement).add(KB.dom('div').attr('id', 'chart').build());
c3.generate({
data: {
diff --git a/assets/js/components/chart-project-lead-cycle-time.js b/assets/js/components/chart-project-lead-cycle-time.js
index a81937ff..208f7ce6 100644
--- a/assets/js/components/chart-project-lead-cycle-time.js
+++ b/assets/js/components/chart-project-lead-cycle-time.js
@@ -20,7 +20,7 @@ KB.component('chart-project-lead-cycle-time', function (containerElement, option
categories.push(metrics[i].day);
}
- KB.el(containerElement).add(KB.el('div').attr('id', 'chart').build());
+ KB.dom(containerElement).add(KB.dom('div').attr('id', 'chart').build());
c3.generate({
data: {
diff --git a/assets/js/components/chart-project-task-distribution.js b/assets/js/components/chart-project-task-distribution.js
index 982aaf7f..3f48d230 100644
--- a/assets/js/components/chart-project-task-distribution.js
+++ b/assets/js/components/chart-project-task-distribution.js
@@ -7,7 +7,7 @@ KB.component('chart-project-task-distribution', function (containerElement, opti
columns.push([options.metrics[i].column_title, options.metrics[i].nb_tasks]);
}
- KB.el(containerElement).add(KB.el('div').attr('id', 'chart').build());
+ KB.dom(containerElement).add(KB.dom('div').attr('id', 'chart').build());
c3.generate({
data: {
diff --git a/assets/js/components/chart-project-time-comparison.js b/assets/js/components/chart-project-time-comparison.js
index a110e6b4..e4b31a13 100644
--- a/assets/js/components/chart-project-time-comparison.js
+++ b/assets/js/components/chart-project-time-comparison.js
@@ -11,7 +11,7 @@ KB.component('chart-project-time-comparison', function (containerElement, option
categories.push(status === 'open' ? options.labelOpen : options.labelClosed);
}
- KB.el(containerElement).add(KB.el('div').attr('id', 'chart').build());
+ KB.dom(containerElement).add(KB.dom('div').attr('id', 'chart').build());
c3.generate({
data: {
diff --git a/assets/js/components/chart-project-user-distribution.js b/assets/js/components/chart-project-user-distribution.js
index 8ab61799..d3c88d56 100644
--- a/assets/js/components/chart-project-user-distribution.js
+++ b/assets/js/components/chart-project-user-distribution.js
@@ -7,7 +7,7 @@ KB.component('chart-project-user-distribution', function (containerElement, opti
columns.push([options.metrics[i].user, options.metrics[i].nb_tasks]);
}
- KB.el(containerElement).add(KB.el('div').attr('id', 'chart').build());
+ KB.dom(containerElement).add(KB.dom('div').attr('id', 'chart').build());
c3.generate({
data: {
diff --git a/assets/js/components/chart-task-time-column.js b/assets/js/components/chart-task-time-column.js
index 02426748..887d24d4 100644
--- a/assets/js/components/chart-task-time-column.js
+++ b/assets/js/components/chart-task-time-column.js
@@ -10,7 +10,7 @@ KB.component('chart-task-time-column', function (containerElement, options) {
categories.push(metrics[i].title);
}
- KB.el(containerElement).add(KB.el('div').attr('id', 'chart').build());
+ KB.dom(containerElement).add(KB.dom('div').attr('id', 'chart').build());
c3.generate({
data: {
diff --git a/assets/js/components/external-task-view.js b/assets/js/components/external-task-view.js
index b63e79d3..d402640b 100644
--- a/assets/js/components/external-task-view.js
+++ b/assets/js/components/external-task-view.js
@@ -5,8 +5,8 @@ KB.component('external-task-view', function (containerElement, options) {
cache: false,
url: options.url,
success: function(data) {
- KB.el(containerElement).html('<div id="external-task-view">' + data + '</div>');
+ KB.dom(containerElement).html('<div id="external-task-view">' + data + '</div>');
}
});
- }
+ };
});
diff --git a/assets/js/components/submit-cancel.js b/assets/js/components/submit-cancel.js
index 061b1146..ccb3c1d9 100644
--- a/assets/js/components/submit-cancel.js
+++ b/assets/js/components/submit-cancel.js
@@ -1,35 +1,52 @@
-Vue.component('submit-cancel', {
- props: ['labelButton', 'labelOr', 'labelCancel', 'callback'],
- template: '<div class="form-actions">' +
- '<button type="button" class="btn btn-blue" @click="onSubmit" :disabled="isLoading">' +
- '<span v-show="isLoading"><i class="fa fa-spinner fa-pulse"></i> </span>' +
- '{{ labelButton }}' +
- '</button> ' +
- '{{ labelOr }} <a href="#" v-on:click.prevent="onCancel">{{ labelCancel }}</a>' +
- '</div>'
- ,
- data: function () {
- return {
- loading: false
- };
- },
- computed: {
- isLoading: function () {
- return this.loading;
- }
- },
- methods: {
- onSubmit: function () {
- this.loading = true;
- this.callback();
- },
- onCancel: function () {
- _KB.get('Popover').close();
- }
- },
- events: {
- 'submitCancelled': function() {
- this.loading = false;
+KB.component('submit-cancel', function (containerElement, options) {
+ var isLoading = false;
+
+ function onSubmit() {
+ isLoading = true;
+ KB.find('#modal-submit-button').replace(buildButton());
+ KB.trigger('modal.submit');
+ }
+
+ function onCancel() {
+ KB.trigger('modal.cancel');
+ _KB.get('Popover').close();
+ }
+
+ function onStop() {
+ isLoading = false;
+ KB.find('#modal-submit-button').replace(buildButton());
+ }
+
+ function buildButton() {
+ var button = KB.dom('button')
+ .click(onSubmit)
+ .attr('id', 'modal-submit-button')
+ .attr('type', 'submit')
+ .attr('class', 'btn btn-blue');
+
+ if (isLoading) {
+ button
+ .disable()
+ .add(KB.dom('i').attr('class', 'fa fa-spinner fa-pulse').build())
+ .text(' ')
+ ;
}
+
+ return button
+ .text(options.submitLabel)
+ .build();
}
+
+ this.render = function () {
+ KB.on('modal.stop', onStop);
+
+ var element = KB.dom('div')
+ .attr('class', 'form-actions')
+ .add(buildButton())
+ .text(' ' + options.orLabel + ' ')
+ .add(KB.dom('a').attr('href', '#').click(onCancel).text(options.cancelLabel).build())
+ .build();
+
+ containerElement.appendChild(element);
+ };
});
diff --git a/assets/js/components/suggest-menu.js b/assets/js/components/suggest-menu.js
new file mode 100644
index 00000000..07539d2c
--- /dev/null
+++ b/assets/js/components/suggest-menu.js
@@ -0,0 +1,225 @@
+KB.component('suggest-menu', function(containerElement, options) {
+
+ function onKeyDown(e) {
+ switch (e.keyCode) {
+ case 27:
+ destroy();
+ break;
+ case 38:
+ e.preventDefault();
+ e.stopImmediatePropagation();
+ moveUp();
+ break;
+ case 40:
+ e.preventDefault();
+ e.stopImmediatePropagation();
+ moveDown();
+ break;
+ case 13:
+ e.preventDefault();
+ e.stopImmediatePropagation();
+ insertSelectedItem();
+ break;
+ }
+ }
+
+ function onClick() {
+ insertSelectedItem();
+ }
+
+ function onMouseOver(element) {
+ if (KB.dom(element).hasClass('suggest-menu-item')) {
+ KB.find('.suggest-menu-item.active').removeClass('active');
+ KB.dom(element).addClass('active');
+ }
+ }
+
+ function insertSelectedItem() {
+ containerElement.focus();
+
+ var element = KB.find('.suggest-menu-item.active');
+ var value = element.data('value');
+ var trigger = element.data('trigger');
+ var content = containerElement.value;
+ var text = getLastWord(containerElement);
+ var substitute = trigger + value + ' ';
+ var selectionPosition = KB.utils.getSelectionPosition(containerElement);
+ var before = content.substring(0, selectionPosition.selectionStart - text.length);
+ var after = content.substring(selectionPosition.selectionEnd);
+ var position = before.length + substitute.length;
+
+ containerElement.value = before + substitute + after;
+ containerElement.setSelectionRange(position, position);
+
+ destroy();
+ }
+
+ function getLastWord(element) {
+ var lines = element.value.substring(0, element.selectionEnd).split("\n");
+ var lastLine = lines[lines.length - 1];
+ var words = lastLine.split(' ');
+ return words[words.length - 1];
+ }
+
+ function getParentElement() {
+ var selectors = ['.popover-form', '#popover-content', 'body'];
+
+ for (var i = 0; i < selectors.length; i++) {
+ var element = document.querySelector(selectors[i]);
+
+ if (element !== null) {
+ return element;
+ }
+ }
+
+ return null;
+ }
+
+ function resetSelection() {
+ var elements = document.querySelectorAll('.suggest-menu-item');
+
+ for (var i = 0; i < elements.length; i++) {
+ if (KB.dom(elements[i]).hasClass('active')) {
+ KB.dom(elements[i]).removeClass('active');
+ break;
+ }
+ }
+
+ return {items: elements, index: i};
+ }
+
+ function moveUp() {
+ var result = resetSelection();
+
+ if (result.index > 0) {
+ result.index = result.index - 1;
+ }
+
+ KB.dom(result.items[result.index]).addClass('active');
+ }
+
+ function moveDown() {
+ var result = resetSelection();
+
+ if (result.index < result.items.length - 1) {
+ result.index++;
+ }
+
+ KB.dom(result.items[result.index]).addClass('active');
+ }
+
+ function destroy() {
+ var element = KB.find('#suggest-menu');
+
+ if (element !== null) {
+ element.remove();
+ }
+
+ document.removeEventListener('keydown', onKeyDown, false);
+ }
+
+ function search(element) {
+ var text = getLastWord(element);
+ var trigger = getTrigger(text, options.triggers);
+
+ destroy();
+
+ if (trigger !== null) {
+ fetchItems(trigger, text.substring(trigger.length), options.triggers[trigger]);
+ }
+ }
+
+ function getTrigger(text, triggers) {
+ for (var trigger in triggers) {
+ if (triggers.hasOwnProperty(trigger) && text.indexOf(trigger) === 0) {
+ return trigger;
+ }
+ }
+
+ return null;
+ }
+
+ function fetchItems(trigger, text, params) {
+ if (typeof params === 'string') {
+ var regex = new RegExp('SEARCH_TERM', 'g');
+ var url = params.replace(regex, text);
+
+ KB.http.get(url).success(function (response) {
+ onItemFetched(trigger, text, response);
+ });
+ } else {
+ onItemFetched(trigger, text, params);
+ }
+ }
+
+ function onItemFetched(trigger, text, items) {
+ items = filterItems(text, items);
+
+ if (items.length > 0) {
+ renderMenu(buildItems(trigger, items));
+ }
+ }
+
+ function filterItems(text, items) {
+ var filteredItems = [];
+
+ if (text.length === 0) {
+ return items;
+ }
+
+ for (var i = 0; i < items.length; i++) {
+ if (items[i].value.toLowerCase().indexOf(text.toLowerCase()) === 0) {
+ filteredItems.push(items[i]);
+ }
+ }
+
+ return filteredItems;
+ }
+
+ function buildItems(trigger, items) {
+ var elements = [];
+
+ for (var i = 0; i < items.length; i++) {
+ var className = 'suggest-menu-item';
+
+ if (i === 0) {
+ className += ' active';
+ }
+
+ elements.push({
+ class: className,
+ html: items[i].html,
+ 'data-value': items[i].value,
+ 'data-trigger': trigger
+ });
+ }
+
+ return elements;
+ }
+
+ function renderMenu(items) {
+ var parentElement = getParentElement();
+ var caretPosition = getCaretCoordinates(containerElement, containerElement.selectionEnd);
+ var left = caretPosition.left + containerElement.offsetLeft - containerElement.scrollLeft;
+ var top = caretPosition.top + containerElement.offsetTop - containerElement.scrollTop + 16;
+
+ document.addEventListener('keydown', onKeyDown, false);
+
+ var menu = KB.dom('ul')
+ .attr('id', 'suggest-menu')
+ .click(onClick)
+ .mouseover(onMouseOver)
+ .style('left', left + 'px')
+ .style('top', top + 'px')
+ .for('li', items)
+ .build();
+
+ parentElement.appendChild(menu);
+ }
+
+ this.render = function () {
+ containerElement.addEventListener('input', function () {
+ search(this);
+ });
+ };
+});
diff --git a/assets/js/components/task-move-position.js b/assets/js/components/task-move-position.js
index 11e1068c..5e559713 100644
--- a/assets/js/components/task-move-position.js
+++ b/assets/js/components/task-move-position.js
@@ -1,86 +1,164 @@
-Vue.component('task-move-position', {
- props: ['board', 'saveUrl'],
- template: '#template-task-move-position',
- data: function () {
- return {
- swimlaneId: 0,
- columnId: 0,
- position: 1,
- columns: [],
- tasks: [],
- positionChoice: 'before',
- errorMessage: ''
+KB.component('task-move-position', function (containerElement, options) {
+
+ function getSelectedValue(id) {
+ var element = KB.dom(document).find('#' + id);
+
+ if (element) {
+ return parseInt(element.options[element.selectedIndex].value);
}
- },
- ready: function () {
- this.columns = this.board[0].columns;
- this.columnId = this.columns[0].id;
- this.tasks = this.columns[0].tasks;
- this.errorMessage = '';
- },
- methods: {
- onChangeSwimlane: function () {
- var self = this;
- this.columnId = 0;
- this.position = 1;
- this.columns = [];
- this.tasks = [];
- this.positionChoice = 'before';
-
- this.board.forEach(function(swimlane) {
- if (swimlane.id === self.swimlaneId) {
- self.columns = swimlane.columns;
- self.tasks = self.columns[0].tasks;
- self.columnId = self.columns[0].id;
- }
- });
- },
- onChangeColumn: function () {
- var self = this;
- this.position = 1;
- this.tasks = [];
- this.positionChoice = 'before';
-
- this.columns.forEach(function(column) {
- if (column.id == self.columnId) {
- self.tasks = column.tasks;
-
- if (self.tasks.length > 0) {
- self.position = parseInt(self.tasks[0]['position']);
- }
- }
- });
- },
- onSubmit: function () {
- var self = this;
-
- if (this.positionChoice == 'after') {
- this.position++;
+
+ return null;
+ }
+
+ function getSwimlaneId() {
+ var swimlaneId = getSelectedValue('form-swimlanes');
+ return swimlaneId === null ? options.board[0].id : swimlaneId;
+ }
+
+ function getColumnId() {
+ var columnId = getSelectedValue('form-columns');
+ return columnId === null ? options.board[0].columns[0].id : columnId;
+ }
+
+ function getPosition() {
+ var position = getSelectedValue('form-position');
+ return position === null ? 1 : position;
+ }
+
+ function getPositionChoice() {
+ var element = KB.find('input[name=positionChoice]:checked');
+
+ if (element) {
+ return element.value;
+ }
+
+ return 'before';
+ }
+
+ function onSwimlaneChanged() {
+ var columnSelect = KB.dom(document).find('#form-columns');
+ KB.dom(columnSelect).replace(buildColumnSelect());
+
+ var taskSection = KB.dom(document).find('#form-tasks');
+ KB.dom(taskSection).replace(buildTasks());
+ }
+
+ function onColumnChanged() {
+ var taskSection = KB.dom(document).find('#form-tasks');
+ KB.dom(taskSection).replace(buildTasks());
+ }
+
+ function onError(message) {
+ KB.trigger('modal.stop');
+
+ KB.find('#message-container')
+ .replace(KB.dom('div')
+ .attr('id', 'message-container')
+ .attr('class', 'alert alert-error')
+ .text(message)
+ .build()
+ );
+ }
+
+ function onSubmit() {
+ var position = getPosition();
+ var positionChoice = getPositionChoice();
+
+ if (positionChoice === 'after') {
+ position++;
+ }
+
+ KB.find('#message-container').replace(KB.dom('div').attr('id', 'message-container').build());
+
+ KB.http.postJson(options.saveUrl, {
+ "column_id": getColumnId(),
+ "swimlane_id": getSwimlaneId(),
+ "position": position
+ }).success(function () {
+ window.location.reload(true);
+ }).error(function (response) {
+ if (response) {
+ onError(response.message);
}
+ });
+ }
+
+ function buildSwimlaneSelect() {
+ var swimlanes = [];
+
+ options.board.forEach(function(swimlane) {
+ swimlanes.push({'value': swimlane.id, 'text': swimlane.name});
+ });
+
+ return KB.dom('select')
+ .attr('id', 'form-swimlanes')
+ .change(onSwimlaneChanged)
+ .for('option', swimlanes)
+ .build();
+ }
+
+ function buildColumnSelect() {
+ var columns = [];
+ var swimlaneId = getSwimlaneId();
- $.ajax({
- cache: false,
- url: this.saveUrl,
- contentType: "application/json",
- type: "POST",
- processData: false,
- data: JSON.stringify({
- "column_id": this.columnId,
- "swimlane_id": this.swimlaneId,
- "position": this.position
- }),
- statusCode: {
- 200: function() {
- window.location.reload(true);
- },
- 403: function(jqXHR) {
- var response = JSON.parse(jqXHR.responseText);
- self.errorMessage = response.message;
-
- self.$broadcast('submitCancelled');
+ options.board.forEach(function(swimlane) {
+ if (swimlaneId === swimlane.id) {
+ swimlane.columns.forEach(function(column) {
+ columns.push({'value': column.id, 'text': column.title});
+ });
+ }
+ });
+
+ return KB.dom('select')
+ .attr('id', 'form-columns')
+ .change(onColumnChanged)
+ .for('option', columns)
+ .build();
+ }
+
+ function buildTasks() {
+ var tasks = [];
+ var swimlaneId = getSwimlaneId();
+ var columnId = getColumnId();
+ var container = KB.dom('div').attr('id', 'form-tasks');
+
+ options.board.forEach(function(swimlane) {
+ if (swimlaneId === swimlane.id) {
+ swimlane.columns.forEach(function(column) {
+ if (columnId === column.id) {
+ column.tasks.forEach(function(task) {
+ tasks.push({'value': task.position, 'text': '#' + task.id + ' - ' + task.title});
+ });
}
- }
- });
+ });
+ }
+ });
+
+ if (tasks.length > 0) {
+ container
+ .add(KB.html.label(options.positionLabel, 'form-position'))
+ .add(KB.dom('select').attr('id', 'form-position').for('option', tasks).build())
+ .add(KB.html.radio(options.beforeLabel, 'positionChoice', 'before'))
+ .add(KB.html.radio(options.afterLabel, 'positionChoice', 'after'))
+ ;
}
+
+ return container.build();
}
+
+ this.render = function () {
+ KB.on('modal.submit', onSubmit);
+
+ var form = KB.dom('div')
+ .on('submit', onSubmit)
+ .add(KB.dom('div').attr('id', 'message-container').build())
+ .add(KB.html.label(options.swimlaneLabel, 'form-swimlanes'))
+ .add(buildSwimlaneSelect())
+ .add(KB.html.label(options.columnLabel, 'form-columns'))
+ .add(buildColumnSelect())
+ .add(buildTasks())
+ .build();
+
+ containerElement.appendChild(form);
+ };
});
diff --git a/assets/js/components/text-editor.js b/assets/js/components/text-editor.js
index 5011318b..57bc0f78 100644
--- a/assets/js/components/text-editor.js
+++ b/assets/js/components/text-editor.js
@@ -5,26 +5,30 @@ KB.component('text-editor', function (containerElement, options) {
writeModeElement = buildWriteMode();
viewModeElement = buildViewMode();
- containerElement.appendChild(KB.el('div')
+ containerElement.appendChild(KB.dom('div')
.attr('class', 'text-editor')
.add(viewModeElement)
.add(writeModeElement)
.build());
+
+ if (options.autofocus) {
+ textarea.focus();
+ }
};
function buildViewMode() {
- var toolbarElement = KB.el('div')
+ var toolbarElement = KB.dom('div')
.attr('class', 'text-editor-toolbar')
.for('a', [
{href: '#', html: '<i class="fa fa-pencil-square-o fa-fw"></i> ' + options.labelWrite, click: function() { toggleViewMode(); }}
])
.build();
- previewElement = KB.el('div')
+ previewElement = KB.dom('div')
.attr('class', 'text-editor-preview-area markdown')
.build();
- return KB.el('div')
+ return KB.dom('div')
.attr('class', 'text-editor-view-mode')
.add(toolbarElement)
.add(previewElement)
@@ -33,7 +37,7 @@ KB.component('text-editor', function (containerElement, options) {
}
function buildWriteMode() {
- var toolbarElement = KB.el('div')
+ var toolbarElement = KB.dom('div')
.attr('class', 'text-editor-toolbar')
.for('a', [
{href: '#', html: '<i class="fa fa-eye fa-fw"></i> ' + options.labelPreview, click: function() { toggleViewMode(); }},
@@ -46,16 +50,31 @@ KB.component('text-editor', function (containerElement, options) {
])
.build();
- textarea = KB.el('textarea')
- .attr('name', options.name)
- .attr('tabindex', options.tabindex || '-1')
- .attr('required', options.required || false)
- .attr('autofocus', options.autofocus || null)
- .attr('placeholder', options.placeholder || '')
- .text(options.text)
- .build();
+ var textareaElement = KB.dom('textarea');
+ textareaElement.attr('name', options.name);
+
+ if (options.tabindex) {
+ textareaElement.attr('tabindex', options.tabindex);
+ }
- return KB.el('div')
+ if (options.required) {
+ textareaElement.attr('required', 'required');
+ }
+
+ // Order is important for IE11 (especially for the placeholder)
+ textareaElement.text(options.text);
+
+ if (options.placeholder) {
+ textareaElement.attr('placeholder', options.placeholder);
+ }
+
+ textarea = textareaElement.build();
+
+ if (options.suggestOptions) {
+ KB.getComponent('suggest-menu', textarea, options.suggestOptions).render();
+ }
+
+ return KB.dom('div')
.attr('class', 'text-editor-write-mode')
.add(toolbarElement)
.add(textarea)
@@ -63,9 +82,9 @@ KB.component('text-editor', function (containerElement, options) {
}
function toggleViewMode() {
- KB.el(previewElement).html(marked(textarea.value, {sanitize: true}));
- KB.el(viewModeElement).toggle();
- KB.el(writeModeElement).toggle();
+ KB.dom(previewElement).html(marked(textarea.value, {sanitize: true}));
+ KB.dom(viewModeElement).toggle();
+ KB.dom(writeModeElement).toggle();
}
function getSelectedText() {
@@ -106,14 +125,18 @@ KB.component('text-editor', function (containerElement, options) {
insertText(lines.join('\n'));
}
+
+ setCursorBeforeClosingTag(tag, 1);
}
function insertText(replacedText) {
+ textarea.focus();
+
var result = false;
+ var selectionPosition = KB.utils.getSelectionPosition(textarea);
- selectionStart = textarea.selectionStart;
- selectionEnd = textarea.selectionEnd;
- textarea.focus();
+ selectionStart = selectionPosition.selectionStart;
+ selectionEnd = selectionPosition.selectionEnd;
if (document.queryCommandSupported('insertText')) {
result = document.execCommand('insertText', false, replacedText);
@@ -124,7 +147,7 @@ KB.component('text-editor', function (containerElement, options) {
document.execCommand('ms-beginUndoUnit');
} catch (error) {}
- textarea.value = replaceTextRange(text, textarea.selectionStart, textarea.selectionEnd, replacedText);
+ textarea.value = replaceTextRange(textarea.value, selectionStart, selectionEnd, replacedText);
try {
document.execCommand('ms-endUndoUnit');
diff --git a/assets/js/core/base.js b/assets/js/core/base.js
new file mode 100644
index 00000000..4ea3ffc2
--- /dev/null
+++ b/assets/js/core/base.js
@@ -0,0 +1,76 @@
+var KB = {
+ components: {},
+ utils: {},
+ html: {},
+ http: {},
+ listeners: {
+ clicks: {},
+ internals: {}
+ }
+};
+
+KB.on = function (eventType, callback) {
+ if (! this.listeners.internals.hasOwnProperty(eventType)) {
+ this.listeners.internals[eventType] = [];
+ }
+
+ this.listeners.internals[eventType].push(callback);
+};
+
+KB.trigger = function (eventType, eventData) {
+ if (this.listeners.internals.hasOwnProperty(eventType)) {
+ for (var i = 0; i < this.listeners.internals[eventType].length; i++) {
+ if (! this.listeners.internals[eventType][i](eventData)) {
+ break;
+ }
+ }
+ }
+};
+
+KB.onClick = function (selector, callback) {
+ this.listeners.clicks[selector] = callback;
+};
+
+KB.listen = function () {
+ var self = this;
+
+ function onClick(e) {
+ for (var selector in self.listeners.clicks) {
+ if (self.listeners.clicks.hasOwnProperty(selector) && e.target.matches(selector)) {
+ e.preventDefault();
+ self.listeners.clicks[selector](e);
+ }
+ }
+ }
+
+ document.addEventListener('click', onClick, false);
+};
+
+KB.component = function (name, object) {
+ this.components[name] = object;
+};
+
+KB.getComponent = function (name, containerElement, options) {
+ var object = this.components[name];
+ return new object(containerElement, options);
+};
+
+KB.render = function () {
+ for (var name in this.components) {
+ var elementList = document.querySelectorAll('.js-' + name);
+
+ for (var i = 0; i < elementList.length; i++) {
+ if (this.components.hasOwnProperty(name)) {
+ var options;
+
+ if (elementList[i].dataset.params) {
+ options = JSON.parse(elementList[i].dataset.params);
+ }
+
+ var component = KB.getComponent(name, elementList[i], options);
+ component.render();
+ elementList[i].className = elementList[i].className + '-rendered';
+ }
+ }
+ }
+};
diff --git a/assets/js/core/bootstrap.js b/assets/js/core/bootstrap.js
new file mode 100644
index 00000000..3af086f1
--- /dev/null
+++ b/assets/js/core/bootstrap.js
@@ -0,0 +1,5 @@
+
+document.addEventListener('DOMContentLoaded', function () {
+ KB.render();
+ KB.listen();
+});
diff --git a/assets/js/core/dom.js b/assets/js/core/dom.js
new file mode 100644
index 00000000..20510d44
--- /dev/null
+++ b/assets/js/core/dom.js
@@ -0,0 +1,175 @@
+KB.dom = function (tag) {
+
+ function DomManipulation(tag) {
+ var element = typeof tag === 'string' ? document.createElement(tag) : tag;
+
+ this.attr = function (attribute, value) {
+ if (value !== null) {
+ element.setAttribute(attribute, value);
+ }
+ return this;
+ };
+
+ this.data = function (attribute, value) {
+ if (arguments.length === 1) {
+ return element.dataset[attribute];
+ }
+ element.dataset[attribute] = value;
+ return this;
+ };
+
+ this.hide = function () {
+ element.style.display = 'none';
+ return this;
+ };
+
+ this.show = function () {
+ element.style.display = 'block';
+ return this;
+ };
+
+ this.toggle = function () {
+ if (element.style.display === 'none') {
+ this.show();
+ } else{
+ this.hide();
+ }
+
+ return this;
+ };
+
+ this.style = function(attribute, value) {
+ element.style[attribute] = value;
+ return this;
+ };
+
+ this.on = function (eventName, callback) {
+ element.addEventListener(eventName, function (e) {
+ e.preventDefault();
+ callback(e.target);
+ });
+
+ return this;
+ };
+
+ this.click = function (callback) {
+ return this.on('click', callback);
+ };
+
+ this.mouseover = function (callback) {
+ return this.on('mouseover', callback);
+ };
+
+ this.change = function (callback) {
+ return this.on('change', callback);
+ };
+
+ this.add = function (node) {
+ element.appendChild(node);
+ return this;
+ };
+
+ this.replace = function (node) {
+ element.parentNode.replaceChild(node, element);
+ return this;
+ };
+
+ this.html = function (html) {
+ element.innerHTML = html;
+ return this;
+ };
+
+ this.text = function (text) {
+ element.appendChild(document.createTextNode(text));
+ return this;
+ };
+
+ this.addClass = function (className) {
+ element.classList.add(className);
+ return this;
+ };
+
+ this.removeClass = function (className) {
+ element.classList.remove(className);
+ return this;
+ };
+
+ this.toggleClass = function (className) {
+ element.classList.toggle(className);
+ return this;
+ };
+
+ this.hasClass = function (className) {
+ return element.classList.contains(className);
+ };
+
+ this.disable = function () {
+ element.disabled = true;
+ return this;
+ };
+
+ this.enable = function () {
+ element.disabled = false;
+ return this;
+ };
+
+ this.remove = function () {
+ element.parentNode.removeChild(element);
+ return this;
+ };
+
+ this.parent = function (selector) {
+ for (; element && element !== document; element = element.parentNode) {
+ if (element.matches(selector)) {
+ return element;
+ }
+ }
+
+ return null;
+ };
+
+ this.find = function (selector) {
+ return element.querySelector(selector);
+ };
+
+ this.for = function (tag, list) {
+ for (var i = 0; i < list.length; i++) {
+ var dict = list[i];
+
+ if (typeof dict !== 'object') {
+ element.appendChild(KB.dom(tag).text(dict).build());
+ } else {
+ var node = KB.dom(tag);
+
+ for (var attribute in dict) {
+ if (dict.hasOwnProperty(attribute) && attribute in this && typeof this[attribute] === 'function') {
+ node[attribute](dict[attribute]);
+ } else {
+ node.attr(attribute, dict[attribute]);
+ }
+ }
+
+ element.appendChild(node.build());
+ }
+ }
+
+ return this;
+ };
+
+ this.build = function () {
+ return element;
+ };
+ }
+
+ return new DomManipulation(tag);
+};
+
+KB.find = function (selector) {
+ var element = document.querySelector(selector);
+
+ if (element) {
+ return KB.dom(element);
+ }
+
+ return null;
+};
diff --git a/assets/js/core/html.js b/assets/js/core/html.js
new file mode 100644
index 00000000..f49a629c
--- /dev/null
+++ b/assets/js/core/html.js
@@ -0,0 +1,25 @@
+KB.html.label = function (label, id) {
+ return KB.dom('label').attr('for', id).text(label).build();
+};
+
+KB.html.radio = function (label, name, value) {
+ return KB.dom('label')
+ .add(KB.dom('input')
+ .attr('type', 'radio')
+ .attr('name', name)
+ .attr('value', value)
+ .build()
+ )
+ .text(label)
+ .build();
+};
+
+KB.html.radios = function (items) {
+ var html = KB.dom('div');
+
+ for (var item in items) {
+ if (items.hasOwnProperty(item)) {
+ html.add(KB.html.radio(item.label, item.name, item.value));
+ }
+ }
+};
diff --git a/assets/js/core/http.js b/assets/js/core/http.js
new file mode 100644
index 00000000..b965ad23
--- /dev/null
+++ b/assets/js/core/http.js
@@ -0,0 +1,66 @@
+KB.http.request = function (method, url, headers, body) {
+ var successCallback = function() {};
+ var errorCallback = function() {};
+
+ function parseResponse(request) {
+ try {
+ return JSON.parse(request.responseText);
+ } catch (e) {
+ return request.responseText;
+ }
+ }
+
+ this.execute = function () {
+ var request = new XMLHttpRequest();
+ request.open(method, url, true);
+ request.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
+
+ for (var header in headers) {
+ if (headers.hasOwnProperty(header)) {
+ request.setRequestHeader(header, headers[header]);
+ }
+ }
+
+ request.onerror = function() {
+ errorCallback();
+ };
+
+ request.onreadystatechange = function() {
+ if (request.readyState === XMLHttpRequest.DONE) {
+ var response = parseResponse(request);
+
+ if (request.status === 200) {
+ successCallback(response);
+ } else {
+ errorCallback(response);
+ }
+ }
+ };
+
+ request.send(body);
+ return this;
+ };
+
+ this.success = function (callback) {
+ successCallback = callback;
+ return this;
+ };
+
+ this.error = function (callback) {
+ errorCallback = callback;
+ return this;
+ };
+};
+
+KB.http.get = function (url) {
+ return (new KB.http.request('GET', url)).execute();
+};
+
+KB.http.postJson = function (url, body) {
+ var headers = {
+ 'Content-Type': 'application/json',
+ 'Accept': 'application/json'
+ };
+
+ return (new KB.http.request('POST', url, headers, JSON.stringify(body))).execute();
+};
diff --git a/assets/js/core/utils.js b/assets/js/core/utils.js
new file mode 100644
index 00000000..e8e74b17
--- /dev/null
+++ b/assets/js/core/utils.js
@@ -0,0 +1,34 @@
+KB.utils.formatDuration = function (d) {
+ if (d >= 86400) {
+ return Math.round(d/86400) + "d";
+ }
+ else if (d >= 3600) {
+ return Math.round(d/3600) + "h";
+ }
+ else if (d >= 60) {
+ return Math.round(d/60) + "m";
+ }
+
+ return d + "s";
+};
+
+KB.utils.getSelectionPosition = function (element) {
+ var selectionStart, selectionEnd;
+
+ if (element.value.length < element.selectionStart) {
+ selectionStart = element.value.length;
+ } else {
+ selectionStart = element.selectionStart;
+ }
+
+ if (element.selectionStart === element.selectionEnd) {
+ selectionEnd = selectionStart;
+ } else {
+ selectionEnd = element.selectionEnd;
+ }
+
+ return {
+ selectionStart: selectionStart,
+ selectionEnd: selectionEnd
+ };
+};
diff --git a/assets/js/polyfills/matches.js b/assets/js/polyfills/matches.js
new file mode 100644
index 00000000..a6f813bf
--- /dev/null
+++ b/assets/js/polyfills/matches.js
@@ -0,0 +1,14 @@
+if (!Element.prototype.matches) {
+ Element.prototype.matches =
+ Element.prototype.matchesSelector ||
+ Element.prototype.mozMatchesSelector ||
+ Element.prototype.msMatchesSelector ||
+ Element.prototype.oMatchesSelector ||
+ Element.prototype.webkitMatchesSelector ||
+ function(s) {
+ var matches = (this.document || this.ownerDocument).querySelectorAll(s),
+ i = matches.length;
+ while (--i >= 0 && matches.item(i) !== this) {}
+ return i > -1;
+ };
+}
diff --git a/assets/js/src/Accordion.js b/assets/js/src/Accordion.js
deleted file mode 100644
index f05dc5ff..00000000
--- a/assets/js/src/Accordion.js
+++ /dev/null
@@ -1,18 +0,0 @@
-Kanboard.Accordion = function(app) {
- this.app = app;
-};
-
-Kanboard.Accordion.prototype.listen = function() {
- $(document).on("click", ".accordion-toggle", function(e) {
- var section = $(this).parents(".accordion-section");
- e.preventDefault();
-
- if (section.hasClass("accordion-collapsed")) {
- section.find(".accordion-content").show();
- section.removeClass("accordion-collapsed");
- } else {
- section.find(".accordion-content").hide();
- section.addClass("accordion-collapsed");
- }
- });
-};
diff --git a/assets/js/src/App.js b/assets/js/src/App.js
index 6fb3ccb7..ab8bd190 100644
--- a/assets/js/src/App.js
+++ b/assets/js/src/App.js
@@ -64,8 +64,10 @@ Kanboard.App.prototype.keyboardShortcuts = function() {
// Close popover and dropdown
Mousetrap.bindGlobal("esc", function() {
- self.get("Popover").close();
- self.get("Dropdown").close();
+ if (! document.getElementById('suggest-menu')) {
+ self.get("Popover").close();
+ self.get("Dropdown").close();
+ }
});
// Show keyboard shortcut
@@ -135,7 +137,7 @@ Kanboard.App.prototype.datePicker = function() {
Kanboard.App.prototype.tagAutoComplete = function() {
$(".tag-autocomplete").select2({
tags: true
- })
+ });
};
Kanboard.App.prototype.autoComplete = function() {
@@ -144,7 +146,7 @@ Kanboard.App.prototype.autoComplete = function() {
var field = input.data("dst-field");
var extraField = input.data("dst-extra-field");
- if ($('#form-' + field).val() == '') {
+ if ($('#form-' + field).val() === '') {
input.parent().find("button[type=submit]").attr('disabled','disabled');
}
@@ -189,7 +191,7 @@ Kanboard.App.prototype.isVisible = function() {
property = "webkitVisibilityState";
}
- if (property != "") {
+ if (property !== "") {
return document[property] == "visible";
}
diff --git a/assets/js/src/BoardDragAndDrop.js b/assets/js/src/BoardDragAndDrop.js
index 5ff6e76a..5d2844de 100644
--- a/assets/js/src/BoardDragAndDrop.js
+++ b/assets/js/src/BoardDragAndDrop.js
@@ -45,7 +45,7 @@ Kanboard.BoardDragAndDrop.prototype.dragAndDrop = function() {
if (isMobile.any) {
$(".task-board-sort-handle").css("display", "inline");
- params["handle"] = ".task-board-sort-handle";
+ params.handle = ".task-board-sort-handle";
}
// Set dropzone height to the height of the table cell
diff --git a/assets/js/src/Bootstrap.js b/assets/js/src/Bootstrap.js
index 7f722b04..94b1f2ca 100644
--- a/assets/js/src/Bootstrap.js
+++ b/assets/js/src/Bootstrap.js
@@ -3,6 +3,4 @@ var _KB = null;
jQuery(document).ready(function() {
_KB = new Kanboard.App();
_KB.execute();
-
- KB.render();
});
diff --git a/assets/js/src/Namespace.js b/assets/js/src/Namespace.js
index de825be4..ada17047 100644
--- a/assets/js/src/Namespace.js
+++ b/assets/js/src/Namespace.js
@@ -1,126 +1 @@
-'use strict';
-
var Kanboard = {};
-
-var KB = {
- components: {},
- utils: {}
-};
-
-KB.component = function (name, object) {
- this.components[name] = object;
-};
-
-KB.render = function () {
- for (var name in this.components) {
- var elementList = document.querySelectorAll('.js-' + name);
-
- for (var i = 0; i < elementList.length; i++) {
- var object = this.components[name];
- var component = new object(elementList[i], JSON.parse(elementList[i].dataset.params));
- component.render();
- elementList[i].className = elementList[i].className + '-rendered';
- }
- }
-};
-
-KB.el = function (tag) {
-
- function DOMBuilder(tag) {
- var element = typeof tag === 'string' ? document.createElement(tag) : tag;
-
- this.attr = function (attribute, value) {
- if (value !== null) {
- element.setAttribute(attribute, value);
- }
- return this;
- };
-
- this.hide = function () {
- element.style.display = 'none';
- return this;
- };
-
- this.show = function () {
- element.style.display = 'block';
- return this;
- };
-
- this.toggle = function () {
- if (element.style.display === 'none') {
- this.show();
- } else{
- this.hide();
- }
-
- return this;
- };
-
- this.click = function (callback) {
- element.onclick = function (e) {
- e.preventDefault();
- callback();
- };
- return this;
- };
-
- this.add = function (node) {
- element.appendChild(node);
- return this;
- };
-
- this.html = function (html) {
- element.innerHTML = html;
- return this;
- };
-
- this.text = function (text) {
- element.appendChild(document.createTextNode(text));
- return this;
- };
-
- this.for = function (tag, list) {
- for (var i = 0; i < list.length; i++) {
- var dict = list[i];
-
- if (typeof dict !== 'object') {
- element.appendChild(KB.el(tag).text(dict).build());
- } else {
- var node = KB.el(tag);
-
- for (var attribute in dict) {
- if (attribute in this && typeof this[attribute] === 'function') {
- node[attribute](dict[attribute]);
- } else {
- node.attr(attribute, dict[attribute]);
- }
- }
-
- element.appendChild(node.build());
- }
- }
-
- return this;
- };
-
- this.build = function () {
- return element;
- };
- }
-
- return new DOMBuilder(tag);
-};
-
-KB.utils.formatDuration = function(d) {
- if (d >= 86400) {
- return Math.round(d/86400) + "d";
- }
- else if (d >= 3600) {
- return Math.round(d/3600) + "h";
- }
- else if (d >= 60) {
- return Math.round(d/60) + "m";
- }
-
- return d + "s";
-};
diff --git a/assets/js/src/Notification.js b/assets/js/src/Notification.js
deleted file mode 100644
index 840ee988..00000000
--- a/assets/js/src/Notification.js
+++ /dev/null
@@ -1,9 +0,0 @@
-Kanboard.Notification = function(app) {
- this.app = app;
-};
-
-Kanboard.Notification.prototype.execute = function() {
- $(".alert-fade-out").delay(4000).fadeOut(800, function() {
- $(this).remove();
- });
-};
diff --git a/assets/js/src/Popover.js b/assets/js/src/Popover.js
index 6e487efa..ab71505a 100644
--- a/assets/js/src/Popover.js
+++ b/assets/js/src/Popover.js
@@ -157,9 +157,5 @@ Kanboard.Popover.prototype.afterOpen = function() {
this.app.autoComplete();
this.app.tagAutoComplete();
- new Vue({
- el: '#popover-container'
- });
-
KB.render();
};
diff --git a/assets/js/src/Screenshot.js b/assets/js/src/Screenshot.js
index 5c74288b..4f69e9c3 100644
--- a/assets/js/src/Screenshot.js
+++ b/assets/js/src/Screenshot.js
@@ -44,7 +44,7 @@ Kanboard.Screenshot.prototype.initialize = function() {
// Destroy contentEditable element
Kanboard.Screenshot.prototype.destroy = function() {
- if (this.pasteCatcher != null) {
+ if (this.pasteCatcher !== null) {
document.body.removeChild(this.pasteCatcher);
}
else if (document.getElementById("screenshot-pastezone")) {
diff --git a/assets/js/vendor.min.js b/assets/js/vendor.min.js
index 21e13569..2f29db5e 100644
--- a/assets/js/vendor.min.js
+++ b/assets/js/vendor.min.js
@@ -1297,7 +1297,7 @@ if(c&&c._defaults.timeOnly&&b.input.val()!==b.lastVal)try{$.datepicker._updateDa
/*! Select2 4.0.2 | https://github.com/select2/select2/blob/master/LICENSE.md */!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):a("object"==typeof exports?require("jquery"):jQuery)}(function(a){var b=function(){if(a&&a.fn&&a.fn.select2&&a.fn.select2.amd)var b=a.fn.select2.amd;var b;return function(){if(!b||!b.requirejs){b?c=b:b={};var a,c,d;!function(b){function e(a,b){return u.call(a,b)}function f(a,b){var c,d,e,f,g,h,i,j,k,l,m,n=b&&b.split("/"),o=s.map,p=o&&o["*"]||{};if(a&&"."===a.charAt(0))if(b){for(a=a.split("/"),g=a.length-1,s.nodeIdCompat&&w.test(a[g])&&(a[g]=a[g].replace(w,"")),a=n.slice(0,n.length-1).concat(a),k=0;k<a.length;k+=1)if(m=a[k],"."===m)a.splice(k,1),k-=1;else if(".."===m){if(1===k&&(".."===a[2]||".."===a[0]))break;k>0&&(a.splice(k-1,2),k-=2)}a=a.join("/")}else 0===a.indexOf("./")&&(a=a.substring(2));if((n||p)&&o){for(c=a.split("/"),k=c.length;k>0;k-=1){if(d=c.slice(0,k).join("/"),n)for(l=n.length;l>0;l-=1)if(e=o[n.slice(0,l).join("/")],e&&(e=e[d])){f=e,h=k;break}if(f)break;!i&&p&&p[d]&&(i=p[d],j=k)}!f&&i&&(f=i,h=j),f&&(c.splice(0,h,f),a=c.join("/"))}return a}function g(a,c){return function(){var d=v.call(arguments,0);return"string"!=typeof d[0]&&1===d.length&&d.push(null),n.apply(b,d.concat([a,c]))}}function h(a){return function(b){return f(b,a)}}function i(a){return function(b){q[a]=b}}function j(a){if(e(r,a)){var c=r[a];delete r[a],t[a]=!0,m.apply(b,c)}if(!e(q,a)&&!e(t,a))throw new Error("No "+a);return q[a]}function k(a){var b,c=a?a.indexOf("!"):-1;return c>-1&&(b=a.substring(0,c),a=a.substring(c+1,a.length)),[b,a]}function l(a){return function(){return s&&s.config&&s.config[a]||{}}}var m,n,o,p,q={},r={},s={},t={},u=Object.prototype.hasOwnProperty,v=[].slice,w=/\.js$/;o=function(a,b){var c,d=k(a),e=d[0];return a=d[1],e&&(e=f(e,b),c=j(e)),e?a=c&&c.normalize?c.normalize(a,h(b)):f(a,b):(a=f(a,b),d=k(a),e=d[0],a=d[1],e&&(c=j(e))),{f:e?e+"!"+a:a,n:a,pr:e,p:c}},p={require:function(a){return g(a)},exports:function(a){var b=q[a];return"undefined"!=typeof b?b:q[a]={}},module:function(a){return{id:a,uri:"",exports:q[a],config:l(a)}}},m=function(a,c,d,f){var h,k,l,m,n,s,u=[],v=typeof d;if(f=f||a,"undefined"===v||"function"===v){for(c=!c.length&&d.length?["require","exports","module"]:c,n=0;n<c.length;n+=1)if(m=o(c[n],f),k=m.f,"require"===k)u[n]=p.require(a);else if("exports"===k)u[n]=p.exports(a),s=!0;else if("module"===k)h=u[n]=p.module(a);else if(e(q,k)||e(r,k)||e(t,k))u[n]=j(k);else{if(!m.p)throw new Error(a+" missing "+k);m.p.load(m.n,g(f,!0),i(k),{}),u[n]=q[k]}l=d?d.apply(q[a],u):void 0,a&&(h&&h.exports!==b&&h.exports!==q[a]?q[a]=h.exports:l===b&&s||(q[a]=l))}else a&&(q[a]=d)},a=c=n=function(a,c,d,e,f){if("string"==typeof a)return p[a]?p[a](c):j(o(a,c).f);if(!a.splice){if(s=a,s.deps&&n(s.deps,s.callback),!c)return;c.splice?(a=c,c=d,d=null):a=b}return c=c||function(){},"function"==typeof d&&(d=e,e=f),e?m(b,a,c,d):setTimeout(function(){m(b,a,c,d)},4),n},n.config=function(a){return n(a)},a._defined=q,d=function(a,b,c){if("string"!=typeof a)throw new Error("See almond README: incorrect module build, no module name");b.splice||(c=b,b=[]),e(q,a)||e(r,a)||(r[a]=[a,b,c])},d.amd={jQuery:!0}}(),b.requirejs=a,b.require=c,b.define=d}}(),b.define("almond",function(){}),b.define("jquery",[],function(){var b=a||$;return null==b&&console&&console.error&&console.error("Select2: An instance of jQuery or a jQuery-compatible library was not found. Make sure that you are including jQuery before Select2 on your web page."),b}),b.define("select2/utils",["jquery"],function(a){function b(a){var b=a.prototype,c=[];for(var d in b){var e=b[d];"function"==typeof e&&"constructor"!==d&&c.push(d)}return c}var c={};c.Extend=function(a,b){function c(){this.constructor=a}var d={}.hasOwnProperty;for(var e in b)d.call(b,e)&&(a[e]=b[e]);return c.prototype=b.prototype,a.prototype=new c,a.__super__=b.prototype,a},c.Decorate=function(a,c){function d(){var b=Array.prototype.unshift,d=c.prototype.constructor.length,e=a.prototype.constructor;d>0&&(b.call(arguments,a.prototype.constructor),e=c.prototype.constructor),e.apply(this,arguments)}function e(){this.constructor=d}var f=b(c),g=b(a);c.displayName=a.displayName,d.prototype=new e;for(var h=0;h<g.length;h++){var i=g[h];d.prototype[i]=a.prototype[i]}for(var j=(function(a){var b=function(){};a in d.prototype&&(b=d.prototype[a]);var e=c.prototype[a];return function(){var a=Array.prototype.unshift;return a.call(arguments,b),e.apply(this,arguments)}}),k=0;k<f.length;k++){var l=f[k];d.prototype[l]=j(l)}return d};var d=function(){this.listeners={}};return d.prototype.on=function(a,b){this.listeners=this.listeners||{},a in this.listeners?this.listeners[a].push(b):this.listeners[a]=[b]},d.prototype.trigger=function(a){var b=Array.prototype.slice;this.listeners=this.listeners||{},a in this.listeners&&this.invoke(this.listeners[a],b.call(arguments,1)),"*"in this.listeners&&this.invoke(this.listeners["*"],arguments)},d.prototype.invoke=function(a,b){for(var c=0,d=a.length;d>c;c++)a[c].apply(this,b)},c.Observable=d,c.generateChars=function(a){for(var b="",c=0;a>c;c++){var d=Math.floor(36*Math.random());b+=d.toString(36)}return b},c.bind=function(a,b){return function(){a.apply(b,arguments)}},c._convertData=function(a){for(var b in a){var c=b.split("-"),d=a;if(1!==c.length){for(var e=0;e<c.length;e++){var f=c[e];f=f.substring(0,1).toLowerCase()+f.substring(1),f in d||(d[f]={}),e==c.length-1&&(d[f]=a[b]),d=d[f]}delete a[b]}}return a},c.hasScroll=function(b,c){var d=a(c),e=c.style.overflowX,f=c.style.overflowY;return e!==f||"hidden"!==f&&"visible"!==f?"scroll"===e||"scroll"===f?!0:d.innerHeight()<c.scrollHeight||d.innerWidth()<c.scrollWidth:!1},c.escapeMarkup=function(a){var b={"\\":"&#92;","&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;","/":"&#47;"};return"string"!=typeof a?a:String(a).replace(/[&<>"'\/\\]/g,function(a){return b[a]})},c.appendMany=function(b,c){if("1.7"===a.fn.jquery.substr(0,3)){var d=a();a.map(c,function(a){d=d.add(a)}),c=d}b.append(c)},c}),b.define("select2/results",["jquery","./utils"],function(a,b){function c(a,b,d){this.$element=a,this.data=d,this.options=b,c.__super__.constructor.call(this)}return b.Extend(c,b.Observable),c.prototype.render=function(){var b=a('<ul class="select2-results__options" role="tree"></ul>');return this.options.get("multiple")&&b.attr("aria-multiselectable","true"),this.$results=b,b},c.prototype.clear=function(){this.$results.empty()},c.prototype.displayMessage=function(b){var c=this.options.get("escapeMarkup");this.clear(),this.hideLoading();var d=a('<li role="treeitem" aria-live="assertive" class="select2-results__option"></li>'),e=this.options.get("translations").get(b.message);d.append(c(e(b.args))),d[0].className+=" select2-results__message",this.$results.append(d)},c.prototype.hideMessages=function(){this.$results.find(".select2-results__message").remove()},c.prototype.append=function(a){this.hideLoading();var b=[];if(null==a.results||0===a.results.length)return void(0===this.$results.children().length&&this.trigger("results:message",{message:"noResults"}));a.results=this.sort(a.results);for(var c=0;c<a.results.length;c++){var d=a.results[c],e=this.option(d);b.push(e)}this.$results.append(b)},c.prototype.position=function(a,b){var c=b.find(".select2-results");c.append(a)},c.prototype.sort=function(a){var b=this.options.get("sorter");return b(a)},c.prototype.setClasses=function(){var b=this;this.data.current(function(c){var d=a.map(c,function(a){return a.id.toString()}),e=b.$results.find(".select2-results__option[aria-selected]");e.each(function(){var b=a(this),c=a.data(this,"data"),e=""+c.id;null!=c.element&&c.element.selected||null==c.element&&a.inArray(e,d)>-1?b.attr("aria-selected","true"):b.attr("aria-selected","false")});var f=e.filter("[aria-selected=true]");f.length>0?f.first().trigger("mouseenter"):e.first().trigger("mouseenter")})},c.prototype.showLoading=function(a){this.hideLoading();var b=this.options.get("translations").get("searching"),c={disabled:!0,loading:!0,text:b(a)},d=this.option(c);d.className+=" loading-results",this.$results.prepend(d)},c.prototype.hideLoading=function(){this.$results.find(".loading-results").remove()},c.prototype.option=function(b){var c=document.createElement("li");c.className="select2-results__option";var d={role:"treeitem","aria-selected":"false"};b.disabled&&(delete d["aria-selected"],d["aria-disabled"]="true"),null==b.id&&delete d["aria-selected"],null!=b._resultId&&(c.id=b._resultId),b.title&&(c.title=b.title),b.children&&(d.role="group",d["aria-label"]=b.text,delete d["aria-selected"]);for(var e in d){var f=d[e];c.setAttribute(e,f)}if(b.children){var g=a(c),h=document.createElement("strong");h.className="select2-results__group";a(h);this.template(b,h);for(var i=[],j=0;j<b.children.length;j++){var k=b.children[j],l=this.option(k);i.push(l)}var m=a("<ul></ul>",{"class":"select2-results__options select2-results__options--nested"});m.append(i),g.append(h),g.append(m)}else this.template(b,c);return a.data(c,"data",b),c},c.prototype.bind=function(b,c){var d=this,e=b.id+"-results";this.$results.attr("id",e),b.on("results:all",function(a){d.clear(),d.append(a.data),b.isOpen()&&d.setClasses()}),b.on("results:append",function(a){d.append(a.data),b.isOpen()&&d.setClasses()}),b.on("query",function(a){d.hideMessages(),d.showLoading(a)}),b.on("select",function(){b.isOpen()&&d.setClasses()}),b.on("unselect",function(){b.isOpen()&&d.setClasses()}),b.on("open",function(){d.$results.attr("aria-expanded","true"),d.$results.attr("aria-hidden","false"),d.setClasses(),d.ensureHighlightVisible()}),b.on("close",function(){d.$results.attr("aria-expanded","false"),d.$results.attr("aria-hidden","true"),d.$results.removeAttr("aria-activedescendant")}),b.on("results:toggle",function(){var a=d.getHighlightedResults();0!==a.length&&a.trigger("mouseup")}),b.on("results:select",function(){var a=d.getHighlightedResults();if(0!==a.length){var b=a.data("data");"true"==a.attr("aria-selected")?d.trigger("close",{}):d.trigger("select",{data:b})}}),b.on("results:previous",function(){var a=d.getHighlightedResults(),b=d.$results.find("[aria-selected]"),c=b.index(a);if(0!==c){var e=c-1;0===a.length&&(e=0);var f=b.eq(e);f.trigger("mouseenter");var g=d.$results.offset().top,h=f.offset().top,i=d.$results.scrollTop()+(h-g);0===e?d.$results.scrollTop(0):0>h-g&&d.$results.scrollTop(i)}}),b.on("results:next",function(){var a=d.getHighlightedResults(),b=d.$results.find("[aria-selected]"),c=b.index(a),e=c+1;if(!(e>=b.length)){var f=b.eq(e);f.trigger("mouseenter");var g=d.$results.offset().top+d.$results.outerHeight(!1),h=f.offset().top+f.outerHeight(!1),i=d.$results.scrollTop()+h-g;0===e?d.$results.scrollTop(0):h>g&&d.$results.scrollTop(i)}}),b.on("results:focus",function(a){a.element.addClass("select2-results__option--highlighted")}),b.on("results:message",function(a){d.displayMessage(a)}),a.fn.mousewheel&&this.$results.on("mousewheel",function(a){var b=d.$results.scrollTop(),c=d.$results.get(0).scrollHeight-b+a.deltaY,e=a.deltaY>0&&b-a.deltaY<=0,f=a.deltaY<0&&c<=d.$results.height();e?(d.$results.scrollTop(0),a.preventDefault(),a.stopPropagation()):f&&(d.$results.scrollTop(d.$results.get(0).scrollHeight-d.$results.height()),a.preventDefault(),a.stopPropagation())}),this.$results.on("mouseup",".select2-results__option[aria-selected]",function(b){var c=a(this),e=c.data("data");return"true"===c.attr("aria-selected")?void(d.options.get("multiple")?d.trigger("unselect",{originalEvent:b,data:e}):d.trigger("close",{})):void d.trigger("select",{originalEvent:b,data:e})}),this.$results.on("mouseenter",".select2-results__option[aria-selected]",function(b){var c=a(this).data("data");d.getHighlightedResults().removeClass("select2-results__option--highlighted"),d.trigger("results:focus",{data:c,element:a(this)})})},c.prototype.getHighlightedResults=function(){var a=this.$results.find(".select2-results__option--highlighted");return a},c.prototype.destroy=function(){this.$results.remove()},c.prototype.ensureHighlightVisible=function(){var a=this.getHighlightedResults();if(0!==a.length){var b=this.$results.find("[aria-selected]"),c=b.index(a),d=this.$results.offset().top,e=a.offset().top,f=this.$results.scrollTop()+(e-d),g=e-d;f-=2*a.outerHeight(!1),2>=c?this.$results.scrollTop(0):(g>this.$results.outerHeight()||0>g)&&this.$results.scrollTop(f)}},c.prototype.template=function(b,c){var d=this.options.get("templateResult"),e=this.options.get("escapeMarkup"),f=d(b,c);null==f?c.style.display="none":"string"==typeof f?c.innerHTML=e(f):a(c).append(f)},c}),b.define("select2/keys",[],function(){var a={BACKSPACE:8,TAB:9,ENTER:13,SHIFT:16,CTRL:17,ALT:18,ESC:27,SPACE:32,PAGE_UP:33,PAGE_DOWN:34,END:35,HOME:36,LEFT:37,UP:38,RIGHT:39,DOWN:40,DELETE:46};return a}),b.define("select2/selection/base",["jquery","../utils","../keys"],function(a,b,c){function d(a,b){this.$element=a,this.options=b,d.__super__.constructor.call(this)}return b.Extend(d,b.Observable),d.prototype.render=function(){var b=a('<span class="select2-selection" role="combobox" aria-haspopup="true" aria-expanded="false"></span>');return this._tabindex=0,null!=this.$element.data("old-tabindex")?this._tabindex=this.$element.data("old-tabindex"):null!=this.$element.attr("tabindex")&&(this._tabindex=this.$element.attr("tabindex")),b.attr("title",this.$element.attr("title")),b.attr("tabindex",this._tabindex),this.$selection=b,b},d.prototype.bind=function(a,b){var d=this,e=(a.id+"-container",a.id+"-results");this.container=a,this.$selection.on("focus",function(a){d.trigger("focus",a)}),this.$selection.on("blur",function(a){d._handleBlur(a)}),this.$selection.on("keydown",function(a){d.trigger("keypress",a),a.which===c.SPACE&&a.preventDefault()}),a.on("results:focus",function(a){d.$selection.attr("aria-activedescendant",a.data._resultId)}),a.on("selection:update",function(a){d.update(a.data)}),a.on("open",function(){d.$selection.attr("aria-expanded","true"),d.$selection.attr("aria-owns",e),d._attachCloseHandler(a)}),a.on("close",function(){d.$selection.attr("aria-expanded","false"),d.$selection.removeAttr("aria-activedescendant"),d.$selection.removeAttr("aria-owns"),d.$selection.focus(),d._detachCloseHandler(a)}),a.on("enable",function(){d.$selection.attr("tabindex",d._tabindex)}),a.on("disable",function(){d.$selection.attr("tabindex","-1")})},d.prototype._handleBlur=function(b){var c=this;window.setTimeout(function(){document.activeElement==c.$selection[0]||a.contains(c.$selection[0],document.activeElement)||c.trigger("blur",b)},1)},d.prototype._attachCloseHandler=function(b){a(document.body).on("mousedown.select2."+b.id,function(b){var c=a(b.target),d=c.closest(".select2"),e=a(".select2.select2-container--open");e.each(function(){var b=a(this);if(this!=d[0]){var c=b.data("element");c.select2("close")}})})},d.prototype._detachCloseHandler=function(b){a(document.body).off("mousedown.select2."+b.id)},d.prototype.position=function(a,b){var c=b.find(".selection");c.append(a)},d.prototype.destroy=function(){this._detachCloseHandler(this.container)},d.prototype.update=function(a){throw new Error("The `update` method must be defined in child classes.")},d}),b.define("select2/selection/single",["jquery","./base","../utils","../keys"],function(a,b,c,d){function e(){e.__super__.constructor.apply(this,arguments)}return c.Extend(e,b),e.prototype.render=function(){var a=e.__super__.render.call(this);return a.addClass("select2-selection--single"),a.html('<span class="select2-selection__rendered"></span><span class="select2-selection__arrow" role="presentation"><b role="presentation"></b></span>'),a},e.prototype.bind=function(a,b){var c=this;e.__super__.bind.apply(this,arguments);var d=a.id+"-container";this.$selection.find(".select2-selection__rendered").attr("id",d),this.$selection.attr("aria-labelledby",d),this.$selection.on("mousedown",function(a){1===a.which&&c.trigger("toggle",{originalEvent:a})}),this.$selection.on("focus",function(a){}),this.$selection.on("blur",function(a){}),a.on("selection:update",function(a){c.update(a.data)})},e.prototype.clear=function(){this.$selection.find(".select2-selection__rendered").empty()},e.prototype.display=function(a,b){var c=this.options.get("templateSelection"),d=this.options.get("escapeMarkup");return d(c(a,b))},e.prototype.selectionContainer=function(){return a("<span></span>")},e.prototype.update=function(a){if(0===a.length)return void this.clear();var b=a[0],c=this.$selection.find(".select2-selection__rendered"),d=this.display(b,c);c.empty().append(d),c.prop("title",b.title||b.text)},e}),b.define("select2/selection/multiple",["jquery","./base","../utils"],function(a,b,c){function d(a,b){d.__super__.constructor.apply(this,arguments)}return c.Extend(d,b),d.prototype.render=function(){var a=d.__super__.render.call(this);return a.addClass("select2-selection--multiple"),a.html('<ul class="select2-selection__rendered"></ul>'),a},d.prototype.bind=function(b,c){var e=this;d.__super__.bind.apply(this,arguments),this.$selection.on("click",function(a){e.trigger("toggle",{originalEvent:a})}),this.$selection.on("click",".select2-selection__choice__remove",function(b){if(!e.options.get("disabled")){var c=a(this),d=c.parent(),f=d.data("data");e.trigger("unselect",{originalEvent:b,data:f})}})},d.prototype.clear=function(){this.$selection.find(".select2-selection__rendered").empty()},d.prototype.display=function(a,b){var c=this.options.get("templateSelection"),d=this.options.get("escapeMarkup");return d(c(a,b))},d.prototype.selectionContainer=function(){var b=a('<li class="select2-selection__choice"><span class="select2-selection__choice__remove" role="presentation">&times;</span></li>');return b},d.prototype.update=function(a){if(this.clear(),0!==a.length){for(var b=[],d=0;d<a.length;d++){var e=a[d],f=this.selectionContainer(),g=this.display(e,f);f.append(g),f.prop("title",e.title||e.text),f.data("data",e),b.push(f)}var h=this.$selection.find(".select2-selection__rendered");c.appendMany(h,b)}},d}),b.define("select2/selection/placeholder",["../utils"],function(a){function b(a,b,c){this.placeholder=this.normalizePlaceholder(c.get("placeholder")),a.call(this,b,c)}return b.prototype.normalizePlaceholder=function(a,b){return"string"==typeof b&&(b={id:"",text:b}),b},b.prototype.createPlaceholder=function(a,b){var c=this.selectionContainer();return c.html(this.display(b)),c.addClass("select2-selection__placeholder").removeClass("select2-selection__choice"),c},b.prototype.update=function(a,b){var c=1==b.length&&b[0].id!=this.placeholder.id,d=b.length>1;if(d||c)return a.call(this,b);this.clear();var e=this.createPlaceholder(this.placeholder);this.$selection.find(".select2-selection__rendered").append(e)},b}),b.define("select2/selection/allowClear",["jquery","../keys"],function(a,b){function c(){}return c.prototype.bind=function(a,b,c){var d=this;a.call(this,b,c),null==this.placeholder&&this.options.get("debug")&&window.console&&console.error&&console.error("Select2: The `allowClear` option should be used in combination with the `placeholder` option."),this.$selection.on("mousedown",".select2-selection__clear",function(a){d._handleClear(a)}),b.on("keypress",function(a){d._handleKeyboardClear(a,b)})},c.prototype._handleClear=function(a,b){if(!this.options.get("disabled")){var c=this.$selection.find(".select2-selection__clear");if(0!==c.length){b.stopPropagation();for(var d=c.data("data"),e=0;e<d.length;e++){var f={data:d[e]};if(this.trigger("unselect",f),f.prevented)return}this.$element.val(this.placeholder.id).trigger("change"),this.trigger("toggle",{})}}},c.prototype._handleKeyboardClear=function(a,c,d){d.isOpen()||(c.which==b.DELETE||c.which==b.BACKSPACE)&&this._handleClear(c)},c.prototype.update=function(b,c){if(b.call(this,c),!(this.$selection.find(".select2-selection__placeholder").length>0||0===c.length)){var d=a('<span class="select2-selection__clear">&times;</span>');d.data("data",c),this.$selection.find(".select2-selection__rendered").prepend(d)}},c}),b.define("select2/selection/search",["jquery","../utils","../keys"],function(a,b,c){function d(a,b,c){a.call(this,b,c)}return d.prototype.render=function(b){var c=a('<li class="select2-search select2-search--inline"><input class="select2-search__field" type="search" tabindex="-1" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" role="textbox" aria-autocomplete="list" /></li>');this.$searchContainer=c,this.$search=c.find("input");var d=b.call(this);return this._transferTabIndex(),d},d.prototype.bind=function(a,b,d){var e=this;a.call(this,b,d),b.on("open",function(){e.$search.trigger("focus")}),b.on("close",function(){e.$search.val(""),e.$search.removeAttr("aria-activedescendant"),e.$search.trigger("focus")}),b.on("enable",function(){e.$search.prop("disabled",!1),e._transferTabIndex()}),b.on("disable",function(){e.$search.prop("disabled",!0)}),b.on("focus",function(a){e.$search.trigger("focus")}),b.on("results:focus",function(a){e.$search.attr("aria-activedescendant",a.id)}),this.$selection.on("focusin",".select2-search--inline",function(a){e.trigger("focus",a)}),this.$selection.on("focusout",".select2-search--inline",function(a){e._handleBlur(a)}),this.$selection.on("keydown",".select2-search--inline",function(a){a.stopPropagation(),e.trigger("keypress",a),e._keyUpPrevented=a.isDefaultPrevented();var b=a.which;if(b===c.BACKSPACE&&""===e.$search.val()){var d=e.$searchContainer.prev(".select2-selection__choice");if(d.length>0){var f=d.data("data");e.searchRemoveChoice(f),a.preventDefault()}}});var f=document.documentMode,g=f&&11>=f;this.$selection.on("input.searchcheck",".select2-search--inline",function(a){return g?void e.$selection.off("input.search input.searchcheck"):void e.$selection.off("keyup.search")}),this.$selection.on("keyup.search input.search",".select2-search--inline",function(a){if(g&&"input"===a.type)return void e.$selection.off("input.search input.searchcheck");var b=a.which;b!=c.SHIFT&&b!=c.CTRL&&b!=c.ALT&&b!=c.TAB&&e.handleSearch(a)})},d.prototype._transferTabIndex=function(a){this.$search.attr("tabindex",this.$selection.attr("tabindex")),this.$selection.attr("tabindex","-1")},d.prototype.createPlaceholder=function(a,b){this.$search.attr("placeholder",b.text)},d.prototype.update=function(a,b){var c=this.$search[0]==document.activeElement;this.$search.attr("placeholder",""),a.call(this,b),this.$selection.find(".select2-selection__rendered").append(this.$searchContainer),this.resizeSearch(),c&&this.$search.focus()},d.prototype.handleSearch=function(){if(this.resizeSearch(),!this._keyUpPrevented){var a=this.$search.val();this.trigger("query",{term:a})}this._keyUpPrevented=!1},d.prototype.searchRemoveChoice=function(a,b){this.trigger("unselect",{data:b}),this.$search.val(b.text),this.handleSearch()},d.prototype.resizeSearch=function(){this.$search.css("width","25px");var a="";if(""!==this.$search.attr("placeholder"))a=this.$selection.find(".select2-selection__rendered").innerWidth();else{var b=this.$search.val().length+1;a=.75*b+"em"}this.$search.css("width",a)},d}),b.define("select2/selection/eventRelay",["jquery"],function(a){function b(){}return b.prototype.bind=function(b,c,d){var e=this,f=["open","opening","close","closing","select","selecting","unselect","unselecting"],g=["opening","closing","selecting","unselecting"];b.call(this,c,d),c.on("*",function(b,c){if(-1!==a.inArray(b,f)){c=c||{};var d=a.Event("select2:"+b,{params:c});e.$element.trigger(d),-1!==a.inArray(b,g)&&(c.prevented=d.isDefaultPrevented())}})},b}),b.define("select2/translation",["jquery","require"],function(a,b){function c(a){this.dict=a||{}}return c.prototype.all=function(){return this.dict},c.prototype.get=function(a){return this.dict[a]},c.prototype.extend=function(b){this.dict=a.extend({},b.all(),this.dict)},c._cache={},c.loadPath=function(a){if(!(a in c._cache)){var d=b(a);c._cache[a]=d}return new c(c._cache[a])},c}),b.define("select2/diacritics",[],function(){var a={"â’¶":"A","A":"A","À":"A","Ã":"A","Â":"A","Ầ":"A","Ấ":"A","Ẫ":"A","Ẩ":"A","Ã":"A","Ä€":"A","Ä‚":"A","Ằ":"A","Ắ":"A","Ẵ":"A","Ẳ":"A","Ȧ":"A","Ç ":"A","Ä":"A","Çž":"A","Ả":"A","Ã…":"A","Ǻ":"A","Ç":"A","È€":"A","È‚":"A","Ạ":"A","Ậ":"A","Ặ":"A","Ḁ":"A","Ä„":"A","Ⱥ":"A","Ɐ":"A","Ꜳ":"AA","Æ":"AE","Ǽ":"AE","Ç¢":"AE","Ꜵ":"AO","Ꜷ":"AU","Ꜹ":"AV","Ꜻ":"AV","Ꜽ":"AY","â’·":"B","ï¼¢":"B","Ḃ":"B","Ḅ":"B","Ḇ":"B","Ƀ":"B","Æ‚":"B","Æ":"B","â’¸":"C","ï¼£":"C","Ć":"C","Ĉ":"C","ÄŠ":"C","ÄŒ":"C","Ç":"C","Ḉ":"C","Ƈ":"C","È»":"C","Ꜿ":"C","â’¹":"D","D":"D","Ḋ":"D","ÄŽ":"D","Ḍ":"D","á¸":"D","Ḓ":"D","Ḏ":"D","Ä":"D","Æ‹":"D","ÆŠ":"D","Ɖ":"D","ê¹":"D","DZ":"DZ","Ç„":"DZ","Dz":"Dz","Ç…":"Dz","â’º":"E","ï¼¥":"E","È":"E","É":"E","Ê":"E","Ề":"E","Ế":"E","Ễ":"E","Ể":"E","Ẽ":"E","Ä’":"E","Ḕ":"E","Ḗ":"E","Ä”":"E","Ä–":"E","Ë":"E","Ẻ":"E","Äš":"E","È„":"E","Ȇ":"E","Ẹ":"E","Ệ":"E","Ȩ":"E","Ḝ":"E","Ę":"E","Ḙ":"E","Ḛ":"E","Æ":"E","ÆŽ":"E","â’»":"F","F":"F","Ḟ":"F","Æ‘":"F","ê»":"F","â’¼":"G","G":"G","Ç´":"G","Äœ":"G","Ḡ":"G","Äž":"G","Ä ":"G","Ǧ":"G","Ä¢":"G","Ǥ":"G","Æ“":"G","êž ":"G","ê½":"G","ê¾":"G","â’½":"H","H":"H","Ĥ":"H","Ḣ":"H","Ḧ":"H","Èž":"H","Ḥ":"H","Ḩ":"H","Ḫ":"H","Ħ":"H","Ⱨ":"H","â±µ":"H","êž":"H","â’¾":"I","I":"I","ÃŒ":"I","Ã":"I","ÃŽ":"I","Ĩ":"I","Ī":"I","Ĭ":"I","Ä°":"I","Ã":"I","Ḯ":"I","Ỉ":"I","Ç":"I","Ȉ":"I","ÈŠ":"I","Ị":"I","Ä®":"I","Ḭ":"I","Æ—":"I","â’¿":"J","J":"J","Ä´":"J","Ɉ":"J","â“€":"K","K":"K","Ḱ":"K","Ǩ":"K","Ḳ":"K","Ķ":"K","Ḵ":"K","Ƙ":"K","Ⱪ":"K","ê€":"K","ê‚":"K","ê„":"K","Ꞣ":"K","â“":"L","L":"L","Ä¿":"L","Ĺ":"L","Ľ":"L","Ḷ":"L","Ḹ":"L","Ä»":"L","Ḽ":"L","Ḻ":"L","Å":"L","Ƚ":"L","â±¢":"L","â± ":"L","êˆ":"L","ê†":"L","Ꞁ":"L","LJ":"LJ","Lj":"Lj","â“‚":"M","ï¼­":"M","Ḿ":"M","á¹€":"M","Ṃ":"M","â±®":"M","Æœ":"M","Ⓝ":"N","ï¼®":"N","Ǹ":"N","Ń":"N","Ñ":"N","Ṅ":"N","Ň":"N","Ṇ":"N","Å…":"N","Ṋ":"N","Ṉ":"N","È ":"N","Æ":"N","êž":"N","Ꞥ":"N","ÇŠ":"NJ","Ç‹":"Nj","â“„":"O","O":"O","Ã’":"O","Ó":"O","Ô":"O","á»’":"O","á»":"O","á»–":"O","á»”":"O","Õ":"O","Ṍ":"O","Ȭ":"O","Ṏ":"O","ÅŒ":"O","á¹":"O","á¹’":"O","ÅŽ":"O","È®":"O","È°":"O","Ö":"O","Ȫ":"O","Ỏ":"O","Å":"O","Ç‘":"O","ÈŒ":"O","ÈŽ":"O","Æ ":"O","Ờ":"O","Ớ":"O","á» ":"O","Ở":"O","Ợ":"O","Ọ":"O","Ộ":"O","Ǫ":"O","Ǭ":"O","Ø":"O","Ǿ":"O","Ɔ":"O","ÆŸ":"O","êŠ":"O","êŒ":"O","Æ¢":"OI","êŽ":"OO","È¢":"OU","â“…":"P","ï¼°":"P","á¹”":"P","á¹–":"P","Ƥ":"P","â±£":"P","ê":"P","ê’":"P","ê”":"P","Ⓠ":"Q","ï¼±":"Q","ê–":"Q","ê˜":"Q","ÉŠ":"Q","Ⓡ":"R","ï¼²":"R","Å”":"R","Ṙ":"R","Ř":"R","È":"R","È’":"R","Ṛ":"R","Ṝ":"R","Å–":"R","Ṟ":"R","ÉŒ":"R","Ɽ":"R","êš":"R","Ꞧ":"R","êž‚":"R","Ⓢ":"S","ï¼³":"S","ẞ":"S","Åš":"S","Ṥ":"S","Åœ":"S","á¹ ":"S","Å ":"S","Ṧ":"S","á¹¢":"S","Ṩ":"S","Ș":"S","Åž":"S","â±¾":"S","Ꞩ":"S","êž„":"S","Ⓣ":"T","ï¼´":"T","Ṫ":"T","Ť":"T","Ṭ":"T","Èš":"T","Å¢":"T","á¹°":"T","á¹®":"T","Ŧ":"T","Ƭ":"T","Æ®":"T","Ⱦ":"T","Ꞇ":"T","Ꜩ":"TZ","â“Š":"U","ï¼µ":"U","Ù":"U","Ú":"U","Û":"U","Ũ":"U","Ṹ":"U","Ū":"U","Ṻ":"U","Ŭ":"U","Ãœ":"U","Ç›":"U","Ç—":"U","Ç•":"U","Ç™":"U","Ủ":"U","Å®":"U","Å°":"U","Ç“":"U","È”":"U","È–":"U","Ư":"U","Ừ":"U","Ứ":"U","á»®":"U","Ử":"U","á»°":"U","Ụ":"U","á¹²":"U","Ų":"U","Ṷ":"U","á¹´":"U","É„":"U","â“‹":"V","V":"V","á¹¼":"V","á¹¾":"V","Ʋ":"V","êž":"V","É…":"V","ê ":"VY","â“Œ":"W","ï¼·":"W","Ẁ":"W","Ẃ":"W","Å´":"W","Ẇ":"W","Ẅ":"W","Ẉ":"W","â±²":"W","â“":"X","X":"X","Ẋ":"X","Ẍ":"X","â“Ž":"Y","ï¼¹":"Y","Ỳ":"Y","Ã":"Y","Ŷ":"Y","Ỹ":"Y","Ȳ":"Y","Ẏ":"Y","Ÿ":"Y","Ỷ":"Y","á»´":"Y","Ƴ":"Y","ÉŽ":"Y","Ỿ":"Y","â“":"Z","Z":"Z","Ź":"Z","áº":"Z","Å»":"Z","Ž":"Z","Ẓ":"Z","Ẕ":"Z","Ƶ":"Z","Ȥ":"Z","Ɀ":"Z","Ⱬ":"Z","ê¢":"Z","â“":"a","ï½":"a","ẚ":"a","à":"a","á":"a","â":"a","ầ":"a","ấ":"a","ẫ":"a","ẩ":"a","ã":"a","Ä":"a","ă":"a","ằ":"a","ắ":"a","ẵ":"a","ẳ":"a","ȧ":"a","Ç¡":"a","ä":"a","ÇŸ":"a","ả":"a","Ã¥":"a","Ç»":"a","ÇŽ":"a","È":"a","ȃ":"a","ạ":"a","ậ":"a","ặ":"a","á¸":"a","Ä…":"a","â±¥":"a","É":"a","ꜳ":"aa","æ":"ae","ǽ":"ae","Ç£":"ae","ꜵ":"ao","ꜷ":"au","ꜹ":"av","ꜻ":"av","ꜽ":"ay","â“‘":"b","b":"b","ḃ":"b","ḅ":"b","ḇ":"b","Æ€":"b","ƃ":"b","É“":"b","â“’":"c","c":"c","ć":"c","ĉ":"c","Ä‹":"c","Ä":"c","ç":"c","ḉ":"c","ƈ":"c","ȼ":"c","ꜿ":"c","ↄ":"c","â““":"d","d":"d","ḋ":"d","Ä":"d","á¸":"d","ḑ":"d","ḓ":"d","á¸":"d","Ä‘":"d","ÆŒ":"d","É–":"d","É—":"d","êº":"d","dz":"dz","dž":"dz","â“”":"e","ï½…":"e","è":"e","é":"e","ê":"e","á»":"e","ế":"e","á»…":"e","ể":"e","ẽ":"e","Ä“":"e","ḕ":"e","ḗ":"e","Ä•":"e","Ä—":"e","ë":"e","ẻ":"e","Ä›":"e","È…":"e","ȇ":"e","ẹ":"e","ệ":"e","È©":"e","á¸":"e","Ä™":"e","ḙ":"e","ḛ":"e","ɇ":"e","É›":"e","Ç":"e","â“•":"f","f":"f","ḟ":"f","Æ’":"f","ê¼":"f","â“–":"g","g":"g","ǵ":"g","Ä":"g","ḡ":"g","ÄŸ":"g","Ä¡":"g","ǧ":"g","Ä£":"g","Ç¥":"g","É ":"g","êž¡":"g","áµ¹":"g","ê¿":"g","â“—":"h","h":"h","Ä¥":"h","ḣ":"h","ḧ":"h","ÈŸ":"h","ḥ":"h","ḩ":"h","ḫ":"h","ẖ":"h","ħ":"h","ⱨ":"h","ⱶ":"h","É¥":"h","Æ•":"hv","ⓘ":"i","i":"i","ì":"i","í":"i","î":"i","Ä©":"i","Ä«":"i","Ä­":"i","ï":"i","ḯ":"i","ỉ":"i","Ç":"i","ȉ":"i","È‹":"i","ị":"i","į":"i","ḭ":"i","ɨ":"i","ı":"i","â“™":"j","j":"j","ĵ":"j","Ç°":"j","ɉ":"j","â“š":"k","k":"k","ḱ":"k","Ç©":"k","ḳ":"k","Ä·":"k","ḵ":"k","Æ™":"k","ⱪ":"k","ê":"k","êƒ":"k","ê…":"k","ꞣ":"k","â“›":"l","l":"l","Å€":"l","ĺ":"l","ľ":"l","ḷ":"l","ḹ":"l","ļ":"l","ḽ":"l","ḻ":"l","Å¿":"l","Å‚":"l","Æš":"l","É«":"l","ⱡ":"l","ê‰":"l","êž":"l","ê‡":"l","lj":"lj","â“œ":"m","ï½":"m","ḿ":"m","á¹":"m","ṃ":"m","ɱ":"m","ɯ":"m","â“":"n","n":"n","ǹ":"n","Å„":"n","ñ":"n","á¹…":"n","ň":"n","ṇ":"n","ņ":"n","ṋ":"n","ṉ":"n","Æž":"n","ɲ":"n","ʼn":"n","êž‘":"n","ꞥ":"n","ÇŒ":"nj","â“ž":"o","ï½":"o","ò":"o","ó":"o","ô":"o","ồ":"o","ố":"o","á»—":"o","ổ":"o","õ":"o","á¹":"o","È­":"o","á¹":"o","Å":"o","ṑ":"o","ṓ":"o","Å":"o","ȯ":"o","ȱ":"o","ö":"o","È«":"o","á»":"o","Å‘":"o","Ç’":"o","È":"o","È":"o","Æ¡":"o","á»":"o","á»›":"o","ỡ":"o","ở":"o","ợ":"o","á»":"o","á»™":"o","Ç«":"o","Ç­":"o","ø":"o","Ç¿":"o","É”":"o","ê‹":"o","ê":"o","ɵ":"o","Æ£":"oi","È£":"ou","ê":"oo","â“Ÿ":"p","ï½":"p","ṕ":"p","á¹—":"p","Æ¥":"p","áµ½":"p","ê‘":"p","ê“":"p","ê•":"p","â“ ":"q","q":"q","É‹":"q","ê—":"q","ê™":"q","â“¡":"r","ï½’":"r","Å•":"r","á¹™":"r","Å™":"r","È‘":"r","È“":"r","á¹›":"r","á¹":"r","Å—":"r","ṟ":"r","É":"r","ɽ":"r","ê›":"r","ꞧ":"r","ꞃ":"r","â“¢":"s","s":"s","ß":"s","Å›":"s","á¹¥":"s","Å":"s","ṡ":"s","Å¡":"s","ṧ":"s","á¹£":"s","ṩ":"s","È™":"s","ÅŸ":"s","È¿":"s","êž©":"s","êž…":"s","ẛ":"s","â“£":"t","ï½”":"t","ṫ":"t","ẗ":"t","Å¥":"t","á¹­":"t","È›":"t","Å£":"t","á¹±":"t","ṯ":"t","ŧ":"t","Æ­":"t","ʈ":"t","ⱦ":"t","ꞇ":"t","ꜩ":"tz","ⓤ":"u","u":"u","ù":"u","ú":"u","û":"u","Å©":"u","á¹¹":"u","Å«":"u","á¹»":"u","Å­":"u","ü":"u","Çœ":"u","ǘ":"u","Ç–":"u","Çš":"u","ủ":"u","ů":"u","ű":"u","Ç”":"u","È•":"u","È—":"u","Æ°":"u","ừ":"u","ứ":"u","ữ":"u","á»­":"u","á»±":"u","ụ":"u","á¹³":"u","ų":"u","á¹·":"u","á¹µ":"u","ʉ":"u","â“¥":"v","ï½–":"v","á¹½":"v","ṿ":"v","Ê‹":"v","êŸ":"v","ÊŒ":"v","ê¡":"vy","ⓦ":"w","ï½—":"w","áº":"w","ẃ":"w","ŵ":"w","ẇ":"w","ẅ":"w","ẘ":"w","ẉ":"w","â±³":"w","ⓧ":"x","x":"x","ẋ":"x","áº":"x","ⓨ":"y","ï½™":"y","ỳ":"y","ý":"y","Å·":"y","ỹ":"y","ȳ":"y","áº":"y","ÿ":"y","á»·":"y","ẙ":"y","ỵ":"y","Æ´":"y","É":"y","ỿ":"y","â“©":"z","z":"z","ź":"z","ẑ":"z","ż":"z","ž":"z","ẓ":"z","ẕ":"z","ƶ":"z","È¥":"z","É€":"z","ⱬ":"z","ê£":"z","Ά":"Α","Έ":"Ε","Ή":"Η","Ί":"Ι","Ϊ":"Ι","ÎŒ":"Ο","ÎŽ":"Î¥","Ϋ":"Î¥","Î":"Ω","ά":"α","έ":"ε","ή":"η","ί":"ι","ÏŠ":"ι","Î":"ι","ÏŒ":"ο","Ï":"Ï…","Ï‹":"Ï…","ΰ":"Ï…","ω":"ω","Ï‚":"σ"};return a}),b.define("select2/data/base",["../utils"],function(a){function b(a,c){b.__super__.constructor.call(this)}return a.Extend(b,a.Observable),b.prototype.current=function(a){throw new Error("The `current` method must be defined in child classes.")},b.prototype.query=function(a,b){throw new Error("The `query` method must be defined in child classes.")},b.prototype.bind=function(a,b){},b.prototype.destroy=function(){},b.prototype.generateResultId=function(b,c){var d=b.id+"-result-";return d+=a.generateChars(4),d+=null!=c.id?"-"+c.id.toString():"-"+a.generateChars(4)},b}),b.define("select2/data/select",["./base","../utils","jquery"],function(a,b,c){function d(a,b){this.$element=a,this.options=b,d.__super__.constructor.call(this)}return b.Extend(d,a),d.prototype.current=function(a){var b=[],d=this;this.$element.find(":selected").each(function(){var a=c(this),e=d.item(a);b.push(e)}),a(b)},d.prototype.select=function(a){var b=this;if(a.selected=!0,c(a.element).is("option"))return a.element.selected=!0,void this.$element.trigger("change");if(this.$element.prop("multiple"))this.current(function(d){var e=[];a=[a],a.push.apply(a,d);for(var f=0;f<a.length;f++){var g=a[f].id;-1===c.inArray(g,e)&&e.push(g)}b.$element.val(e),b.$element.trigger("change")});else{var d=a.id;this.$element.val(d),this.$element.trigger("change")}},d.prototype.unselect=function(a){var b=this;if(this.$element.prop("multiple"))return a.selected=!1,
c(a.element).is("option")?(a.element.selected=!1,void this.$element.trigger("change")):void this.current(function(d){for(var e=[],f=0;f<d.length;f++){var g=d[f].id;g!==a.id&&-1===c.inArray(g,e)&&e.push(g)}b.$element.val(e),b.$element.trigger("change")})},d.prototype.bind=function(a,b){var c=this;this.container=a,a.on("select",function(a){c.select(a.data)}),a.on("unselect",function(a){c.unselect(a.data)})},d.prototype.destroy=function(){this.$element.find("*").each(function(){c.removeData(this,"data")})},d.prototype.query=function(a,b){var d=[],e=this,f=this.$element.children();f.each(function(){var b=c(this);if(b.is("option")||b.is("optgroup")){var f=e.item(b),g=e.matches(a,f);null!==g&&d.push(g)}}),b({results:d})},d.prototype.addOptions=function(a){b.appendMany(this.$element,a)},d.prototype.option=function(a){var b;a.children?(b=document.createElement("optgroup"),b.label=a.text):(b=document.createElement("option"),void 0!==b.textContent?b.textContent=a.text:b.innerText=a.text),a.id&&(b.value=a.id),a.disabled&&(b.disabled=!0),a.selected&&(b.selected=!0),a.title&&(b.title=a.title);var d=c(b),e=this._normalizeItem(a);return e.element=b,c.data(b,"data",e),d},d.prototype.item=function(a){var b={};if(b=c.data(a[0],"data"),null!=b)return b;if(a.is("option"))b={id:a.val(),text:a.text(),disabled:a.prop("disabled"),selected:a.prop("selected"),title:a.prop("title")};else if(a.is("optgroup")){b={text:a.prop("label"),children:[],title:a.prop("title")};for(var d=a.children("option"),e=[],f=0;f<d.length;f++){var g=c(d[f]),h=this.item(g);e.push(h)}b.children=e}return b=this._normalizeItem(b),b.element=a[0],c.data(a[0],"data",b),b},d.prototype._normalizeItem=function(a){c.isPlainObject(a)||(a={id:a,text:a}),a=c.extend({},{text:""},a);var b={selected:!1,disabled:!1};return null!=a.id&&(a.id=a.id.toString()),null!=a.text&&(a.text=a.text.toString()),null==a._resultId&&a.id&&null!=this.container&&(a._resultId=this.generateResultId(this.container,a)),c.extend({},b,a)},d.prototype.matches=function(a,b){var c=this.options.get("matcher");return c(a,b)},d}),b.define("select2/data/array",["./select","../utils","jquery"],function(a,b,c){function d(a,b){var c=b.get("data")||[];d.__super__.constructor.call(this,a,b),this.addOptions(this.convertToOptions(c))}return b.Extend(d,a),d.prototype.select=function(a){var b=this.$element.find("option").filter(function(b,c){return c.value==a.id.toString()});0===b.length&&(b=this.option(a),this.addOptions(b)),d.__super__.select.call(this,a)},d.prototype.convertToOptions=function(a){function d(a){return function(){return c(this).val()==a.id}}for(var e=this,f=this.$element.find("option"),g=f.map(function(){return e.item(c(this)).id}).get(),h=[],i=0;i<a.length;i++){var j=this._normalizeItem(a[i]);if(c.inArray(j.id,g)>=0){var k=f.filter(d(j)),l=this.item(k),m=c.extend(!0,{},j,l),n=this.option(m);k.replaceWith(n)}else{var o=this.option(j);if(j.children){var p=this.convertToOptions(j.children);b.appendMany(o,p)}h.push(o)}}return h},d}),b.define("select2/data/ajax",["./array","../utils","jquery"],function(a,b,c){function d(a,b){this.ajaxOptions=this._applyDefaults(b.get("ajax")),null!=this.ajaxOptions.processResults&&(this.processResults=this.ajaxOptions.processResults),d.__super__.constructor.call(this,a,b)}return b.Extend(d,a),d.prototype._applyDefaults=function(a){var b={data:function(a){return c.extend({},a,{q:a.term})},transport:function(a,b,d){var e=c.ajax(a);return e.then(b),e.fail(d),e}};return c.extend({},b,a,!0)},d.prototype.processResults=function(a){return a},d.prototype.query=function(a,b){function d(){var d=f.transport(f,function(d){var f=e.processResults(d,a);e.options.get("debug")&&window.console&&console.error&&(f&&f.results&&c.isArray(f.results)||console.error("Select2: The AJAX results did not return an array in the `results` key of the response.")),b(f)},function(){e.trigger("results:message",{message:"errorLoading"})});e._request=d}var e=this;null!=this._request&&(c.isFunction(this._request.abort)&&this._request.abort(),this._request=null);var f=c.extend({type:"GET"},this.ajaxOptions);"function"==typeof f.url&&(f.url=f.url.call(this.$element,a)),"function"==typeof f.data&&(f.data=f.data.call(this.$element,a)),this.ajaxOptions.delay&&""!==a.term?(this._queryTimeout&&window.clearTimeout(this._queryTimeout),this._queryTimeout=window.setTimeout(d,this.ajaxOptions.delay)):d()},d}),b.define("select2/data/tags",["jquery"],function(a){function b(b,c,d){var e=d.get("tags"),f=d.get("createTag");void 0!==f&&(this.createTag=f);var g=d.get("insertTag");if(void 0!==g&&(this.insertTag=g),b.call(this,c,d),a.isArray(e))for(var h=0;h<e.length;h++){var i=e[h],j=this._normalizeItem(i),k=this.option(j);this.$element.append(k)}}return b.prototype.query=function(a,b,c){function d(a,f){for(var g=a.results,h=0;h<g.length;h++){var i=g[h],j=null!=i.children&&!d({results:i.children},!0),k=i.text===b.term;if(k||j)return f?!1:(a.data=g,void c(a))}if(f)return!0;var l=e.createTag(b);if(null!=l){var m=e.option(l);m.attr("data-select2-tag",!0),e.addOptions([m]),e.insertTag(g,l)}a.results=g,c(a)}var e=this;return this._removeOldTags(),null==b.term||null!=b.page?void a.call(this,b,c):void a.call(this,b,d)},b.prototype.createTag=function(b,c){var d=a.trim(c.term);return""===d?null:{id:d,text:d}},b.prototype.insertTag=function(a,b,c){b.unshift(c)},b.prototype._removeOldTags=function(b){var c=(this._lastTag,this.$element.find("option[data-select2-tag]"));c.each(function(){this.selected||a(this).remove()})},b}),b.define("select2/data/tokenizer",["jquery"],function(a){function b(a,b,c){var d=c.get("tokenizer");void 0!==d&&(this.tokenizer=d),a.call(this,b,c)}return b.prototype.bind=function(a,b,c){a.call(this,b,c),this.$search=b.dropdown.$search||b.selection.$search||c.find(".select2-search__field")},b.prototype.query=function(a,b,c){function d(a){e.trigger("select",{data:a})}var e=this;b.term=b.term||"";var f=this.tokenizer(b,this.options,d);f.term!==b.term&&(this.$search.length&&(this.$search.val(f.term),this.$search.focus()),b.term=f.term),a.call(this,b,c)},b.prototype.tokenizer=function(b,c,d,e){for(var f=d.get("tokenSeparators")||[],g=c.term,h=0,i=this.createTag||function(a){return{id:a.term,text:a.term}};h<g.length;){var j=g[h];if(-1!==a.inArray(j,f)){var k=g.substr(0,h),l=a.extend({},c,{term:k}),m=i(l);null!=m?(e(m),g=g.substr(h+1)||"",h=0):h++}else h++}return{term:g}},b}),b.define("select2/data/minimumInputLength",[],function(){function a(a,b,c){this.minimumInputLength=c.get("minimumInputLength"),a.call(this,b,c)}return a.prototype.query=function(a,b,c){return b.term=b.term||"",b.term.length<this.minimumInputLength?void this.trigger("results:message",{message:"inputTooShort",args:{minimum:this.minimumInputLength,input:b.term,params:b}}):void a.call(this,b,c)},a}),b.define("select2/data/maximumInputLength",[],function(){function a(a,b,c){this.maximumInputLength=c.get("maximumInputLength"),a.call(this,b,c)}return a.prototype.query=function(a,b,c){return b.term=b.term||"",this.maximumInputLength>0&&b.term.length>this.maximumInputLength?void this.trigger("results:message",{message:"inputTooLong",args:{maximum:this.maximumInputLength,input:b.term,params:b}}):void a.call(this,b,c)},a}),b.define("select2/data/maximumSelectionLength",[],function(){function a(a,b,c){this.maximumSelectionLength=c.get("maximumSelectionLength"),a.call(this,b,c)}return a.prototype.query=function(a,b,c){var d=this;this.current(function(e){var f=null!=e?e.length:0;return d.maximumSelectionLength>0&&f>=d.maximumSelectionLength?void d.trigger("results:message",{message:"maximumSelected",args:{maximum:d.maximumSelectionLength}}):void a.call(d,b,c)})},a}),b.define("select2/dropdown",["jquery","./utils"],function(a,b){function c(a,b){this.$element=a,this.options=b,c.__super__.constructor.call(this)}return b.Extend(c,b.Observable),c.prototype.render=function(){var b=a('<span class="select2-dropdown"><span class="select2-results"></span></span>');return b.attr("dir",this.options.get("dir")),this.$dropdown=b,b},c.prototype.bind=function(){},c.prototype.position=function(a,b){},c.prototype.destroy=function(){this.$dropdown.remove()},c}),b.define("select2/dropdown/search",["jquery","../utils"],function(a,b){function c(){}return c.prototype.render=function(b){var c=b.call(this),d=a('<span class="select2-search select2-search--dropdown"><input class="select2-search__field" type="search" tabindex="-1" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" role="textbox" /></span>');return this.$searchContainer=d,this.$search=d.find("input"),c.prepend(d),c},c.prototype.bind=function(b,c,d){var e=this;b.call(this,c,d),this.$search.on("keydown",function(a){e.trigger("keypress",a),e._keyUpPrevented=a.isDefaultPrevented()}),this.$search.on("input",function(b){a(this).off("keyup")}),this.$search.on("keyup input",function(a){e.handleSearch(a)}),c.on("open",function(){e.$search.attr("tabindex",0),e.$search.focus(),window.setTimeout(function(){e.$search.focus()},0)}),c.on("close",function(){e.$search.attr("tabindex",-1),e.$search.val("")}),c.on("results:all",function(a){if(null==a.query.term||""===a.query.term){var b=e.showSearch(a);b?e.$searchContainer.removeClass("select2-search--hide"):e.$searchContainer.addClass("select2-search--hide")}})},c.prototype.handleSearch=function(a){if(!this._keyUpPrevented){var b=this.$search.val();this.trigger("query",{term:b})}this._keyUpPrevented=!1},c.prototype.showSearch=function(a,b){return!0},c}),b.define("select2/dropdown/hidePlaceholder",[],function(){function a(a,b,c,d){this.placeholder=this.normalizePlaceholder(c.get("placeholder")),a.call(this,b,c,d)}return a.prototype.append=function(a,b){b.results=this.removePlaceholder(b.results),a.call(this,b)},a.prototype.normalizePlaceholder=function(a,b){return"string"==typeof b&&(b={id:"",text:b}),b},a.prototype.removePlaceholder=function(a,b){for(var c=b.slice(0),d=b.length-1;d>=0;d--){var e=b[d];this.placeholder.id===e.id&&c.splice(d,1)}return c},a}),b.define("select2/dropdown/infiniteScroll",["jquery"],function(a){function b(a,b,c,d){this.lastParams={},a.call(this,b,c,d),this.$loadingMore=this.createLoadingMore(),this.loading=!1}return b.prototype.append=function(a,b){this.$loadingMore.remove(),this.loading=!1,a.call(this,b),this.showLoadingMore(b)&&this.$results.append(this.$loadingMore)},b.prototype.bind=function(b,c,d){var e=this;b.call(this,c,d),c.on("query",function(a){e.lastParams=a,e.loading=!0}),c.on("query:append",function(a){e.lastParams=a,e.loading=!0}),this.$results.on("scroll",function(){var b=a.contains(document.documentElement,e.$loadingMore[0]);if(!e.loading&&b){var c=e.$results.offset().top+e.$results.outerHeight(!1),d=e.$loadingMore.offset().top+e.$loadingMore.outerHeight(!1);c+50>=d&&e.loadMore()}})},b.prototype.loadMore=function(){this.loading=!0;var b=a.extend({},{page:1},this.lastParams);b.page++,this.trigger("query:append",b)},b.prototype.showLoadingMore=function(a,b){return b.pagination&&b.pagination.more},b.prototype.createLoadingMore=function(){var b=a('<li class="select2-results__option select2-results__option--load-more"role="treeitem" aria-disabled="true"></li>'),c=this.options.get("translations").get("loadingMore");return b.html(c(this.lastParams)),b},b}),b.define("select2/dropdown/attachBody",["jquery","../utils"],function(a,b){function c(b,c,d){this.$dropdownParent=d.get("dropdownParent")||a(document.body),b.call(this,c,d)}return c.prototype.bind=function(a,b,c){var d=this,e=!1;a.call(this,b,c),b.on("open",function(){d._showDropdown(),d._attachPositioningHandler(b),e||(e=!0,b.on("results:all",function(){d._positionDropdown(),d._resizeDropdown()}),b.on("results:append",function(){d._positionDropdown(),d._resizeDropdown()}))}),b.on("close",function(){d._hideDropdown(),d._detachPositioningHandler(b)}),this.$dropdownContainer.on("mousedown",function(a){a.stopPropagation()})},c.prototype.destroy=function(a){a.call(this),this.$dropdownContainer.remove()},c.prototype.position=function(a,b,c){b.attr("class",c.attr("class")),b.removeClass("select2"),b.addClass("select2-container--open"),b.css({position:"absolute",top:-999999}),this.$container=c},c.prototype.render=function(b){var c=a("<span></span>"),d=b.call(this);return c.append(d),this.$dropdownContainer=c,c},c.prototype._hideDropdown=function(a){this.$dropdownContainer.detach()},c.prototype._attachPositioningHandler=function(c,d){var e=this,f="scroll.select2."+d.id,g="resize.select2."+d.id,h="orientationchange.select2."+d.id,i=this.$container.parents().filter(b.hasScroll);i.each(function(){a(this).data("select2-scroll-position",{x:a(this).scrollLeft(),y:a(this).scrollTop()})}),i.on(f,function(b){var c=a(this).data("select2-scroll-position");a(this).scrollTop(c.y)}),a(window).on(f+" "+g+" "+h,function(a){e._positionDropdown(),e._resizeDropdown()})},c.prototype._detachPositioningHandler=function(c,d){var e="scroll.select2."+d.id,f="resize.select2."+d.id,g="orientationchange.select2."+d.id,h=this.$container.parents().filter(b.hasScroll);h.off(e),a(window).off(e+" "+f+" "+g)},c.prototype._positionDropdown=function(){var b=a(window),c=this.$dropdown.hasClass("select2-dropdown--above"),d=this.$dropdown.hasClass("select2-dropdown--below"),e=null,f=this.$container.offset();f.bottom=f.top+this.$container.outerHeight(!1);var g={height:this.$container.outerHeight(!1)};g.top=f.top,g.bottom=f.top+g.height;var h={height:this.$dropdown.outerHeight(!1)},i={top:b.scrollTop(),bottom:b.scrollTop()+b.height()},j=i.top<f.top-h.height,k=i.bottom>f.bottom+h.height,l={left:f.left,top:g.bottom},m=this.$dropdownParent;"static"===m.css("position")&&(m=m.offsetParent());var n=m.offset();l.top-=n.top,l.left-=n.left,c||d||(e="below"),k||!j||c?!j&&k&&c&&(e="below"):e="above",("above"==e||c&&"below"!==e)&&(l.top=g.top-h.height),null!=e&&(this.$dropdown.removeClass("select2-dropdown--below select2-dropdown--above").addClass("select2-dropdown--"+e),this.$container.removeClass("select2-container--below select2-container--above").addClass("select2-container--"+e)),this.$dropdownContainer.css(l)},c.prototype._resizeDropdown=function(){var a={width:this.$container.outerWidth(!1)+"px"};this.options.get("dropdownAutoWidth")&&(a.minWidth=a.width,a.width="auto"),this.$dropdown.css(a)},c.prototype._showDropdown=function(a){this.$dropdownContainer.appendTo(this.$dropdownParent),this._positionDropdown(),this._resizeDropdown()},c}),b.define("select2/dropdown/minimumResultsForSearch",[],function(){function a(b){for(var c=0,d=0;d<b.length;d++){var e=b[d];e.children?c+=a(e.children):c++}return c}function b(a,b,c,d){this.minimumResultsForSearch=c.get("minimumResultsForSearch"),this.minimumResultsForSearch<0&&(this.minimumResultsForSearch=1/0),a.call(this,b,c,d)}return b.prototype.showSearch=function(b,c){return a(c.data.results)<this.minimumResultsForSearch?!1:b.call(this,c)},b}),b.define("select2/dropdown/selectOnClose",[],function(){function a(){}return a.prototype.bind=function(a,b,c){var d=this;a.call(this,b,c),b.on("close",function(){d._handleSelectOnClose()})},a.prototype._handleSelectOnClose=function(){var a=this.getHighlightedResults();if(!(a.length<1)){var b=a.data("data");null!=b.element&&b.element.selected||null==b.element&&b.selected||this.trigger("select",{data:b})}},a}),b.define("select2/dropdown/closeOnSelect",[],function(){function a(){}return a.prototype.bind=function(a,b,c){var d=this;a.call(this,b,c),b.on("select",function(a){d._selectTriggered(a)}),b.on("unselect",function(a){d._selectTriggered(a)})},a.prototype._selectTriggered=function(a,b){var c=b.originalEvent;c&&c.ctrlKey||this.trigger("close",{})},a}),b.define("select2/i18n/en",[],function(){return{errorLoading:function(){return"The results could not be loaded."},inputTooLong:function(a){var b=a.input.length-a.maximum,c="Please delete "+b+" character";return 1!=b&&(c+="s"),c},inputTooShort:function(a){var b=a.minimum-a.input.length,c="Please enter "+b+" or more characters";return c},loadingMore:function(){return"Loading more results…"},maximumSelected:function(a){var b="You can only select "+a.maximum+" item";return 1!=a.maximum&&(b+="s"),b},noResults:function(){return"No results found"},searching:function(){return"Searching…"}}}),b.define("select2/defaults",["jquery","require","./results","./selection/single","./selection/multiple","./selection/placeholder","./selection/allowClear","./selection/search","./selection/eventRelay","./utils","./translation","./diacritics","./data/select","./data/array","./data/ajax","./data/tags","./data/tokenizer","./data/minimumInputLength","./data/maximumInputLength","./data/maximumSelectionLength","./dropdown","./dropdown/search","./dropdown/hidePlaceholder","./dropdown/infiniteScroll","./dropdown/attachBody","./dropdown/minimumResultsForSearch","./dropdown/selectOnClose","./dropdown/closeOnSelect","./i18n/en"],function(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,A,B,C){function D(){this.reset()}D.prototype.apply=function(l){if(l=a.extend(!0,{},this.defaults,l),null==l.dataAdapter){if(null!=l.ajax?l.dataAdapter=o:null!=l.data?l.dataAdapter=n:l.dataAdapter=m,l.minimumInputLength>0&&(l.dataAdapter=j.Decorate(l.dataAdapter,r)),l.maximumInputLength>0&&(l.dataAdapter=j.Decorate(l.dataAdapter,s)),l.maximumSelectionLength>0&&(l.dataAdapter=j.Decorate(l.dataAdapter,t)),l.tags&&(l.dataAdapter=j.Decorate(l.dataAdapter,p)),(null!=l.tokenSeparators||null!=l.tokenizer)&&(l.dataAdapter=j.Decorate(l.dataAdapter,q)),null!=l.query){var C=b(l.amdBase+"compat/query");l.dataAdapter=j.Decorate(l.dataAdapter,C)}if(null!=l.initSelection){var D=b(l.amdBase+"compat/initSelection");l.dataAdapter=j.Decorate(l.dataAdapter,D)}}if(null==l.resultsAdapter&&(l.resultsAdapter=c,null!=l.ajax&&(l.resultsAdapter=j.Decorate(l.resultsAdapter,x)),null!=l.placeholder&&(l.resultsAdapter=j.Decorate(l.resultsAdapter,w)),l.selectOnClose&&(l.resultsAdapter=j.Decorate(l.resultsAdapter,A))),null==l.dropdownAdapter){if(l.multiple)l.dropdownAdapter=u;else{var E=j.Decorate(u,v);l.dropdownAdapter=E}if(0!==l.minimumResultsForSearch&&(l.dropdownAdapter=j.Decorate(l.dropdownAdapter,z)),l.closeOnSelect&&(l.dropdownAdapter=j.Decorate(l.dropdownAdapter,B)),null!=l.dropdownCssClass||null!=l.dropdownCss||null!=l.adaptDropdownCssClass){var F=b(l.amdBase+"compat/dropdownCss");l.dropdownAdapter=j.Decorate(l.dropdownAdapter,F)}l.dropdownAdapter=j.Decorate(l.dropdownAdapter,y)}if(null==l.selectionAdapter){if(l.multiple?l.selectionAdapter=e:l.selectionAdapter=d,null!=l.placeholder&&(l.selectionAdapter=j.Decorate(l.selectionAdapter,f)),l.allowClear&&(l.selectionAdapter=j.Decorate(l.selectionAdapter,g)),l.multiple&&(l.selectionAdapter=j.Decorate(l.selectionAdapter,h)),null!=l.containerCssClass||null!=l.containerCss||null!=l.adaptContainerCssClass){var G=b(l.amdBase+"compat/containerCss");l.selectionAdapter=j.Decorate(l.selectionAdapter,G)}l.selectionAdapter=j.Decorate(l.selectionAdapter,i)}if("string"==typeof l.language)if(l.language.indexOf("-")>0){var H=l.language.split("-"),I=H[0];l.language=[l.language,I]}else l.language=[l.language];if(a.isArray(l.language)){var J=new k;l.language.push("en");for(var K=l.language,L=0;L<K.length;L++){var M=K[L],N={};try{N=k.loadPath(M)}catch(O){try{M=this.defaults.amdLanguageBase+M,N=k.loadPath(M)}catch(P){l.debug&&window.console&&console.warn&&console.warn('Select2: The language file for "'+M+'" could not be automatically loaded. A fallback will be used instead.');continue}}J.extend(N)}l.translations=J}else{var Q=k.loadPath(this.defaults.amdLanguageBase+"en"),R=new k(l.language);R.extend(Q),l.translations=R}return l},D.prototype.reset=function(){function b(a){function b(a){return l[a]||a}return a.replace(/[^\u0000-\u007E]/g,b)}function c(d,e){if(""===a.trim(d.term))return e;if(e.children&&e.children.length>0){for(var f=a.extend(!0,{},e),g=e.children.length-1;g>=0;g--){var h=e.children[g],i=c(d,h);null==i&&f.children.splice(g,1)}return f.children.length>0?f:c(d,f)}var j=b(e.text).toUpperCase(),k=b(d.term).toUpperCase();return j.indexOf(k)>-1?e:null}this.defaults={amdBase:"./",amdLanguageBase:"./i18n/",closeOnSelect:!0,debug:!1,dropdownAutoWidth:!1,escapeMarkup:j.escapeMarkup,language:C,matcher:c,minimumInputLength:0,maximumInputLength:0,maximumSelectionLength:0,minimumResultsForSearch:0,selectOnClose:!1,sorter:function(a){return a},templateResult:function(a){return a.text},templateSelection:function(a){return a.text},theme:"default",width:"resolve"}},D.prototype.set=function(b,c){var d=a.camelCase(b),e={};e[d]=c;var f=j._convertData(e);a.extend(this.defaults,f)};var E=new D;return E}),b.define("select2/options",["require","jquery","./defaults","./utils"],function(a,b,c,d){function e(b,e){if(this.options=b,null!=e&&this.fromElement(e),this.options=c.apply(this.options),e&&e.is("input")){var f=a(this.get("amdBase")+"compat/inputData");this.options.dataAdapter=d.Decorate(this.options.dataAdapter,f)}}return e.prototype.fromElement=function(a){var c=["select2"];null==this.options.multiple&&(this.options.multiple=a.prop("multiple")),null==this.options.disabled&&(this.options.disabled=a.prop("disabled")),null==this.options.language&&(a.prop("lang")?this.options.language=a.prop("lang").toLowerCase():a.closest("[lang]").prop("lang")&&(this.options.language=a.closest("[lang]").prop("lang"))),null==this.options.dir&&(a.prop("dir")?this.options.dir=a.prop("dir"):a.closest("[dir]").prop("dir")?this.options.dir=a.closest("[dir]").prop("dir"):this.options.dir="ltr"),a.prop("disabled",this.options.disabled),a.prop("multiple",this.options.multiple),a.data("select2Tags")&&(this.options.debug&&window.console&&console.warn&&console.warn('Select2: The `data-select2-tags` attribute has been changed to use the `data-data` and `data-tags="true"` attributes and will be removed in future versions of Select2.'),a.data("data",a.data("select2Tags")),a.data("tags",!0)),a.data("ajaxUrl")&&(this.options.debug&&window.console&&console.warn&&console.warn("Select2: The `data-ajax-url` attribute has been changed to `data-ajax--url` and support for the old attribute will be removed in future versions of Select2."),a.attr("ajax--url",a.data("ajaxUrl")),a.data("ajax--url",a.data("ajaxUrl")));var e={};e=b.fn.jquery&&"1."==b.fn.jquery.substr(0,2)&&a[0].dataset?b.extend(!0,{},a[0].dataset,a.data()):a.data();var f=b.extend(!0,{},e);f=d._convertData(f);for(var g in f)b.inArray(g,c)>-1||(b.isPlainObject(this.options[g])?b.extend(this.options[g],f[g]):this.options[g]=f[g]);return this},e.prototype.get=function(a){return this.options[a]},e.prototype.set=function(a,b){this.options[a]=b},e}),b.define("select2/core",["jquery","./options","./utils","./keys"],function(a,b,c,d){var e=function(a,c){null!=a.data("select2")&&a.data("select2").destroy(),this.$element=a,this.id=this._generateId(a),c=c||{},this.options=new b(c,a),e.__super__.constructor.call(this);var d=a.attr("tabindex")||0;a.data("old-tabindex",d),a.attr("tabindex","-1");var f=this.options.get("dataAdapter");this.dataAdapter=new f(a,this.options);var g=this.render();this._placeContainer(g);var h=this.options.get("selectionAdapter");this.selection=new h(a,this.options),this.$selection=this.selection.render(),this.selection.position(this.$selection,g);var i=this.options.get("dropdownAdapter");this.dropdown=new i(a,this.options),this.$dropdown=this.dropdown.render(),this.dropdown.position(this.$dropdown,g);var j=this.options.get("resultsAdapter");this.results=new j(a,this.options,this.dataAdapter),this.$results=this.results.render(),this.results.position(this.$results,this.$dropdown);var k=this;this._bindAdapters(),this._registerDomEvents(),this._registerDataEvents(),this._registerSelectionEvents(),this._registerDropdownEvents(),this._registerResultsEvents(),this._registerEvents(),this.dataAdapter.current(function(a){k.trigger("selection:update",{data:a})}),a.addClass("select2-hidden-accessible"),a.attr("aria-hidden","true"),this._syncAttributes(),a.data("select2",this)};return c.Extend(e,c.Observable),e.prototype._generateId=function(a){var b="";return b=null!=a.attr("id")?a.attr("id"):null!=a.attr("name")?a.attr("name")+"-"+c.generateChars(2):c.generateChars(4),b=b.replace(/(:|\.|\[|\]|,)/g,""),b="select2-"+b},e.prototype._placeContainer=function(a){a.insertAfter(this.$element);var b=this._resolveWidth(this.$element,this.options.get("width"));null!=b&&a.css("width",b)},e.prototype._resolveWidth=function(a,b){var c=/^width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i;if("resolve"==b){var d=this._resolveWidth(a,"style");return null!=d?d:this._resolveWidth(a,"element")}if("element"==b){var e=a.outerWidth(!1);return 0>=e?"auto":e+"px"}if("style"==b){var f=a.attr("style");if("string"!=typeof f)return null;for(var g=f.split(";"),h=0,i=g.length;i>h;h+=1){var j=g[h].replace(/\s/g,""),k=j.match(c);if(null!==k&&k.length>=1)return k[1]}return null}return b},e.prototype._bindAdapters=function(){this.dataAdapter.bind(this,this.$container),this.selection.bind(this,this.$container),this.dropdown.bind(this,this.$container),this.results.bind(this,this.$container)},e.prototype._registerDomEvents=function(){var b=this;this.$element.on("change.select2",function(){b.dataAdapter.current(function(a){b.trigger("selection:update",{data:a})})}),this._sync=c.bind(this._syncAttributes,this),this.$element[0].attachEvent&&this.$element[0].attachEvent("onpropertychange",this._sync);var d=window.MutationObserver||window.WebKitMutationObserver||window.MozMutationObserver;null!=d?(this._observer=new d(function(c){a.each(c,b._sync)}),this._observer.observe(this.$element[0],{attributes:!0,subtree:!1})):this.$element[0].addEventListener&&this.$element[0].addEventListener("DOMAttrModified",b._sync,!1)},e.prototype._registerDataEvents=function(){var a=this;this.dataAdapter.on("*",function(b,c){a.trigger(b,c)})},e.prototype._registerSelectionEvents=function(){var b=this,c=["toggle","focus"];this.selection.on("toggle",function(){b.toggleDropdown()}),this.selection.on("focus",function(a){b.focus(a)}),this.selection.on("*",function(d,e){-1===a.inArray(d,c)&&b.trigger(d,e)})},e.prototype._registerDropdownEvents=function(){var a=this;this.dropdown.on("*",function(b,c){a.trigger(b,c)})},e.prototype._registerResultsEvents=function(){var a=this;this.results.on("*",function(b,c){a.trigger(b,c)})},e.prototype._registerEvents=function(){var a=this;this.on("open",function(){a.$container.addClass("select2-container--open")}),this.on("close",function(){a.$container.removeClass("select2-container--open")}),this.on("enable",function(){a.$container.removeClass("select2-container--disabled")}),this.on("disable",function(){a.$container.addClass("select2-container--disabled")}),this.on("blur",function(){a.$container.removeClass("select2-container--focus")}),this.on("query",function(b){a.isOpen()||a.trigger("open",{}),this.dataAdapter.query(b,function(c){a.trigger("results:all",{data:c,query:b})})}),this.on("query:append",function(b){this.dataAdapter.query(b,function(c){a.trigger("results:append",{data:c,query:b})})}),this.on("keypress",function(b){var c=b.which;a.isOpen()?c===d.ESC||c===d.TAB||c===d.UP&&b.altKey?(a.close(),b.preventDefault()):c===d.ENTER?(a.trigger("results:select",{}),b.preventDefault()):c===d.SPACE&&b.ctrlKey?(a.trigger("results:toggle",{}),b.preventDefault()):c===d.UP?(a.trigger("results:previous",{}),b.preventDefault()):c===d.DOWN&&(a.trigger("results:next",{}),b.preventDefault()):(c===d.ENTER||c===d.SPACE||c===d.DOWN&&b.altKey)&&(a.open(),b.preventDefault())})},e.prototype._syncAttributes=function(){this.options.set("disabled",this.$element.prop("disabled")),this.options.get("disabled")?(this.isOpen()&&this.close(),this.trigger("disable",{})):this.trigger("enable",{})},e.prototype.trigger=function(a,b){var c=e.__super__.trigger,d={open:"opening",close:"closing",select:"selecting",unselect:"unselecting"};if(void 0===b&&(b={}),a in d){var f=d[a],g={prevented:!1,name:a,args:b};if(c.call(this,f,g),g.prevented)return void(b.prevented=!0)}c.call(this,a,b)},e.prototype.toggleDropdown=function(){this.options.get("disabled")||(this.isOpen()?this.close():this.open())},e.prototype.open=function(){this.isOpen()||this.trigger("query",{})},e.prototype.close=function(){this.isOpen()&&this.trigger("close",{})},e.prototype.isOpen=function(){return this.$container.hasClass("select2-container--open")},e.prototype.hasFocus=function(){return this.$container.hasClass("select2-container--focus")},e.prototype.focus=function(a){this.hasFocus()||(this.$container.addClass("select2-container--focus"),this.trigger("focus",{}))},e.prototype.enable=function(a){this.options.get("debug")&&window.console&&console.warn&&console.warn('Select2: The `select2("enable")` method has been deprecated and will be removed in later Select2 versions. Use $element.prop("disabled") instead.'),(null==a||0===a.length)&&(a=[!0]);var b=!a[0];this.$element.prop("disabled",b)},e.prototype.data=function(){this.options.get("debug")&&arguments.length>0&&window.console&&console.warn&&console.warn('Select2: Data can no longer be set using `select2("data")`. You should consider setting the value instead using `$element.val()`.');var a=[];return this.dataAdapter.current(function(b){a=b}),a},e.prototype.val=function(b){if(this.options.get("debug")&&window.console&&console.warn&&console.warn('Select2: The `select2("val")` method has been deprecated and will be removed in later Select2 versions. Use $element.val() instead.'),null==b||0===b.length)return this.$element.val();var c=b[0];a.isArray(c)&&(c=a.map(c,function(a){return a.toString()})),this.$element.val(c).trigger("change")},e.prototype.destroy=function(){this.$container.remove(),this.$element[0].detachEvent&&this.$element[0].detachEvent("onpropertychange",this._sync),null!=this._observer?(this._observer.disconnect(),this._observer=null):this.$element[0].removeEventListener&&this.$element[0].removeEventListener("DOMAttrModified",this._sync,!1),this._sync=null,this.$element.off(".select2"),this.$element.attr("tabindex",this.$element.data("old-tabindex")),this.$element.removeClass("select2-hidden-accessible"),this.$element.attr("aria-hidden","false"),this.$element.removeData("select2"),this.dataAdapter.destroy(),this.selection.destroy(),this.dropdown.destroy(),this.results.destroy(),this.dataAdapter=null,this.selection=null,this.dropdown=null,this.results=null},e.prototype.render=function(){var b=a('<span class="select2 select2-container"><span class="selection"></span><span class="dropdown-wrapper" aria-hidden="true"></span></span>');return b.attr("dir",this.options.get("dir")),this.$container=b,this.$container.addClass("select2-container--"+this.options.get("theme")),b.data("element",this.$element),b},e}),b.define("jquery-mousewheel",["jquery"],function(a){return a}),b.define("jquery.select2",["jquery","jquery-mousewheel","./select2/core","./select2/defaults"],function(a,b,c,d){if(null==a.fn.select2){var e=["open","close","destroy"];a.fn.select2=function(b){if(b=b||{},"object"==typeof b)return this.each(function(){var d=a.extend(!0,{},b);new c(a(this),d)}),this;if("string"==typeof b){var d;return this.each(function(){var c=a(this).data("select2");null==c&&window.console&&console.error&&console.error("The select2('"+b+"') method was called on an element that is not using Select2.");var e=Array.prototype.slice.call(arguments,1);d=c[b].apply(c,e)}),a.inArray(b,e)>-1?this:d}throw new Error("Invalid arguments for Select2: "+b)}}return null==a.fn.select2.defaults&&(a.fn.select2.defaults=d),c}),{define:b.define,require:b.require}}(),c=b.require("jquery.select2");return a.fn.select2.amd=b,c});
//! moment.js
-//! version : 2.16.0
+//! version : 2.17.0
//! authors : Tim Wood, Iskren Chernev, Moment.js contributors
//! license : MIT
//! momentjs.com
@@ -1309,11 +1309,11 @@ function b(a){od=a}function c(a){return a instanceof Array||"[object Array]"===O
// input != null
return null!=a&&"[object Object]"===Object.prototype.toString.call(a)}function e(a){var b;for(b in a)
// even if its not own property I'd still call it non-empty
-return!1;return!0}function f(a){return"number"==typeof value||"[object Number]"===Object.prototype.toString.call(a)}function g(a){return a instanceof Date||"[object Date]"===Object.prototype.toString.call(a)}function h(a,b){var c,d=[];for(c=0;c<a.length;++c)d.push(b(a[c],c));return d}function i(a,b){return Object.prototype.hasOwnProperty.call(a,b)}function j(a,b){for(var c in b)i(b,c)&&(a[c]=b[c]);return i(b,"toString")&&(a.toString=b.toString),i(b,"valueOf")&&(a.valueOf=b.valueOf),a}function k(a,b,c,d){return rb(a,b,c,d,!0).utc()}function l(){
+return!1;return!0}function f(a){return"number"==typeof a||"[object Number]"===Object.prototype.toString.call(a)}function g(a){return a instanceof Date||"[object Date]"===Object.prototype.toString.call(a)}function h(a,b){var c,d=[];for(c=0;c<a.length;++c)d.push(b(a[c],c));return d}function i(a,b){return Object.prototype.hasOwnProperty.call(a,b)}function j(a,b){for(var c in b)i(b,c)&&(a[c]=b[c]);return i(b,"toString")&&(a.toString=b.toString),i(b,"valueOf")&&(a.valueOf=b.valueOf),a}function k(a,b,c,d){return rb(a,b,c,d,!0).utc()}function l(){
// We need to deep clone this object.
return{empty:!1,unusedTokens:[],unusedInput:[],overflow:-2,charsLeftOver:0,nullInput:!1,invalidMonth:null,invalidFormat:!1,userInvalidated:!1,iso:!1,parsedDateParts:[],meridiem:null}}function m(a){return null==a._pf&&(a._pf=l()),a._pf}function n(a){if(null==a._isValid){var b=m(a),c=qd.call(b.parsedDateParts,function(a){return null!=a}),d=!isNaN(a._d.getTime())&&b.overflow<0&&!b.empty&&!b.invalidMonth&&!b.invalidWeekday&&!b.nullInput&&!b.invalidFormat&&!b.userInvalidated&&(!b.meridiem||b.meridiem&&c);if(a._strict&&(d=d&&0===b.charsLeftOver&&0===b.unusedTokens.length&&void 0===b.bigHour),null!=Object.isFrozen&&Object.isFrozen(a))return d;a._isValid=d}return a._isValid}function o(a){var b=k(NaN);return null!=a?j(m(b),a):m(b).userInvalidated=!0,b}function p(a){return void 0===a}function q(a,b){var c,d,e;if(p(b._isAMomentObject)||(a._isAMomentObject=b._isAMomentObject),p(b._i)||(a._i=b._i),p(b._f)||(a._f=b._f),p(b._l)||(a._l=b._l),p(b._strict)||(a._strict=b._strict),p(b._tzm)||(a._tzm=b._tzm),p(b._isUTC)||(a._isUTC=b._isUTC),p(b._offset)||(a._offset=b._offset),p(b._pf)||(a._pf=m(b)),p(b._locale)||(a._locale=b._locale),rd.length>0)for(c in rd)d=rd[c],e=b[d],p(e)||(a[d]=e);return a}
// Moment prototype object
-function r(b){q(this,b),this._d=new Date(null!=b._d?b._d.getTime():NaN),
+function r(b){q(this,b),this._d=new Date(null!=b._d?b._d.getTime():NaN),this.isValid()||(this._d=new Date(NaN)),
// Prevent infinite loop in case updateOffset creates new moment
// objects.
sd===!1&&(sd=!0,a.updateOffset(this),sd=!1)}function s(a){return a instanceof r||null!=a&&null!=a._isAMomentObject}function t(a){return a<0?Math.ceil(a)||0:Math.floor(a)}function u(a){var b=+a,c=0;return 0!==b&&isFinite(b)&&(c=t(b)),c}
@@ -1846,7 +1846,7 @@ M:11},qf=Math.abs,rf=wb.prototype;
// FORMATTING
// PARSING
// Side effect imports
-return rf.abs=Wc,rf.add=Yc,rf.subtract=Zc,rf.as=cd,rf.asMilliseconds=$e,rf.asSeconds=_e,rf.asMinutes=af,rf.asHours=bf,rf.asDays=cf,rf.asWeeks=df,rf.asMonths=ef,rf.asYears=ff,rf.valueOf=dd,rf._bubble=_c,rf.get=fd,rf.milliseconds=gf,rf.seconds=hf,rf.minutes=jf,rf.hours=kf,rf.days=lf,rf.weeks=hd,rf.months=mf,rf.years=nf,rf.humanize=md,rf.toISOString=nd,rf.toString=nd,rf.toJSON=nd,rf.locale=lc,rf.localeData=mc,rf.toIsoString=x("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",nd),rf.lang=Re,U("X",0,0,"unix"),U("x",0,0,"valueOf"),Z("x",Vd),Z("X",Yd),ba("X",function(a,b,c){c._d=new Date(1e3*parseFloat(a,10))}),ba("x",function(a,b,c){c._d=new Date(u(a))}),a.version="2.16.0",b(sb),a.fn=Xe,a.min=ub,a.max=vb,a.now=Le,a.utc=k,a.unix=Lc,a.months=Rc,a.isDate=g,a.locale=$a,a.invalid=o,a.duration=Ob,a.isMoment=s,a.weekdays=Tc,a.parseZone=Mc,a.localeData=bb,a.isDuration=xb,a.monthsShort=Sc,a.weekdaysMin=Vc,a.defineLocale=_a,a.updateLocale=ab,a.locales=cb,a.weekdaysShort=Uc,a.normalizeUnits=K,a.relativeTimeRounding=kd,a.relativeTimeThreshold=ld,a.calendarFormat=Ub,a.prototype=Xe,a});
+return rf.abs=Wc,rf.add=Yc,rf.subtract=Zc,rf.as=cd,rf.asMilliseconds=$e,rf.asSeconds=_e,rf.asMinutes=af,rf.asHours=bf,rf.asDays=cf,rf.asWeeks=df,rf.asMonths=ef,rf.asYears=ff,rf.valueOf=dd,rf._bubble=_c,rf.get=fd,rf.milliseconds=gf,rf.seconds=hf,rf.minutes=jf,rf.hours=kf,rf.days=lf,rf.weeks=hd,rf.months=mf,rf.years=nf,rf.humanize=md,rf.toISOString=nd,rf.toString=nd,rf.toJSON=nd,rf.locale=lc,rf.localeData=mc,rf.toIsoString=x("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",nd),rf.lang=Re,U("X",0,0,"unix"),U("x",0,0,"valueOf"),Z("x",Vd),Z("X",Yd),ba("X",function(a,b,c){c._d=new Date(1e3*parseFloat(a,10))}),ba("x",function(a,b,c){c._d=new Date(u(a))}),a.version="2.17.0",b(sb),a.fn=Xe,a.min=ub,a.max=vb,a.now=Le,a.utc=k,a.unix=Lc,a.months=Rc,a.isDate=g,a.locale=$a,a.invalid=o,a.duration=Ob,a.isMoment=s,a.weekdays=Tc,a.parseZone=Mc,a.localeData=bb,a.isDuration=xb,a.monthsShort=Sc,a.weekdaysMin=Vc,a.defineLocale=_a,a.updateLocale=ab,a.locales=cb,a.weekdaysShort=Uc,a.normalizeUnits=K,a.relativeTimeRounding=kd,a.relativeTimeThreshold=ld,a.calendarFormat=Ub,a.prototype=Xe,a});
/*!
* FullCalendar v3.0.1
* Docs & License: http://fullcalendar.io/
@@ -1892,9 +1892,4 @@ SVGPathSeg.call(this,SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL,"v",a),this._y=b},SV
* 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:/^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\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",/<!--[\s\S]*?-->/)("closed",/<(tag)[\s\S]+?<\/\1>/)("closing",/<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)(/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:/^/,heading:/^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/});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<item.align.length;i++){if(/^ *-+: *$/.test(item.align[i])){item.align[i]="right"}else if(/^ *:-+: *$/.test(item.align[i])){item.align[i]="center"}else if(/^ *:-+ *$/.test(item.align[i])){item.align[i]="left"}else{item.align[i]=null}}for(i=0;i<item.cells.length;i++){item.cells[i]=item.cells[i].split(/ *\| */)}this.tokens.push(item);continue}if(cap=this.rules.lheading.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"heading",depth:cap[2]==="="?1:2,text:cap[1]});continue}if(cap=this.rules.hr.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"hr"});continue}if(cap=this.rules.blockquote.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"blockquote_start"});cap=cap[0].replace(/^ *> ?/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(;i<l;i++){item=cap[i];space=item.length;item=item.replace(/^ *([*+-]|\d+\.) +/,"");if(~item.indexOf("\n ")){space-=item.length;item=!this.options.pedantic?item.replace(new RegExp("^ {1,"+space+"}","gm"),""):item.replace(/^ {1,4}/gm,"")}if(this.options.smartLists&&i!==l-1){b=block.bullet.exec(cap[i+1])[0];if(bull!==b&&!(bull.length>1&&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:!this.options.sanitizer&&(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<item.align.length;i++){if(/^ *-+: *$/.test(item.align[i])){item.align[i]="right"}else if(/^ *:-+: *$/.test(item.align[i])){item.align[i]="center"}else if(/^ *:-+ *$/.test(item.align[i])){item.align[i]="left"}else{item.align[i]=null}}for(i=0;i<item.cells.length;i++){item.cells[i]=item.cells[i].replace(/^ *\| *| *\| *$/g,"").split(/ *\| */)}this.tokens.push(item);continue}if(top&&(cap=this.rules.paragraph.exec(src))){src=src.substring(cap[0].length);this.tokens.push({type:"paragraph",text:cap[1].charAt(cap[1].length-1)==="\n"?cap[1].slice(0,-1):cap[1]});continue}if(cap=this.rules.text.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"text",text:cap[0]});continue}if(src){throw new Error("Infinite loop on byte: "+src.charCodeAt(0))}}return this.tokens};var inline={escape:/^\\([\\`*{}\[\]()#+\-.!_>])/,autolink:/^<([^ >]+(@|:\/)[^ >]+)>/,url:noop,tag:/^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,link:/^!?\[(inside)\]\(href\)/,reflink:/^!?\[(inside)\]\s*\[([^\]]*)\]/,nolink:/^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,strong:/^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,em:/^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,code:/^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,br:/^ {2,}\n(?!\s*$)/,del:noop,text:/^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/};inline._inside=/(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;inline._href=/\s*<?([\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&&/^<a /i.test(cap[0])){this.inLink=true}else if(this.inLink&&/^<\/a>/i.test(cap[0])){this.inLink=false}src=src.substring(cap[0].length);out+=this.options.sanitize?this.options.sanitizer?this.options.sanitizer(cap[0]):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+=this.renderer.text(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,"—").replace(/--/g,"–").replace(/(^|[-\u2014/(\[{"\s])'/g,"$1‘").replace(/'/g,"’").replace(/(^|[-\u2014/(\[{\u2018\s])"/g,"$1“").replace(/"/g,"â€").replace(/\.{3}/g,"…")};InlineLexer.prototype.mangle=function(text){if(!this.options.mangle)return text;var out="",l=text.length,i=0,ch;for(;i<l;i++){ch=text.charCodeAt(i);if(Math.random()>.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"<pre><code>"+(escaped?code:escape(code,true))+"\n</code></pre>"}return'<pre><code class="'+this.options.langPrefix+escape(lang,true)+'">'+(escaped?code:escape(code,true))+"\n</code></pre>\n"};Renderer.prototype.blockquote=function(quote){return"<blockquote>\n"+quote+"</blockquote>\n"};Renderer.prototype.html=function(html){return html};Renderer.prototype.heading=function(text,level,raw){return"<h"+level+' id="'+this.options.headerPrefix+raw.toLowerCase().replace(/[^\w]+/g,"-")+'">'+text+"</h"+level+">\n"};Renderer.prototype.hr=function(){return this.options.xhtml?"<hr/>\n":"<hr>\n"};Renderer.prototype.list=function(body,ordered){var type=ordered?"ol":"ul";return"<"+type+">\n"+body+"</"+type+">\n"};Renderer.prototype.listitem=function(text){return"<li>"+text+"</li>\n"};Renderer.prototype.paragraph=function(text){return"<p>"+text+"</p>\n"};Renderer.prototype.table=function(header,body){return"<table>\n"+"<thead>\n"+header+"</thead>\n"+"<tbody>\n"+body+"</tbody>\n"+"</table>\n"};Renderer.prototype.tablerow=function(content){return"<tr>\n"+content+"</tr>\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+"</"+type+">\n"};Renderer.prototype.strong=function(text){return"<strong>"+text+"</strong>"};Renderer.prototype.em=function(text){return"<em>"+text+"</em>"};Renderer.prototype.codespan=function(text){return"<code>"+text+"</code>"};Renderer.prototype.br=function(){return this.options.xhtml?"<br/>":"<br>"};Renderer.prototype.del=function(text){return"<del>"+text+"</del>"};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='<a href="'+href+'"';if(title){out+=' title="'+title+'"'}out+=">"+text+"</a>";return out};Renderer.prototype.image=function(href,title,text){var out='<img src="'+href+'" alt="'+text+'"';if(title){out+=' title="'+title+'"'}out+=this.options.xhtml?"/>":">";return out};Renderer.prototype.text=function(text){return text};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<this.token.header.length;i++){flags={header:true,align:this.token.align[i]};cell+=this.renderer.tablecell(this.inline.output(this.token.header[i]),{header:true,align:this.token.align[i]})}header+=this.renderer.tablerow(cell);for(i=0;i<this.token.cells.length;i++){row=this.token.cells[i];cell="";for(j=0;j<row.length;j++){cell+=this.renderer.tablecell(this.inline.output(row[j]),{header:false,align:this.token.align[j]})}body+=this.renderer.tablerow(cell)}return this.renderer.table(header,body)}case"blockquote_start":{var body="";while(this.next().type!=="blockquote_end"){body+=this.tok()}return this.renderer.blockquote(body)}case"list_start":{var body="",ordered=this.token.ordered;while(this.next().type!=="list_end"){body+=this.tok()}return this.renderer.list(body,ordered)}case"list_item_start":{var body="";while(this.next().type!=="list_item_end"){body+=this.token.type==="text"?this.parseText():this.tok()}return this.renderer.listitem(body)}case"loose_item_start":{var body="";while(this.next().type!=="list_item_end"){body+=this.tok()}return this.renderer.listitem(body)}case"html":{var html=!this.token.pre&&!this.options.pedantic?this.inline.output(this.token.text):this.token.text;return this.renderer.html(html)}case"paragraph":{return this.renderer.paragraph(this.inline.output(this.token.text))}case"text":{return this.renderer.paragraph(this.parseText())}}};function escape(html,encode){return html.replace(!encode?/&(?!#?\w+;)/g:/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}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(;i<arguments.length;i++){target=arguments[i];for(key in target){if(Object.prototype.hasOwnProperty.call(target,key)){obj[key]=target[key]}}}return obj}function marked(src,opt,callback){if(callback||typeof opt==="function"){if(!callback){callback=opt;opt=null}opt=merge({},marked.defaults,opt||{});var highlight=opt.highlight,tokens,pending,i=0;try{tokens=Lexer.lex(src,opt)}catch(e){return callback(e)}pending=tokens.length;var done=function(err){if(err){opt.highlight=highlight;return callback(err)}var out;try{out=Parser.parse(tokens,opt)}catch(e){err=e}opt.highlight=highlight;return err?callback(err):callback(null,out)};if(!highlight||highlight.length<3){return done()}delete opt.highlight;if(!pending)return done();for(;i<tokens.length;i++){(function(token){if(token.type!=="code"){return--pending||done()}return highlight(token.text,token.lang,function(err,code){if(err)return done(err);if(code==null||code===token.text){return--pending||done()}token.text=code;token.escaped=true;--pending||done()})})(tokens[i])}return}try{if(opt)opt=merge({},marked.defaults,opt);return Parser.parse(Lexer.lex(src,opt),opt)}catch(e){e.message+="\nPlease report this to https://github.com/chjj/marked.";if((opt||marked.defaults).silent){return"<p>An error occured:</p><pre>"+escape(e.message+"",true)+"</pre>"}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,sanitizer:null,mangle:true,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)}());
-!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.Vue=t()}(this,function(){"use strict";function e(t,r,i){if(n(t,r))return void(t[r]=i);if(t._isVue)return void e(t._data,r,i);var a=t.__ob__;if(!a)return void(t[r]=i);if(a.convert(r,i),a.dep.notify(),a.vms)for(var o=a.vms.length;o--;){var s=a.vms[o];s._proxy(r),s._digest()}return i}function t(e,t){if(n(e,t)){delete e[t];var r=e.__ob__;if(!r)return void(e._isVue&&(delete e._data[t],e._digest()));if(r.dep.notify(),r.vms)for(var i=r.vms.length;i--;){var a=r.vms[i];a._unproxy(t),a._digest()}}}function n(e,t){return $n.call(e,t)}function r(e){return An.test(e)}function i(e){var t=(e+"").charCodeAt(0);return 36===t||95===t}function a(e){return null==e?"":e.toString()}function o(e){if("string"!=typeof e)return e;var t=Number(e);return isNaN(t)?e:t}function s(e){return"true"===e?!0:"false"===e?!1:e}function l(e){var t=e.charCodeAt(0),n=e.charCodeAt(e.length-1);return t!==n||34!==t&&39!==t?e:e.slice(1,-1)}function u(e){return e.replace(Nn,c)}function c(e,t){return t?t.toUpperCase():""}function p(e){return e.replace(Ln,"$1-$2").toLowerCase()}function h(e){return e.replace(In,c)}function f(e,t){return function(n){var r=arguments.length;return r?r>1?e.apply(t,arguments):e.call(t,n):e.call(t)}}function d(e,t){t=t||0;for(var n=e.length-t,r=new Array(n);n--;)r[n]=e[n+t];return r}function v(e,t){for(var n=Object.keys(t),r=n.length;r--;)e[n[r]]=t[n[r]];return e}function m(e){return null!==e&&"object"==typeof e}function y(e){return Pn.call(e)===jn}function g(e,t,n,r){Object.defineProperty(e,t,{value:n,enumerable:!!r,writable:!0,configurable:!0})}function b(e,t){var n,r,i,a,o,s=function l(){var s=Date.now()-a;t>s&&s>=0?n=setTimeout(l,t-s):(n=null,o=e.apply(i,r),n||(i=r=null))};return function(){return i=this,r=arguments,a=Date.now(),n||(n=setTimeout(s,t)),o}}function _(e,t){for(var n=e.length;n--;)if(e[n]===t)return n;return-1}function x(e){var t=function n(){return n.cancelled?void 0:e.apply(this,arguments)};return t.cancel=function(){t.cancelled=!0},t}function w(e,t){return e==t||(m(e)&&m(t)?JSON.stringify(e)===JSON.stringify(t):!1)}function k(e){this.size=0,this.limit=e,this.head=this.tail=void 0,this._keymap=Object.create(null)}function S(){var e,t=nr.slice(lr,or).trim();if(t){e={};var n=t.match(vr);e.name=n[0],n.length>1&&(e.args=n.slice(1).map(C))}e&&(rr.filters=rr.filters||[]).push(e),lr=or+1}function C(e){if(mr.test(e))return{value:o(e),dynamic:!1};var t=l(e),n=t===e;return{value:n?e:t,dynamic:n}}function E(e){var t=dr.get(e);if(t)return t;for(nr=e,ur=cr=!1,pr=hr=fr=0,lr=0,rr={},or=0,sr=nr.length;sr>or;or++)if(ar=ir,ir=nr.charCodeAt(or),ur)39===ir&&92!==ar&&(ur=!ur);else if(cr)34===ir&&92!==ar&&(cr=!cr);else if(124===ir&&124!==nr.charCodeAt(or+1)&&124!==nr.charCodeAt(or-1))null==rr.expression?(lr=or+1,rr.expression=nr.slice(0,or).trim()):S();else switch(ir){case 34:cr=!0;break;case 39:ur=!0;break;case 40:fr++;break;case 41:fr--;break;case 91:hr++;break;case 93:hr--;break;case 123:pr++;break;case 125:pr--}return null==rr.expression?rr.expression=nr.slice(0,or).trim():0!==lr&&S(),dr.put(e,rr),rr}function O(e){return e.replace(gr,"\\$&")}function $(){var e=O(Er.delimiters[0]),t=O(Er.delimiters[1]),n=O(Er.unsafeDelimiters[0]),r=O(Er.unsafeDelimiters[1]);_r=new RegExp(n+"((?:.|\\n)+?)"+r+"|"+e+"((?:.|\\n)+?)"+t,"g"),xr=new RegExp("^"+n+"((?:.|\\n)+?)"+r+"$"),br=new k(1e3)}function A(e){br||$();var t=br.get(e);if(t)return t;if(!_r.test(e))return null;for(var n,r,i,a,o,s,l=[],u=_r.lastIndex=0;n=_r.exec(e);)r=n.index,r>u&&l.push({value:e.slice(u,r)}),i=xr.test(n[0]),a=i?n[1]:n[2],o=a.charCodeAt(0),s=42===o,a=s?a.slice(1):a,l.push({tag:!0,value:a.trim(),html:i,oneTime:s}),u=r+n[0].length;return u<e.length&&l.push({value:e.slice(u)}),br.put(e,l),l}function N(e,t){return e.length>1?e.map(function(e){return L(e,t)}).join("+"):L(e[0],t,!0)}function L(e,t,n){return e.tag?e.oneTime&&t?'"'+t.$eval(e.value)+'"':I(e.value,n):'"'+e.value+'"'}function I(e,t){if(wr.test(e)){var n=E(e);return n.filters?"this._applyFilters("+n.expression+",null,"+JSON.stringify(n.filters)+",false)":"("+e+")"}return t?e:"("+e+")"}function P(e,t,n,r){F(e,1,function(){t.appendChild(e)},n,r)}function j(e,t,n,r){F(e,1,function(){V(e,t)},n,r)}function T(e,t,n){F(e,-1,function(){W(e)},t,n)}function F(e,t,n,r,i){var a=e.__v_trans;if(!a||!a.hooks&&!Jn||!r._isCompiled||r.$parent&&!r.$parent._isCompiled)return n(),void(i&&i());var o=t>0?"enter":"leave";a[o](n,i)}function D(e){if("string"==typeof e){e=document.querySelector(e)}return e}function R(e){if(!e)return!1;var t=e.ownerDocument.documentElement,n=e.parentNode;return t===e||t===n||!(!n||1!==n.nodeType||!t.contains(n))}function B(e,t){var n=e.getAttribute(t);return null!==n&&e.removeAttribute(t),n}function U(e,t){var n=B(e,":"+t);return null===n&&(n=B(e,"v-bind:"+t)),n}function M(e,t){return e.hasAttribute(t)||e.hasAttribute(":"+t)||e.hasAttribute("v-bind:"+t)}function V(e,t){t.parentNode.insertBefore(e,t)}function H(e,t){t.nextSibling?V(e,t.nextSibling):t.parentNode.appendChild(e)}function W(e){e.parentNode.removeChild(e)}function z(e,t){t.firstChild?V(e,t.firstChild):t.appendChild(e)}function q(e,t){var n=e.parentNode;n&&n.replaceChild(t,e)}function G(e,t,n,r){e.addEventListener(t,n,r)}function J(e,t,n){e.removeEventListener(t,n)}function K(e){var t=e.className;return"object"==typeof t&&(t=t.baseVal||""),t}function Q(e,t){Mn&&!/svg$/.test(e.namespaceURI)?e.className=t:e.setAttribute("class",t)}function X(e,t){if(e.classList)e.classList.add(t);else{var n=" "+K(e)+" ";n.indexOf(" "+t+" ")<0&&Q(e,(n+t).trim())}}function Z(e,t){if(e.classList)e.classList.remove(t);else{for(var n=" "+K(e)+" ",r=" "+t+" ";n.indexOf(r)>=0;)n=n.replace(r," ");Q(e,n.trim())}e.className||e.removeAttribute("class")}function Y(e,t){var n,r;if(ne(e)&&se(e.content)&&(e=e.content),e.hasChildNodes())for(ee(e),r=t?document.createDocumentFragment():document.createElement("div");n=e.firstChild;)r.appendChild(n);return r}function ee(e){for(var t;t=e.firstChild,te(t);)e.removeChild(t);for(;t=e.lastChild,te(t);)e.removeChild(t)}function te(e){return e&&(3===e.nodeType&&!e.data.trim()||8===e.nodeType)}function ne(e){return e.tagName&&"template"===e.tagName.toLowerCase()}function re(e,t){var n=Er.debug?document.createComment(e):document.createTextNode(t?" ":"");return n.__v_anchor=!0,n}function ie(e){if(e.hasAttributes())for(var t=e.attributes,n=0,r=t.length;r>n;n++){var i=t[n].name;if(Ar.test(i))return u(i.replace(Ar,""))}}function ae(e,t,n){for(var r;e!==t;)r=e.nextSibling,n(e),e=r;n(t)}function oe(e,t,n,r,i){function a(){if(s++,o&&s>=l.length){for(var e=0;e<l.length;e++)r.appendChild(l[e]);i&&i()}}var o=!1,s=0,l=[];ae(e,t,function(e){e===t&&(o=!0),l.push(e),T(e,n,a)})}function se(e){return e&&11===e.nodeType}function le(e){if(e.outerHTML)return e.outerHTML;var t=document.createElement("div");return t.appendChild(e.cloneNode(!0)),t.innerHTML}function ue(e,t){var n=e.tagName.toLowerCase(),r=e.hasAttributes();if(Nr.test(n)||Lr.test(n)){if(r)return ce(e,t)}else{if(ye(t,"components",n))return{id:n};var i=r&&ce(e,t);if(i)return i}}function ce(e,t){var n=e.getAttribute("is");if(null!=n){if(ye(t,"components",n))return e.removeAttribute("is"),{id:n}}else if(n=U(e,"is"),null!=n)return{id:n,dynamic:!0}}function pe(t,r){var i,a,o;for(i in r)a=t[i],o=r[i],n(t,i)?m(a)&&m(o)&&pe(a,o):e(t,i,o);return t}function he(e,t){var n=Object.create(e||null);return t?v(n,ve(t)):n}function fe(e){if(e.components)for(var t,n=e.components=ve(e.components),r=Object.keys(n),i=0,a=r.length;a>i;i++){var o=r[i];Nr.test(o)||Lr.test(o)||(t=n[o],y(t)&&(n[o]=wn.extend(t)))}}function de(e){var t,n,r=e.props;if(Tn(r))for(e.props={},t=r.length;t--;)n=r[t],"string"==typeof n?e.props[n]=null:n.name&&(e.props[n.name]=n);else if(y(r)){var i=Object.keys(r);for(t=i.length;t--;)n=r[i[t]],"function"==typeof n&&(r[i[t]]={type:n})}}function ve(e){if(Tn(e)){for(var t,n={},r=e.length;r--;){t=e[r];var i="function"==typeof t?t.options&&t.options.name||t.id:t.name||t.id;i&&(n[i]=t)}return n}return e}function me(e,t,r){function i(n){var i=Ir[n]||Pr;o[n]=i(e[n],t[n],r,n)}fe(t),de(t);var a,o={};if(t["extends"]&&(e="function"==typeof t["extends"]?me(e,t["extends"].options,r):me(e,t["extends"],r)),t.mixins)for(var s=0,l=t.mixins.length;l>s;s++){var u=t.mixins[s],c=u.prototype instanceof wn?u.options:u;e=me(e,c,r)}for(a in e)i(a);for(a in t)n(e,a)||i(a);return o}function ye(e,t,n,r){if("string"==typeof n){var i,a=e[t],o=a[n]||a[i=u(n)]||a[i.charAt(0).toUpperCase()+i.slice(1)];return o}}function ge(){this.id=jr++,this.subs=[]}function be(e){Rr=!1,e(),Rr=!0}function _e(e){if(this.value=e,this.dep=new ge,g(e,"__ob__",this),Tn(e)){var t=Fn?xe:we;t(e,Fr,Dr),this.observeArray(e)}else this.walk(e)}function xe(e,t){e.__proto__=t}function we(e,t,n){for(var r=0,i=n.length;i>r;r++){var a=n[r];g(e,a,t[a])}}function ke(e,t){if(e&&"object"==typeof e){var r;return n(e,"__ob__")&&e.__ob__ instanceof _e?r=e.__ob__:Rr&&(Tn(e)||y(e))&&Object.isExtensible(e)&&!e._isVue&&(r=new _e(e)),r&&t&&r.addVm(t),r}}function Se(e,t,n){var r=new ge,i=Object.getOwnPropertyDescriptor(e,t);if(!i||i.configurable!==!1){var a=i&&i.get,o=i&&i.set,s=ke(n);Object.defineProperty(e,t,{enumerable:!0,configurable:!0,get:function(){var t=a?a.call(e):n;if(ge.target&&(r.depend(),s&&s.dep.depend(),Tn(t)))for(var i,o=0,l=t.length;l>o;o++)i=t[o],i&&i.__ob__&&i.__ob__.dep.depend();return t},set:function(t){var i=a?a.call(e):n;t!==i&&(o?o.call(e,t):n=t,s=ke(t),r.notify())}})}}function Ce(e){e.prototype._init=function(e){e=e||{},this.$el=null,this.$parent=e.parent,this.$root=this.$parent?this.$parent.$root:this,this.$children=[],this.$refs={},this.$els={},this._watchers=[],this._directives=[],this._uid=Ur++,this._isVue=!0,this._events={},this._eventsCount={},this._isFragment=!1,this._fragment=this._fragmentStart=this._fragmentEnd=null,this._isCompiled=this._isDestroyed=this._isReady=this._isAttached=this._isBeingDestroyed=this._vForRemoving=!1,this._unlinkFn=null,this._context=e._context||this.$parent,this._scope=e._scope,this._frag=e._frag,this._frag&&this._frag.children.push(this),this.$parent&&this.$parent.$children.push(this),e=this.$options=me(this.constructor.options,e,this),this._updateRef(),this._data={},this._callHook("init"),this._initState(),this._initEvents(),this._callHook("created"),e.el&&this.$mount(e.el)}}function Ee(e){if(void 0===e)return"eof";var t=e.charCodeAt(0);switch(t){case 91:case 93:case 46:case 34:case 39:case 48:return e;case 95:case 36:return"ident";case 32:case 9:case 10:case 13:case 160:case 65279:case 8232:case 8233:return"ws"}return t>=97&&122>=t||t>=65&&90>=t?"ident":t>=49&&57>=t?"number":"else"}function Oe(e){var t=e.trim();return"0"===e.charAt(0)&&isNaN(e)?!1:r(t)?l(t):"*"+t}function $e(e){function t(){var t=e[c+1];return p===ii&&"'"===t||p===ai&&'"'===t?(c++,r="\\"+t,f[Kr](),!0):void 0}var n,r,i,a,o,s,l,u=[],c=-1,p=Yr,h=0,f=[];for(f[Qr]=function(){void 0!==i&&(u.push(i),i=void 0)},f[Kr]=function(){void 0===i?i=r:i+=r},f[Xr]=function(){f[Kr](),h++},f[Zr]=function(){if(h>0)h--,p=ri,f[Kr]();else{if(h=0,i=Oe(i),i===!1)return!1;f[Qr]()}};null!=p;)if(c++,n=e[c],"\\"!==n||!t()){if(a=Ee(n),l=li[p],o=l[a]||l["else"]||si,o===si)return;if(p=o[0],s=f[o[1]],s&&(r=o[2],r=void 0===r?n:r,s()===!1))return;if(p===oi)return u.raw=e,u}}function Ae(e){var t=Jr.get(e);return t||(t=$e(e),t&&Jr.put(e,t)),t}function Ne(e,t){return Be(t).get(e)}function Le(t,n,r){var i=t;if("string"==typeof n&&(n=$e(n)),!n||!m(t))return!1;for(var a,o,s=0,l=n.length;l>s;s++)a=t,o=n[s],"*"===o.charAt(0)&&(o=Be(o.slice(1)).get.call(i,i)),l-1>s?(t=t[o],m(t)||(t={},e(a,o,t))):Tn(t)?t.$set(o,r):o in t?t[o]=r:e(t,o,r);return!0}function Ie(){}function Pe(e,t){var n=wi.length;return wi[n]=t?e.replace(mi,"\\n"):e,'"'+n+'"'}function je(e){var t=e.charAt(0),n=e.slice(1);return hi.test(n)?e:(n=n.indexOf('"')>-1?n.replace(gi,Te):n,t+"scope."+n)}function Te(e,t){return wi[t]}function Fe(e){di.test(e),wi.length=0;var t=e.replace(yi,Pe).replace(vi,"");return t=(" "+t).replace(_i,je).replace(gi,Te),De(t)}function De(e){try{var t=qr.Function("scope","Math","return "+e);return function(e){return t.call(this,e,Math)}}catch(n){return Ie}}function Re(e){var t=Ae(e);return t?function(e,n){Le(e,t,n)}:void 0}function Be(e,t){e=e.trim();var n=ci.get(e);if(n)return t&&!n.set&&(n.set=Re(n.exp)),n;var r={exp:e};return r.get=Ue(e)&&e.indexOf("[")<0?De("scope."+e):Fe(e),t&&(r.set=Re(e)),ci.put(e,r),r}function Ue(e){return bi.test(e)&&!xi.test(e)&&"Math."!==e.slice(0,5)}function Me(){Si.length=0,Ci.length=0,Ei={},Oi={},$i=!1}function Ve(){for(var e=!0;e;)e=!1,He(Si),He(Ci),Si.length?e=!0:(Rn&&Er.devtools&&Rn.emit("flush"),Me())}function He(e){for(var t=0;t<e.length;t++){var n=e[t],r=n.id;Ei[r]=null,n.run()}e.length=0}function We(e){var t=e.id;if(null==Ei[t]){var n=e.user?Ci:Si;Ei[t]=n.length,n.push(e),$i||($i=!0,Yn(Ve))}}function ze(e,t,n,r){r&&v(this,r);var i="function"==typeof t;if(this.vm=e,e._watchers.push(this),this.expression=t,this.cb=n,this.id=++Ai,this.active=!0,this.dirty=this.lazy,this.deps=[],this.newDeps=[],this.depIds=new er,this.newDepIds=new er,this.prevError=null,i)this.getter=t,this.setter=void 0;else{var a=Be(t,this.twoWay);this.getter=a.get,this.setter=a.set}this.value=this.lazy?void 0:this.get(),this.queued=this.shallow=!1}function qe(e,t){var n=void 0,r=void 0;t||(t=Ni,t.clear());var i=Tn(e),a=m(e);if((i||a)&&Object.isExtensible(e)){if(e.__ob__){var o=e.__ob__.dep.id;if(t.has(o))return;t.add(o)}if(i)for(n=e.length;n--;)qe(e[n],t);else if(a)for(r=Object.keys(e),n=r.length;n--;)qe(e[r[n]],t)}}function Ge(e){return ne(e)&&se(e.content)}function Je(e,t){var n=t?e:e.trim(),r=Ii.get(n);if(r)return r;var i=document.createDocumentFragment(),a=e.match(Ti),o=Fi.test(e),s=Di.test(e);if(a||o||s){var l=a&&a[1],u=ji[l]||ji.efault,c=u[0],p=u[1],h=u[2],f=document.createElement("div");for(f.innerHTML=p+e+h;c--;)f=f.lastChild;for(var d;d=f.firstChild;)i.appendChild(d)}else i.appendChild(document.createTextNode(e));return t||ee(i),Ii.put(n,i),i}function Ke(e){if(Ge(e))return Je(e.innerHTML);if("SCRIPT"===e.tagName)return Je(e.textContent);for(var t,n=Qe(e),r=document.createDocumentFragment();t=n.firstChild;)r.appendChild(t);return ee(r),r}function Qe(e){if(!e.querySelectorAll)return e.cloneNode();var t,n,r,i=e.cloneNode(!0);if(Ri){var a=i;if(Ge(e)&&(e=e.content,a=i.content),n=e.querySelectorAll("template"),n.length)for(r=a.querySelectorAll("template"),t=r.length;t--;)r[t].parentNode.replaceChild(Qe(n[t]),r[t])}if(Bi)if("TEXTAREA"===e.tagName)i.value=e.value;else if(n=e.querySelectorAll("textarea"),n.length)for(r=i.querySelectorAll("textarea"),t=r.length;t--;)r[t].value=n[t].value;return i}function Xe(e,t,n){var r,i;return se(e)?(ee(e),t?Qe(e):e):("string"==typeof e?n||"#"!==e.charAt(0)?i=Je(e,n):(i=Pi.get(e),i||(r=document.getElementById(e.slice(1)),r&&(i=Ke(r),Pi.put(e,i)))):e.nodeType&&(i=Ke(e)),i&&t?Qe(i):i)}function Ze(e,t,n,r,i,a){this.children=[],this.childFrags=[],this.vm=t,this.scope=i,this.inserted=!1,this.parentFrag=a,a&&a.childFrags.push(this),this.unlink=e(t,n,r,i,this);var o=this.single=1===n.childNodes.length&&!n.childNodes[0].__v_anchor;o?(this.node=n.childNodes[0],this.before=Ye,this.remove=et):(this.node=re("fragment-start"),this.end=re("fragment-end"),this.frag=n,z(this.node,n),n.appendChild(this.end),this.before=tt,this.remove=nt),this.node.__v_frag=this}function Ye(e,t){this.inserted=!0;var n=t!==!1?j:V;n(this.node,e,this.vm),R(this.node)&&this.callHook(rt)}function et(){this.inserted=!1;var e=R(this.node),t=this;this.beforeRemove(),T(this.node,this.vm,function(){e&&t.callHook(it),t.destroy()})}function tt(e,t){this.inserted=!0;var n=this.vm,r=t!==!1?j:V;ae(this.node,this.end,function(t){r(t,e,n)}),R(this.node)&&this.callHook(rt)}function nt(){this.inserted=!1;var e=this,t=R(this.node);this.beforeRemove(),oe(this.node,this.end,this.vm,this.frag,function(){t&&e.callHook(it),e.destroy()})}function rt(e){!e._isAttached&&R(e.$el)&&e._callHook("attached")}function it(e){e._isAttached&&!R(e.$el)&&e._callHook("detached")}function at(e,t){this.vm=e;var n,r="string"==typeof t;r||ne(t)&&!t.hasAttribute("v-if")?n=Xe(t,!0):(n=document.createDocumentFragment(),n.appendChild(t)),this.template=n;var i,a=e.constructor.cid;if(a>0){var o=a+(r?t:le(t));i=Vi.get(o),i||(i=jt(n,e.$options,!0),Vi.put(o,i))}else i=jt(n,e.$options,!0);this.linker=i}function ot(e,t,n){var r=e.node.previousSibling;if(r){for(e=r.__v_frag;!(e&&e.forId===n&&e.inserted||r===t);){if(r=r.previousSibling,!r)return;e=r.__v_frag}return e}}function st(e){var t=e.node;if(e.end)for(;!t.__vue__&&t!==e.end&&t.nextSibling;)t=t.nextSibling;return t.__vue__}function lt(e){for(var t=-1,n=new Array(Math.floor(e));++t<e;)n[t]=t;return n}function ut(e,t,n,r){return r?"$index"===r?e:r.charAt(0).match(/\w/)?Ne(n,r):n[r]:t||n}function ct(e,t,n){for(var r,i,a,o=t?[]:null,s=0,l=e.options.length;l>s;s++)if(r=e.options[s],a=n?r.hasAttribute("selected"):r.selected){if(i=r.hasOwnProperty("_value")?r._value:r.value,!t)return i;o.push(i)}return o}function pt(e,t){for(var n=e.length;n--;)if(w(e[n],t))return n;return-1}function ht(e,t){var n=t.map(function(e){var t=e.charCodeAt(0);return t>47&&58>t?parseInt(e,10):1===e.length&&(t=e.toUpperCase().charCodeAt(0),t>64&&91>t)?t:ua[e]});return n=[].concat.apply([],n),function(t){return n.indexOf(t.keyCode)>-1?e.call(this,t):void 0}}function ft(e){return function(t){return t.stopPropagation(),e.call(this,t)}}function dt(e){return function(t){return t.preventDefault(),e.call(this,t)}}function vt(e){return function(t){return t.target===t.currentTarget?e.call(this,t):void 0}}function mt(e){if(da[e])return da[e];var t=yt(e);return da[e]=da[t]=t,t}function yt(e){e=p(e);var t=u(e),n=t.charAt(0).toUpperCase()+t.slice(1);va||(va=document.createElement("div"));var r,i=pa.length;if("filter"!==t&&t in va.style)return{kebab:e,camel:t};for(;i--;)if(r=ha[i]+n,r in va.style)return{kebab:pa[i]+e,camel:r}}function gt(e){var t=[];if(Tn(e))for(var n=0,r=e.length;r>n;n++){var i=e[n];if(i)if("string"==typeof i)t.push(i);else for(var a in i)i[a]&&t.push(a)}else if(m(e))for(var o in e)e[o]&&t.push(o);return t}function bt(e,t,n){if(t=t.trim(),-1===t.indexOf(" "))return void n(e,t);for(var r=t.split(/\s+/),i=0,a=r.length;a>i;i++)n(e,r[i])}function _t(e,t,n){function r(){++a>=i?n():e[a].call(t,r)}var i=e.length,a=0;e[0].call(t,r)}function xt(e,t,n){for(var i,a,o,s,l,c,h,f=[],d=Object.keys(t),v=d.length;v--;)a=d[v],i=t[a]||La,l=u(a),Ia.test(l)&&(h={name:a,path:l,options:i,mode:Na.ONE_WAY,raw:null},o=p(a),null===(s=U(e,o))&&(null!==(s=U(e,o+".sync"))?h.mode=Na.TWO_WAY:null!==(s=U(e,o+".once"))&&(h.mode=Na.ONE_TIME)),null!==s?(h.raw=s,c=E(s),s=c.expression,h.filters=c.filters,r(s)&&!c.filters?h.optimizedLiteral=!0:h.dynamic=!0,h.parentPath=s):null!==(s=B(e,o))&&(h.raw=s),f.push(h));return wt(f)}function wt(e){return function(t,r){t._props={};for(var i,a,u,c,h,f=t.$options.propsData,d=e.length;d--;)if(i=e[d],h=i.raw,a=i.path,u=i.options,t._props[a]=i,f&&n(f,a)&&St(t,i,f[a]),null===h)St(t,i,void 0);else if(i.dynamic)i.mode===Na.ONE_TIME?(c=(r||t._context||t).$get(i.parentPath),St(t,i,c)):t._context?t._bindDir({name:"prop",def:ja,prop:i},null,null,r):St(t,i,t.$get(i.parentPath));else if(i.optimizedLiteral){var v=l(h);c=v===h?s(o(h)):v,St(t,i,c)}else c=u.type!==Boolean||""!==h&&h!==p(i.name)?h:!0,St(t,i,c)}}function kt(e,t,n,r){var i=t.dynamic&&Ue(t.parentPath),a=n;void 0===a&&(a=Et(e,t)),a=$t(t,a,e);var o=a!==n;Ot(t,a,e)||(a=void 0),i&&!o?be(function(){r(a)}):r(a)}function St(e,t,n){kt(e,t,n,function(n){Se(e,t.path,n)})}function Ct(e,t,n){kt(e,t,n,function(n){e[t.path]=n})}function Et(e,t){var r=t.options;if(!n(r,"default"))return r.type===Boolean?!1:void 0;var i=r["default"];return m(i),"function"==typeof i&&r.type!==Function?i.call(e):i}function Ot(e,t,n){if(!e.options.required&&(null===e.raw||null==t))return!0;var r=e.options,i=r.type,a=!i,o=[];if(i){Tn(i)||(i=[i]);for(var s=0;s<i.length&&!a;s++){var l=At(t,i[s]);o.push(l.expectedType),a=l.valid}}if(!a)return!1;var u=r.validator;return!u||u(t)}function $t(e,t,n){var r=e.options.coerce;return r&&"function"==typeof r?r(t):t}function At(e,t){var n,r;return t===String?(r="string",n=typeof e===r):t===Number?(r="number",n=typeof e===r):t===Boolean?(r="boolean",n=typeof e===r):t===Function?(r="function",n=typeof e===r):t===Object?(r="object",n=y(e)):t===Array?(r="array",n=Tn(e)):n=e instanceof t,{valid:n,expectedType:r}}function Nt(e){Ta.push(e),Fa||(Fa=!0,Yn(Lt))}function Lt(){for(var e=document.documentElement.offsetHeight,t=0;t<Ta.length;t++)Ta[t]();return Ta=[],Fa=!1,e}function It(e,t,n,r){this.id=t,this.el=e,this.enterClass=n&&n.enterClass||t+"-enter",this.leaveClass=n&&n.leaveClass||t+"-leave",this.hooks=n,this.vm=r,this.pendingCssEvent=this.pendingCssCb=this.cancel=this.pendingJsCb=this.op=this.cb=null,this.justEntered=!1,this.entered=this.left=!1,this.typeCache={},this.type=n&&n.type;var i=this;["enterNextTick","enterDone","leaveNextTick","leaveDone"].forEach(function(e){i[e]=f(i[e],i)})}function Pt(e){if(/svg$/.test(e.namespaceURI)){var t=e.getBoundingClientRect();return!(t.width||t.height)}return!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)}function jt(e,t,n){var r=n||!t._asComponent?Mt(e,t):null,i=r&&r.terminal||an(e)||!e.hasChildNodes()?null:Gt(e.childNodes,t);return function(e,t,n,a,o){var s=d(t.childNodes),l=Tt(function(){r&&r(e,t,n,a,o),i&&i(e,s,n,a,o)},e);return Dt(e,l)}}function Tt(e,t){t._directives=[];var n=t._directives.length;e();var r=t._directives.slice(n);r.sort(Ft);for(var i=0,a=r.length;a>i;i++)r[i]._bind();return r}function Ft(e,t){return e=e.descriptor.def.priority||Xa,t=t.descriptor.def.priority||Xa,e>t?-1:e===t?0:1}function Dt(e,t,n,r){function i(i){Rt(e,t,i),n&&r&&Rt(n,r)}return i.dirs=t,i}function Rt(e,t,n){for(var r=t.length;r--;)t[r]._teardown()}function Bt(e,t,n,r){var i=xt(t,n,e),a=Tt(function(){i(e,r)},e);return Dt(e,a)}function Ut(e,t,n){var r,i,a=t._containerAttrs,o=t._replacerAttrs;return 11!==e.nodeType&&(t._asComponent?(a&&n&&(r=en(a,n)),o&&(i=en(o,t))):i=en(e.attributes,t)),t._containerAttrs=t._replacerAttrs=null,function(e,t,n){var a,o=e._context;o&&r&&(a=Tt(function(){r(o,t,null,n)},o));var s=Tt(function(){i&&i(e,t)},e);return Dt(e,s,o,a)}}function Mt(e,t){var n=e.nodeType;return 1!==n||an(e)?3===n&&e.data.trim()?Ht(e,t):null:Vt(e,t)}function Vt(e,t){if("TEXTAREA"===e.tagName){var n=A(e.value);n&&(e.setAttribute(":value",N(n)),e.value="")}var r,i=e.hasAttributes(),a=i&&d(e.attributes);return i&&(r=Xt(e,a,t)),r||(r=Kt(e,t)),r||(r=Qt(e,t)),!r&&i&&(r=en(a,t)),r}function Ht(e,t){if(e._skip)return Wt;var n=A(e.wholeText);if(!n)return null;for(var r=e.nextSibling;r&&3===r.nodeType;)r._skip=!0,r=r.nextSibling;for(var i,a,o=document.createDocumentFragment(),s=0,l=n.length;l>s;s++)a=n[s],i=a.tag?zt(a,t):document.createTextNode(a.value),o.appendChild(i);return qt(n,o,t)}function Wt(e,t){W(t)}function zt(e,t){function n(t){if(!e.descriptor){var n=E(e.value);e.descriptor={name:t,def:Oa[t],expression:n.expression,filters:n.filters}}}var r;return e.oneTime?r=document.createTextNode(e.value):e.html?(r=document.createComment("v-html"),n("html")):(r=document.createTextNode(" "),n("text")),r}function qt(e,t){return function(n,r,i,o){for(var s,l,u,c=t.cloneNode(!0),p=d(c.childNodes),h=0,f=e.length;f>h;h++)s=e[h],l=s.value,s.tag&&(u=p[h],s.oneTime?(l=(o||n).$eval(l),s.html?q(u,Xe(l,!0)):u.data=a(l)):n._bindDir(s.descriptor,u,i,o));q(r,c)}}function Gt(e,t){for(var n,r,i,a=[],o=0,s=e.length;s>o;o++)i=e[o],n=Mt(i,t),r=n&&n.terminal||"SCRIPT"===i.tagName||!i.hasChildNodes()?null:Gt(i.childNodes,t),a.push(n,r);return a.length?Jt(a):null}function Jt(e){return function(t,n,r,i,a){for(var o,s,l,u=0,c=0,p=e.length;p>u;c++){o=n[c],s=e[u++],l=e[u++];var h=d(o.childNodes);s&&s(t,o,r,i,a),l&&l(t,h,r,i,a)}}}function Kt(e,t){var n=e.tagName.toLowerCase();if(!Nr.test(n)){var r=ye(t,"elementDirectives",n);return r?Yt(e,n,"",t,r):void 0}}function Qt(e,t){var n=ue(e,t);if(n){var r=ie(e),i={name:"component",ref:r,expression:n.id,def:za.component,modifiers:{literal:!n.dynamic}},a=function(e,t,n,a,o){r&&Se((a||e).$refs,r,null),e._bindDir(i,t,n,a,o)};return a.terminal=!0,a}}function Xt(e,t,n){if(null!==B(e,"v-pre"))return Zt;if(e.hasAttribute("v-else")){var r=e.previousElementSibling;if(r&&r.hasAttribute("v-if"))return Zt}for(var i,a,o,s,l,u,c,p,h,f,d=0,v=t.length;v>d;d++)i=t[d],a=i.name.replace(Ka,""),(l=a.match(Ja))&&(h=ye(n,"directives",l[1]),h&&h.terminal&&(!f||(h.priority||Za)>f.priority)&&(f=h,c=i.name,s=tn(i.name),o=i.value,u=l[1],p=l[2]));return f?Yt(e,u,o,n,f,c,p,s):void 0}function Zt(){}function Yt(e,t,n,r,i,a,o,s){var l=E(n),u={name:t,arg:o,expression:l.expression,filters:l.filters,raw:n,attr:a,modifiers:s,def:i};"for"!==t&&"router-view"!==t||(u.ref=ie(e));var c=function(e,t,n,r,i){u.ref&&Se((r||e).$refs,u.ref,null),e._bindDir(u,t,n,r,i)};return c.terminal=!0,c}function en(e,t){function n(e,t,n){var r=n&&rn(n),i=!r&&E(a);v.push({name:e,attr:o,raw:s,def:t,arg:u,modifiers:c,expression:i&&i.expression,filters:i&&i.filters,interp:n,hasOneTime:r})}for(var r,i,a,o,s,l,u,c,p,h,f,d=e.length,v=[];d--;)if(r=e[d],i=o=r.name,a=s=r.value,h=A(a),u=null,c=tn(i),i=i.replace(Ka,""),h)a=N(h),u=i,n("bind",Oa.bind,h);else if(Qa.test(i))c.literal=!qa.test(i),n("transition",za.transition);else if(Ga.test(i))u=i.replace(Ga,""),n("on",Oa.on);else if(qa.test(i))l=i.replace(qa,""),"style"===l||"class"===l?n(l,za[l]):(u=l,n("bind",Oa.bind));else if(f=i.match(Ja)){if(l=f[1],u=f[2],"else"===l)continue;p=ye(t,"directives",l,!0),p&&n(l,p)}return v.length?nn(v):void 0}function tn(e){var t=Object.create(null),n=e.match(Ka);if(n)for(var r=n.length;r--;)t[n[r].slice(1)]=!0;return t}function nn(e){return function(t,n,r,i,a){for(var o=e.length;o--;)t._bindDir(e[o],n,r,i,a)}}function rn(e){for(var t=e.length;t--;)if(e[t].oneTime)return!0}function an(e){return"SCRIPT"===e.tagName&&(!e.hasAttribute("type")||"text/javascript"===e.getAttribute("type"))}function on(e,t){return t&&(t._containerAttrs=ln(e)),ne(e)&&(e=Xe(e)),t&&(t._asComponent&&!t.template&&(t.template="<slot></slot>"),t.template&&(t._content=Y(e),e=sn(e,t))),se(e)&&(z(re("v-start",!0),e),e.appendChild(re("v-end",!0))),e}function sn(e,t){var n=t.template,r=Xe(n,!0);if(r){var i=r.firstChild,a=i.tagName&&i.tagName.toLowerCase();return t.replace?(e===document.body,r.childNodes.length>1||1!==i.nodeType||"component"===a||ye(t,"components",a)||M(i,"is")||ye(t,"elementDirectives",a)||i.hasAttribute("v-for")||i.hasAttribute("v-if")?r:(t._replacerAttrs=ln(i),un(e,i),i)):(e.appendChild(r),e)}}function ln(e){return 1===e.nodeType&&e.hasAttributes()?d(e.attributes):void 0}function un(e,t){for(var n,r,i=e.attributes,a=i.length;a--;)n=i[a].name,r=i[a].value,t.hasAttribute(n)||Ya.test(n)?"class"===n&&!A(r)&&(r=r.trim())&&r.split(/\s+/).forEach(function(e){X(t,e)}):t.setAttribute(n,r)}function cn(e,t){if(t){for(var n,r,i=e._slotContents=Object.create(null),a=0,o=t.children.length;o>a;a++)n=t.children[a],(r=n.getAttribute("slot"))&&(i[r]||(i[r]=[])).push(n);for(r in i)i[r]=pn(i[r],t);if(t.hasChildNodes()){var s=t.childNodes;if(1===s.length&&3===s[0].nodeType&&!s[0].data.trim())return;i["default"]=pn(t.childNodes,t)}}}function pn(e,t){var n=document.createDocumentFragment();e=d(e);for(var r=0,i=e.length;i>r;r++){var a=e[r];!ne(a)||a.hasAttribute("v-if")||a.hasAttribute("v-for")||(t.removeChild(a),a=Xe(a,!0)),n.appendChild(a)}return n}function hn(e){function t(){}function r(e,t){var n=new ze(t,e,null,{lazy:!0});return function(){return n.dirty&&n.evaluate(),ge.target&&n.depend(),n.value}}Object.defineProperty(e.prototype,"$data",{get:function(){return this._data},set:function(e){e!==this._data&&this._setData(e)}}),e.prototype._initState=function(){this._initProps(),this._initMeta(),this._initMethods(),this._initData(),this._initComputed()},e.prototype._initProps=function(){var e=this.$options,t=e.el,n=e.props;t=e.el=D(t),this._propsUnlinkFn=t&&1===t.nodeType&&n?Bt(this,t,n,this._scope):null},e.prototype._initData=function(){var e=this.$options.data,t=this._data=e?e():{};y(t)||(t={});var r,i,a=this._props,o=Object.keys(t);for(r=o.length;r--;)i=o[r],a&&n(a,i)||this._proxy(i);ke(t,this)},e.prototype._setData=function(e){e=e||{};var t=this._data;this._data=e;var r,i,a;for(r=Object.keys(t),a=r.length;a--;)i=r[a],i in e||this._unproxy(i);for(r=Object.keys(e),a=r.length;a--;)i=r[a],n(this,i)||this._proxy(i);t.__ob__.removeVm(this),ke(e,this),this._digest()},e.prototype._proxy=function(e){if(!i(e)){var t=this;Object.defineProperty(t,e,{configurable:!0,enumerable:!0,get:function(){return t._data[e]},set:function(n){t._data[e]=n}})}},e.prototype._unproxy=function(e){i(e)||delete this[e]},e.prototype._digest=function(){for(var e=0,t=this._watchers.length;t>e;e++)this._watchers[e].update(!0)},e.prototype._initComputed=function(){var e=this.$options.computed;if(e)for(var n in e){var i=e[n],a={enumerable:!0,configurable:!0};"function"==typeof i?(a.get=r(i,this),a.set=t):(a.get=i.get?i.cache!==!1?r(i.get,this):f(i.get,this):t,a.set=i.set?f(i.set,this):t),Object.defineProperty(this,n,a)}},e.prototype._initMethods=function(){var e=this.$options.methods;if(e)for(var t in e)this[t]=f(e[t],this)},e.prototype._initMeta=function(){var e=this.$options._meta;if(e)for(var t in e)Se(this,t,e[t])}}function fn(e){function t(e,t){for(var n,r,i,a=t.attributes,o=0,s=a.length;s>o;o++)n=a[o].name,to.test(n)&&(n=n.replace(to,""),r=a[o].value,Ue(r)&&(r+=".apply(this, $arguments)"),i=(e._scope||e._context).$eval(r,!0),i._fromParent=!0,e.$on(n.replace(to),i))}function n(e,t,n){if(n){var i,a,o,s;for(a in n)if(i=n[a],Tn(i))for(o=0,s=i.length;s>o;o++)r(e,t,a,i[o]);else r(e,t,a,i)}}function r(e,t,n,i,a){var o=typeof i;if("function"===o)e[t](n,i,a);else if("string"===o){var s=e.$options.methods,l=s&&s[i];l&&e[t](n,l,a)}else i&&"object"===o&&r(e,t,n,i.handler,i)}function i(){this._isAttached||(this._isAttached=!0,this.$children.forEach(a))}function a(e){!e._isAttached&&R(e.$el)&&e._callHook("attached")}function o(){this._isAttached&&(this._isAttached=!1,this.$children.forEach(s))}function s(e){e._isAttached&&!R(e.$el)&&e._callHook("detached")}e.prototype._initEvents=function(){var e=this.$options;e._asComponent&&t(this,e.el),n(this,"$on",e.events),n(this,"$watch",e.watch)},e.prototype._initDOMHooks=function(){this.$on("hook:attached",i),this.$on("hook:detached",o)},e.prototype._callHook=function(e){this.$emit("pre-hook:"+e);var t=this.$options[e];if(t)for(var n=0,r=t.length;r>n;n++)t[n].call(this);this.$emit("hook:"+e)}}function dn(){}function vn(e,t,n,r,i,a){this.vm=t,this.el=n,this.descriptor=e,this.name=e.name,this.expression=e.expression,this.arg=e.arg,this.modifiers=e.modifiers,this.filters=e.filters,this.literal=this.modifiers&&this.modifiers.literal,this._locked=!1,this._bound=!1,this._listeners=null,this._host=r,this._scope=i,this._frag=a}function mn(e){e.prototype._updateRef=function(e){var t=this.$options._ref;if(t){var n=(this._scope||this._context).$refs;e?n[t]===this&&(n[t]=null):n[t]=this}},e.prototype._compile=function(e){var t=this.$options,n=e;if(e=on(e,t),this._initElement(e),1!==e.nodeType||null===B(e,"v-pre")){var r=this._context&&this._context.$options,i=Ut(e,t,r);cn(this,t._content);var a,o=this.constructor;t._linkerCachable&&(a=o.linker,a||(a=o.linker=jt(e,t)));var s=i(this,e,this._scope),l=a?a(this,e):jt(e,t)(this,e);this._unlinkFn=function(){s(),l(!0)},t.replace&&q(n,e),this._isCompiled=!0,this._callHook("compiled")}},e.prototype._initElement=function(e){se(e)?(this._isFragment=!0,this.$el=this._fragmentStart=e.firstChild,this._fragmentEnd=e.lastChild,3===this._fragmentStart.nodeType&&(this._fragmentStart.data=this._fragmentEnd.data=""),this._fragment=e):this.$el=e,this.$el.__vue__=this,this._callHook("beforeCompile")},e.prototype._bindDir=function(e,t,n,r,i){this._directives.push(new vn(e,this,t,n,r,i))},e.prototype._destroy=function(e,t){if(this._isBeingDestroyed)return void(t||this._cleanup());var n,r,i=this,a=function(){!n||r||t||i._cleanup();
-};e&&this.$el&&(r=!0,this.$remove(function(){r=!1,a()})),this._callHook("beforeDestroy"),this._isBeingDestroyed=!0;var o,s=this.$parent;for(s&&!s._isBeingDestroyed&&(s.$children.$remove(this),this._updateRef(!0)),o=this.$children.length;o--;)this.$children[o].$destroy();for(this._propsUnlinkFn&&this._propsUnlinkFn(),this._unlinkFn&&this._unlinkFn(),o=this._watchers.length;o--;)this._watchers[o].teardown();this.$el&&(this.$el.__vue__=null),n=!0,a()},e.prototype._cleanup=function(){this._isDestroyed||(this._frag&&this._frag.children.$remove(this),this._data&&this._data.__ob__&&this._data.__ob__.removeVm(this),this.$el=this.$parent=this.$root=this.$children=this._watchers=this._context=this._scope=this._directives=null,this._isDestroyed=!0,this._callHook("destroyed"),this.$off())}}function yn(e){e.prototype._applyFilters=function(e,t,n,r){var i,a,o,s,l,u,c,p,h;for(u=0,c=n.length;c>u;u++)if(i=n[r?c-u-1:u],a=ye(this.$options,"filters",i.name,!0),a&&(a=r?a.write:a.read||a,"function"==typeof a)){if(o=r?[e,t]:[e],l=r?2:1,i.args)for(p=0,h=i.args.length;h>p;p++)s=i.args[p],o[p+l]=s.dynamic?this.$get(s.value):s.value;e=a.apply(this,o)}return e},e.prototype._resolveComponent=function(t,n){var r;if(r="function"==typeof t?t:ye(this.$options,"components",t,!0))if(r.options)n(r);else if(r.resolved)n(r.resolved);else if(r.requested)r.pendingCallbacks.push(n);else{r.requested=!0;var i=r.pendingCallbacks=[n];r.call(this,function(t){y(t)&&(t=e.extend(t)),r.resolved=t;for(var n=0,a=i.length;a>n;n++)i[n](t)},function(e){})}}}function gn(e){function n(e){return JSON.parse(JSON.stringify(e))}e.prototype.$get=function(e,t){var n=Be(e);if(n){if(t){var r=this;return function(){r.$arguments=d(arguments);var e=n.get.call(r,r);return r.$arguments=null,e}}try{return n.get.call(this,this)}catch(i){}}},e.prototype.$set=function(e,t){var n=Be(e,!0);n&&n.set&&n.set.call(this,this,t)},e.prototype.$delete=function(e){t(this._data,e)},e.prototype.$watch=function(e,t,n){var r,i=this;"string"==typeof e&&(r=E(e),e=r.expression);var a=new ze(i,e,t,{deep:n&&n.deep,sync:n&&n.sync,filters:r&&r.filters,user:!n||n.user!==!1});return n&&n.immediate&&t.call(i,a.value),function(){a.teardown()}},e.prototype.$eval=function(e,t){if(no.test(e)){var n=E(e),r=this.$get(n.expression,t);return n.filters?this._applyFilters(r,null,n.filters):r}return this.$get(e,t)},e.prototype.$interpolate=function(e){var t=A(e),n=this;return t?1===t.length?n.$eval(t[0].value)+"":t.map(function(e){return e.tag?n.$eval(e.value):e.value}).join(""):e},e.prototype.$log=function(e){var t=e?Ne(this._data,e):this._data;if(t&&(t=n(t)),!e){var r;for(r in this.$options.computed)t[r]=n(this[r]);if(this._props)for(r in this._props)t[r]=n(this[r])}console.log(t)}}function bn(e){function t(e,t,r,i,a,o){t=n(t);var s=!R(t),l=i===!1||s?a:o,u=!s&&!e._isAttached&&!R(e.$el);return e._isFragment?(ae(e._fragmentStart,e._fragmentEnd,function(n){l(n,t,e)}),r&&r()):l(e.$el,t,e,r),u&&e._callHook("attached"),e}function n(e){return"string"==typeof e?document.querySelector(e):e}function r(e,t,n,r){t.appendChild(e),r&&r()}function i(e,t,n,r){V(e,t),r&&r()}function a(e,t,n){W(e),n&&n()}e.prototype.$nextTick=function(e){Yn(e,this)},e.prototype.$appendTo=function(e,n,i){return t(this,e,n,i,r,P)},e.prototype.$prependTo=function(e,t,r){return e=n(e),e.hasChildNodes()?this.$before(e.firstChild,t,r):this.$appendTo(e,t,r),this},e.prototype.$before=function(e,n,r){return t(this,e,n,r,i,j)},e.prototype.$after=function(e,t,r){return e=n(e),e.nextSibling?this.$before(e.nextSibling,t,r):this.$appendTo(e.parentNode,t,r),this},e.prototype.$remove=function(e,t){if(!this.$el.parentNode)return e&&e();var n=this._isAttached&&R(this.$el);n||(t=!1);var r=this,i=function(){n&&r._callHook("detached"),e&&e()};if(this._isFragment)oe(this._fragmentStart,this._fragmentEnd,this,this._fragment,i);else{var o=t===!1?a:T;o(this.$el,this,i)}return this}}function _n(e){function t(e,t,r){var i=e.$parent;if(i&&r&&!n.test(t))for(;i;)i._eventsCount[t]=(i._eventsCount[t]||0)+r,i=i.$parent}e.prototype.$on=function(e,n){return(this._events[e]||(this._events[e]=[])).push(n),t(this,e,1),this},e.prototype.$once=function(e,t){function n(){r.$off(e,n),t.apply(this,arguments)}var r=this;return n.fn=t,this.$on(e,n),this},e.prototype.$off=function(e,n){var r;if(!arguments.length){if(this.$parent)for(e in this._events)r=this._events[e],r&&t(this,e,-r.length);return this._events={},this}if(r=this._events[e],!r)return this;if(1===arguments.length)return t(this,e,-r.length),this._events[e]=null,this;for(var i,a=r.length;a--;)if(i=r[a],i===n||i.fn===n){t(this,e,-1),r.splice(a,1);break}return this},e.prototype.$emit=function(e){var t="string"==typeof e;e=t?e:e.name;var n=this._events[e],r=t||!n;if(n){n=n.length>1?d(n):n;var i=t&&n.some(function(e){return e._fromParent});i&&(r=!1);for(var a=d(arguments,1),o=0,s=n.length;s>o;o++){var l=n[o],u=l.apply(this,a);u!==!0||i&&!l._fromParent||(r=!0)}}return r},e.prototype.$broadcast=function(e){var t="string"==typeof e;if(e=t?e:e.name,this._eventsCount[e]){var n=this.$children,r=d(arguments);t&&(r[0]={name:e,source:this});for(var i=0,a=n.length;a>i;i++){var o=n[i],s=o.$emit.apply(o,r);s&&o.$broadcast.apply(o,r)}return this}},e.prototype.$dispatch=function(e){var t=this.$emit.apply(this,arguments);if(t){var n=this.$parent,r=d(arguments);for(r[0]={name:e,source:this};n;)t=n.$emit.apply(n,r),n=t?n.$parent:null;return this}};var n=/^hook:/}function xn(e){function t(){this._isAttached=!0,this._isReady=!0,this._callHook("ready")}e.prototype.$mount=function(e){return this._isCompiled?void 0:(e=D(e),e||(e=document.createElement("div")),this._compile(e),this._initDOMHooks(),R(this.$el)?(this._callHook("attached"),t.call(this)):this.$once("hook:attached",t),this)},e.prototype.$destroy=function(e,t){this._destroy(e,t)},e.prototype.$compile=function(e,t,n,r){return jt(e,this.$options,!0)(this,e,t,n,r)}}function wn(e){this._init(e)}function kn(e,t,n){return n=n?parseInt(n,10):0,t=o(t),"number"==typeof t?e.slice(n,n+t):e}function Sn(e,t,n){if(e=oo(e),null==t)return e;if("function"==typeof t)return e.filter(t);t=(""+t).toLowerCase();for(var r,i,a,o,s="in"===n?3:2,l=Array.prototype.concat.apply([],d(arguments,s)),u=[],c=0,p=e.length;p>c;c++)if(r=e[c],a=r&&r.$value||r,o=l.length){for(;o--;)if(i=l[o],"$key"===i&&En(r.$key,t)||En(Ne(a,i),t)){u.push(r);break}}else En(r,t)&&u.push(r);return u}function Cn(e){function t(e,t,n){var i=r[n];return i&&("$key"!==i&&(m(e)&&"$value"in e&&(e=e.$value),m(t)&&"$value"in t&&(t=t.$value)),e=m(e)?Ne(e,i):e,t=m(t)?Ne(t,i):t),e===t?0:e>t?a:-a}var n=null,r=void 0;e=oo(e);var i=d(arguments,1),a=i[i.length-1];"number"==typeof a?(a=0>a?-1:1,i=i.length>1?i.slice(0,-1):i):a=1;var o=i[0];return o?("function"==typeof o?n=function(e,t){return o(e,t)*a}:(r=Array.prototype.concat.apply([],i),n=function(e,i,a){return a=a||0,a>=r.length-1?t(e,i,a):t(e,i,a)||n(e,i,a+1)}),e.slice().sort(n)):e}function En(e,t){var n;if(y(e)){var r=Object.keys(e);for(n=r.length;n--;)if(En(e[r[n]],t))return!0}else if(Tn(e)){for(n=e.length;n--;)if(En(e[n],t))return!0}else if(null!=e)return e.toString().toLowerCase().indexOf(t)>-1}function On(n){n.options={directives:Oa,elementDirectives:ao,filters:lo,transitions:{},components:{},partials:{},replace:!0},n.util=Br,n.config=Er,n.set=e,n["delete"]=t,n.nextTick=Yn,n.compiler=eo,n.FragmentFactory=at,n.internalDirectives=za,n.parsers={path:ui,text:kr,template:Ui,directive:yr,expression:ki},n.cid=0;var r=1;n.extend=function(e){e=e||{};var t=this,i=0===t.cid;if(i&&e._Ctor)return e._Ctor;var a=e.name||t.options.name,o=function(e){n.call(this,e)};return o.prototype=Object.create(t.prototype),o.prototype.constructor=o,o.cid=r++,o.options=me(t.options,e),o["super"]=t,o.extend=t.extend,Er._assetTypes.forEach(function(e){o[e]=t[e]}),a&&(o.options.components[a]=o),i&&(e._Ctor=o),o},n.use=function(e){if(!e.installed){var t=d(arguments,1);return t.unshift(this),"function"==typeof e.install?e.install.apply(e,t):e.apply(null,t),e.installed=!0,this}},n.mixin=function(e){n.options=me(n.options,e)},Er._assetTypes.forEach(function(e){n[e]=function(t,r){return r?("component"===e&&y(r)&&(r.name||(r.name=t),r=n.extend(r)),this.options[e+"s"][t]=r,r):this.options[e+"s"][t]}}),v(n.transition,$r)}var $n=Object.prototype.hasOwnProperty,An=/^\s?(true|false|-?[\d\.]+|'[^']*'|"[^"]*")\s?$/,Nn=/-(\w)/g,Ln=/([a-z\d])([A-Z])/g,In=/(?:^|[-_\/])(\w)/g,Pn=Object.prototype.toString,jn="[object Object]",Tn=Array.isArray,Fn="__proto__"in{},Dn="undefined"!=typeof window&&"[object Object]"!==Object.prototype.toString.call(window),Rn=Dn&&window.__VUE_DEVTOOLS_GLOBAL_HOOK__,Bn=Dn&&window.navigator.userAgent.toLowerCase(),Un=Bn&&Bn.indexOf("trident")>0,Mn=Bn&&Bn.indexOf("msie 9.0")>0,Vn=Bn&&Bn.indexOf("android")>0,Hn=Bn&&/(iphone|ipad|ipod|ios)/i.test(Bn),Wn=Hn&&Bn.match(/os ([\d_]+)/),zn=Wn&&Wn[1].split("_"),qn=zn&&Number(zn[0])>=9&&Number(zn[1])>=3&&!window.indexedDB,Gn=void 0,Jn=void 0,Kn=void 0,Qn=void 0;if(Dn&&!Mn){var Xn=void 0===window.ontransitionend&&void 0!==window.onwebkittransitionend,Zn=void 0===window.onanimationend&&void 0!==window.onwebkitanimationend;Gn=Xn?"WebkitTransition":"transition",Jn=Xn?"webkitTransitionEnd":"transitionend",Kn=Zn?"WebkitAnimation":"animation",Qn=Zn?"webkitAnimationEnd":"animationend"}var Yn=function(){function e(){r=!1;var e=n.slice(0);n=[];for(var t=0;t<e.length;t++)e[t]()}var t,n=[],r=!1;if("undefined"==typeof MutationObserver||qn){var i=Dn?window:"undefined"!=typeof global?global:{};t=i.setImmediate||setTimeout}else{var a=1,o=new MutationObserver(e),s=document.createTextNode(a);o.observe(s,{characterData:!0}),t=function(){a=(a+1)%2,s.data=a}}return function(i,a){var o=a?function(){i.call(a)}:i;n.push(o),r||(r=!0,t(e,0))}}(),er=void 0;"undefined"!=typeof Set&&Set.toString().match(/native code/)?er=Set:(er=function(){this.set=Object.create(null)},er.prototype.has=function(e){return void 0!==this.set[e]},er.prototype.add=function(e){this.set[e]=1},er.prototype.clear=function(){this.set=Object.create(null)});var tr=k.prototype;tr.put=function(e,t){var n,r=this.get(e,!0);return r||(this.size===this.limit&&(n=this.shift()),r={key:e},this._keymap[e]=r,this.tail?(this.tail.newer=r,r.older=this.tail):this.head=r,this.tail=r,this.size++),r.value=t,n},tr.shift=function(){var e=this.head;return e&&(this.head=this.head.newer,this.head.older=void 0,e.newer=e.older=void 0,this._keymap[e.key]=void 0,this.size--),e},tr.get=function(e,t){var n=this._keymap[e];if(void 0!==n)return n===this.tail?t?n:n.value:(n.newer&&(n===this.head&&(this.head=n.newer),n.newer.older=n.older),n.older&&(n.older.newer=n.newer),n.newer=void 0,n.older=this.tail,this.tail&&(this.tail.newer=n),this.tail=n,t?n:n.value)};var nr,rr,ir,ar,or,sr,lr,ur,cr,pr,hr,fr,dr=new k(1e3),vr=/[^\s'"]+|'[^']*'|"[^"]*"/g,mr=/^in$|^-?\d+/,yr=Object.freeze({parseDirective:E}),gr=/[-.*+?^${}()|[\]\/\\]/g,br=void 0,_r=void 0,xr=void 0,wr=/[^|]\|[^|]/,kr=Object.freeze({compileRegex:$,parseText:A,tokensToExp:N}),Sr=["{{","}}"],Cr=["{{{","}}}"],Er=Object.defineProperties({debug:!1,silent:!1,async:!0,warnExpressionErrors:!0,devtools:!1,_delimitersChanged:!0,_assetTypes:["component","directive","elementDirective","filter","transition","partial"],_propBindingModes:{ONE_WAY:0,TWO_WAY:1,ONE_TIME:2},_maxUpdateCount:100},{delimiters:{get:function(){return Sr},set:function(e){Sr=e,$()},configurable:!0,enumerable:!0},unsafeDelimiters:{get:function(){return Cr},set:function(e){Cr=e,$()},configurable:!0,enumerable:!0}}),Or=void 0,$r=Object.freeze({appendWithTransition:P,beforeWithTransition:j,removeWithTransition:T,applyTransition:F}),Ar=/^v-ref:/,Nr=/^(div|p|span|img|a|b|i|br|ul|ol|li|h1|h2|h3|h4|h5|h6|code|pre|table|th|td|tr|form|label|input|select|option|nav|article|section|header|footer)$/i,Lr=/^(slot|partial|component)$/i,Ir=Er.optionMergeStrategies=Object.create(null);Ir.data=function(e,t,n){return n?e||t?function(){var r="function"==typeof t?t.call(n):t,i="function"==typeof e?e.call(n):void 0;return r?pe(r,i):i}:void 0:t?"function"!=typeof t?e:e?function(){return pe(t.call(this),e.call(this))}:t:e},Ir.el=function(e,t,n){if(n||!t||"function"==typeof t){var r=t||e;return n&&"function"==typeof r?r.call(n):r}},Ir.init=Ir.created=Ir.ready=Ir.attached=Ir.detached=Ir.beforeCompile=Ir.compiled=Ir.beforeDestroy=Ir.destroyed=Ir.activate=function(e,t){return t?e?e.concat(t):Tn(t)?t:[t]:e},Er._assetTypes.forEach(function(e){Ir[e+"s"]=he}),Ir.watch=Ir.events=function(e,t){if(!t)return e;if(!e)return t;var n={};v(n,e);for(var r in t){var i=n[r],a=t[r];i&&!Tn(i)&&(i=[i]),n[r]=i?i.concat(a):[a]}return n},Ir.props=Ir.methods=Ir.computed=function(e,t){if(!t)return e;if(!e)return t;var n=Object.create(null);return v(n,e),v(n,t),n};var Pr=function(e,t){return void 0===t?e:t},jr=0;ge.target=null,ge.prototype.addSub=function(e){this.subs.push(e)},ge.prototype.removeSub=function(e){this.subs.$remove(e)},ge.prototype.depend=function(){ge.target.addDep(this)},ge.prototype.notify=function(){for(var e=d(this.subs),t=0,n=e.length;n>t;t++)e[t].update()};var Tr=Array.prototype,Fr=Object.create(Tr);["push","pop","shift","unshift","splice","sort","reverse"].forEach(function(e){var t=Tr[e];g(Fr,e,function(){for(var n=arguments.length,r=new Array(n);n--;)r[n]=arguments[n];var i,a=t.apply(this,r),o=this.__ob__;switch(e){case"push":i=r;break;case"unshift":i=r;break;case"splice":i=r.slice(2)}return i&&o.observeArray(i),o.dep.notify(),a})}),g(Tr,"$set",function(e,t){return e>=this.length&&(this.length=Number(e)+1),this.splice(e,1,t)[0]}),g(Tr,"$remove",function(e){if(this.length){var t=_(this,e);return t>-1?this.splice(t,1):void 0}});var Dr=Object.getOwnPropertyNames(Fr),Rr=!0;_e.prototype.walk=function(e){for(var t=Object.keys(e),n=0,r=t.length;r>n;n++)this.convert(t[n],e[t[n]])},_e.prototype.observeArray=function(e){for(var t=0,n=e.length;n>t;t++)ke(e[t])},_e.prototype.convert=function(e,t){Se(this.value,e,t)},_e.prototype.addVm=function(e){(this.vms||(this.vms=[])).push(e)},_e.prototype.removeVm=function(e){this.vms.$remove(e)};var Br=Object.freeze({defineReactive:Se,set:e,del:t,hasOwn:n,isLiteral:r,isReserved:i,_toString:a,toNumber:o,toBoolean:s,stripQuotes:l,camelize:u,hyphenate:p,classify:h,bind:f,toArray:d,extend:v,isObject:m,isPlainObject:y,def:g,debounce:b,indexOf:_,cancellable:x,looseEqual:w,isArray:Tn,hasProto:Fn,inBrowser:Dn,devtools:Rn,isIE:Un,isIE9:Mn,isAndroid:Vn,isIos:Hn,iosVersionMatch:Wn,iosVersion:zn,hasMutationObserverBug:qn,get transitionProp(){return Gn},get transitionEndEvent(){return Jn},get animationProp(){return Kn},get animationEndEvent(){return Qn},nextTick:Yn,get _Set(){return er},query:D,inDoc:R,getAttr:B,getBindAttr:U,hasBindAttr:M,before:V,after:H,remove:W,prepend:z,replace:q,on:G,off:J,setClass:Q,addClass:X,removeClass:Z,extractContent:Y,trimNode:ee,isTemplate:ne,createAnchor:re,findRef:ie,mapNodeRange:ae,removeNodeRange:oe,isFragment:se,getOuterHTML:le,mergeOptions:me,resolveAsset:ye,checkComponentAttr:ue,commonTagRE:Nr,reservedTagRE:Lr,warn:Or}),Ur=0,Mr="undefined"!=typeof window?window:"undefined"!=typeof global?global:this,Vr=function(e,t){function n(e){if(!(this instanceof n))return new n(e);this.context=e;for(var t=0;t<s.length;t++)this.context[s[t]]||(this.context[s[t]]=o(u[t]))}function r(e){return e.prototype}function i(e){return t[e]}function a(e,t){e.__proto__=t}function o(e){var t=Object.create(e.prototype),n=function(){if(!(this instanceof n)){var r=e.apply(null,arguments);return a(r,t),r}e.apply(this,arguments)};return a(n,e),n.prototype=t,n.wrapped=!0,n}var s=(e.exports,["Object","String","Boolean","Number","RegExp","Date","Array"]),l={string:"String","boolean":"Boolean",number:"Number"},u=s.map(i),c=u.map(r);return e.exports=n,n.prototype.replace=function(e){var t=u.indexOf(e),n=c.indexOf(e);if(~t){var r=s[t];return this.context[r]}if(~n){var r=s[n];return this.context[r].prototype}return e},n.prototype.getPropertyObject=function(e,t){return l[typeof e]?this.getPrototypeOf(e):e},n.prototype.isPrimitive=function(e){return!!~u.indexOf(e)||!!~c.indexOf(e)},n.prototype.getPrototypeOf=function(e){if(null==e)return e;var t=l[typeof e];if(t)var n=this.context[t].prototype;else var n=Object.getPrototypeOf(e);if(n&&n!==Object.prototype){var r=this.replace(n);return r===e&&(r=this.replace(Object.prototype)),r}return null},n.prototype.applyNew=function(e,t){if(e.wrapped){var n=Object.getPrototypeOf(e),r=new(Function.prototype.bind.apply(n,arguments));return a(r,e.prototype),r}return new(Function.prototype.bind.apply(e,arguments))},e.exports}({exports:{}},Mr),Hr=function(e){function t(e){return this instanceof t?(this.maxIterations=e,void(this.count=0)):new t(e)}e.exports;return e.exports=t,t.prototype.check=function(){if(this.count+=1,this.count>this.maxIterations)throw new Error("Infinite loop detected - reached max iterations")},e.exports}({exports:{}}),Wr=function(e){function t(e){function i(e){for(var t=null,n=0;n<e.length;n++){var r=e[n];if("EmptyStatement"!==r.type){var t=a(r);"remove"===t&&e.splice(n--,1)}}}function a(e){var r=o[o.length-1],u=!1;o.push(e);var c=!1;n(e,r)&&(t(e.body),c=!0),"VariableDeclarator"===e.type&&s.push(e),"FunctionDeclaration"===e.type&&(l.push(e),u=!0);for(var p in e)"type"===p||c&&"body"===p||p in e&&e[p]&&"object"==typeof e[p]&&(e[p].type?a(e[p]):Array.isArray(e[p])&&i(e[p]));return o.pop(),u?"remove":void 0}var o=[],s=[],l=[];return Array.isArray(e)?(i(e),r(e,s,l)):a(e),e}function n(e,t){return"Program"===e.type?!0:"BlockStatement"!==e.type||!t||"FunctionExpression"!==t.type&&"FunctionDeclaration"!==t.type?void 0:!0}function r(e,t,n){if(t&&t.length){for(var r=[],i=0;i<t.length;i++)r.push({type:"VariableDeclarator",id:t[i].id,init:null});e.unshift({type:"VariableDeclaration",kind:"var",declarations:r})}if(n&&n.length)for(var i=0;i<n.length;i++)e.unshift(n[i])}e.exports;return e.exports=t,e.exports}({exports:{}}),zr=function(e){var t=e.exports;return function(e,n){"function"==typeof define&&define.amd?define(["exports"],n):n("undefined"!=typeof t?t:e.esprima={})}(this,function(e){function t(e,t){if(!e)throw new Error("ASSERT: "+t)}function n(e,t){return ht.slice(e,t)}function r(e){return"0123456789".indexOf(e)>=0}function i(e){return"0123456789abcdefABCDEF".indexOf(e)>=0}function a(e){return"01234567".indexOf(e)>=0}function o(e){return" "===e||" "===e||"\x0B"===e||"\f"===e||"\xa0"===e||e.charCodeAt(0)>=5760&&"\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\ufeff".indexOf(e)>=0}function s(e){return"\n"===e||"\r"===e||"\u2028"===e||"\u2029"===e}function l(e){return"$"===e||"_"===e||"\\"===e||e>="a"&&"z">=e||e>="A"&&"Z">=e||e.charCodeAt(0)>=128&&pt.NonAsciiIdentifierStart.test(e)}function u(e){return"$"===e||"_"===e||"\\"===e||e>="a"&&"z">=e||e>="A"&&"Z">=e||e>="0"&&"9">=e||e.charCodeAt(0)>=128&&pt.NonAsciiIdentifierPart.test(e)}function c(e){switch(e){case"class":case"enum":case"export":case"extends":case"import":case"super":return!0}return!1}function p(e){switch(e){case"implements":case"interface":case"package":case"private":case"protected":case"public":case"static":case"yield":case"let":return!0}return!1}function h(e){return"eval"===e||"arguments"===e}function f(e){var t=!1;switch(e.length){case 2:t="if"===e||"in"===e||"do"===e;break;case 3:t="var"===e||"for"===e||"new"===e||"try"===e;break;case 4:t="this"===e||"else"===e||"case"===e||"void"===e||"with"===e;break;case 5:t="while"===e||"break"===e||"catch"===e||"throw"===e;break;case 6:t="return"===e||"typeof"===e||"delete"===e||"switch"===e;break;case 7:t="default"===e||"finally"===e;break;case 8:t="function"===e||"continue"===e||"debugger"===e;break;case 10:t="instanceof"===e}if(t)return!0;switch(e){case"const":return!0;case"yield":case"let":return!0}return ft&&p(e)?!0:c(e)}function d(){var e,t,n;for(t=!1,n=!1;yt>dt;)if(e=ht[dt],n)e=ht[dt++],s(e)&&(n=!1,"\r"===e&&"\n"===ht[dt]&&++dt,++vt,mt=dt);else if(t)s(e)?("\r"===e&&"\n"===ht[dt+1]&&++dt,++vt,++dt,mt=dt,dt>=yt&&E({},ct.UnexpectedToken,"ILLEGAL")):(e=ht[dt++],dt>=yt&&E({},ct.UnexpectedToken,"ILLEGAL"),"*"===e&&(e=ht[dt],"/"===e&&(++dt,t=!1)));else if("/"===e)if(e=ht[dt+1],"/"===e)dt+=2,n=!0;else{if("*"!==e)break;dt+=2,t=!0,dt>=yt&&E({},ct.UnexpectedToken,"ILLEGAL")}else if(o(e))++dt;else{if(!s(e))break;++dt,"\r"===e&&"\n"===ht[dt]&&++dt,++vt,mt=dt}}function v(e){var t,n,r,a=0;for(n="u"===e?4:2,t=0;n>t;++t){if(!(yt>dt&&i(ht[dt])))return"";r=ht[dt++],a=16*a+"0123456789abcdef".indexOf(r.toLowerCase())}return String.fromCharCode(a)}function m(){var e,t,n,r;if(e=ht[dt],l(e)){if(t=dt,"\\"===e){if(++dt,"u"!==ht[dt])return;if(++dt,r=dt,e=v("u")){if("\\"===e||!l(e))return;n=e}else dt=r,n="u"}else n=ht[dt++];for(;yt>dt&&(e=ht[dt],u(e));)if("\\"===e){if(++dt,"u"!==ht[dt])return;if(++dt,r=dt,e=v("u")){if("\\"===e||!u(e))return;n+=e}else dt=r,n+="u"}else n+=ht[dt++];return 1===n.length?{type:ot.Identifier,value:n,lineNumber:vt,lineStart:mt,range:[t,dt]}:f(n)?{type:ot.Keyword,value:n,lineNumber:vt,lineStart:mt,range:[t,dt]}:"null"===n?{type:ot.NullLiteral,value:n,lineNumber:vt,lineStart:mt,range:[t,dt]}:"true"===n||"false"===n?{type:ot.BooleanLiteral,value:n,lineNumber:vt,lineStart:mt,range:[t,dt]}:{type:ot.Identifier,value:n,lineNumber:vt,lineStart:mt,range:[t,dt]}}}function y(){var e,t,n,i=dt,a=ht[dt];return";"===a||"{"===a||"}"===a?(++dt,{type:ot.Punctuator,value:a,lineNumber:vt,lineStart:mt,range:[i,dt]}):","===a||"("===a||")"===a?(++dt,{type:ot.Punctuator,value:a,lineNumber:vt,lineStart:mt,range:[i,dt]}):(e=ht[dt+1],"."!==a||r(e)?(t=ht[dt+2],n=ht[dt+3],">"===a&&">"===e&&">"===t&&"="===n?(dt+=4,{type:ot.Punctuator,value:">>>=",lineNumber:vt,lineStart:mt,range:[i,dt]}):"="===a&&"="===e&&"="===t?(dt+=3,{type:ot.Punctuator,value:"===",lineNumber:vt,lineStart:mt,range:[i,dt]}):"!"===a&&"="===e&&"="===t?(dt+=3,{type:ot.Punctuator,value:"!==",lineNumber:vt,lineStart:mt,range:[i,dt]}):">"===a&&">"===e&&">"===t?(dt+=3,{type:ot.Punctuator,value:">>>",lineNumber:vt,lineStart:mt,range:[i,dt]}):"<"===a&&"<"===e&&"="===t?(dt+=3,{type:ot.Punctuator,value:"<<=",lineNumber:vt,lineStart:mt,range:[i,dt]}):">"===a&&">"===e&&"="===t?(dt+=3,{type:ot.Punctuator,value:">>=",lineNumber:vt,lineStart:mt,range:[i,dt]}):"="===e&&"<>=!+-*%&|^/".indexOf(a)>=0?(dt+=2,{type:ot.Punctuator,value:a+e,lineNumber:vt,lineStart:mt,range:[i,dt]}):a===e&&"+-<>&|".indexOf(a)>=0&&"+-<>&|".indexOf(e)>=0?(dt+=2,{type:ot.Punctuator,value:a+e,lineNumber:vt,lineStart:mt,range:[i,dt]}):"[]<>+-*%&|^!~?:=/".indexOf(a)>=0?{type:ot.Punctuator,value:ht[dt++],lineNumber:vt,lineStart:mt,range:[i,dt]}:void 0):{type:ot.Punctuator,value:ht[dt++],lineNumber:vt,lineStart:mt,range:[i,dt]})}function g(){var e,n,o;if(o=ht[dt],t(r(o)||"."===o,"Numeric literal must start with a decimal digit or a decimal point"),n=dt,e="","."!==o){if(e=ht[dt++],o=ht[dt],"0"===e){if("x"===o||"X"===o){for(e+=ht[dt++];yt>dt&&(o=ht[dt],i(o));)e+=ht[dt++];return e.length<=2&&E({},ct.UnexpectedToken,"ILLEGAL"),yt>dt&&(o=ht[dt],l(o)&&E({},ct.UnexpectedToken,"ILLEGAL")),{type:ot.NumericLiteral,value:parseInt(e,16),lineNumber:vt,lineStart:mt,range:[n,dt]}}if(a(o)){for(e+=ht[dt++];yt>dt&&(o=ht[dt],a(o));)e+=ht[dt++];return yt>dt&&(o=ht[dt],(l(o)||r(o))&&E({},ct.UnexpectedToken,"ILLEGAL")),{type:ot.NumericLiteral,value:parseInt(e,8),octal:!0,lineNumber:vt,lineStart:mt,range:[n,dt]}}r(o)&&E({},ct.UnexpectedToken,"ILLEGAL")}for(;yt>dt&&(o=ht[dt],r(o));)e+=ht[dt++]}if("."===o)for(e+=ht[dt++];yt>dt&&(o=ht[dt],r(o));)e+=ht[dt++];if("e"===o||"E"===o)if(e+=ht[dt++],o=ht[dt],"+"!==o&&"-"!==o||(e+=ht[dt++]),o=ht[dt],r(o))for(e+=ht[dt++];yt>dt&&(o=ht[dt],r(o));)e+=ht[dt++];else o="character "+o,dt>=yt&&(o="<end>"),E({},ct.UnexpectedToken,"ILLEGAL");return yt>dt&&(o=ht[dt],l(o)&&E({},ct.UnexpectedToken,"ILLEGAL")),{type:ot.NumericLiteral,value:parseFloat(e),lineNumber:vt,lineStart:mt,range:[n,dt]}}function b(){var e,n,r,i,o,l,u="",c=!1;for(e=ht[dt],t("'"===e||'"'===e,"String literal must starts with a quote"),n=dt,++dt;yt>dt;){if(r=ht[dt++],r===e){e="";break}if("\\"===r)if(r=ht[dt++],s(r))++vt,"\r"===r&&"\n"===ht[dt]&&++dt;else switch(r){case"n":u+="\n";break;case"r":u+="\r";break;case"t":u+=" ";break;case"u":case"x":l=dt,o=v(r),o?u+=o:(dt=l,u+=r);break;case"b":u+="\b";break;case"f":u+="\f";break;case"v":u+="\x0B";break;default:a(r)?(i="01234567".indexOf(r),0!==i&&(c=!0),yt>dt&&a(ht[dt])&&(c=!0,i=8*i+"01234567".indexOf(ht[dt++]),"0123".indexOf(r)>=0&&yt>dt&&a(ht[dt])&&(i=8*i+"01234567".indexOf(ht[dt++]))),u+=String.fromCharCode(i)):u+=r}else{if(s(r))break;u+=r}}return""!==e&&E({},ct.UnexpectedToken,"ILLEGAL"),{type:ot.StringLiteral,value:u,octal:c,lineNumber:vt,lineStart:mt,range:[n,dt]}}function _(){var e,n,r,i,a,o,l,c=!1,p=!1;for(gt=null,d(),r=dt,n=ht[dt],t("/"===n,"Regular expression literal must start with a slash"),e=ht[dt++];yt>dt;)if(n=ht[dt++],e+=n,"\\"===n)n=ht[dt++],s(n)&&E({},ct.UnterminatedRegExp),e+=n;else if(c)"]"===n&&(c=!1);else{if("/"===n){p=!0;break}"["===n?c=!0:s(n)&&E({},ct.UnterminatedRegExp)}for(p||E({},ct.UnterminatedRegExp),i=e.substr(1,e.length-2),a="";yt>dt&&(n=ht[dt],u(n));)if(++dt,"\\"===n&&yt>dt)if(n=ht[dt],"u"===n)if(++dt,l=dt,n=v("u"))for(a+=n,e+="\\u";dt>l;++l)e+=ht[l];else dt=l,a+="u",e+="\\u";else e+="\\";else a+=n,e+=n;try{o=new RegExp(i,a)}catch(h){E({},ct.InvalidRegExp)}return{literal:e,value:o,range:[r,dt]}}function x(e){return e.type===ot.Identifier||e.type===ot.Keyword||e.type===ot.BooleanLiteral||e.type===ot.NullLiteral}function w(){var e,t;return d(),dt>=yt?{type:ot.EOF,lineNumber:vt,lineStart:mt,range:[dt,dt]}:(t=y(),"undefined"!=typeof t?t:(e=ht[dt],"'"===e||'"'===e?b():"."===e||r(e)?g():(t=m(),"undefined"!=typeof t?t:void E({},ct.UnexpectedToken,"ILLEGAL"))))}function k(){var e;return gt?(dt=gt.range[1],vt=gt.lineNumber,mt=gt.lineStart,e=gt,gt=null,e):(gt=null,w())}function S(){var e,t,n;return null!==gt?gt:(e=dt,t=vt,n=mt,gt=w(),dt=e,vt=t,mt=n,gt)}function C(){var e,t,n,r;return e=dt,t=vt,n=mt,d(),r=vt!==t,dt=e,vt=t,mt=n,r}function E(e,t){var n,r=Array.prototype.slice.call(arguments,2),i=t.replace(/%(\d)/g,function(e,t){return r[t]||""});throw"number"==typeof e.lineNumber?(n=new Error("Line "+e.lineNumber+": "+i),n.index=e.range[0],n.lineNumber=e.lineNumber,n.column=e.range[0]-mt+1):(n=new Error("Line "+vt+": "+i),n.index=dt,n.lineNumber=vt,n.column=dt-mt+1),n}function O(){try{E.apply(null,arguments)}catch(e){if(!_t.errors)throw e;_t.errors.push(e)}}function $(e){if(e.type===ot.EOF&&E(e,ct.UnexpectedEOS),e.type===ot.NumericLiteral&&E(e,ct.UnexpectedNumber),e.type===ot.StringLiteral&&E(e,ct.UnexpectedString),e.type===ot.Identifier&&E(e,ct.UnexpectedIdentifier),e.type===ot.Keyword){if(c(e.value))E(e,ct.UnexpectedReserved);else if(ft&&p(e.value))return void O(e,ct.StrictReservedWord);E(e,ct.UnexpectedToken,e.value)}E(e,ct.UnexpectedToken,e.value)}function A(e){var t=k();t.type===ot.Punctuator&&t.value===e||$(t)}function N(e){var t=k();t.type===ot.Keyword&&t.value===e||$(t)}function L(e){var t=S();return t.type===ot.Punctuator&&t.value===e}function I(e){var t=S();return t.type===ot.Keyword&&t.value===e}function P(){var e=S(),t=e.value;return e.type!==ot.Punctuator?!1:"="===t||"*="===t||"/="===t||"%="===t||"+="===t||"-="===t||"<<="===t||">>="===t||">>>="===t||"&="===t||"^="===t||"|="===t}function j(){var e,t;if(";"===ht[dt])return void k();if(t=vt,d(),vt===t){if(L(";"))return void k();e=S(),e.type===ot.EOF||L("}")||$(e)}}function T(e){return e.type===lt.Identifier||e.type===lt.MemberExpression}function F(){var e=[];for(A("[");!L("]");)L(",")?(k(),e.push(null)):(e.push(ue()),L("]")||A(","));return A("]"),{type:lt.ArrayExpression,elements:e}}function D(e,t){var n,r;return n=ft,r=Fe(),t&&ft&&h(e[0].name)&&O(t,ct.StrictParamName),ft=n,{type:lt.FunctionExpression,id:null,params:e,defaults:[],body:r,rest:null,generator:!1,expression:!1}}function R(){var e=k();return e.type===ot.StringLiteral||e.type===ot.NumericLiteral?(ft&&e.octal&&O(e,ct.StrictOctalLiteral),Je(e)):{type:lt.Identifier,name:e.value}}function B(){var e,t,n,r;return e=S(),e.type===ot.Identifier?(n=R(),"get"!==e.value||L(":")?"set"!==e.value||L(":")?(A(":"),{type:lt.Property,key:n,value:ue(),kind:"init"}):(t=R(),A("("),e=S(),e.type!==ot.Identifier?(A(")"),O(e,ct.UnexpectedToken,e.value),{type:lt.Property,key:t,value:D([]),kind:"set"}):(r=[fe()],A(")"),{type:lt.Property,key:t,value:D(r,e),kind:"set"})):(t=R(),A("("),A(")"),{type:lt.Property,key:t,value:D([]),kind:"get"})):e.type!==ot.EOF&&e.type!==ot.Punctuator?(t=R(),A(":"),{type:lt.Property,key:t,value:ue(),kind:"init"}):void $(e)}function U(){var e,t,n,r=[],i={},a=String;for(A("{");!L("}");)e=B(),t=e.key.type===lt.Identifier?e.key.name:a(e.key.value),n="init"===e.kind?ut.Data:"get"===e.kind?ut.Get:ut.Set,Object.prototype.hasOwnProperty.call(i,t)?(i[t]===ut.Data?ft&&n===ut.Data?O({},ct.StrictDuplicateProperty):n!==ut.Data&&O({},ct.AccessorDataProperty):n===ut.Data?O({},ct.AccessorDataProperty):i[t]&n&&O({},ct.AccessorGetSet),i[t]|=n):i[t]=n,r.push(e),L("}")||A(",");return A("}"),{type:lt.ObjectExpression,properties:r}}function M(){var e;return A("("),e=ce(),A(")"),e}function V(){var e=S(),t=e.type;if(t===ot.Identifier)return{type:lt.Identifier,name:k().value};if(t===ot.StringLiteral||t===ot.NumericLiteral)return ft&&e.octal&&O(e,ct.StrictOctalLiteral),Je(k());if(t===ot.Keyword){if(I("this"))return k(),{type:lt.ThisExpression};if(I("function"))return Re()}return t===ot.BooleanLiteral?(k(),e.value="true"===e.value,Je(e)):t===ot.NullLiteral?(k(),e.value=null,Je(e)):L("[")?F():L("{")?U():L("(")?M():L("/")||L("/=")?Je(_()):$(k())}function H(){var e=[];if(A("("),!L(")"))for(;yt>dt&&(e.push(ue()),!L(")"));)A(",");return A(")"),e}function W(){var e=k();return x(e)||$(e),{type:lt.Identifier,name:e.value}}function z(){return A("."),W()}function q(){var e;return A("["),e=ce(),A("]"),e}function G(){var e;return N("new"),e={type:lt.NewExpression,callee:K(),arguments:[]},L("(")&&(e.arguments=H()),e}function J(){var e;for(e=I("new")?G():V();L(".")||L("[")||L("(");)e=L("(")?{type:lt.CallExpression,callee:e,arguments:H()}:L("[")?{type:lt.MemberExpression,computed:!0,object:e,property:q()}:{type:lt.MemberExpression,computed:!1,object:e,property:z()};return e}function K(){var e;for(e=I("new")?G():V();L(".")||L("[");)e=L("[")?{type:lt.MemberExpression,computed:!0,object:e,property:q()}:{type:lt.MemberExpression,computed:!1,object:e,property:z()};return e}function Q(){var e,t=J();return e=S(),e.type!==ot.Punctuator?t:(!L("++")&&!L("--")||C()||(ft&&t.type===lt.Identifier&&h(t.name)&&O({},ct.StrictLHSPostfix),T(t)||O({},ct.InvalidLHSInAssignment),t={type:lt.UpdateExpression,operator:k().value,argument:t,prefix:!1}),t)}function X(){var e,t;return e=S(),e.type!==ot.Punctuator&&e.type!==ot.Keyword?Q():L("++")||L("--")?(e=k(),t=X(),ft&&t.type===lt.Identifier&&h(t.name)&&O({},ct.StrictLHSPrefix),T(t)||O({},ct.InvalidLHSInAssignment),t={type:lt.UpdateExpression,operator:e.value,argument:t,prefix:!0}):L("+")||L("-")||L("~")||L("!")?t={type:lt.UnaryExpression,operator:k().value,argument:X(),prefix:!0}:I("delete")||I("void")||I("typeof")?(t={type:lt.UnaryExpression,operator:k().value,argument:X(),prefix:!0},ft&&"delete"===t.operator&&t.argument.type===lt.Identifier&&O({},ct.StrictDelete),t):Q()}function Z(){for(var e=X();L("*")||L("/")||L("%");)e={type:lt.BinaryExpression,operator:k().value,left:e,right:X()};return e}function Y(){for(var e=Z();L("+")||L("-");)e={type:lt.BinaryExpression,operator:k().value,left:e,right:Z()};return e}function ee(){for(var e=Y();L("<<")||L(">>")||L(">>>");)e={type:lt.BinaryExpression,operator:k().value,left:e,right:Y()};return e}function te(){var e,t;for(t=bt.allowIn,bt.allowIn=!0,e=ee();L("<")||L(">")||L("<=")||L(">=")||t&&I("in")||I("instanceof");)e={type:lt.BinaryExpression,operator:k().value,left:e,right:ee()};return bt.allowIn=t,e}function ne(){for(var e=te();L("==")||L("!=")||L("===")||L("!==");)e={type:lt.BinaryExpression,operator:k().value,left:e,right:te()};return e}function re(){for(var e=ne();L("&");)k(),e={type:lt.BinaryExpression,operator:"&",left:e,right:ne()};return e}function ie(){for(var e=re();L("^");)k(),e={
-type:lt.BinaryExpression,operator:"^",left:e,right:re()};return e}function ae(){for(var e=ie();L("|");)k(),e={type:lt.BinaryExpression,operator:"|",left:e,right:ie()};return e}function oe(){for(var e=ae();L("&&");)k(),e={type:lt.LogicalExpression,operator:"&&",left:e,right:ae()};return e}function se(){for(var e=oe();L("||");)k(),e={type:lt.LogicalExpression,operator:"||",left:e,right:oe()};return e}function le(){var e,t,n;return e=se(),L("?")&&(k(),t=bt.allowIn,bt.allowIn=!0,n=ue(),bt.allowIn=t,A(":"),e={type:lt.ConditionalExpression,test:e,consequent:n,alternate:ue()}),e}function ue(){var e,t;return e=S(),t=le(),P()&&(T(t)||O({},ct.InvalidLHSInAssignment),ft&&t.type===lt.Identifier&&h(t.name)&&O(e,ct.StrictLHSAssignment),t={type:lt.AssignmentExpression,operator:k().value,left:t,right:ue()}),t}function ce(){var e=ue();if(L(","))for(e={type:lt.SequenceExpression,expressions:[e]};yt>dt&&L(",");)k(),e.expressions.push(ue());return e}function pe(){for(var e,t=[];yt>dt&&!L("}")&&(e=Be(),"undefined"!=typeof e);)t.push(e);return t}function he(){var e;return A("{"),e=pe(),A("}"),{type:lt.BlockStatement,body:e}}function fe(){var e=k();return e.type!==ot.Identifier&&$(e),{type:lt.Identifier,name:e.value}}function de(e){var t=fe(),n=null;return ft&&h(t.name)&&O({},ct.StrictVarName),"const"===e?(A("="),n=ue()):L("=")&&(k(),n=ue()),{type:lt.VariableDeclarator,id:t,init:n}}function ve(e){var t=[];do{if(t.push(de(e)),!L(","))break;k()}while(yt>dt);return t}function me(){var e;return N("var"),e=ve(),j(),{type:lt.VariableDeclaration,declarations:e,kind:"var"}}function ye(e){var t;return N(e),t=ve(e),j(),{type:lt.VariableDeclaration,declarations:t,kind:e}}function ge(){return A(";"),{type:lt.EmptyStatement}}function be(){var e=ce();return j(),{type:lt.ExpressionStatement,expression:e}}function _e(){var e,t,n;return N("if"),A("("),e=ce(),A(")"),t=Te(),I("else")?(k(),n=Te()):n=null,{type:lt.IfStatement,test:e,consequent:t,alternate:n}}function xe(){var e,t,n;return N("do"),n=bt.inIteration,bt.inIteration=!0,e=Te(),bt.inIteration=n,N("while"),A("("),t=ce(),A(")"),L(";")&&k(),{type:lt.DoWhileStatement,body:e,test:t}}function we(){var e,t,n;return N("while"),A("("),e=ce(),A(")"),n=bt.inIteration,bt.inIteration=!0,t=Te(),bt.inIteration=n,{type:lt.WhileStatement,test:e,body:t}}function ke(){var e=k();return{type:lt.VariableDeclaration,declarations:ve(),kind:e.value}}function Se(){var e,t,n,r,i,a,o;return e=t=n=null,N("for"),A("("),L(";")?k():(I("var")||I("let")?(bt.allowIn=!1,e=ke(),bt.allowIn=!0,1===e.declarations.length&&I("in")&&(k(),r=e,i=ce(),e=null)):(bt.allowIn=!1,e=ce(),bt.allowIn=!0,I("in")&&(T(e)||O({},ct.InvalidLHSInForIn),k(),r=e,i=ce(),e=null)),"undefined"==typeof r&&A(";")),"undefined"==typeof r&&(L(";")||(t=ce()),A(";"),L(")")||(n=ce())),A(")"),o=bt.inIteration,bt.inIteration=!0,a=Te(),bt.inIteration=o,"undefined"==typeof r?{type:lt.ForStatement,init:e,test:t,update:n,body:a}:{type:lt.ForInStatement,left:r,right:i,body:a,each:!1}}function Ce(){var e,t=null;return N("continue"),";"===ht[dt]?(k(),bt.inIteration||E({},ct.IllegalContinue),{type:lt.ContinueStatement,label:null}):C()?(bt.inIteration||E({},ct.IllegalContinue),{type:lt.ContinueStatement,label:null}):(e=S(),e.type===ot.Identifier&&(t=fe(),Object.prototype.hasOwnProperty.call(bt.labelSet,t.name)||E({},ct.UnknownLabel,t.name)),j(),null!==t||bt.inIteration||E({},ct.IllegalContinue),{type:lt.ContinueStatement,label:t})}function Ee(){var e,t=null;return N("break"),";"===ht[dt]?(k(),bt.inIteration||bt.inSwitch||E({},ct.IllegalBreak),{type:lt.BreakStatement,label:null}):C()?(bt.inIteration||bt.inSwitch||E({},ct.IllegalBreak),{type:lt.BreakStatement,label:null}):(e=S(),e.type===ot.Identifier&&(t=fe(),Object.prototype.hasOwnProperty.call(bt.labelSet,t.name)||E({},ct.UnknownLabel,t.name)),j(),null!==t||bt.inIteration||bt.inSwitch||E({},ct.IllegalBreak),{type:lt.BreakStatement,label:t})}function Oe(){var e,t=null;return N("return"),bt.inFunctionBody||O({},ct.IllegalReturn)," "===ht[dt]&&l(ht[dt+1])?(t=ce(),j(),{type:lt.ReturnStatement,argument:t}):C()?{type:lt.ReturnStatement,argument:null}:(L(";")||(e=S(),L("}")||e.type===ot.EOF||(t=ce())),j(),{type:lt.ReturnStatement,argument:t})}function $e(){var e,t;return ft&&O({},ct.StrictModeWith),N("with"),A("("),e=ce(),A(")"),t=Te(),{type:lt.WithStatement,object:e,body:t}}function Ae(){var e,t,n=[];for(I("default")?(k(),e=null):(N("case"),e=ce()),A(":");yt>dt&&!(L("}")||I("default")||I("case"))&&(t=Te(),"undefined"!=typeof t);)n.push(t);return{type:lt.SwitchCase,test:e,consequent:n}}function Ne(){var e,t,n,r,i;if(N("switch"),A("("),e=ce(),A(")"),A("{"),t=[],L("}"))return k(),{type:lt.SwitchStatement,discriminant:e,cases:t};for(r=bt.inSwitch,bt.inSwitch=!0,i=!1;yt>dt&&!L("}");)n=Ae(),null===n.test&&(i&&E({},ct.MultipleDefaultsInSwitch),i=!0),t.push(n);return bt.inSwitch=r,A("}"),{type:lt.SwitchStatement,discriminant:e,cases:t}}function Le(){var e;return N("throw"),C()&&E({},ct.NewlineAfterThrow),e=ce(),j(),{type:lt.ThrowStatement,argument:e}}function Ie(){var e;return N("catch"),A("("),L(")")&&$(S()),e=fe(),ft&&h(e.name)&&O({},ct.StrictCatchVariable),A(")"),{type:lt.CatchClause,param:e,body:he()}}function Pe(){var e,t=[],n=null;return N("try"),e=he(),I("catch")&&t.push(Ie()),I("finally")&&(k(),n=he()),0!==t.length||n||E({},ct.NoCatchOrFinally),{type:lt.TryStatement,block:e,guardedHandlers:[],handlers:t,finalizer:n}}function je(){return N("debugger"),j(),{type:lt.DebuggerStatement}}function Te(){var e,t,n=S();if(n.type===ot.EOF&&$(n),n.type===ot.Punctuator)switch(n.value){case";":return ge();case"{":return he();case"(":return be()}if(n.type===ot.Keyword)switch(n.value){case"break":return Ee();case"continue":return Ce();case"debugger":return je();case"do":return xe();case"for":return Se();case"function":return De();case"if":return _e();case"return":return Oe();case"switch":return Ne();case"throw":return Le();case"try":return Pe();case"var":return me();case"while":return we();case"with":return $e()}return e=ce(),e.type===lt.Identifier&&L(":")?(k(),Object.prototype.hasOwnProperty.call(bt.labelSet,e.name)&&E({},ct.Redeclaration,"Label",e.name),bt.labelSet[e.name]=!0,t=Te(),delete bt.labelSet[e.name],{type:lt.LabeledStatement,label:e,body:t}):(j(),{type:lt.ExpressionStatement,expression:e})}function Fe(){var e,t,r,i,a,o,s,l,u=[];for(A("{");yt>dt&&(t=S(),t.type===ot.StringLiteral)&&(e=Be(),u.push(e),e.expression.type===lt.Literal);)r=n(t.range[0]+1,t.range[1]-1),"use strict"===r?(ft=!0,i&&O(i,ct.StrictOctalLiteral)):!i&&t.octal&&(i=t);for(a=bt.labelSet,o=bt.inIteration,s=bt.inSwitch,l=bt.inFunctionBody,bt.labelSet={},bt.inIteration=!1,bt.inSwitch=!1,bt.inFunctionBody=!0;yt>dt&&!L("}")&&(e=Be(),"undefined"!=typeof e);)u.push(e);return A("}"),bt.labelSet=a,bt.inIteration=o,bt.inSwitch=s,bt.inFunctionBody=l,{type:lt.BlockStatement,body:u}}function De(){var e,t,n,r,i,a,o,s,l,u=[];if(N("function"),r=S(),e=fe(),ft?h(r.value)&&O(r,ct.StrictFunctionName):h(r.value)?(a=r,o=ct.StrictFunctionName):p(r.value)&&(a=r,o=ct.StrictReservedWord),A("("),!L(")"))for(l={};yt>dt&&(r=S(),t=fe(),ft?(h(r.value)&&(i=r,o=ct.StrictParamName),Object.prototype.hasOwnProperty.call(l,r.value)&&(i=r,o=ct.StrictParamDupe)):a||(h(r.value)?(a=r,o=ct.StrictParamName):p(r.value)?(a=r,o=ct.StrictReservedWord):Object.prototype.hasOwnProperty.call(l,r.value)&&(a=r,o=ct.StrictParamDupe)),u.push(t),l[t.name]=!0,!L(")"));)A(",");return A(")"),s=ft,n=Fe(),ft&&a&&E(a,o),ft&&i&&O(i,o),ft=s,{type:lt.FunctionDeclaration,id:e,params:u,defaults:[],body:n,rest:null,generator:!1,expression:!1}}function Re(){var e,t,n,r,i,a,o,s,l=null,u=[];if(N("function"),L("(")||(e=S(),l=fe(),ft?h(e.value)&&O(e,ct.StrictFunctionName):h(e.value)?(n=e,r=ct.StrictFunctionName):p(e.value)&&(n=e,r=ct.StrictReservedWord)),A("("),!L(")"))for(s={};yt>dt&&(e=S(),i=fe(),ft?(h(e.value)&&(t=e,r=ct.StrictParamName),Object.prototype.hasOwnProperty.call(s,e.value)&&(t=e,r=ct.StrictParamDupe)):n||(h(e.value)?(n=e,r=ct.StrictParamName):p(e.value)?(n=e,r=ct.StrictReservedWord):Object.prototype.hasOwnProperty.call(s,e.value)&&(n=e,r=ct.StrictParamDupe)),u.push(i),s[i.name]=!0,!L(")"));)A(",");return A(")"),o=ft,a=Fe(),ft&&n&&E(n,r),ft&&t&&O(t,r),ft=o,{type:lt.FunctionExpression,id:l,params:u,defaults:[],body:a,rest:null,generator:!1,expression:!1}}function Be(){var e=S();if(e.type===ot.Keyword)switch(e.value){case"const":case"let":return ye(e.value);case"function":return De();default:return Te()}return e.type!==ot.EOF?Te():void 0}function Ue(){for(var e,t,r,i,a=[];yt>dt&&(t=S(),t.type===ot.StringLiteral)&&(e=Be(),a.push(e),e.expression.type===lt.Literal);)r=n(t.range[0]+1,t.range[1]-1),"use strict"===r?(ft=!0,i&&O(i,ct.StrictOctalLiteral)):!i&&t.octal&&(i=t);for(;yt>dt&&(e=Be(),"undefined"!=typeof e);)a.push(e);return a}function Me(){var e;return ft=!1,e={type:lt.Program,body:Ue()}}function Ve(e,n,r,i,a){t("number"==typeof r,"Comment must have valid position"),_t.comments.length>0&&_t.comments[_t.comments.length-1].range[1]>r||_t.comments.push({type:e,value:n,range:[r,i],loc:a})}function He(){var e,t,n,r,i,a;for(e="",i=!1,a=!1;yt>dt;)if(t=ht[dt],a)t=ht[dt++],s(t)?(n.end={line:vt,column:dt-mt-1},a=!1,Ve("Line",e,r,dt-1,n),"\r"===t&&"\n"===ht[dt]&&++dt,++vt,mt=dt,e=""):dt>=yt?(a=!1,e+=t,n.end={line:vt,column:yt-mt},Ve("Line",e,r,yt,n)):e+=t;else if(i)s(t)?("\r"===t&&"\n"===ht[dt+1]?(++dt,e+="\r\n"):e+=t,++vt,++dt,mt=dt,dt>=yt&&E({},ct.UnexpectedToken,"ILLEGAL")):(t=ht[dt++],dt>=yt&&E({},ct.UnexpectedToken,"ILLEGAL"),e+=t,"*"===t&&(t=ht[dt],"/"===t&&(e=e.substr(0,e.length-1),i=!1,++dt,n.end={line:vt,column:dt-mt},Ve("Block",e,r,dt,n),e="")));else if("/"===t)if(t=ht[dt+1],"/"===t)n={start:{line:vt,column:dt-mt}},r=dt,dt+=2,a=!0,dt>=yt&&(n.end={line:vt,column:dt-mt},a=!1,Ve("Line",e,r,dt,n));else{if("*"!==t)break;r=dt,dt+=2,i=!0,n={start:{line:vt,column:dt-mt-2}},dt>=yt&&E({},ct.UnexpectedToken,"ILLEGAL")}else if(o(t))++dt;else{if(!s(t))break;++dt,"\r"===t&&"\n"===ht[dt]&&++dt,++vt,mt=dt}}function We(){var e,t,n,r=[];for(e=0;e<_t.comments.length;++e)t=_t.comments[e],n={type:t.type,value:t.value},_t.range&&(n.range=t.range),_t.loc&&(n.loc=t.loc),r.push(n);_t.comments=r}function ze(){var e,t,r,i,a;return d(),e=dt,t={start:{line:vt,column:dt-mt}},r=_t.advance(),t.end={line:vt,column:dt-mt},r.type!==ot.EOF&&(i=[r.range[0],r.range[1]],a=n(r.range[0],r.range[1]),_t.tokens.push({type:st[r.type],value:a,range:i,loc:t})),r}function qe(){var e,t,n,r;return d(),e=dt,t={start:{line:vt,column:dt-mt}},n=_t.scanRegExp(),t.end={line:vt,column:dt-mt},_t.tokens.length>0&&(r=_t.tokens[_t.tokens.length-1],r.range[0]===e&&"Punctuator"===r.type&&("/"!==r.value&&"/="!==r.value||_t.tokens.pop())),_t.tokens.push({type:"RegularExpression",value:n.literal,range:[e,dt],loc:t}),n}function Ge(){var e,t,n,r=[];for(e=0;e<_t.tokens.length;++e)t=_t.tokens[e],n={type:t.type,value:t.value},_t.range&&(n.range=t.range),_t.loc&&(n.loc=t.loc),r.push(n);_t.tokens=r}function Je(e){return{type:lt.Literal,value:e.value}}function Ke(e){return{type:lt.Literal,value:e.value,raw:n(e.range[0],e.range[1])}}function Qe(){var e={};return e.range=[dt,dt],e.loc={start:{line:vt,column:dt-mt},end:{line:vt,column:dt-mt}},e.end=function(){this.range[1]=dt,this.loc.end.line=vt,this.loc.end.column=dt-mt},e.applyGroup=function(e){_t.range&&(e.groupRange=[this.range[0],this.range[1]]),_t.loc&&(e.groupLoc={start:{line:this.loc.start.line,column:this.loc.start.column},end:{line:this.loc.end.line,column:this.loc.end.column}})},e.apply=function(e){_t.range&&(e.range=[this.range[0],this.range[1]]),_t.loc&&(e.loc={start:{line:this.loc.start.line,column:this.loc.start.column},end:{line:this.loc.end.line,column:this.loc.end.column}})},e}function Xe(){var e,t;return d(),e=Qe(),A("("),t=ce(),A(")"),e.end(),e.applyGroup(t),t}function Ze(){var e,t;for(d(),e=Qe(),t=I("new")?G():V();L(".")||L("[");)L("[")?(t={type:lt.MemberExpression,computed:!0,object:t,property:q()},e.end(),e.apply(t)):(t={type:lt.MemberExpression,computed:!1,object:t,property:z()},e.end(),e.apply(t));return t}function Ye(){var e,t;for(d(),e=Qe(),t=I("new")?G():V();L(".")||L("[")||L("(");)L("(")?(t={type:lt.CallExpression,callee:t,arguments:H()},e.end(),e.apply(t)):L("[")?(t={type:lt.MemberExpression,computed:!0,object:t,property:q()},e.end(),e.apply(t)):(t={type:lt.MemberExpression,computed:!1,object:t,property:z()},e.end(),e.apply(t));return t}function et(e){var t,n,r;t="[object Array]"===Object.prototype.toString.apply(e)?[]:{};for(n in e)e.hasOwnProperty(n)&&"groupRange"!==n&&"groupLoc"!==n&&(r=e[n],null===r||"object"!=typeof r||r instanceof RegExp?t[n]=r:t[n]=et(r));return t}function tt(e,t){return function(n){function r(e){return e.type===lt.LogicalExpression||e.type===lt.BinaryExpression}function i(n){var a,o;r(n.left)&&i(n.left),r(n.right)&&i(n.right),e&&(n.left.groupRange||n.right.groupRange?(a=n.left.groupRange?n.left.groupRange[0]:n.left.range[0],o=n.right.groupRange?n.right.groupRange[1]:n.right.range[1],n.range=[a,o]):"undefined"==typeof n.range&&(a=n.left.range[0],o=n.right.range[1],n.range=[a,o])),t&&(n.left.groupLoc||n.right.groupLoc?(a=n.left.groupLoc?n.left.groupLoc.start:n.left.loc.start,o=n.right.groupLoc?n.right.groupLoc.end:n.right.loc.end,n.loc={start:a,end:o}):"undefined"==typeof n.loc&&(n.loc={start:n.left.loc.start,end:n.right.loc.end}))}return function(){var a,o;return d(),a=Qe(),o=n.apply(null,arguments),a.end(),e&&"undefined"==typeof o.range&&a.apply(o),t&&"undefined"==typeof o.loc&&a.apply(o),r(o)&&i(o),o}}}function nt(){var e;_t.comments&&(_t.skipComment=d,d=He),_t.raw&&(_t.createLiteral=Je,Je=Ke),(_t.range||_t.loc)&&(_t.parseGroupExpression=M,_t.parseLeftHandSideExpression=K,_t.parseLeftHandSideExpressionAllowCall=J,M=Xe,K=Ze,J=Ye,e=tt(_t.range,_t.loc),_t.parseAdditiveExpression=Y,_t.parseAssignmentExpression=ue,_t.parseBitwiseANDExpression=re,_t.parseBitwiseORExpression=ae,_t.parseBitwiseXORExpression=ie,_t.parseBlock=he,_t.parseFunctionSourceElements=Fe,_t.parseCatchClause=Ie,_t.parseComputedMember=q,_t.parseConditionalExpression=le,_t.parseConstLetDeclaration=ye,_t.parseEqualityExpression=ne,_t.parseExpression=ce,_t.parseForVariableDeclaration=ke,_t.parseFunctionDeclaration=De,_t.parseFunctionExpression=Re,_t.parseLogicalANDExpression=oe,_t.parseLogicalORExpression=se,_t.parseMultiplicativeExpression=Z,_t.parseNewExpression=G,_t.parseNonComputedProperty=W,_t.parseObjectProperty=B,_t.parseObjectPropertyKey=R,_t.parsePostfixExpression=Q,_t.parsePrimaryExpression=V,_t.parseProgram=Me,_t.parsePropertyFunction=D,_t.parseRelationalExpression=te,_t.parseStatement=Te,_t.parseShiftExpression=ee,_t.parseSwitchCase=Ae,_t.parseUnaryExpression=X,_t.parseVariableDeclaration=de,_t.parseVariableIdentifier=fe,Y=e(_t.parseAdditiveExpression),ue=e(_t.parseAssignmentExpression),re=e(_t.parseBitwiseANDExpression),ae=e(_t.parseBitwiseORExpression),ie=e(_t.parseBitwiseXORExpression),he=e(_t.parseBlock),Fe=e(_t.parseFunctionSourceElements),Ie=e(_t.parseCatchClause),q=e(_t.parseComputedMember),le=e(_t.parseConditionalExpression),ye=e(_t.parseConstLetDeclaration),ne=e(_t.parseEqualityExpression),ce=e(_t.parseExpression),ke=e(_t.parseForVariableDeclaration),De=e(_t.parseFunctionDeclaration),Re=e(_t.parseFunctionExpression),K=e(K),oe=e(_t.parseLogicalANDExpression),se=e(_t.parseLogicalORExpression),Z=e(_t.parseMultiplicativeExpression),G=e(_t.parseNewExpression),W=e(_t.parseNonComputedProperty),B=e(_t.parseObjectProperty),R=e(_t.parseObjectPropertyKey),Q=e(_t.parsePostfixExpression),V=e(_t.parsePrimaryExpression),Me=e(_t.parseProgram),D=e(_t.parsePropertyFunction),te=e(_t.parseRelationalExpression),Te=e(_t.parseStatement),ee=e(_t.parseShiftExpression),Ae=e(_t.parseSwitchCase),X=e(_t.parseUnaryExpression),de=e(_t.parseVariableDeclaration),fe=e(_t.parseVariableIdentifier)),"undefined"!=typeof _t.tokens&&(_t.advance=w,_t.scanRegExp=_,w=ze,_=qe)}function rt(){"function"==typeof _t.skipComment&&(d=_t.skipComment),_t.raw&&(Je=_t.createLiteral),(_t.range||_t.loc)&&(Y=_t.parseAdditiveExpression,ue=_t.parseAssignmentExpression,re=_t.parseBitwiseANDExpression,ae=_t.parseBitwiseORExpression,ie=_t.parseBitwiseXORExpression,he=_t.parseBlock,Fe=_t.parseFunctionSourceElements,Ie=_t.parseCatchClause,q=_t.parseComputedMember,le=_t.parseConditionalExpression,ye=_t.parseConstLetDeclaration,ne=_t.parseEqualityExpression,ce=_t.parseExpression,ke=_t.parseForVariableDeclaration,De=_t.parseFunctionDeclaration,Re=_t.parseFunctionExpression,M=_t.parseGroupExpression,K=_t.parseLeftHandSideExpression,J=_t.parseLeftHandSideExpressionAllowCall,oe=_t.parseLogicalANDExpression,se=_t.parseLogicalORExpression,Z=_t.parseMultiplicativeExpression,G=_t.parseNewExpression,W=_t.parseNonComputedProperty,B=_t.parseObjectProperty,R=_t.parseObjectPropertyKey,V=_t.parsePrimaryExpression,Q=_t.parsePostfixExpression,Me=_t.parseProgram,D=_t.parsePropertyFunction,te=_t.parseRelationalExpression,Te=_t.parseStatement,ee=_t.parseShiftExpression,Ae=_t.parseSwitchCase,X=_t.parseUnaryExpression,de=_t.parseVariableDeclaration,fe=_t.parseVariableIdentifier),"function"==typeof _t.scanRegExp&&(w=_t.advance,_=_t.scanRegExp)}function it(e){var t,n=e.length,r=[];for(t=0;n>t;++t)r[t]=e.charAt(t);return r}function at(e,t){var n,r;r=String,"string"==typeof e||e instanceof String||(e=r(e)),ht=e,dt=0,vt=ht.length>0?1:0,mt=0,yt=ht.length,gt=null,bt={allowIn:!0,labelSet:{},inFunctionBody:!1,inIteration:!1,inSwitch:!1},_t={},"undefined"!=typeof t&&(_t.range="boolean"==typeof t.range&&t.range,_t.loc="boolean"==typeof t.loc&&t.loc,_t.raw="boolean"==typeof t.raw&&t.raw,"boolean"==typeof t.tokens&&t.tokens&&(_t.tokens=[]),"boolean"==typeof t.comment&&t.comment&&(_t.comments=[]),"boolean"==typeof t.tolerant&&t.tolerant&&(_t.errors=[])),yt>0&&"undefined"==typeof ht[0]&&(e instanceof String&&(ht=e.valueOf()),"undefined"==typeof ht[0]&&(ht=it(e))),nt();try{n=Me(),"undefined"!=typeof _t.comments&&(We(),n.comments=_t.comments),"undefined"!=typeof _t.tokens&&(Ge(),n.tokens=_t.tokens),"undefined"!=typeof _t.errors&&(n.errors=_t.errors),(_t.range||_t.loc)&&(n.body=et(n.body))}catch(i){throw i}finally{rt(),_t={}}return n}var ot,st,lt,ut,ct,pt,ht,ft,dt,vt,mt,yt,gt,bt,_t;ot={BooleanLiteral:1,EOF:2,Identifier:3,Keyword:4,NullLiteral:5,NumericLiteral:6,Punctuator:7,StringLiteral:8},st={},st[ot.BooleanLiteral]="Boolean",st[ot.EOF]="<end>",st[ot.Identifier]="Identifier",st[ot.Keyword]="Keyword",st[ot.NullLiteral]="Null",st[ot.NumericLiteral]="Numeric",st[ot.Punctuator]="Punctuator",st[ot.StringLiteral]="String",lt={AssignmentExpression:"AssignmentExpression",ArrayExpression:"ArrayExpression",BlockStatement:"BlockStatement",BinaryExpression:"BinaryExpression",BreakStatement:"BreakStatement",CallExpression:"CallExpression",CatchClause:"CatchClause",ConditionalExpression:"ConditionalExpression",ContinueStatement:"ContinueStatement",DoWhileStatement:"DoWhileStatement",DebuggerStatement:"DebuggerStatement",EmptyStatement:"EmptyStatement",ExpressionStatement:"ExpressionStatement",ForStatement:"ForStatement",ForInStatement:"ForInStatement",FunctionDeclaration:"FunctionDeclaration",FunctionExpression:"FunctionExpression",Identifier:"Identifier",IfStatement:"IfStatement",Literal:"Literal",LabeledStatement:"LabeledStatement",LogicalExpression:"LogicalExpression",MemberExpression:"MemberExpression",NewExpression:"NewExpression",ObjectExpression:"ObjectExpression",Program:"Program",Property:"Property",ReturnStatement:"ReturnStatement",SequenceExpression:"SequenceExpression",SwitchStatement:"SwitchStatement",SwitchCase:"SwitchCase",ThisExpression:"ThisExpression",ThrowStatement:"ThrowStatement",TryStatement:"TryStatement",UnaryExpression:"UnaryExpression",UpdateExpression:"UpdateExpression",VariableDeclaration:"VariableDeclaration",VariableDeclarator:"VariableDeclarator",WhileStatement:"WhileStatement",WithStatement:"WithStatement"},ut={Data:1,Get:2,Set:4},ct={UnexpectedToken:"Unexpected token %0",UnexpectedNumber:"Unexpected number",UnexpectedString:"Unexpected string",UnexpectedIdentifier:"Unexpected identifier",UnexpectedReserved:"Unexpected reserved word",UnexpectedEOS:"Unexpected end of input",NewlineAfterThrow:"Illegal newline after throw",InvalidRegExp:"Invalid regular expression",UnterminatedRegExp:"Invalid regular expression: missing /",InvalidLHSInAssignment:"Invalid left-hand side in assignment",InvalidLHSInForIn:"Invalid left-hand side in for-in",MultipleDefaultsInSwitch:"More than one default clause in switch statement",NoCatchOrFinally:"Missing catch or finally after try",UnknownLabel:"Undefined label '%0'",Redeclaration:"%0 '%1' has already been declared",IllegalContinue:"Illegal continue statement",IllegalBreak:"Illegal break statement",IllegalReturn:"Illegal return statement",StrictModeWith:"Strict mode code may not include a with statement",StrictCatchVariable:"Catch variable may not be eval or arguments in strict mode",StrictVarName:"Variable name may not be eval or arguments in strict mode",StrictParamName:"Parameter name eval or arguments is not allowed in strict mode",StrictParamDupe:"Strict mode function may not have duplicate parameter names",StrictFunctionName:"Function name may not be eval or arguments in strict mode",StrictOctalLiteral:"Octal literals are not allowed in strict mode.",StrictDelete:"Delete of an unqualified identifier in strict mode.",StrictDuplicateProperty:"Duplicate data property in object literal not allowed in strict mode",AccessorDataProperty:"Object literal may not have data and accessor property with the same name",AccessorGetSet:"Object literal may not have multiple get/set accessors with the same name",StrictLHSAssignment:"Assignment to eval or arguments is not allowed in strict mode",StrictLHSPostfix:"Postfix increment/decrement may not have eval or arguments operand in strict mode",StrictLHSPrefix:"Prefix increment/decrement may not have eval or arguments operand in strict mode",StrictReservedWord:"Use of future reserved word in strict mode"},pt={NonAsciiIdentifierStart:new RegExp("[\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05d0-\u05ea\u05f0-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u08a0\u08a2-\u08ac\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097f\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d\u0c58\u0c59\u0c60\u0c61\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d60\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1877\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191c\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19c1-\u19c7\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4b\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1ce9-\u1cec\u1cee-\u1cf1\u1cf5\u1cf6\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2e2f\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua697\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa80-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc]"),NonAsciiIdentifierPart:new RegExp("[\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0300-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u0483-\u0487\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u05d0-\u05ea\u05f0-\u05f2\u0610-\u061a\u0620-\u0669\u066e-\u06d3\u06d5-\u06dc\u06df-\u06e8\u06ea-\u06fc\u06ff\u0710-\u074a\u074d-\u07b1\u07c0-\u07f5\u07fa\u0800-\u082d\u0840-\u085b\u08a0\u08a2-\u08ac\u08e4-\u08fe\u0900-\u0963\u0966-\u096f\u0971-\u0977\u0979-\u097f\u0981-\u0983\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bc-\u09c4\u09c7\u09c8\u09cb-\u09ce\u09d7\u09dc\u09dd\u09df-\u09e3\u09e6-\u09f1\u0a01-\u0a03\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a59-\u0a5c\u0a5e\u0a66-\u0a75\u0a81-\u0a83\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abc-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ad0\u0ae0-\u0ae3\u0ae6-\u0aef\u0b01-\u0b03\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3c-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b56\u0b57\u0b5c\u0b5d\u0b5f-\u0b63\u0b66-\u0b6f\u0b71\u0b82\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd0\u0bd7\u0be6-\u0bef\u0c01-\u0c03\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d-\u0c44\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c58\u0c59\u0c60-\u0c63\u0c66-\u0c6f\u0c82\u0c83\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbc-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0cde\u0ce0-\u0ce3\u0ce6-\u0cef\u0cf1\u0cf2\u0d02\u0d03\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d-\u0d44\u0d46-\u0d48\u0d4a-\u0d4e\u0d57\u0d60-\u0d63\u0d66-\u0d6f\u0d7a-\u0d7f\u0d82\u0d83\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0df2\u0df3\u0e01-\u0e3a\u0e40-\u0e4e\u0e50-\u0e59\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb9\u0ebb-\u0ebd\u0ec0-\u0ec4\u0ec6\u0ec8-\u0ecd\u0ed0-\u0ed9\u0edc-\u0edf\u0f00\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f3e-\u0f47\u0f49-\u0f6c\u0f71-\u0f84\u0f86-\u0f97\u0f99-\u0fbc\u0fc6\u1000-\u1049\u1050-\u109d\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u135d-\u135f\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176c\u176e-\u1770\u1772\u1773\u1780-\u17d3\u17d7\u17dc\u17dd\u17e0-\u17e9\u180b-\u180d\u1810-\u1819\u1820-\u1877\u1880-\u18aa\u18b0-\u18f5\u1900-\u191c\u1920-\u192b\u1930-\u193b\u1946-\u196d\u1970-\u1974\u1980-\u19ab\u19b0-\u19c9\u19d0-\u19d9\u1a00-\u1a1b\u1a20-\u1a5e\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1aa7\u1b00-\u1b4b\u1b50-\u1b59\u1b6b-\u1b73\u1b80-\u1bf3\u1c00-\u1c37\u1c40-\u1c49\u1c4d-\u1c7d\u1cd0-\u1cd2\u1cd4-\u1cf6\u1d00-\u1de6\u1dfc-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u200c\u200d\u203f\u2040\u2054\u2071\u207f\u2090-\u209c\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d7f-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2de0-\u2dff\u2e2f\u3005-\u3007\u3021-\u302f\u3031-\u3035\u3038-\u303c\u3041-\u3096\u3099\u309a\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua62b\ua640-\ua66f\ua674-\ua67d\ua67f-\ua697\ua69f-\ua6f1\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua827\ua840-\ua873\ua880-\ua8c4\ua8d0-\ua8d9\ua8e0-\ua8f7\ua8fb\ua900-\ua92d\ua930-\ua953\ua960-\ua97c\ua980-\ua9c0\ua9cf-\ua9d9\uaa00-\uaa36\uaa40-\uaa4d\uaa50-\uaa59\uaa60-\uaa76\uaa7a\uaa7b\uaa80-\uaac2\uaadb-\uaadd\uaae0-\uaaef\uaaf2-\uaaf6\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabea\uabec\uabed\uabf0-\uabf9\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe00-\ufe0f\ufe20-\ufe26\ufe33\ufe34\ufe4d-\ufe4f\ufe70-\ufe74\ufe76-\ufefc\uff10-\uff19\uff21-\uff3a\uff3f\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc]")},"undefined"==typeof"esprima"[0]&&(n=function(e,t){return ht.slice(e,t).join("")}),e.version="1.0.4",e.parse=at,e.Syntax=function(){var e,t={};"function"==typeof Object.create&&(t=Object.create(null));for(e in lt)lt.hasOwnProperty(e)&&(t[e]=lt[e]);return"function"==typeof Object.freeze&&Object.freeze(t),t}()}),e.exports}({exports:{}}),qr=function(e,t){function n(e,t){var n=i(e),r=Object.create(t||{});return f(a(n,r))}function r(e){var t=Object.create(e||{});return function(){var e=Array.prototype.slice.call(arguments),n=e.slice(-1)[0];e=e.slice(0,-1),"string"==typeof n&&(n=m("function a(){"+n+"}").body[0].body);var r=i(n);return h(r,e,t)}}function i(e){var t="string"==typeof e?m(e):e;return y(t)}function a(e,t){function n(e){for(var t=void 0,n=0;n<e.length;n++){var r=e[n];if("EmptyStatement"!==r.type&&(t=i(r),
-t instanceof v))return t}return t}function i(e){if(e)switch(e.type){case"Program":return n(e.body);case"BlockStatement":u();var r=n(e.body);return c(),r;case"FunctionDeclaration":var s=e.params.map(d),p=h(e.body,s,w);return t[e.id.name]=p;case"FunctionExpression":var s=e.params.map(d);return h(e.body,s,w);case"ReturnStatement":var p=i(e.argument);return new v("return",p);case"BreakStatement":return new v("break");case"ContinueStatement":return new v("continue");case"ExpressionStatement":return i(e.expression);case"AssignmentExpression":return m(w,e.left,e.right,e.operator);case"UpdateExpression":return m(w,e.argument,null,e.operator);case"VariableDeclaration":e.declarations.forEach(function(n){var r="let"===e.kind?w:t;n.init?r[n.id.name]=i(n.init):r[n.id.name]=void 0});break;case"SwitchStatement":var y=null,b=!1,p=i(e.discriminant),r=void 0;u();for(var k=0;null==r;)if(k<e.cases.length){if(e.cases[k].test?b=b||i(e.cases[k].test)===p:null==y&&(y=k),b){var S=n(e.cases[k].consequent);if(S instanceof v){if("break"==S.type)break;r=S}}k+=1}else{if(b||null==y)break;k=y,b=!0}return c(),r;case"IfStatement":if(i(e.test))return i(e.consequent);if(e.alternate)return i(e.alternate);case"ForStatement":var C=g(_),r=void 0;for(u(),i(e.init);i(e.test);i(e.update)){var S=i(e.body);if(S instanceof v){if("continue"==S.type)continue;if("break"==S.type)break;r=S;break}C.check()}return c(),r;case"ForInStatement":var C=g(_),r=void 0,p=i(e.right),E=e.left,O=t;u(),"VariableDeclaration"==E.type&&(i(E),E=E.declarations[0].id,"let"===E.kind&&(O=w));for(var $ in p){m(O,E,{type:"Literal",value:$});var S=i(e.body);if(S instanceof v){if("continue"==S.type)continue;if("break"==S.type)break;r=S;break}C.check()}return c(),r;case"WhileStatement":for(var C=g(_);i(e.test);)i(e.body),C.check();break;case"TryStatement":try{i(e.block)}catch(A){u();var N=e.handlers[0];N&&(w[N.param.name]=A,i(N.body)),c()}finally{e.finalizer&&i(e.finalizer)}break;case"Literal":return e.value;case"UnaryExpression":var L=i(e.argument);switch(e.operator){case"+":return+L;case"-":return-L;case"~":return~L;case"!":return!L;case"typeof":return typeof L;default:return o(e)}case"ArrayExpression":for(var I=w.Array(),k=0;k<e.elements.length;k++)I.push(i(e.elements[k]));return I;case"ObjectExpression":for(var I=w.Object(),k=0;k<e.properties.length;k++){var P=e.properties[k],p=null===P.value?P.value:i(P.value);I[P.key.value||P.key.name]=p}return I;case"NewExpression":var j=e.arguments.map(function(e){return i(e)}),O=i(e.callee);return x.applyNew(O,j);case"BinaryExpression":var T=i(e.left),S=i(e.right);switch(e.operator){case"==":return T===S;case"===":return T===S;case"!=":return T!=S;case"!==":return T!==S;case"+":return T+S;case"-":return T-S;case"*":return T*S;case"/":return T/S;case"%":return T%S;case"<":return S>T;case"<=":return S>=T;case">":return T>S;case">=":return T>=S;case"|":return T|S;case"&":return T&S;case"^":return T^S;case"instanceof":return T instanceof S;default:return o(e)}case"LogicalExpression":switch(e.operator){case"&&":return i(e.left)&&i(e.right);case"||":return i(e.left)||i(e.right);default:return o(e)}case"ThisExpression":return w["this"];case"Identifier":if("undefined"===e.name)return;if(l(w,e.name,x))return f(w[e.name]);throw new ReferenceError(e.name+" is not defined");case"CallExpression":var j=e.arguments.map(function(e){return i(e)}),F=null,O=i(e.callee);return"MemberExpression"===e.callee.type&&(F=i(e.callee.object)),O.apply(F,j);case"MemberExpression":var I=i(e.object);if(e.computed)var P=i(e.property);else var P=e.property.name;return I=x.getPropertyObject(I,P),a(I[P]);case"ConditionalExpression":var L=i(e.test);return i(L?e.consequent:e.alternate);case"EmptyStatement":return;default:return o(e)}}function a(e){return e===Gr&&(e=y),f(e)}function u(){w=Object.create(w)}function c(){w=Object.getPrototypeOf(w)}function m(e,t,n,r){var a=null;if("Identifier"===t.type?(a=t.name,e=s(e,a,x)):"MemberExpression"===t.type&&(a=t.computed?i(t.property):t.property.name,e=i(t.object)),p(e,a,x))switch(r){case void 0:return e[a]=i(n);case"=":return e[a]=i(n);case"+=":return e[a]+=i(n);case"-=":return e[a]-=i(n);case"++":return e[a]++;case"--":return e[a]--}}var y=r(t),x=b(t),w=t;return i(e)}function o(e){console.error(e);var t=new Error("Unsupported expression: "+e.type);throw t.node=e,t}function s(e,t,n){var r=n.getPrototypeOf(e);return!r||u(e,t)?e:s(r,t,n)}function l(e,t,n){var r=n.getPrototypeOf(e),i=u(e,t);return void 0!==e[t]?!0:!r||i?i:l(r,t,n)}function u(e,t){return Object.prototype.hasOwnProperty.call(e,t)}function c(e,t){return Object.prototype.propertyIsEnumerable.call(e,t)}function p(e,t,n){return"__proto__"===t||n.isPrimitive(e)?!1:null!=e?u(e,t)?!!c(e,t):p(n.getPrototypeOf(e),t,n):!0}function h(e,n,r){return function(){var i=Object.create(r);this==t?i["this"]=null:i["this"]=this;var o=Array.prototype.slice.call(arguments);i.arguments=arguments,o.forEach(function(e,t){var r=n[t];r&&(i[r]=e)});var s=a(e,i);return s instanceof v?s.value:void 0}}function f(e){return e instanceof v?e.value:e}function d(e){return e.name}function v(e,t){this.type=e,this.value=t}var m=(e.exports,zr.parse),y=Wr,g=Hr,b=Vr;e.exports=n,e.exports.FunctionFactory=r,e.exports.Function=r();var _=1e6;return e.exports}({exports:{}},Mr),Gr=qr.Function,Jr=new k(1e3),Kr=0,Qr=1,Xr=2,Zr=3,Yr=0,ei=1,ti=2,ni=3,ri=4,ii=5,ai=6,oi=7,si=8,li=[];li[Yr]={ws:[Yr],ident:[ni,Kr],"[":[ri],eof:[oi]},li[ei]={ws:[ei],".":[ti],"[":[ri],eof:[oi]},li[ti]={ws:[ti],ident:[ni,Kr]},li[ni]={ident:[ni,Kr],0:[ni,Kr],number:[ni,Kr],ws:[ei,Qr],".":[ti,Qr],"[":[ri,Qr],eof:[oi,Qr]},li[ri]={"'":[ii,Kr],'"':[ai,Kr],"[":[ri,Xr],"]":[ei,Zr],eof:si,"else":[ri,Kr]},li[ii]={"'":[ri,Kr],eof:si,"else":[ii,Kr]},li[ai]={'"':[ri,Kr],eof:si,"else":[ai,Kr]};var ui=Object.freeze({parsePath:Ae,getPath:Ne,setPath:Le}),ci=new k(1e3),pi="Math,Date,this,true,false,null,undefined,Infinity,NaN,isNaN,isFinite,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,parseInt,parseFloat",hi=new RegExp("^("+pi.replace(/,/g,"\\b|")+"\\b)"),fi="break,case,class,catch,const,continue,debugger,default,delete,do,else,export,extends,finally,for,function,if,import,in,instanceof,let,return,super,switch,throw,try,var,while,with,yield,enum,await,implements,package,protected,static,interface,private,public",di=new RegExp("^("+fi.replace(/,/g,"\\b|")+"\\b)"),vi=/\s/g,mi=/\n/g,yi=/[\{,]\s*[\w\$_]+\s*:|('(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"|`(?:[^`\\]|\\.)*\$\{|\}(?:[^`\\]|\\.)*`|`(?:[^`\\]|\\.)*`)|new |typeof |void /g,gi=/"(\d+)"/g,bi=/^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\['.*?'\]|\[".*?"\]|\[\d+\]|\[[A-Za-z_$][\w$]*\])*$/,_i=/[^\w$\.](?:[A-Za-z_$][\w$]*)/g,xi=/^(?:true|false|null|undefined|Infinity|NaN)$/,wi=[],ki=Object.freeze({parseExpression:Be,isSimplePath:Ue}),Si=[],Ci=[],Ei={},Oi={},$i=!1,Ai=0;ze.prototype.get=function(){this.beforeGet();var e,t=this.scope||this.vm;try{e=this.getter.call(t,t)}catch(n){}return this.deep&&qe(e),this.preProcess&&(e=this.preProcess(e)),this.filters&&(e=t._applyFilters(e,null,this.filters,!1)),this.postProcess&&(e=this.postProcess(e)),this.afterGet(),e},ze.prototype.set=function(e){var t=this.scope||this.vm;this.filters&&(e=t._applyFilters(e,this.value,this.filters,!0));try{this.setter.call(t,t,e)}catch(n){}var r=t.$forContext;if(r&&r.alias===this.expression){if(r.filters)return;r._withLock(function(){t.$key?r.rawValue[t.$key]=e:r.rawValue.$set(t.$index,e)})}},ze.prototype.beforeGet=function(){ge.target=this},ze.prototype.addDep=function(e){var t=e.id;this.newDepIds.has(t)||(this.newDepIds.add(t),this.newDeps.push(e),this.depIds.has(t)||e.addSub(this))},ze.prototype.afterGet=function(){ge.target=null;for(var e=this.deps.length;e--;){var t=this.deps[e];this.newDepIds.has(t.id)||t.removeSub(this)}var n=this.depIds;this.depIds=this.newDepIds,this.newDepIds=n,this.newDepIds.clear(),n=this.deps,this.deps=this.newDeps,this.newDeps=n,this.newDeps.length=0},ze.prototype.update=function(e){this.lazy?this.dirty=!0:this.sync||!Er.async?this.run():(this.shallow=this.queued?e?this.shallow:!1:!!e,this.queued=!0,We(this))},ze.prototype.run=function(){if(this.active){var e=this.get();if(e!==this.value||(m(e)||this.deep)&&!this.shallow){var t=this.value;this.value=e;this.prevError;this.cb.call(this.vm,e,t)}this.queued=this.shallow=!1}},ze.prototype.evaluate=function(){var e=ge.target;this.value=this.get(),this.dirty=!1,ge.target=e},ze.prototype.depend=function(){for(var e=this.deps.length;e--;)this.deps[e].depend()},ze.prototype.teardown=function(){if(this.active){this.vm._isBeingDestroyed||this.vm._vForRemoving||this.vm._watchers.$remove(this);for(var e=this.deps.length;e--;)this.deps[e].removeSub(this);this.active=!1,this.vm=this.cb=this.value=null}};var Ni=new er,Li={bind:function(){this.attr=3===this.el.nodeType?"data":"textContent"},update:function(e){this.el[this.attr]=a(e)}},Ii=new k(1e3),Pi=new k(1e3),ji={efault:[0,"",""],legend:[1,"<fieldset>","</fieldset>"],tr:[2,"<table><tbody>","</tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"]};ji.td=ji.th=[3,"<table><tbody><tr>","</tr></tbody></table>"],ji.option=ji.optgroup=[1,'<select multiple="multiple">',"</select>"],ji.thead=ji.tbody=ji.colgroup=ji.caption=ji.tfoot=[1,"<table>","</table>"],ji.g=ji.defs=ji.symbol=ji.use=ji.image=ji.text=ji.circle=ji.ellipse=ji.line=ji.path=ji.polygon=ji.polyline=ji.rect=[1,'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ev="http://www.w3.org/2001/xml-events"version="1.1">',"</svg>"];var Ti=/<([\w:-]+)/,Fi=/&#?\w+?;/,Di=/<!--/,Ri=function(){if(Dn){var e=document.createElement("div");return e.innerHTML="<template>1</template>",!e.cloneNode(!0).firstChild.innerHTML}return!1}(),Bi=function(){if(Dn){var e=document.createElement("textarea");return e.placeholder="t","t"===e.cloneNode(!0).value}return!1}(),Ui=Object.freeze({cloneNode:Qe,parseTemplate:Xe}),Mi={bind:function(){8===this.el.nodeType&&(this.nodes=[],this.anchor=re("v-html"),q(this.el,this.anchor))},update:function(e){e=a(e),this.nodes?this.swap(e):this.el.innerHTML=e},swap:function(e){for(var t=this.nodes.length;t--;)W(this.nodes[t]);var n=Xe(e,!0,!0);this.nodes=d(n.childNodes),V(n,this.anchor)}};Ze.prototype.callHook=function(e){var t,n;for(t=0,n=this.childFrags.length;n>t;t++)this.childFrags[t].callHook(e);for(t=0,n=this.children.length;n>t;t++)e(this.children[t])},Ze.prototype.beforeRemove=function(){var e,t;for(e=0,t=this.childFrags.length;t>e;e++)this.childFrags[e].beforeRemove(!1);for(e=0,t=this.children.length;t>e;e++)this.children[e].$destroy(!1,!0);var n=this.unlink.dirs;for(e=0,t=n.length;t>e;e++)n[e]._watcher&&n[e]._watcher.teardown()},Ze.prototype.destroy=function(){this.parentFrag&&this.parentFrag.childFrags.$remove(this),this.node.__v_frag=null,this.unlink()};var Vi=new k(5e3);at.prototype.create=function(e,t,n){var r=Qe(this.template);return new Ze(this.linker,this.vm,r,e,t,n)};var Hi=700,Wi=800,zi=850,qi=1100,Gi=1500,Ji=1500,Ki=1750,Qi=2100,Xi=2200,Zi=2300,Yi=0,ea={priority:Xi,terminal:!0,params:["track-by","stagger","enter-stagger","leave-stagger"],bind:function(){var e=this.expression.match(/(.*) (?:in|of) (.*)/);if(e){var t=e[1].match(/\((.*),(.*)\)/);t?(this.iterator=t[1].trim(),this.alias=t[2].trim()):this.alias=e[1].trim(),this.expression=e[2]}if(this.alias){this.id="__v-for__"+ ++Yi;var n=this.el.tagName;this.isOption=("OPTION"===n||"OPTGROUP"===n)&&"SELECT"===this.el.parentNode.tagName,this.start=re("v-for-start"),this.end=re("v-for-end"),q(this.el,this.end),V(this.start,this.end),this.cache=Object.create(null),this.factory=new at(this.vm,this.el)}},update:function(e){this.diff(e),this.updateRef(),this.updateModel()},diff:function(e){var t,r,i,a,o,s,l=e[0],u=this.fromObject=m(l)&&n(l,"$key")&&n(l,"$value"),c=this.params.trackBy,p=this.frags,h=this.frags=new Array(e.length),f=this.alias,d=this.iterator,v=this.start,y=this.end,g=R(v),b=!p;for(t=0,r=e.length;r>t;t++)l=e[t],a=u?l.$key:null,o=u?l.$value:l,s=!m(o),i=!b&&this.getCachedFrag(o,t,a),i?(i.reused=!0,i.scope.$index=t,a&&(i.scope.$key=a),d&&(i.scope[d]=null!==a?a:t),(c||u||s)&&be(function(){i.scope[f]=o})):(i=this.create(o,f,t,a),i.fresh=!b),h[t]=i,b&&i.before(y);if(!b){var _=0,x=p.length-h.length;for(this.vm._vForRemoving=!0,t=0,r=p.length;r>t;t++)i=p[t],i.reused||(this.deleteCachedFrag(i),this.remove(i,_++,x,g));this.vm._vForRemoving=!1,_&&(this.vm._watchers=this.vm._watchers.filter(function(e){return e.active}));var w,k,S,C=0;for(t=0,r=h.length;r>t;t++)i=h[t],w=h[t-1],k=w?w.staggerCb?w.staggerAnchor:w.end||w.node:v,i.reused&&!i.staggerCb?(S=ot(i,v,this.id),S===w||S&&ot(S,v,this.id)===w||this.move(i,k)):this.insert(i,C++,k,g),i.reused=i.fresh=!1}},create:function(e,t,n,r){var i=this._host,a=this._scope||this.vm,o=Object.create(a);o.$refs=Object.create(a.$refs),o.$els=Object.create(a.$els),o.$parent=a,o.$forContext=this,be(function(){Se(o,t,e)}),Se(o,"$index",n),r?Se(o,"$key",r):o.$key&&g(o,"$key",null),this.iterator&&Se(o,this.iterator,null!==r?r:n);var s=this.factory.create(i,o,this._frag);return s.forId=this.id,this.cacheFrag(e,s,n,r),s},updateRef:function(){var e=this.descriptor.ref;if(e){var t,n=(this._scope||this.vm).$refs;this.fromObject?(t={},this.frags.forEach(function(e){t[e.scope.$key]=st(e)})):t=this.frags.map(st),n[e]=t}},updateModel:function(){if(this.isOption){var e=this.start.parentNode,t=e&&e.__v_model;t&&t.forceUpdate()}},insert:function(e,t,n,r){e.staggerCb&&(e.staggerCb.cancel(),e.staggerCb=null);var i=this.getStagger(e,t,null,"enter");if(r&&i){var a=e.staggerAnchor;a||(a=e.staggerAnchor=re("stagger-anchor"),a.__v_frag=e),H(a,n);var o=e.staggerCb=x(function(){e.staggerCb=null,e.before(a),W(a)});setTimeout(o,i)}else{var s=n.nextSibling;s||(H(this.end,n),s=this.end),e.before(s)}},remove:function(e,t,n,r){if(e.staggerCb)return e.staggerCb.cancel(),void(e.staggerCb=null);var i=this.getStagger(e,t,n,"leave");if(r&&i){var a=e.staggerCb=x(function(){e.staggerCb=null,e.remove()});setTimeout(a,i)}else e.remove()},move:function(e,t){t.nextSibling||this.end.parentNode.appendChild(this.end),e.before(t.nextSibling,!1)},cacheFrag:function(e,t,r,i){var a,o=this.params.trackBy,s=this.cache,l=!m(e);i||o||l?(a=ut(r,i,e,o),s[a]||(s[a]=t)):(a=this.id,n(e,a)?null===e[a]&&(e[a]=t):Object.isExtensible(e)&&g(e,a,t)),t.raw=e},getCachedFrag:function(e,t,n){var r,i=this.params.trackBy,a=!m(e);if(n||i||a){var o=ut(t,n,e,i);r=this.cache[o]}else r=e[this.id];return r&&(r.reused||r.fresh),r},deleteCachedFrag:function(e){var t=e.raw,r=this.params.trackBy,i=e.scope,a=i.$index,o=n(i,"$key")&&i.$key,s=!m(t);if(r||o||s){var l=ut(a,o,t,r);this.cache[l]=null}else t[this.id]=null,e.raw=null},getStagger:function(e,t,n,r){r+="Stagger";var i=e.node.__v_trans,a=i&&i.hooks,o=a&&(a[r]||a.stagger);return o?o.call(e,t,n):t*parseInt(this.params[r]||this.params.stagger,10)},_preProcess:function(e){return this.rawValue=e,e},_postProcess:function(e){if(Tn(e))return e;if(y(e)){for(var t,n=Object.keys(e),r=n.length,i=new Array(r);r--;)t=n[r],i[r]={$key:t,$value:e[t]};return i}return"number"!=typeof e||isNaN(e)||(e=lt(e)),e||[]},unbind:function(){if(this.descriptor.ref&&((this._scope||this.vm).$refs[this.descriptor.ref]=null),this.frags)for(var e,t=this.frags.length;t--;)e=this.frags[t],this.deleteCachedFrag(e),e.destroy()}},ta={priority:Qi,terminal:!0,bind:function(){var e=this.el;if(e.__vue__)this.invalid=!0;else{var t=e.nextElementSibling;t&&null!==B(t,"v-else")&&(W(t),this.elseEl=t),this.anchor=re("v-if"),q(e,this.anchor)}},update:function(e){this.invalid||(e?this.frag||this.insert():this.remove())},insert:function(){this.elseFrag&&(this.elseFrag.remove(),this.elseFrag=null),this.factory||(this.factory=new at(this.vm,this.el)),this.frag=this.factory.create(this._host,this._scope,this._frag),this.frag.before(this.anchor)},remove:function(){this.frag&&(this.frag.remove(),this.frag=null),this.elseEl&&!this.elseFrag&&(this.elseFactory||(this.elseFactory=new at(this.elseEl._context||this.vm,this.elseEl)),this.elseFrag=this.elseFactory.create(this._host,this._scope,this._frag),this.elseFrag.before(this.anchor))},unbind:function(){this.frag&&this.frag.destroy(),this.elseFrag&&this.elseFrag.destroy()}},na={bind:function(){var e=this.el.nextElementSibling;e&&null!==B(e,"v-else")&&(this.elseEl=e)},update:function(e){this.apply(this.el,e),this.elseEl&&this.apply(this.elseEl,!e)},apply:function(e,t){function n(){e.style.display=t?"":"none"}R(e)?F(e,t?1:-1,n,this.vm):n()}},ra={bind:function(){var e=this,t=this.el,n="range"===t.type,r=this.params.lazy,i=this.params.number,a=this.params.debounce,s=!1;if(Vn||n||(this.on("compositionstart",function(){s=!0}),this.on("compositionend",function(){s=!1,r||e.listener()})),this.focused=!1,n||r||(this.on("focus",function(){e.focused=!0}),this.on("blur",function(){e.focused=!1,e._frag&&!e._frag.inserted||e.rawListener()})),this.listener=this.rawListener=function(){if(!s&&e._bound){var r=i||n?o(t.value):t.value;e.set(r),Yn(function(){e._bound&&!e.focused&&e.update(e._watcher.value)})}},a&&(this.listener=b(this.listener,a)),this.hasjQuery="function"==typeof jQuery,this.hasjQuery){var l=jQuery.fn.on?"on":"bind";jQuery(t)[l]("change",this.rawListener),r||jQuery(t)[l]("input",this.listener)}else this.on("change",this.rawListener),r||this.on("input",this.listener);!r&&Mn&&(this.on("cut",function(){Yn(e.listener)}),this.on("keyup",function(t){46!==t.keyCode&&8!==t.keyCode||e.listener()})),(t.hasAttribute("value")||"TEXTAREA"===t.tagName&&t.value.trim())&&(this.afterBind=this.listener)},update:function(e){e=a(e),e!==this.el.value&&(this.el.value=e)},unbind:function(){var e=this.el;if(this.hasjQuery){var t=jQuery.fn.off?"off":"unbind";jQuery(e)[t]("change",this.listener),jQuery(e)[t]("input",this.listener)}}},ia={bind:function(){var e=this,t=this.el;this.getValue=function(){if(t.hasOwnProperty("_value"))return t._value;var n=t.value;return e.params.number&&(n=o(n)),n},this.listener=function(){e.set(e.getValue())},this.on("change",this.listener),t.hasAttribute("checked")&&(this.afterBind=this.listener)},update:function(e){this.el.checked=w(e,this.getValue())}},aa={bind:function(){var e=this,t=this,n=this.el;this.forceUpdate=function(){t._watcher&&t.update(t._watcher.get())};var r=this.multiple=n.hasAttribute("multiple");this.listener=function(){var e=ct(n,r);e=t.params.number?Tn(e)?e.map(o):o(e):e,t.set(e)},this.on("change",this.listener);var i=ct(n,r,!0);(r&&i.length||!r&&null!==i)&&(this.afterBind=this.listener),this.vm.$on("hook:attached",function(){Yn(e.forceUpdate)}),R(n)||Yn(this.forceUpdate)},update:function(e){var t=this.el;t.selectedIndex=-1;for(var n,r,i=this.multiple&&Tn(e),a=t.options,o=a.length;o--;)n=a[o],r=n.hasOwnProperty("_value")?n._value:n.value,n.selected=i?pt(e,r)>-1:w(e,r)},unbind:function(){this.vm.$off("hook:attached",this.forceUpdate)}},oa={bind:function(){function e(){var e=n.checked;return e&&n.hasOwnProperty("_trueValue")?n._trueValue:!e&&n.hasOwnProperty("_falseValue")?n._falseValue:e}var t=this,n=this.el;this.getValue=function(){return n.hasOwnProperty("_value")?n._value:t.params.number?o(n.value):n.value},this.listener=function(){var r=t._watcher.value;if(Tn(r)){var i=t.getValue();n.checked?_(r,i)<0&&r.push(i):r.$remove(i)}else t.set(e())},this.on("change",this.listener),n.hasAttribute("checked")&&(this.afterBind=this.listener)},update:function(e){var t=this.el;Tn(e)?t.checked=_(e,this.getValue())>-1:t.hasOwnProperty("_trueValue")?t.checked=w(e,t._trueValue):t.checked=!!e}},sa={text:ra,radio:ia,select:aa,checkbox:oa},la={priority:Wi,twoWay:!0,handlers:sa,params:["lazy","number","debounce"],bind:function(){this.checkFilters(),this.hasRead&&!this.hasWrite;var e,t=this.el,n=t.tagName;if("INPUT"===n)e=sa[t.type]||sa.text;else if("SELECT"===n)e=sa.select;else{if("TEXTAREA"!==n)return;e=sa.text}t.__v_model=this,e.bind.call(this),this.update=e.update,this._unbind=e.unbind},checkFilters:function(){var e=this.filters;if(e)for(var t=e.length;t--;){var n=ye(this.vm.$options,"filters",e[t].name);("function"==typeof n||n.read)&&(this.hasRead=!0),n.write&&(this.hasWrite=!0)}},unbind:function(){this.el.__v_model=null,this._unbind&&this._unbind()}},ua={esc:27,tab:9,enter:13,space:32,"delete":[8,46],up:38,left:37,right:39,down:40},ca={priority:Hi,acceptStatement:!0,keyCodes:ua,bind:function(){if("IFRAME"===this.el.tagName&&"load"!==this.arg){var e=this;this.iframeBind=function(){G(e.el.contentWindow,e.arg,e.handler,e.modifiers.capture)},this.on("load",this.iframeBind)}},update:function(e){if(this.descriptor.raw||(e=function(){}),"function"==typeof e){this.modifiers.stop&&(e=ft(e)),this.modifiers.prevent&&(e=dt(e)),this.modifiers.self&&(e=vt(e));var t=Object.keys(this.modifiers).filter(function(e){return"stop"!==e&&"prevent"!==e&&"self"!==e&&"capture"!==e});t.length&&(e=ht(e,t)),this.reset(),this.handler=e,this.iframeBind?this.iframeBind():G(this.el,this.arg,this.handler,this.modifiers.capture)}},reset:function(){var e=this.iframeBind?this.el.contentWindow:this.el;this.handler&&J(e,this.arg,this.handler)},unbind:function(){this.reset()}},pa=["-webkit-","-moz-","-ms-"],ha=["Webkit","Moz","ms"],fa=/!important;?$/,da=Object.create(null),va=null,ma={deep:!0,update:function(e){"string"==typeof e?this.el.style.cssText=e:Tn(e)?this.handleObject(e.reduce(v,{})):this.handleObject(e||{})},handleObject:function(e){var t,n,r=this.cache||(this.cache={});for(t in r)t in e||(this.handleSingle(t,null),delete r[t]);for(t in e)n=e[t],n!==r[t]&&(r[t]=n,this.handleSingle(t,n))},handleSingle:function(e,t){if(e=mt(e))if(null!=t&&(t+=""),t){var n=fa.test(t)?"important":"";n?(t=t.replace(fa,"").trim(),this.el.style.setProperty(e.kebab,t,n)):this.el.style[e.camel]=t}else this.el.style[e.camel]=""}},ya="http://www.w3.org/1999/xlink",ga=/^xlink:/,ba=/^v-|^:|^@|^(?:is|transition|transition-mode|debounce|track-by|stagger|enter-stagger|leave-stagger)$/,_a=/^(?:value|checked|selected|muted)$/,xa=/^(?:draggable|contenteditable|spellcheck)$/,wa={value:"_value","true-value":"_trueValue","false-value":"_falseValue"},ka={priority:zi,bind:function(){var e=this.arg,t=this.el.tagName;e||(this.deep=!0);var n=this.descriptor,r=n.interp;r&&(n.hasOneTime&&(this.expression=N(r,this._scope||this.vm)),(ba.test(e)||"name"===e&&("PARTIAL"===t||"SLOT"===t))&&(this.el.removeAttribute(e),this.invalid=!0))},update:function(e){if(!this.invalid){var t=this.arg;this.arg?this.handleSingle(t,e):this.handleObject(e||{})}},handleObject:ma.handleObject,handleSingle:function(e,t){var n=this.el,r=this.descriptor.interp;if(this.modifiers.camel&&(e=u(e)),!r&&_a.test(e)&&e in n){var i="value"===e&&null==t?"":t;n[e]!==i&&(n[e]=i)}var a=wa[e];if(!r&&a){n[a]=t;var o=n.__v_model;o&&o.listener()}return"value"===e&&"TEXTAREA"===n.tagName?void n.removeAttribute(e):void(xa.test(e)?n.setAttribute(e,t?"true":"false"):null!=t&&t!==!1?"class"===e?(n.__v_trans&&(t+=" "+n.__v_trans.id+"-transition"),Q(n,t)):ga.test(e)?n.setAttributeNS(ya,e,t===!0?"":t):n.setAttribute(e,t===!0?"":t):n.removeAttribute(e))}},Sa={priority:Gi,bind:function(){if(this.arg){var e=this.id=u(this.arg),t=(this._scope||this.vm).$els;n(t,e)?t[e]=this.el:Se(t,e,this.el)}},unbind:function(){var e=(this._scope||this.vm).$els;e[this.id]===this.el&&(e[this.id]=null)}},Ca={bind:function(){}},Ea={bind:function(){var e=this.el;this.vm.$once("pre-hook:compiled",function(){e.removeAttribute("v-cloak")})}},Oa={text:Li,html:Mi,"for":ea,"if":ta,show:na,model:la,on:ca,bind:ka,el:Sa,ref:Ca,cloak:Ea},$a={deep:!0,update:function(e){e?"string"==typeof e?this.setClass(e.trim().split(/\s+/)):this.setClass(gt(e)):this.cleanup()},setClass:function(e){this.cleanup(e);for(var t=0,n=e.length;n>t;t++){var r=e[t];r&&bt(this.el,r,X)}this.prevKeys=e},cleanup:function(e){var t=this.prevKeys;if(t)for(var n=t.length;n--;){var r=t[n];(!e||e.indexOf(r)<0)&&bt(this.el,r,Z)}}},Aa={priority:Ji,params:["keep-alive","transition-mode","inline-template"],bind:function(){this.el.__vue__||(this.keepAlive=this.params.keepAlive,this.keepAlive&&(this.cache={}),this.params.inlineTemplate&&(this.inlineTemplate=Y(this.el,!0)),this.pendingComponentCb=this.Component=null,this.pendingRemovals=0,this.pendingRemovalCb=null,this.anchor=re("v-component"),q(this.el,this.anchor),this.el.removeAttribute("is"),this.el.removeAttribute(":is"),this.descriptor.ref&&this.el.removeAttribute("v-ref:"+p(this.descriptor.ref)),this.literal&&this.setComponent(this.expression))},update:function(e){this.literal||this.setComponent(e)},setComponent:function(e,t){if(this.invalidatePending(),e){var n=this;this.resolveComponent(e,function(){n.mountComponent(t)})}else this.unbuild(!0),this.remove(this.childVM,t),this.childVM=null},resolveComponent:function(e,t){var n=this;this.pendingComponentCb=x(function(r){n.ComponentName=r.options.name||("string"==typeof e?e:null),n.Component=r,t()}),this.vm._resolveComponent(e,this.pendingComponentCb)},mountComponent:function(e){this.unbuild(!0);var t=this,n=this.Component.options.activate,r=this.getCached(),i=this.build();n&&!r?(this.waitingFor=i,_t(n,i,function(){t.waitingFor===i&&(t.waitingFor=null,t.transition(i,e))})):(r&&i._updateRef(),this.transition(i,e))},invalidatePending:function(){this.pendingComponentCb&&(this.pendingComponentCb.cancel(),this.pendingComponentCb=null)},build:function(e){var t=this.getCached();if(t)return t;if(this.Component){var n={name:this.ComponentName,el:Qe(this.el),template:this.inlineTemplate,parent:this._host||this.vm,_linkerCachable:!this.inlineTemplate,_ref:this.descriptor.ref,_asComponent:!0,_isRouterView:this._isRouterView,_context:this.vm,_scope:this._scope,_frag:this._frag};e&&v(n,e);var r=new this.Component(n);return this.keepAlive&&(this.cache[this.Component.cid]=r),r}},getCached:function(){return this.keepAlive&&this.cache[this.Component.cid]},unbuild:function(e){this.waitingFor&&(this.keepAlive||this.waitingFor.$destroy(),this.waitingFor=null);var t=this.childVM;return!t||this.keepAlive?void(t&&(t._inactive=!0,t._updateRef(!0))):void t.$destroy(!1,e)},remove:function(e,t){var n=this.keepAlive;if(e){this.pendingRemovals++,this.pendingRemovalCb=t;var r=this;e.$remove(function(){r.pendingRemovals--,n||e._cleanup(),!r.pendingRemovals&&r.pendingRemovalCb&&(r.pendingRemovalCb(),r.pendingRemovalCb=null)})}else t&&t()},transition:function(e,t){var n=this,r=this.childVM;switch(r&&(r._inactive=!0),e._inactive=!1,this.childVM=e,n.params.transitionMode){case"in-out":e.$before(n.anchor,function(){n.remove(r,t)});break;case"out-in":n.remove(r,function(){e.$before(n.anchor,t)});break;default:n.remove(r),e.$before(n.anchor,t)}},unbind:function(){if(this.invalidatePending(),this.unbuild(),this.cache){for(var e in this.cache)this.cache[e].$destroy();this.cache=null}}},Na=Er._propBindingModes,La={},Ia=/^[$_a-zA-Z]+[\w$]*$/,Pa=Er._propBindingModes,ja={bind:function(){var e=this.vm,t=e._context,n=this.descriptor.prop,r=n.path,i=n.parentPath,a=n.mode===Pa.TWO_WAY,o=this.parentWatcher=new ze(t,i,function(t){Ct(e,n,t)},{twoWay:a,filters:n.filters,scope:this._scope});if(St(e,n,o.value),a){var s=this;e.$once("pre-hook:created",function(){s.childWatcher=new ze(e,r,function(e){o.set(e)},{sync:!0})})}},unbind:function(){this.parentWatcher.teardown(),this.childWatcher&&this.childWatcher.teardown()}},Ta=[],Fa=!1,Da="transition",Ra="animation",Ba=Gn+"Duration",Ua=Kn+"Duration",Ma=Dn&&window.requestAnimationFrame,Va=Ma?function(e){Ma(function(){Ma(e)})}:function(e){setTimeout(e,50)},Ha=It.prototype;Ha.enter=function(e,t){this.cancelPending(),this.callHook("beforeEnter"),this.cb=t,X(this.el,this.enterClass),e(),this.entered=!1,this.callHookWithCb("enter"),this.entered||(this.cancel=this.hooks&&this.hooks.enterCancelled,Nt(this.enterNextTick))},Ha.enterNextTick=function(){var e=this;this.justEntered=!0,Va(function(){e.justEntered=!1});var t=this.enterDone,n=this.getCssTransitionType(this.enterClass);this.pendingJsCb?n===Da&&Z(this.el,this.enterClass):n===Da?(Z(this.el,this.enterClass),this.setupCssCb(Jn,t)):n===Ra?this.setupCssCb(Qn,t):t()},Ha.enterDone=function(){this.entered=!0,this.cancel=this.pendingJsCb=null,Z(this.el,this.enterClass),this.callHook("afterEnter"),this.cb&&this.cb()},Ha.leave=function(e,t){this.cancelPending(),this.callHook("beforeLeave"),this.op=e,this.cb=t,X(this.el,this.leaveClass),this.left=!1,this.callHookWithCb("leave"),this.left||(this.cancel=this.hooks&&this.hooks.leaveCancelled,this.op&&!this.pendingJsCb&&(this.justEntered?this.leaveDone():Nt(this.leaveNextTick)))},Ha.leaveNextTick=function(){var e=this.getCssTransitionType(this.leaveClass);if(e){var t=e===Da?Jn:Qn;this.setupCssCb(t,this.leaveDone)}else this.leaveDone()},Ha.leaveDone=function(){this.left=!0,this.cancel=this.pendingJsCb=null,this.op(),Z(this.el,this.leaveClass),this.callHook("afterLeave"),this.cb&&this.cb(),this.op=null},Ha.cancelPending=function(){this.op=this.cb=null;var e=!1;this.pendingCssCb&&(e=!0,J(this.el,this.pendingCssEvent,this.pendingCssCb),this.pendingCssEvent=this.pendingCssCb=null),this.pendingJsCb&&(e=!0,this.pendingJsCb.cancel(),this.pendingJsCb=null),e&&(Z(this.el,this.enterClass),Z(this.el,this.leaveClass)),this.cancel&&(this.cancel.call(this.vm,this.el),this.cancel=null)},Ha.callHook=function(e){this.hooks&&this.hooks[e]&&this.hooks[e].call(this.vm,this.el)},Ha.callHookWithCb=function(e){var t=this.hooks&&this.hooks[e];t&&(t.length>1&&(this.pendingJsCb=x(this[e+"Done"])),t.call(this.vm,this.el,this.pendingJsCb))},Ha.getCssTransitionType=function(e){if(!(!Jn||document.hidden||this.hooks&&this.hooks.css===!1||Pt(this.el))){var t=this.type||this.typeCache[e];if(t)return t;var n=this.el.style,r=window.getComputedStyle(this.el),i=n[Ba]||r[Ba];if(i&&"0s"!==i)t=Da;else{var a=n[Ua]||r[Ua];a&&"0s"!==a&&(t=Ra)}return t&&(this.typeCache[e]=t),t}},Ha.setupCssCb=function(e,t){this.pendingCssEvent=e;var n=this,r=this.el,i=this.pendingCssCb=function(a){a.target===r&&(J(r,e,i),n.pendingCssEvent=n.pendingCssCb=null,!n.pendingJsCb&&t&&t())};G(r,e,i)};var Wa={priority:qi,update:function(e,t){var n=this.el,r=ye(this.vm.$options,"transitions",e);e=e||"v",t=t||"v",n.__v_trans=new It(n,e,r,this.vm),Z(n,t+"-transition"),X(n,e+"-transition")}},za={style:ma,"class":$a,component:Aa,prop:ja,transition:Wa},qa=/^v-bind:|^:/,Ga=/^v-on:|^@/,Ja=/^v-([^:]+)(?:$|:(.*)$)/,Ka=/\.[^\.]+/g,Qa=/^(v-bind:|:)?transition$/,Xa=1e3,Za=2e3;Zt.terminal=!0;var Ya=/[^\w\-:\.]/,eo=Object.freeze({compile:jt,compileAndLinkProps:Bt,compileRoot:Ut,transclude:on,resolveSlots:cn}),to=/^v-on:|^@/;vn.prototype._bind=function(){var e=this.name,t=this.descriptor;if(("cloak"!==e||this.vm._isCompiled)&&this.el&&this.el.removeAttribute){var n=t.attr||"v-"+e;this.el.removeAttribute(n)}var r=t.def;if("function"==typeof r?this.update=r:v(this,r),this._setupParams(),this.bind&&this.bind(),this._bound=!0,this.literal)this.update&&this.update(t.raw);else if((this.expression||this.modifiers)&&(this.update||this.twoWay)&&!this._checkStatement()){var i=this;this.update?this._update=function(e,t){i._locked||i.update(e,t)}:this._update=dn;var a=this._preProcess?f(this._preProcess,this):null,o=this._postProcess?f(this._postProcess,this):null,s=this._watcher=new ze(this.vm,this.expression,this._update,{filters:this.filters,twoWay:this.twoWay,deep:this.deep,preProcess:a,postProcess:o,scope:this._scope});this.afterBind?this.afterBind():this.update&&this.update(s.value)}},vn.prototype._setupParams=function(){if(this.params){var e=this.params;this.params=Object.create(null);for(var t,n,r,i=e.length;i--;)t=p(e[i]),r=u(t),n=U(this.el,t),null!=n?this._setupParamWatcher(r,n):(n=B(this.el,t),null!=n&&(this.params[r]=""===n?!0:n))}},vn.prototype._setupParamWatcher=function(e,t){var n=this,r=!1,i=(this._scope||this.vm).$watch(t,function(t,i){if(n.params[e]=t,r){var a=n.paramWatchers&&n.paramWatchers[e];a&&a.call(n,t,i)}else r=!0},{immediate:!0,user:!1});(this._paramUnwatchFns||(this._paramUnwatchFns=[])).push(i)},vn.prototype._checkStatement=function(){var e=this.expression;if(e&&this.acceptStatement&&!Ue(e)){var t=Be(e).get,n=this._scope||this.vm,r=function(e){n.$event=e,t.call(n,n),n.$event=null};return this.filters&&(r=n._applyFilters(r,null,this.filters)),
-this.update(r),!0}},vn.prototype.set=function(e){this.twoWay&&this._withLock(function(){this._watcher.set(e)})},vn.prototype._withLock=function(e){var t=this;t._locked=!0,e.call(t),Yn(function(){t._locked=!1})},vn.prototype.on=function(e,t,n){G(this.el,e,t,n),(this._listeners||(this._listeners=[])).push([e,t])},vn.prototype._teardown=function(){if(this._bound){this._bound=!1,this.unbind&&this.unbind(),this._watcher&&this._watcher.teardown();var e,t=this._listeners;if(t)for(e=t.length;e--;)J(this.el,t[e][0],t[e][1]);var n=this._paramUnwatchFns;if(n)for(e=n.length;e--;)n[e]();this.vm=this.el=this._watcher=this._listeners=null}};var no=/[^|]\|[^|]/;Ce(wn),hn(wn),fn(wn),mn(wn),yn(wn),gn(wn),bn(wn),_n(wn),xn(wn);var ro={priority:Zi,params:["name"],bind:function(){var e=this.params.name||"default",t=this.vm._slotContents&&this.vm._slotContents[e];t&&t.hasChildNodes()?this.compile(t.cloneNode(!0),this.vm._context,this.vm):this.fallback()},compile:function(e,t,n){if(e&&t){if(this.el.hasChildNodes()&&1===e.childNodes.length&&1===e.childNodes[0].nodeType&&e.childNodes[0].hasAttribute("v-if")){var r=document.createElement("template");r.setAttribute("v-else",""),r.innerHTML=this.el.innerHTML,r._context=this.vm,e.appendChild(r)}var i=n?n._scope:this._scope;this.unlink=t.$compile(e,n,i,this._frag)}e?q(this.el,e):W(this.el)},fallback:function(){this.compile(Y(this.el,!0),this.vm)},unbind:function(){this.unlink&&this.unlink()}},io={priority:Ki,params:["name"],paramWatchers:{name:function(e){ta.remove.call(this),e&&this.insert(e)}},bind:function(){this.anchor=re("v-partial"),q(this.el,this.anchor),this.insert(this.params.name)},insert:function(e){var t=ye(this.vm.$options,"partials",e,!0);t&&(this.factory=new at(this.vm,t),ta.insert.call(this))},unbind:function(){this.frag&&this.frag.destroy()}},ao={slot:ro,partial:io},oo=ea._postProcess,so=/(\d{3})(?=\d)/g,lo={orderBy:Cn,filterBy:Sn,limitBy:kn,json:{read:function(e,t){return"string"==typeof e?e:JSON.stringify(e,null,arguments.length>1?t:2)},write:function(e){try{return JSON.parse(e)}catch(t){return e}}},capitalize:function(e){return e||0===e?(e=e.toString(),e.charAt(0).toUpperCase()+e.slice(1)):""},uppercase:function(e){return e||0===e?e.toString().toUpperCase():""},lowercase:function(e){return e||0===e?e.toString().toLowerCase():""},currency:function(e,t,n){if(e=parseFloat(e),!isFinite(e)||!e&&0!==e)return"";t=null!=t?t:"$",n=null!=n?n:2;var r=Math.abs(e).toFixed(n),i=n?r.slice(0,-1-n):r,a=i.length%3,o=a>0?i.slice(0,a)+(i.length>3?",":""):"",s=n?r.slice(-1-n):"",l=0>e?"-":"";return l+t+o+i.slice(a).replace(so,"$1,")+s},pluralize:function(e){var t=d(arguments,1),n=t.length;if(n>1){var r=e%10-1;return r in t?t[r]:t[n-1]}return t[0]+(1===e?"":"s")},debounce:function(e,t){return e?(t||(t=300),b(e,t)):void 0}};return On(wn),wn.version="1.0.26-csp",setTimeout(function(){Er.devtools&&Rn&&Rn.emit("init",wn)},0),wn});
+(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:/^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\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",/<!--[\s\S]*?-->/)("closed",/<(tag)[\s\S]+?<\/\1>/)("closing",/<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)(/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:/^/,heading:/^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/});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<item.align.length;i++){if(/^ *-+: *$/.test(item.align[i])){item.align[i]="right"}else if(/^ *:-+: *$/.test(item.align[i])){item.align[i]="center"}else if(/^ *:-+ *$/.test(item.align[i])){item.align[i]="left"}else{item.align[i]=null}}for(i=0;i<item.cells.length;i++){item.cells[i]=item.cells[i].split(/ *\| */)}this.tokens.push(item);continue}if(cap=this.rules.lheading.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"heading",depth:cap[2]==="="?1:2,text:cap[1]});continue}if(cap=this.rules.hr.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"hr"});continue}if(cap=this.rules.blockquote.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"blockquote_start"});cap=cap[0].replace(/^ *> ?/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(;i<l;i++){item=cap[i];space=item.length;item=item.replace(/^ *([*+-]|\d+\.) +/,"");if(~item.indexOf("\n ")){space-=item.length;item=!this.options.pedantic?item.replace(new RegExp("^ {1,"+space+"}","gm"),""):item.replace(/^ {1,4}/gm,"")}if(this.options.smartLists&&i!==l-1){b=block.bullet.exec(cap[i+1])[0];if(bull!==b&&!(bull.length>1&&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:!this.options.sanitizer&&(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<item.align.length;i++){if(/^ *-+: *$/.test(item.align[i])){item.align[i]="right"}else if(/^ *:-+: *$/.test(item.align[i])){item.align[i]="center"}else if(/^ *:-+ *$/.test(item.align[i])){item.align[i]="left"}else{item.align[i]=null}}for(i=0;i<item.cells.length;i++){item.cells[i]=item.cells[i].replace(/^ *\| *| *\| *$/g,"").split(/ *\| */)}this.tokens.push(item);continue}if(top&&(cap=this.rules.paragraph.exec(src))){src=src.substring(cap[0].length);this.tokens.push({type:"paragraph",text:cap[1].charAt(cap[1].length-1)==="\n"?cap[1].slice(0,-1):cap[1]});continue}if(cap=this.rules.text.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"text",text:cap[0]});continue}if(src){throw new Error("Infinite loop on byte: "+src.charCodeAt(0))}}return this.tokens};var inline={escape:/^\\([\\`*{}\[\]()#+\-.!_>])/,autolink:/^<([^ >]+(@|:\/)[^ >]+)>/,url:noop,tag:/^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,link:/^!?\[(inside)\]\(href\)/,reflink:/^!?\[(inside)\]\s*\[([^\]]*)\]/,nolink:/^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,strong:/^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,em:/^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,code:/^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,br:/^ {2,}\n(?!\s*$)/,del:noop,text:/^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/};inline._inside=/(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;inline._href=/\s*<?([\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&&/^<a /i.test(cap[0])){this.inLink=true}else if(this.inLink&&/^<\/a>/i.test(cap[0])){this.inLink=false}src=src.substring(cap[0].length);out+=this.options.sanitize?this.options.sanitizer?this.options.sanitizer(cap[0]):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+=this.renderer.text(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,"—").replace(/--/g,"–").replace(/(^|[-\u2014/(\[{"\s])'/g,"$1‘").replace(/'/g,"’").replace(/(^|[-\u2014/(\[{\u2018\s])"/g,"$1“").replace(/"/g,"â€").replace(/\.{3}/g,"…")};InlineLexer.prototype.mangle=function(text){if(!this.options.mangle)return text;var out="",l=text.length,i=0,ch;for(;i<l;i++){ch=text.charCodeAt(i);if(Math.random()>.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"<pre><code>"+(escaped?code:escape(code,true))+"\n</code></pre>"}return'<pre><code class="'+this.options.langPrefix+escape(lang,true)+'">'+(escaped?code:escape(code,true))+"\n</code></pre>\n"};Renderer.prototype.blockquote=function(quote){return"<blockquote>\n"+quote+"</blockquote>\n"};Renderer.prototype.html=function(html){return html};Renderer.prototype.heading=function(text,level,raw){return"<h"+level+' id="'+this.options.headerPrefix+raw.toLowerCase().replace(/[^\w]+/g,"-")+'">'+text+"</h"+level+">\n"};Renderer.prototype.hr=function(){return this.options.xhtml?"<hr/>\n":"<hr>\n"};Renderer.prototype.list=function(body,ordered){var type=ordered?"ol":"ul";return"<"+type+">\n"+body+"</"+type+">\n"};Renderer.prototype.listitem=function(text){return"<li>"+text+"</li>\n"};Renderer.prototype.paragraph=function(text){return"<p>"+text+"</p>\n"};Renderer.prototype.table=function(header,body){return"<table>\n"+"<thead>\n"+header+"</thead>\n"+"<tbody>\n"+body+"</tbody>\n"+"</table>\n"};Renderer.prototype.tablerow=function(content){return"<tr>\n"+content+"</tr>\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+"</"+type+">\n"};Renderer.prototype.strong=function(text){return"<strong>"+text+"</strong>"};Renderer.prototype.em=function(text){return"<em>"+text+"</em>"};Renderer.prototype.codespan=function(text){return"<code>"+text+"</code>"};Renderer.prototype.br=function(){return this.options.xhtml?"<br/>":"<br>"};Renderer.prototype.del=function(text){return"<del>"+text+"</del>"};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='<a href="'+href+'"';if(title){out+=' title="'+title+'"'}out+=">"+text+"</a>";return out};Renderer.prototype.image=function(href,title,text){var out='<img src="'+href+'" alt="'+text+'"';if(title){out+=' title="'+title+'"'}out+=this.options.xhtml?"/>":">";return out};Renderer.prototype.text=function(text){return text};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<this.token.header.length;i++){flags={header:true,align:this.token.align[i]};cell+=this.renderer.tablecell(this.inline.output(this.token.header[i]),{header:true,align:this.token.align[i]})}header+=this.renderer.tablerow(cell);for(i=0;i<this.token.cells.length;i++){row=this.token.cells[i];cell="";for(j=0;j<row.length;j++){cell+=this.renderer.tablecell(this.inline.output(row[j]),{header:false,align:this.token.align[j]})}body+=this.renderer.tablerow(cell)}return this.renderer.table(header,body)}case"blockquote_start":{var body="";while(this.next().type!=="blockquote_end"){body+=this.tok()}return this.renderer.blockquote(body)}case"list_start":{var body="",ordered=this.token.ordered;while(this.next().type!=="list_end"){body+=this.tok()}return this.renderer.list(body,ordered)}case"list_item_start":{var body="";while(this.next().type!=="list_item_end"){body+=this.token.type==="text"?this.parseText():this.tok()}return this.renderer.listitem(body)}case"loose_item_start":{var body="";while(this.next().type!=="list_item_end"){body+=this.tok()}return this.renderer.listitem(body)}case"html":{var html=!this.token.pre&&!this.options.pedantic?this.inline.output(this.token.text):this.token.text;return this.renderer.html(html)}case"paragraph":{return this.renderer.paragraph(this.inline.output(this.token.text))}case"text":{return this.renderer.paragraph(this.parseText())}}};function escape(html,encode){return html.replace(!encode?/&(?!#?\w+;)/g:/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}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(;i<arguments.length;i++){target=arguments[i];for(key in target){if(Object.prototype.hasOwnProperty.call(target,key)){obj[key]=target[key]}}}return obj}function marked(src,opt,callback){if(callback||typeof opt==="function"){if(!callback){callback=opt;opt=null}opt=merge({},marked.defaults,opt||{});var highlight=opt.highlight,tokens,pending,i=0;try{tokens=Lexer.lex(src,opt)}catch(e){return callback(e)}pending=tokens.length;var done=function(err){if(err){opt.highlight=highlight;return callback(err)}var out;try{out=Parser.parse(tokens,opt)}catch(e){err=e}opt.highlight=highlight;return err?callback(err):callback(null,out)};if(!highlight||highlight.length<3){return done()}delete opt.highlight;if(!pending)return done();for(;i<tokens.length;i++){(function(token){if(token.type!=="code"){return--pending||done()}return highlight(token.text,token.lang,function(err,code){if(err)return done(err);if(code==null||code===token.text){return--pending||done()}token.text=code;token.escaped=true;--pending||done()})})(tokens[i])}return}try{if(opt)opt=merge({},marked.defaults,opt);return Parser.parse(Lexer.lex(src,opt),opt)}catch(e){e.message+="\nPlease report this to https://github.com/chjj/marked.";if((opt||marked.defaults).silent){return"<p>An error occured:</p><pre>"+escape(e.message+"",true)+"</pre>"}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,sanitizer:null,mangle:true,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/assets/sass/_alert.sass b/assets/sass/_alert.sass
index 5a90c825..6de1c2f6 100644
--- a/assets/sass/_alert.sass
+++ b/assets/sass/_alert.sass
@@ -48,3 +48,11 @@
border-width: 1px 0 0
border-radius: 4px 4px 0 0
z-index: 9999
+ opacity: 1
+ animation: fadeout 5s linear forwards
+
+@keyframes fadeout
+ 0%
+ opacity: 1
+ 100%
+ opacity: 0
diff --git a/assets/sass/_suggest_menu.sass b/assets/sass/_suggest_menu.sass
new file mode 100644
index 00000000..76580d56
--- /dev/null
+++ b/assets/sass/_suggest_menu.sass
@@ -0,0 +1,28 @@
+@import variables
+
+#suggest-menu
+ position: absolute
+ display: block
+ z-index: 1000
+ min-width: 160px
+ padding: 5px 0
+ background: #fff
+ list-style: none
+ border: 1px solid #ccc
+ border-radius: 3px
+ box-shadow: 0 6px 12px rgba(0, 0, 0, .175)
+
+.suggest-menu-item
+ white-space: nowrap
+ padding: 3px 10px
+ color: color('primary')
+ font-weight: bold
+ cursor: pointer
+ &.active
+ color: #fff
+ background: #428bca
+ small
+ color: #fff
+ small
+ color: color('light')
+ font-weight: normal
diff --git a/assets/sass/app.sass b/assets/sass/app.sass
index 9a93e4ab..45f9ef59 100644
--- a/assets/sass/app.sass
+++ b/assets/sass/app.sass
@@ -11,6 +11,7 @@
@import tooltip
@import dropdown
@import accordion
+@import suggest_menu
@import dialog_box
@import popover
@import pagination
diff --git a/kanboard b/cli
index 3d8140af..8d82cc5d 100755
--- a/kanboard
+++ b/cli
@@ -3,6 +3,11 @@
use Symfony\Component\EventDispatcher\Event;
+if (php_sapi_name() !== 'cli') {
+ echo 'This script run only from the command line'.PHP_EOL;
+ exit(255);
+}
+
try {
require __DIR__.'/app/common.php';
$container['dispatcher']->dispatch('app.bootstrap', new Event);
diff --git a/config.default.php b/config.default.php
index b9dc8d77..09774689 100644
--- a/config.default.php
+++ b/config.default.php
@@ -19,6 +19,12 @@ define('LOG_FILE', DATA_DIR.DIRECTORY_SEPARATOR.'debug.log');
// Plugins directory
define('PLUGINS_DIR', 'plugins');
+// Plugins directory URL
+define('PLUGIN_API_URL', 'https://kanboard.net/plugins.json');
+
+// Enable/Disable plugin installer
+define('PLUGIN_INSTALLER', true);
+
// Available cache drivers are "file" and "memory"
define('CACHE_DRIVER', 'memory');
@@ -44,6 +50,11 @@ define('MAIL_SMTP_ENCRYPTION', null); // Valid values are "null", "ssl" or "tls"
// Sendmail command to use when the transport is "sendmail"
define('MAIL_SENDMAIL_COMMAND', '/usr/sbin/sendmail -bs');
+// Run automatically database migrations
+// If set to false, you will have to run manually the SQL migrations from the CLI during the next Kanboard upgrade
+// Do not run the migrations from multiple processes at the same time (example: web page + background worker)
+define('DB_RUN_MIGRATIONS', true);
+
// Database driver: sqlite, mysql or postgres (sqlite by default)
define('DB_DRIVER', 'sqlite');
@@ -196,7 +207,7 @@ define('ENABLE_URL_REWRITE', false);
// Hide login form, useful if all your users use Google/Github/ReverseProxy authentication
define('HIDE_LOGIN_FORM', false);
-// Disabling logout (for external SSO authentication)
+// Disabling logout (useful for external SSO authentication)
define('DISABLE_LOGOUT', false);
// Enable captcha after 3 authentication failure
@@ -220,3 +231,6 @@ define('HTTP_PROXY_PASSWORD', '');
// Set to false to allow self-signed certificates
define('HTTP_VERIFY_SSL_CERTIFICATE', true);
+
+// TOTP (2FA) issuer name
+define('TOTP_ISSUER', 'Kanboard');
diff --git a/doc/api-authentication.markdown b/doc/api-authentication.markdown
index 3ba1e8f5..be536be3 100644
--- a/doc/api-authentication.markdown
+++ b/doc/api-authentication.markdown
@@ -17,7 +17,8 @@ Default method (HTTP Basic)
### User credentials
-- Use the real username and password
+- Username: username
+- Password: user password or personal access token
The API use the [HTTP Basic Authentication Scheme described in the RFC2617](http://www.ietf.org/rfc/rfc2617.txt).
diff --git a/doc/api-json-rpc.markdown b/doc/api-json-rpc.markdown
index ab1056f0..fc612682 100644
--- a/doc/api-json-rpc.markdown
+++ b/doc/api-json-rpc.markdown
@@ -18,6 +18,7 @@ There are two types of API access:
### User API
- Access to the API with the user credentials (username and password)
+- You can also generate a personal access token instead of your password
- Application role and project permissions are checked for each procedure
- A user session is created on the server
- Example of possible clients: native mobile/desktop application, command line utility, etc...
diff --git a/doc/cli.markdown b/doc/cli.markdown
index 37cc7ee8..8bd5bde5 100644
--- a/doc/cli.markdown
+++ b/doc/cli.markdown
@@ -10,7 +10,7 @@ Usage
-----
- Open a terminal and go to your Kanboard directory (example: `cd /var/www/kanboard`)
-- Run the command `./kanboard`
+- Run the command `./cli` or `php cli`
```bash
Kanboard version master
@@ -32,6 +32,9 @@ Available commands:
help Displays help for a command
list Lists commands
worker Execute queue worker
+ db
+ db:migrate Execute SQL migrations
+ db:version Show database schema version
export
export:daily-project-column-stats Daily project column stats CSV export (number of tasks per column and per day)
export:subtasks Subtasks CSV export
@@ -63,13 +66,13 @@ Available commands
Usage:
```bash
-./kanboard export:tasks <project_id> <start_date> <end_date>
+./cli export:tasks <project_id> <start_date> <end_date>
```
Example:
```bash
-./kanboard export:tasks 1 2014-10-01 2014-11-30 > /tmp/my_custom_export.csv
+./cli export:tasks 1 2014-10-01 2014-11-30 > /tmp/my_custom_export.csv
```
CSV data are sent to `stdout`.
@@ -79,13 +82,13 @@ CSV data are sent to `stdout`.
Usage:
```bash
-./kanboard export:subtasks <project_id> <start_date> <end_date>
+./cli export:subtasks <project_id> <start_date> <end_date>
```
Example:
```bash
-./kanboard export:subtasks 1 2014-10-01 2014-11-30 > /tmp/my_custom_export.csv
+./cli export:subtasks 1 2014-10-01 2014-11-30 > /tmp/my_custom_export.csv
```
### Task transitions CSV export
@@ -93,13 +96,13 @@ Example:
Usage:
```bash
-./kanboard export:transitions <project_id> <start_date> <end_date>
+./cli export:transitions <project_id> <start_date> <end_date>
```
Example:
```bash
-./kanboard export:transitions 1 2014-10-01 2014-11-30 > /tmp/my_custom_export.csv
+./cli export:transitions 1 2014-10-01 2014-11-30 > /tmp/my_custom_export.csv
```
### Export daily summaries data in CSV
@@ -107,13 +110,13 @@ Example:
The exported data will be printed on the standard output:
```bash
-./kanboard export:daily-project-column-stats <project_id> <start_date> <end_date>
+./cli export:daily-project-column-stats <project_id> <start_date> <end_date>
```
Example:
```bash
-./kanboard export:daily-project-column-stats 1 2014-10-01 2014-11-30 > /tmp/my_custom_export.csv
+./cli export:daily-project-column-stats 1 2014-10-01 2014-11-30 > /tmp/my_custom_export.csv
```
### Send notifications for overdue tasks
@@ -121,7 +124,7 @@ Example:
Emails will be sent to all users with notifications enabled.
```bash
-./kanboard notification:overdue-tasks
+./cli notification:overdue-tasks
```
Optional parameters:
@@ -147,7 +150,7 @@ You can also display the overdue tasks with the flag `--show`:
This command calculate the statistics of each project:
```bash
-./kanboard projects:daily-stats
+./cli projects:daily-stats
Run calculation for Project #0
Run calculation for Project #1
Run calculation for Project #10
@@ -158,14 +161,14 @@ Run calculation for Project #10
This command send a "daily cronjob event" to all open tasks of each project.
```bash
-./kanboard trigger:tasks
+./cli trigger:tasks
Trigger task event: project_id=2, nb_tasks=1
```
### Reset user password
```bash
-./kanboard user:reset-password my_user
+./cli user:reset-password my_user
```
You will be prompted for a password and confirmation. Characters are not printed to the screen.
@@ -173,13 +176,13 @@ You will be prompted for a password and confirmation. Characters are not printed
### Remove two-factor authentication for a user
```bash
-./kanboard user:reset-2fa my_user
+./cli user:reset-2fa my_user
```
### Install a plugin
```bash
-./kanboard plugin:install https://github.com/kanboard/plugin-github-auth/releases/download/v1.0.1/GithubAuth-1.0.1.zip
+./cli plugin:install https://github.com/kanboard/plugin-github-auth/releases/download/v1.0.1/GithubAuth-1.0.1.zip
```
Note: Installed files will have the same permissions as the current user
@@ -187,13 +190,13 @@ Note: Installed files will have the same permissions as the current user
### Remove a plugin
```bash
-./kanboard plugin:uninstall Budget
+./cli plugin:uninstall Budget
```
### Upgrade all plugins
```bash
-./kanboard plugin:upgrade
+./cli plugin:upgrade
* Updating plugin: Budget Planning
* Plugin up to date: Github Authentication
```
@@ -201,5 +204,21 @@ Note: Installed files will have the same permissions as the current user
### Run Background worker
```bash
-./kanboard worker
+./cli worker
+```
+
+### Execute database migrations
+
+If the parameter `DB_RUN_MIGRATIONS` is set to `false`, you have run the database migrations manually:
+
+```bash
+./cli db:migrate
+```
+
+### Check database schema version
+
+```bash
+./cli db:version
+Current version: 95
+Last version: 96
```
diff --git a/doc/config.markdown b/doc/config.markdown
index 853fa6f2..a2046989 100644
--- a/doc/config.markdown
+++ b/doc/config.markdown
@@ -30,6 +30,12 @@ Enable/disable plugin installation from the user interface:
define('PLUGIN_INSTALLER', true); // Default is true
```
+Change default plugin directory URL:
+
+```php
+define('PLUGIN_API_URL', 'https://kanboard.net/plugins.json');
+```
+
Folder for uploaded files
-------------------------
@@ -80,6 +86,11 @@ Database settings
-----------------
```php
+// Run automatically database migrations
+// If set to false, you will have to run manually the SQL migrations from the CLI during the next Kanboard upgrade
+// Do not run the migrations from multiple processes at the same time (example: web page + background worker)
+define('DB_RUN_MIGRATIONS', true);
+
// Database driver: sqlite, mysql or postgres (sqlite by default)
define('DB_DRIVER', 'sqlite');
@@ -315,4 +326,7 @@ define('DISABLE_LOGOUT', false);
// Override API token stored in the database, useful for automated tests
define('API_AUTHENTICATION_TOKEN', 'My unique API Token');
+
+// TOTP (2FA) issuer name
+define('TOTP_ISSUER', 'Kanboard');
```
diff --git a/doc/cronjob.markdown b/doc/cronjob.markdown
index 780f0025..743aac95 100644
--- a/doc/cronjob.markdown
+++ b/doc/cronjob.markdown
@@ -25,7 +25,7 @@ sudo crontab -u www-data -e
Example to execute the daily cronjob at 8am:
```bash
-0 8 * * * cd /path/to/kanboard && ./kanboard cronjob >/dev/null 2>&1
+0 8 * * * cd /path/to/kanboard && ./cli cronjob >/dev/null 2>&1
```
Note: the cronjob process must have write access to the database in case you are using Sqlite.
diff --git a/doc/es_ES/cli.markdown b/doc/es_ES/cli.markdown
index 3f19b39d..ec46bdd6 100755
--- a/doc/es_ES/cli.markdown
+++ b/doc/es_ES/cli.markdown
@@ -10,7 +10,7 @@ Uso
-----
- Abre una terminal y ve a tu directorio de kanboard (ejemplo : `cd /var/www/kanboard`)
-- Corre el comando `./kanboard`
+- Corre el comando `./cli` / `php cli`
```bash
Kanboard version master
@@ -33,10 +33,10 @@ Available commands:
list Lista de comandos
worker Execute queue worker
export
- export:daily-project-column-stats Diariamente estadísticas de exportación de CSV (número de tareas por columna y por día )
+ export:daily-project-column-stats Diariamente estad�sticas de exportaci�n de CSV (n�mero de tareas por columna y por d�a )
export:subtasks Exportar a CSV las subtareas
export:tasks Exportar a CSV las tareas
- export:transitions Exportar a CSV tareas de transición
+ export:transitions Exportar a CSV tareas de transici�n
locale
locale:compare Comparar aplicacion de traducciones con el locale fr_FR
locale:sync Sincronizar todas las traducciones basadas en el locale fr_FR
@@ -51,7 +51,7 @@ Available commands:
trigger
trigger:tasks Disparadores de eventos calendarizados para todas las tareas
user
- user:reset-2fa Eliminar la autenticación two-factor para un usuario
+ user:reset-2fa Eliminar la autenticaci�n two-factor para un usuario
user:reset-password Cambiar el passwor del usuario
```
@@ -63,13 +63,13 @@ Comandos disponibles
Uso:
```bash
-./kanboard export:tasks <project_id> <start_date> <end_date>
+./cli export:tasks <project_id> <start_date> <end_date>
```
Ejemplo:
```bash
-./kanboard export:tasks 1 2014-10-01 2014-11-30 > /tmp/my_custom_export.csv
+./cli export:tasks 1 2014-10-01 2014-11-30 > /tmp/my_custom_export.csv
```
CSV los datos son enviados a `stdout`.
@@ -79,41 +79,41 @@ CSV los datos son enviados a `stdout`.
Uso:
```bash
-./kanboard export:subtasks <project_id> <start_date> <end_date>
+./cli export:subtasks <project_id> <start_date> <end_date>
```
Ejemplo:
```bash
-./kanboard export:subtasks 1 2014-10-01 2014-11-30 > /tmp/my_custom_export.csv
+./cli export:subtasks 1 2014-10-01 2014-11-30 > /tmp/my_custom_export.csv
```
-### Exportación a CSV de tareas de transición
+### Exportaci�n a CSV de tareas de transici�n
Uso:
```bash
-./kanboard export:transitions <project_id> <start_date> <end_date>
+./cli export:transitions <project_id> <start_date> <end_date>
```
Ejemplo:
```bash
-./kanboard export:transitions 1 2014-10-01 2014-11-30 > /tmp/my_custom_export.csv
+./cli export:transitions 1 2014-10-01 2014-11-30 > /tmp/my_custom_export.csv
```
### Exportar diariamente resumenes de datos en CSV
-Los datos exportados se pueden imprimir en la salida estándar:
+Los datos exportados se pueden imprimir en la salida est�ndar:
```bash
-./kanboard export:daily-project-column-stats <project_id> <start_date> <end_date>
+./cli export:daily-project-column-stats <project_id> <start_date> <end_date>
```
Ejemplo:
```bash
-./kanboard export:daily-project-column-stats 1 2014-10-01 2014-11-30 > /tmp/my_custom_export.csv
+./cli export:daily-project-column-stats 1 2014-10-01 2014-11-30 > /tmp/my_custom_export.csv
```
### Envio de notificaciones para tareas atrasadas
@@ -121,7 +121,7 @@ Ejemplo:
Los Emails se enviaran a todos los usuarios con las notificaciones habilitadas.
```bash
-./kanboard notification:overdue-tasks
+./cli notification:overdue-tasks
```
Parametros opcionales:
@@ -130,10 +130,10 @@ Parametros opcionales:
- `--group`: Grupo tareas atrasadas todo para un usuario (desde todos los proyectos) en un email
- `--manager`: Enviar todas las tareas atrasadas a un project manager(s) en un email
-También puede mostrar las tareas atrasadas con la bandera `--show`:
+Tambi�n puede mostrar las tareas atrasadas con la bandera `--show`:
```bash
-./kanboard notification:overdue-tasks --show
+./cli notification:overdue-tasks --show
+-----+---------+------------+------------+--------------+----------+
| Id | Title | Due date | Project Id | Project name | Assignee |
+-----+---------+------------+------------+--------------+----------+
@@ -147,7 +147,7 @@ También puede mostrar las tareas atrasadas con la bandera `--show`:
Este comando calcula las estadisticas por cada proyecto:
```bash
-./kanboard projects:daily-stats
+./cli projects:daily-stats
Run calculation for Project #0
Run calculation for Project #1
Run calculation for Project #10
@@ -158,42 +158,42 @@ Run calculation for Project #10
Este comando envia a "daily cronjob event" a todas las tareas abiertas de cada proyecto.
```bash
-./kanboard trigger:tasks
+./cli trigger:tasks
Trigger task event: project_id=2, nb_tasks=1
```
### Resetear el password del usuario
```bash
-./kanboard user:reset-password my_user
+./cli user:reset-password my_user
```
-Se le pedirá una contraseña y la confirmación. Los caracteres no se imprimen en la pantalla.
+Se le pedir� una contrase�a y la confirmaci�n. Los caracteres no se imprimen en la pantalla.
-### Eliminar la autenticación two-factor para un usuario
+### Eliminar la autenticaci�n two-factor para un usuario
```bash
-./kanboard user:reset-2fa my_user
+./cli user:reset-2fa my_user
```
### Instalar un plugin
```bash
-./kanboard plugin:install https://github.com/kanboard/plugin-github-auth/releases/download/v1.0.1/GithubAuth-1.0.1.zip
+./cli plugin:install https://github.com/kanboard/plugin-github-auth/releases/download/v1.0.1/GithubAuth-1.0.1.zip
```
-Nota: Los archivos instalados tendrán los mismos permisos que el usuario actual
+Nota: Los archivos instalados tendr�n los mismos permisos que el usuario actual
### Eliminar un usuario
```bash
-./kanboard plugin:uninstall Budget
+./cli plugin:uninstall Budget
```
### Upgrade todos los plugins
```bash
-./kanboard plugin:upgrade
+./cli plugin:upgrade
* Updating plugin: Budget Planning
* Plugin up to date: Github Authentication
```
@@ -201,5 +201,5 @@ Nota: Los archivos instalados tendrán los mismos permisos que el usuario actual
### Run Background worker
```bash
-./kanboard worker
+./cli worker
```
diff --git a/doc/es_ES/cronjob.markdown b/doc/es_ES/cronjob.markdown
index f8f9ebc8..b7dc5cee 100755
--- a/doc/es_ES/cronjob.markdown
+++ b/doc/es_ES/cronjob.markdown
@@ -1,4 +1,4 @@
-Programación de Jobs en background
+Programaci�n de Jobs en background
==================================
Para trabajar correctamente,Kanboard requiere que se corra un job en background diariamente.
@@ -10,7 +10,7 @@ Este job es necesario para estas caracteristicas:
- Enviar notificaciones de tareas atrasadas.
- Ejecutar automaticamente acciones conectadas a el evento "Daily background job for tasks"
-Configuración de plataformas Unix y Linux
+Configuraci�n de plataformas Unix y Linux
-----------------------------------------
Hay varias maneras de definir una tarea programada en sistemas operativos Unix/Linux , este ejemplo es para Ubuntu 14.04 .
@@ -25,7 +25,7 @@ sudo crontab -u www-data -e
Ejemplo para ejecutar diariamente cronjob a las 8am:
```bash
-0 8 * * * cd /path/to/kanboard && ./kanboard cronjob >/dev/null 2>&1
+0 8 * * * cd /path/to/kanboard && ./cli cronjob >/dev/null 2>&1
```
Nota : El proceso del cronjob debe tener acceso a escritura de la base de datos en caso de usar Sqlite.
diff --git a/doc/es_ES/installation.markdown b/doc/es_ES/installation.markdown
index 9491d591..f3dfc495 100644
--- a/doc/es_ES/installation.markdown
+++ b/doc/es_ES/installation.markdown
@@ -44,6 +44,7 @@ Si desea instalar Kanboard fuera de la raíz de documentos del servidor web, es
```bash
.
├── assets -> ../kanboard/assets
+├── cli -> ../kanboard/cli
├── doc -> ../kanboard/doc
├── favicon.ico -> ../kanboard/favicon.ico
├── index.php -> ../kanboard/index.php
diff --git a/doc/es_ES/translations.markdown b/doc/es_ES/translations.markdown
index 074d9ae3..66fd2a4c 100644
--- a/doc/es_ES/translations.markdown
+++ b/doc/es_ES/translations.markdown
@@ -50,7 +50,7 @@ How to find missing translations in the applications?
From a terminal, run the following command:
```bash
-./kanboard locale:compare
+./cli locale:compare
```
All missing and unused translations are displayed on the screen.
@@ -62,7 +62,7 @@ How to synchronize translation files?
From a Unix shell run this command:
```bash
-./kanboard locale:sync
+./cli locale:sync
```
The French translation is used a reference to other locales.
diff --git a/doc/fr_FR/index.markdown b/doc/fr_FR/index.markdown
index d48c94ca..b33baf85 100644
--- a/doc/fr_FR/index.markdown
+++ b/doc/fr_FR/index.markdown
@@ -46,6 +46,7 @@ Utiliser Kanboard
- [Créer des tâches par email](create-tasks-by-email.markdown)
- [Sous-tâches](subtasks.markdown)
- [Analytique des tâches](analytics-tasks.markdown)
+- [Mentionner les utilisateurs](user-mentions.markdown)
### Travailler avec les utilisateurs
diff --git a/doc/fr_FR/installation.markdown b/doc/fr_FR/installation.markdown
index 4f7569ab..9e4cb47a 100644
--- a/doc/fr_FR/installation.markdown
+++ b/doc/fr_FR/installation.markdown
@@ -42,6 +42,7 @@ Si vous souhaitez installer Kanboard en dehors du document root de votre serveur
```bash
.
├── assets -> ../kanboard/assets
+├── cli -> ../kanboard/cli
├── doc -> ../kanboard/doc
├── favicon.ico -> ../kanboard/favicon.ico
├── index.php -> ../kanboard/index.php
diff --git a/doc/fr_FR/update.markdown b/doc/fr_FR/update.markdown
index 508f729d..68468e50 100644
--- a/doc/fr_FR/update.markdown
+++ b/doc/fr_FR/update.markdown
@@ -12,7 +12,8 @@ Choses importantes à faire avant la mise à jour
- **Vérifiez que votre sauvegarde est valide !**
- Vérifiez encore
- Toujours lire la [liste des changements](https://github.com/kanboard/kanboard/blob/master/ChangeLog) pour vérifier sil y a des opérations manuelles à faire
-- Toujours fermer les sessions des utilisateurs sur le serveur
+- Stoppez le _worker_
+- Mettez le serveur web en mode maintenance pour éviter que les gens utilisent l'application pendant la mise à jour
Depuis l'archive (version stable)
---------------------------------
@@ -33,3 +34,21 @@ Depuis le dépôt git (version de développement)
3. Testez que tout fonctionne correctement
Cette méthode va installer **la version en cours de développement**, utilisez là à vos risques.
+
+Appliquer les migrations SQL manuellement
+-----------------------------------------
+
+Par défaut, les migrations SQL sont exécutées automatiquement.
+La version du schéma est vérifiée à chaque requête.
+De cette manière, les changements de base de données sont appliqués automatiquement.
+
+Vous pouvez désactiver ce comportement si vous le souhaitez en fonction de votre configuration.
+Par exemple, si plusieurs processus essaient de mettre à jour le schéma en même temps, il se peut que vous ayez des problèmes même si chaque opération se fait dans une transaction.
+
+Pour désactiver cette fonctionnalité, mettez le paramètre `DB_RUN_MIGRATIONS` à `false` dans votre fichier de [configuration](config.markdown).
+
+Lorsque vous allez mettre à jour Kanboard, exécutez cette commande :
+
+```bash
+./cli db:migrate
+```
diff --git a/doc/fr_FR/user-mentions.markdown b/doc/fr_FR/user-mentions.markdown
new file mode 100644
index 00000000..af322bb8
--- /dev/null
+++ b/doc/fr_FR/user-mentions.markdown
@@ -0,0 +1,13 @@
+Mentionner les utilisateurs
+===========================
+
+Kanboard offre la possibilité d'envoyer des notifications lorsque quelqu'un est mentionné.
+
+Si vous avez besoin d'obtenir l'attention de quelqu'un dans un commentaire ou une tâche, utilisez le symbole @ suivi de l'identifiant de l'utilisateur.
+Kanboard va automatiquement suggérer une liste d'utilisateurs :
+
+![Mentions](screenshots/user-mentions.png)
+
+- Pour le moment, cette fonctionnalité est activée uniquement pour la description des tâches et les commentaires
+- Cela fonctionne seulement lors de la création des tâches ou commentaires
+- Pour être mentionné, les utilisateurs doivent être membres du projet
diff --git a/doc/index.markdown b/doc/index.markdown
index 54010d0c..09b39d9f 100644
--- a/doc/index.markdown
+++ b/doc/index.markdown
@@ -89,6 +89,7 @@ Using Kanboard
- [Solving database migration issues](solving-database-migration-issues.markdown)
- [Blank page after upgrading](solving-blank-page-issue.markdown)
+- [Unable to open a session on Windows IIS and Internet Explorer](solving-session-issue-windows-iis-ie.markdown)
- [Performances](performances.markdown)
Technical details
@@ -110,7 +111,6 @@ Technical details
- [Run Kanboard with Docker](docker.markdown)
- [Run Kanboard with Vagrant](vagrant.markdown)
- [Run Kanboard on Cloudron](cloudron.markdown)
-- [Run Kanboard on Nitrous](nitrous.markdown)
### Configuration
diff --git a/doc/installation.markdown b/doc/installation.markdown
index 67b010a9..518282be 100644
--- a/doc/installation.markdown
+++ b/doc/installation.markdown
@@ -21,7 +21,7 @@ The `data` folder is used to store:
- Uploaded files: `files/*`
- Image thumbnails: `files/thumbnails/*`
-People who are using a remote database (Mysql/Postgresql) and a remote file storage (Aws S3 or similar) don't necessarily need to have a persistent local data folder or to change the permission.
+People who are using a remote database (Mysql/Postgresql) and a remote object storage (Aws S3 or similar) don't necessarily need to have a persistent local data folder or to change the permission.
From the git repository (development version)
---------------------------------------------
@@ -42,6 +42,7 @@ If you would like to install Kanboard outside of the web server document root, y
```bash
.
├── assets -> ../kanboard/assets
+├── cli -> ../kanboard/cli
├── doc -> ../kanboard/doc
├── favicon.ico -> ../kanboard/favicon.ico
├── index.php -> ../kanboard/index.php
@@ -53,7 +54,16 @@ The `.htaccess` is optional because its content can be included directly in the
You can also define a custom location for the plugins and files folders by changing the [config file](config.markdown).
-Optional installation
+
+Other Database Types
+--------------------
+
+Kanboard supports Mysql and Postgres as alternative to Sqlite.
+
+- [Mysql configuration](mysql-configuration.markdown]
+- [Postgres configuration](postgresql-configuration.markdown)
+
+Optional Installation
---------------------
- Some features of Kanboard require that you run [a daily background job](cronjob.markdown) (Reports and analytics)
diff --git a/doc/nitrous.markdown b/doc/nitrous.markdown
deleted file mode 100644
index daaedcef..00000000
--- a/doc/nitrous.markdown
+++ /dev/null
@@ -1,10 +0,0 @@
-Nitrous Quickstart
-==================
-
-Create a free development environment for this Kanboard project in the cloud on [Nitrous.io](https://www.nitrous.io) by clicking the button below.
-
-<a href="https://www.nitrous.io/quickstart">
- <img src="https://nitrous-image-icons.s3.amazonaws.com/quickstart.png" alt="Nitrous Quickstart" width=142 height=34>
-</a>
-
-Simply access your site via the `Preview > 3000` link in the IDE.
diff --git a/doc/plugin-registration.markdown b/doc/plugin-registration.markdown
index a9273e1d..2c80aab3 100644
--- a/doc/plugin-registration.markdown
+++ b/doc/plugin-registration.markdown
@@ -1,6 +1,28 @@
Plugin Registration
===================
+Project skeleton generator
+--------------------------
+
+You can use `cookiecutter` to create the project structure of your plugin automatically.
+
+Install Cookiecutter:
+
+```bash
+pip install -U cookiecutter
+```
+
+Run Kanboard cookiecutter:
+
+```bash
+cookiecutter gh:kanboard/cookiecutter-plugin
+plugin_name [My Plugin]: Some Plugin
+plugin_namespace [MyPlugin]: SomePlugin
+plugin_author [Plugin Author]: Me
+plugin_description [My plugin is awesome]:
+plugin_homepage [https://github.com/kanboard/plugin-myplugin]:
+```
+
Directory structure
-------------------
diff --git a/doc/postgresql-configuration.markdown b/doc/postgresql-configuration.markdown
index 627e2ded..bab15313 100644
--- a/doc/postgresql-configuration.markdown
+++ b/doc/postgresql-configuration.markdown
@@ -6,11 +6,9 @@ By default, Kanboard use Sqlite to store its data but it's also possible to use
Requirements
------------
-- Postgresql server already installed and configured
+- Postgresql >= 9.3
- The PHP extension `pdo_pgsql` installed (Debian/Ubuntu: `apt-get install php5-pgsql`)
-Note: Kanboard is tested with **Postgresql 9.3 and 9.4**
-
Configuration
-------------
@@ -43,10 +41,10 @@ Note: You can also rename the template file `config.default.php` to `config.php`
For the first time, Kanboard will run one by one each database migration and this process can take some time according to your configuration.
-To avoid any issues or potential timeouts you can initialize the database directly by importing the SQL schema:
+To avoid any issues or potential timeouts, you can initialize the database directly by importing the SQL schema:
```bash
psql -U postgres my_database < app/Schema/Sql/postgres.sql
```
-The file `app/Schema/Sql/postgres.sql` is a sql dump that represents the last version of the database.
+The file `app/Schema/Sql/postgres.sql` is a SQL dump that represents the last version of the database.
diff --git a/doc/ru_RU/cli.markdown b/doc/ru_RU/cli.markdown
index 9c7b56a7..5ac2b4ec 100644
--- a/doc/ru_RU/cli.markdown
+++ b/doc/ru_RU/cli.markdown
@@ -1,236 +1,125 @@
Ð˜Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð½Ð¾Ð¹ Ñтроки
==========================
-
-
Канборд обеÑпечивает проÑтой Ð¸Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð½Ð¾Ð¹ Ñтроки, которым можно воÑпользоватьÑÑ Ñ‚Ð¾Ð»ÑŒÐºÐ¾ из Unix терминала. Эта возможноÑÑ‚ÑŒ доÑтупна только Ñ Ð»Ð¾ÐºÐ°Ð»ÑŒÐ½Ð¾Ð¹ машины.
-
-
Ð˜Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð½Ð¾Ð¹ Ñтроки полезен Ð´Ð»Ñ Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´ вне процеÑÑов веб Ñервера.
-
-
ИÑпользование[¶](#usage "СÑылка на Ñтот заголовок")
---------------------------------------------------
-
-
- Откройте терминал и перейдите в директорию Канборд (например: `cd /var/www/kanboard`)
+- Выполните команду `./cli`
-
-- Выполните команду `./kanboard`
-
-
-
-<!-- -->
-
-
-
- Kanboard version master
-
-
-
- Usage:
-
- command [options] [arguments]
-
-
-
- Options:
-
- -h, --help Display this help message
-
- -q, --quiet Do not output any message
-
- -V, --version Display this application version
-
- --ansi Force ANSI output
-
- --no-ansi Disable ANSI output
-
- -n, --no-interaction Do not ask any interactive question
-
- -v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
-
-
-
- Available commands:
-
- cronjob Execute daily cronjob
-
- help Displays help for a command
-
- list Lists commands
-
- export
-
- export:daily-project-column-stats Daily project column stats CSV export (number of tasks per column and per day)
-
- export:subtasks Subtasks CSV export
-
- export:tasks Tasks CSV export
-
- export:transitions Task transitions CSV export
-
- locale
-
- locale:compare Compare application translations with the fr_FR locale
-
- locale:sync Synchronize all translations based on the fr_FR locale
-
- notification
-
- notification:overdue-tasks Send notifications for overdue tasks
-
- plugin
-
- plugin:install Install a plugin from a remote Zip archive
-
- plugin:uninstall Remove a plugin
-
- plugin:upgrade Update all installed plugins
-
- projects
-
- projects:daily-stats Calculate daily statistics for all projects
-
- trigger
-
- trigger:tasks Trigger scheduler event for all tasks
-
- user
-
- user:reset-2fa Remove two-factor authentication for a user
-
- user:reset-password Change user password
-
+```bash
+Kanboard version master
+
+Usage:
+ command [options] [arguments]
+
+Options:
+ -h, --help Display this help message
+ -q, --quiet Do not output any message
+ -V, --version Display this application version
+ --ansi Force ANSI output
+ --no-ansi Disable ANSI output
+ -n, --no-interaction Do not ask any interactive question
+ -v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
+
+Available commands:
+ cronjob Execute daily cronjob
+ help Displays help for a command
+ list Lists commands
+ worker Execute queue worker
+ db
+ db:migrate Execute SQL migrations
+ db:version Show database schema version
+ export
+ export:daily-project-column-stats Daily project column stats CSV export (number of tasks per column and per day)
+ export:subtasks Subtasks CSV export
+ export:tasks Tasks CSV export
+ export:transitions Task transitions CSV export
+ locale
+ locale:compare Compare application translations with the fr_FR locale
+ locale:sync Synchronize all translations based on the fr_FR locale
+ notification
+ notification:overdue-tasks Send notifications for overdue tasks
+ plugin
+ plugin:install Install a plugin from a remote Zip archive
+ plugin:uninstall Remove a plugin
+ plugin:upgrade Update all installed plugins
+ projects
+ projects:daily-stats Calculate daily statistics for all projects
+ trigger
+ trigger:tasks Trigger scheduler event for all tasks
+ user
+ user:reset-2fa Remove two-factor authentication for a user
+ user:reset-password Change user password
+```
ДоÑтупные команды[¶](#available-commands "СÑылка на Ñтот заголовок")
--------------------------------------------------------------------
-
-
### ЭкÑпорт задач в формате CSV[¶](#tasks-csv-export "СÑылка на Ñтот заголовок")
-
-
Применение:
-
-
- ./kanboard export:tasks <project_id> <start_date> <end_date>
-
-
+ ./cli export:tasks <project_id> <start_date> <end_date>
Пример:
-
-
- ./kanboard export:tasks 1 2014-10-01 2014-11-30 > /tmp/my_custom_export.csv
-
-
+ ./cli export:tasks 1 2014-10-01 2014-11-30 > /tmp/my_custom_export.csv
Данные CSV передаютÑÑ Ð² `stdout`.
-
-
### ЭкÑпорт подзадач в формате CSV[¶](#subtasks-csv-export "СÑылка на Ñтот заголовок")
-
-
Применение:
-
-
- ./kanboard export:subtasks <project_id> <start_date> <end_date>
-
-
+ ./cli export:subtasks <project_id> <start_date> <end_date>
Пример:
-
-
- ./kanboard export:subtasks 1 2014-10-01 2014-11-30 > /tmp/my_custom_export.csv
-
-
+ ./cli export:subtasks 1 2014-10-01 2014-11-30 > /tmp/my_custom_export.csv
### ЭкÑпорт Ð¿ÐµÑ€ÐµÐ¼ÐµÑ‰ÐµÐ½Ð¸Ñ Ð·Ð°Ð´Ð°Ñ‡ в формате CSV[¶](#task-transitions-csv-export "СÑылка на Ñтот заголовок")
-
-
Применение:
-
-
- ./kanboard export:transitions <project_id> <start_date> <end_date>
-
-
+ ./cli export:transitions <project_id> <start_date> <end_date>
Пример:
-
-
- ./kanboard export:transitions 1 2014-10-01 2014-11-30 > /tmp/my_custom_export.csv
-
-
+ ./cli export:transitions 1 2014-10-01 2014-11-30 > /tmp/my_custom_export.csv
### ЭкÑпорт ежедневных Ñведений в формате CSV[¶](#export-daily-summaries-data-in-csv "СÑылка на Ñтот заголовок")
-
-
ЭкÑпортированные данные будут выведены в Ñтандартный вывод:
-
-
- ./kanboard export:daily-project-column-stats <project_id> <start_date> <end_date>
-
-
+ ./cli export:daily-project-column-stats <project_id> <start_date> <end_date>
Пример:
-
-
- ./kanboard export:daily-project-column-stats 1 2014-10-01 2014-11-30 > /tmp/my_custom_export.csv
-
-
+ ./cli export:daily-project-column-stats 1 2014-10-01 2014-11-30 > /tmp/my_custom_export.csv
### Отправка уведомлений Ð´Ð»Ñ Ð¿Ñ€Ð¾Ñроченных задач[¶](#send-notifications-for-overdue-tasks "СÑылка на Ñтот заголовок")
-
-
Email ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð±ÑƒÐ´ÑƒÑ‚ отправлены вÑем пользователÑм, у которых включено оповещение.
-
-
- ./kanboard notification:overdue-tasks
-
-
+ ./cli notification:overdue-tasks
ÐеобÑзательные параметры:
-
-
- `--show`: Показывать отправку уведомлений
-
-
-
- `--group`: Группировать вÑе проÑроченные задачи Ð´Ð»Ñ Ð¾Ð´Ð½Ð¾Ð³Ð¾ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ (Ñо вÑех проектов) на один email
-
-
-
- `--manager`: ПоÑылать вÑе проÑроченные задачи менеджеру (менеджерам) проекта в одном email Ñообщении
-
-
Ð’Ñ‹ можете проÑмотреть проÑроченные задачи Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ параметра `--show`:
-
-
```bash
-./kanboard notification:overdue-tasks --show
+./cli notification:overdue-tasks --show
+-----+---------+------------+------------+--------------+----------+
| Id | Title | Due date | Project Id | Project name | Assignee |
+-----+---------+------------+------------+--------------+----------+
@@ -239,93 +128,46 @@ Email ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð±ÑƒÐ´ÑƒÑ‚ отправлены вÑем пользов
+-----+---------+------------+------------+--------------+----------+
```
-
### ЗапуÑк ежедневной калькулÑции ÑтатиÑтики[¶](#run-daily-project-stats-calculation "СÑылка на Ñтот заголовок")
-
-
Эта команда Ñчитает ÑтатиÑтику Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð³Ð¾ проекта:
-
-
- ./kanboard projects:daily-stats
-
+ ./cli projects:daily-stats
Run calculation for Project #0
-
Run calculation for Project #1
-
Run calculation for Project #10
-
-
### Триггеры Ð´Ð»Ñ Ð·Ð°Ð´Ð°Ñ‡[¶](#trigger-for-tasks)
-
-
Эта команда поÑылает “Ñобытие Ð´Ð»Ñ ÐµÐ¶ÐµÐ´Ð½ÐµÐ²Ð½Ñ‹Ñ… фоновых Ð·Ð°Ð´Ð°Ð½Ð¸Ð¹â€ Ð´Ð»Ñ Ð²Ñех открытых задач в каждом проекте.
-
-
- ./kanboard trigger:tasks
-
+ ./cli trigger:tasks
Trigger task event: project_id=2, nb_tasks=1
-
-
### Ð¡Ð±Ñ€Ð¾Ñ Ð¿Ð°Ñ€Ð¾Ð»Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ[¶](#reset-user-password "СÑылка на Ñтот заголовок")
-
-
- ./kanboard user:reset-password my_user
-
-
+ ./cli user:reset-password my_user
Будет запрошен пароль и подтверждение. Символы не отображаютÑÑ Ð½Ð° Ñкране.
-
-
### Удаление двухуровневой аутентификации Ð´Ð»Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ[¶](#remove-two-factor-authentication-for-a-user "СÑылка на Ñтот заголовок")
-
-
- ./kanboard user:reset-2fa my_user
-
-
+ ./cli user:reset-2fa my_user
### УÑтановка плагина[¶](#install-a-plugin "СÑылка на Ñтот заголовок")
-
-
- ./kanboard plugin:install https://github.com/kanboard/plugin-github-auth/releases/download/v1.0.1/GithubAuth-1.0.1.zip
-
-
+ ./cli plugin:install https://github.com/kanboard/plugin-github-auth/releases/download/v1.0.1/GithubAuth-1.0.1.zip
Заметка: УÑтановленные файлы будут иметь теже права, что и у текущего пользователÑ
-
-
### Удаление плагина[¶](#remove-a-plugin "СÑылка на Ñтот заголовок")
-
-
- ./kanboard plugin:uninstall Budget
-
-
+ ./cli plugin:uninstall Budget
### Обновление вÑех плагинов[¶](#upgrade-all-plugins "СÑылка на Ñтот заголовок")
-
-
- ./kanboard plugin:upgrade
-
+ ./cli plugin:upgrade
* Updating plugin: Budget Planning
-
* Plugin up to date: Github Authentication
-
-
-
-
-
[РуÑÑÐºÐ°Ñ Ð´Ð¾ÐºÑƒÐ¼ÐµÐ½Ñ‚Ð°Ñ†Ð¸Ñ Kanboard](http://kanboard.ru/doc/)
-
diff --git a/doc/ru_RU/cronjob.markdown b/doc/ru_RU/cronjob.markdown
index 62f8e886..f6d3a2af 100644
--- a/doc/ru_RU/cronjob.markdown
+++ b/doc/ru_RU/cronjob.markdown
@@ -1,7 +1,6 @@
Ежедневные фоновые задачи
=========================
-
Ð”Ð»Ñ ÐºÐ¾Ñ€Ñ€ÐµÐºÑ‚Ð½Ð¾Ð¹ работы, Канборд должен запуÑкать ежедневные фоновые задачи. Ðа Unix платформах Ñтот процеÑÑ Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÑÑ‚ÑÑ Ð² `cron`.
Фоновые задачи необходимы Ð´Ð»Ñ Ñледующих возможноÑтей:
@@ -16,26 +15,14 @@
Ð”Ð»Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ñ„Ð¾Ð½Ð¾Ð²Ñ‹Ñ… задач под операционной ÑиÑтемой Unix/Linux иÑпользуютÑÑ Ñ€Ð°Ð·Ð½Ñ‹Ðµ решениÑ. ЗдеÑÑŒ приведен пример Ð´Ð»Ñ Ubuntu 14.04. Ð”Ð»Ñ Ð´Ñ€ÑƒÐ³Ð¸Ñ… ÑиÑтем процедура похожа.
-
Отредактируйте crontab под пользователем вашего веб Ñервера:
-
sudo crontab -u www-data -e
-
Пример запуÑка ежедневной фоновой задачи в 8 утра:
-
- 0 8 * * * cd /path/to/kanboard && ./kanboard cronjob >/dev/null 2>&1
-
+ 0 8 * * * cd /path/to/kanboard && ./cli cronjob >/dev/null 2>&1
Примечание: Ð¿Ñ€Ð¾Ñ†ÐµÑ Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ñ„Ð¾Ð½Ð¾Ð²Ñ‹Ñ… задач должен иметь права доÑтупа к вашей базе данных в Ñлучае еÑли вы иÑпользуете Sqlite. Обычно, доÑтаточно запуÑкать фоновую задачу под пользователем веб Ñервера.
-
-
-
-
-
-
[РуÑÑÐºÐ°Ñ Ð´Ð¾ÐºÑƒÐ¼ÐµÐ½Ñ‚Ð°Ñ†Ð¸Ñ Kanboard](http://kanboard.ru/doc/)
-
diff --git a/doc/ru_RU/index.markdown b/doc/ru_RU/index.markdown
index c4a12d52..88467206 100644
--- a/doc/ru_RU/index.markdown
+++ b/doc/ru_RU/index.markdown
@@ -178,7 +178,6 @@
- [ЗапуÑк Kanboard на Cloudron](cloudron.markdown)
-- [ЗапуÑк Kanboard на Nitrous](nitrous.markdown)
### ÐаÑтройка[¶](#configuration "СÑылка на Ñтот заголовок")
diff --git a/doc/ru_RU/installation.markdown b/doc/ru_RU/installation.markdown
index e59e43d2..ff989b19 100644
--- a/doc/ru_RU/installation.markdown
+++ b/doc/ru_RU/installation.markdown
@@ -75,6 +75,7 @@
├── assets -> ../kanboard/assets
├── doc -> ../kanboard/doc
+ ├── cli -> ../kanboard/cli
├── favicon.ico -> ../kanboard/favicon.ico
├── index.php -> ../kanboard/index.php
├── jsonrpc.php -> ../kanboard/jsonrpc.php
diff --git a/doc/ru_RU/translations.markdown b/doc/ru_RU/translations.markdown
index f4bcafc0..0b9c6752 100644
--- a/doc/ru_RU/translations.markdown
+++ b/doc/ru_RU/translations.markdown
@@ -1,61 +1,25 @@
Переводы на другие Ñзыки (локализациÑ)
======================================
-
-
Как перевеÑти Канборд на новый Ñзык?[¶](#how-to-translate-kanboard-to-a-new-language "СÑылка на Ñтот заголовок")
----------------------------------------------------------------------------------------------------------------
-
-
- Переводы хранÑÑ‚ÑÑ Ð² директории `app/Locale`
-
-
-
- Ð’ Ñтой директории еÑÑ‚ÑŒ поддиректории Ð´Ð»Ñ Ñ€Ð°Ð·Ð½Ñ‹Ñ… Ñзыков, например, Ð´Ð»Ñ Ñ€ÑƒÑÑкого имеетÑÑ `ru_RU`, Ð´Ð»Ñ Ñ„Ñ€Ð°Ð½Ñ†ÑƒÐ·Ñкого - `fr_FR` и Ñ‚.д.
-
-
-
- Переводы находÑÑ‚ÑÑ Ð² PHP файле, который возвращает маÑÑив Ñ Ð¿Ð°Ñ€Ð¾Ð¹ ключ-значение
-
-
-
- Ключ - оригинальный текÑÑ‚ на английÑком и значение - перевод на ÑоответÑвующем Ñзыке
-
-
-
- **ФранцузÑкие переводы вÑегда в актуальном ÑоÑтоÑнии**
-
-
-
- Ð’Ñегда иÑпользуйте поÑледнюю верÑию (branch master)
-
-
### Создание нового перевода[¶](#create-a-new-translation "СÑылка на Ñтот заголовок")
1. Создайте новую директорию: `app/Locale/xx_XX`, например `app/Locale/fr_CA` Ð´Ð»Ñ ÐºÐ°Ð½Ð°Ð´Ñкого фрацузÑкого
-
-
-
2. Создайте новый файл Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ²Ð¾Ð´Ð°: `app/Locale/xx_XX/translations.php`
-
-
-
3. ИÑпользуйте как образец Ñодержимое французÑкого перевода (локализации) и замените значениÑ
-
-
-
4. ВнеÑите Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð² файл `app/Model/Language.php`
-
-
-
5. Проверьте добавленный Ñзык на локальной верÑии Канборда
-
-
-
6. Пошлите [pull-request на Github](https://help.github.com/articles/using-pull-requests/)
@@ -63,93 +27,46 @@
Как обновить имеющийÑÑ Ð¿ÐµÑ€ÐµÐ²Ð¾Ð´?[¶](#how-to-update-an-existing-translation "СÑылка на Ñтот заголовок")
-----------------------------------------------------------------------------------------------------
-
-
1. Откройте файл перевода `app/Locale/xx_XX/translations.php`
-
-
-
2. ОтÑутÑвующие переводы закоментированы - `//` и Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð¿ÑƒÑтые, нужно заполнить Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð¸ удалить коментарий
-
-
-
3. Проверьте внеÑенные Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð½Ð° локальной верÑии Канборда и пошлите [pull-request](https://help.github.com/articles/using-pull-requests/)
-
Как добавить новый текÑÑ‚ перевода в приложение?[¶](#how-to-add-new-translated-text-in-the-application "СÑылка на Ñтот заголовок")
---------------------------------------------------------------------------------------------------------------------------------
-
-
Переводы отображаютÑÑ Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ функций в иÑходном коде:
-
- `t()`: показывает текÑÑ‚ Ñ HTML escaping
-
-
-
- `e()`: показывает текÑÑ‚ без HTML escaping
-
Ð’Ñегда иÑпользуйте английÑкую верÑию иÑходного кода.
-
-
-
ТекÑтовые Ñтроки иÑпользуют функцию `sprintf()` Ð´Ð»Ñ Ð·Ð°Ð¼ÐµÐ½Ñ‹ Ñлементов:
-
-
- `%s` иÑпользуетÑÑ Ð´Ð»Ñ Ð·Ð°Ð¼ÐµÐ½Ñ‹ Ñтроки
-
-
-
- `%d` иÑпользуетÑÑ Ð´Ð»Ñ Ð·Ð°Ð¼ÐµÐ½Ñ‹ цифры
-
ОзнакомитÑÑ Ñ Ð´Ð¾Ñтупными форматами вы можете в [документации PHP](http://php.net/sprintf).
-
-
Как найти отÑутÑтвующие переводы в приложении?[¶](#how-to-find-missing-translations-in-the-applications "СÑылка на Ñтот заголовок")
-----------------------------------------------------------------------------------------------------------------------------------
-
-
Из терминала запуÑтите Ñледующую команду:
-
-
- ./kanboard locale:compare
-
-
+ ./cli locale:compare
Ð’Ñе отÑутÑтвующие и неиÑпользуемые переводы будут показаны на Ñкране. Добавьте их во французÑкую локализацию и Ñинхронизируйте Ñ Ð´Ñ€ÑƒÐ³Ð¸Ð¼Ð¸ локализациÑми (Ñмотрите ниже)
-
-
Как Ñинхронизировать файлы переводов?[¶](#how-to-synchronize-translation-files "СÑылка на Ñтот заголовок")
----------------------------------------------------------------------------------------------------------
-
-
Ð’ оболочке Unix запуÑтите Ñледующую команду:
-
-
- ./kanboard locale:sync
-
-
+ ./cli locale:sync
ФранцузÑкий перевод иÑпользуетÑÑ Ð´Ð»Ñ ÑÑылки на другие локализации.
-
-
-
-
-
[РуÑÑÐºÐ°Ñ Ð´Ð¾ÐºÑƒÐ¼ÐµÐ½Ñ‚Ð°Ñ†Ð¸Ñ Kanboard](http://kanboard.ru/doc/)
-
diff --git a/doc/screenshots/mention-autocomplete.png b/doc/screenshots/mention-autocomplete.png
deleted file mode 100644
index f23fb6d1..00000000
--- a/doc/screenshots/mention-autocomplete.png
+++ /dev/null
Binary files differ
diff --git a/doc/screenshots/user-mentions.png b/doc/screenshots/user-mentions.png
new file mode 100644
index 00000000..d5f7bcc6
--- /dev/null
+++ b/doc/screenshots/user-mentions.png
Binary files differ
diff --git a/doc/solving-session-issue-windows-iis-ie.markdown b/doc/solving-session-issue-windows-iis-ie.markdown
new file mode 100644
index 00000000..1ad3124b
--- /dev/null
+++ b/doc/solving-session-issue-windows-iis-ie.markdown
@@ -0,0 +1,19 @@
+I'm not able to login with Internet Explorer and Microsoft IIS
+==============================================================
+
+If you are not able to login and always get the error **"Username or password required"** even if you have entered the right credentials,
+that means there is a problem with the session.
+
+For example, this is a known issue if you meet these criteria:
+
+- You are using a domain name with an underscore: `kanboard_something.mycompany.tld`
+- You are using Microsoft Windows Server and IIS
+- Your browser is Internet Explorer
+
+Solution: **Do not use underscore in the domain name because this is not a valid domain name**.
+
+Explanation: Internet Explorer doesn't accept cookies with a domain name with underscores because it's not valid.
+
+Reference:
+
+- https://support.microsoft.com/en-us/kb/316112
diff --git a/doc/translations.markdown b/doc/translations.markdown
index 074d9ae3..66fd2a4c 100644
--- a/doc/translations.markdown
+++ b/doc/translations.markdown
@@ -50,7 +50,7 @@ How to find missing translations in the applications?
From a terminal, run the following command:
```bash
-./kanboard locale:compare
+./cli locale:compare
```
All missing and unused translations are displayed on the screen.
@@ -62,7 +62,7 @@ How to synchronize translation files?
From a Unix shell run this command:
```bash
-./kanboard locale:sync
+./cli locale:sync
```
The French translation is used a reference to other locales.
diff --git a/doc/update.markdown b/doc/update.markdown
index fca0d7d4..76cac27a 100644
--- a/doc/update.markdown
+++ b/doc/update.markdown
@@ -11,8 +11,9 @@ Important things to do before updating
- **Always make a backup of your data before upgrading**
- **Check that your backup is valid!**
- Check again
-- Always read the [change log](https://github.com/kanboard/kanboard/blob/master/ChangeLog) to check for breaking changes
-- Always close all user sessions (flush all sessions on the server)
+- Always read the [change history](https://github.com/kanboard/kanboard/blob/master/ChangeLog) to check for breaking changes
+- Stop the worker if you use it
+- Put the web server in maintenance mode to avoid people use the software while upgrading
From the archive (stable version)
---------------------------------
@@ -33,3 +34,20 @@ From the repository (development version)
3. Login and check if everything is ok
Note: This method will install the **current development version**, use at your own risk.
+
+Running SQL migrations manually
+-------------------------------
+
+By default, SQL migrations are executed automatically. The schema version is checked at each request.
+In this way, when you upgrade Kanboard to another version, the database schema is updated for you.
+
+You may want to disable this behaviour is case you have a specific configuration.
+For example, if multiple processes try to apply the migrations in the same time you might have some concurrency problems even if each operation is executed inside a transaction.
+
+To disable this feature, set the parameter `DB_RUN_MIGRATIONS` at `false` in your [config file](config.markdown).
+
+When you will have to upgrade Kanboard, run this command:
+
+```bash
+./cli db:migrate
+```
diff --git a/doc/user-mentions.markdown b/doc/user-mentions.markdown
index 156456d6..4ce47054 100644
--- a/doc/user-mentions.markdown
+++ b/doc/user-mentions.markdown
@@ -6,7 +6,7 @@ Kanboard offers the possibility to send notifications when someone is mentioned.
If you need to get the attention of someone in a comment or in a task, use the @ symbol followed by their username.
Kanboard will automatically suggest a list of users:
-![User Mention](screenshots/mention-autocomplete.png)
+![User Mention](screenshots/user-mentions.png)
- At the moment, only the task description and the comment text area have this feature enabled.
- The user mentions works only during tasks and comments creation.
diff --git a/doc/worker.markdown b/doc/worker.markdown
index 8516068b..89becacd 100644
--- a/doc/worker.markdown
+++ b/doc/worker.markdown
@@ -19,7 +19,7 @@ This feature is optional and require the installation of a queue daemon on your
- To install Beanstalk, you can simply use the package manager of your Linux distribution
- Install the [Kanboard plugin for Beanstalk](https://kanboard.net/plugin/beanstalk)
-- Start the worker with the Kanboard command line tool: `./kanboard worker`
+- Start the worker with the Kanboard command line tool: `./cli worker`
### RabbitMQ
@@ -27,7 +27,7 @@ This feature is optional and require the installation of a queue daemon on your
- Follow the official documentation of RabbitMQ for the installation and the configuration
- Install the [Kanboard plugin for RabbitMQ](https://kanboard.net/plugin/rabbitmq)
-- Start the worker with the Kanboard command line tool: `./kanboard worker`
+- Start the worker with the Kanboard command line tool: `./cli worker`
### Notes
diff --git a/docker/crontab/cronjob.alpine b/docker/crontab/cronjob.alpine
index d051ff28..e92aa0e3 100644
--- a/docker/crontab/cronjob.alpine
+++ b/docker/crontab/cronjob.alpine
@@ -1 +1 @@
-1 0 * * * cd /var/www/app && ./kanboard cronjob
+1 0 * * * cd /var/www/app && ./cli cronjob
diff --git a/gulpfile.js b/gulpfile.js
index 0ff5b651..c9076ffa 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -7,10 +7,15 @@ var strip = require('gulp-strip-comments');
var src = {
js: [
+ 'node_modules/textarea-caret/index.js',
+ 'assets/js/polyfills/*.js',
+ 'assets/js/core/base.js',
+ 'assets/js/core/!(base|bootstrap)*.js',
+ 'assets/js/components/*.js',
+ 'assets/js/core/bootstrap.js',
'assets/js/src/Namespace.js',
'assets/js/src/!(Namespace|Bootstrap|BoardDragAndDrop)*.js',
'assets/js/src/BoardDragAndDrop.js',
- 'assets/js/components/*.js',
'assets/js/src/Bootstrap.js'
]
};
@@ -66,13 +71,6 @@ gulp.task('bower', function() {
});
gulp.task('vendor', function() {
- gulp.src('node_modules/vue/dist/vue.min.js')
- .pipe(strip({trim: true}))
- .pipe(gulp.dest('node_modules/vue/dist/'))
- ;
-
- vendor.js.push('node_modules/vue/dist/vue.min.js');
-
gulp.src(vendor.js)
.pipe(concat('vendor.min.js'))
.pipe(gulp.dest(dist.js))
diff --git a/nitrous-post-create.sh b/nitrous-post-create.sh
deleted file mode 100755
index 558cc753..00000000
--- a/nitrous-post-create.sh
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/bin/bash
-rm -rf ~/code/public_html
-
-sudo apt-get update
-sudo apt-get install -y php5-sqlite
-sudo apt-get clean
-
-cd ~/code
-mv kanboard public_html
-cd public_html
-composer install
-cd ~/code
-sudo chown -R nitrous:www-data public_html
-sudo service apache2 reload
diff --git a/nitrous.json b/nitrous.json
deleted file mode 100644
index 1cf4ab67..00000000
--- a/nitrous.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "template": "php-apache",
- "ports": [3000],
- "name": "Kanboard",
- "description": "Kanban project management software"
-}
diff --git a/package.json b/package.json
index ac74f034..d2a47830 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "kanboard",
- "dependencies": {
+ "devDependencies": {
"bower": "^1.7.9",
"gulp": "^3.9.1",
"gulp-bower": "0.0.13",
@@ -9,6 +9,9 @@
"gulp-sass": "^2.3.2",
"gulp-strip-comments": "^2.4.3",
"gulp-uglify": "^1.5.3",
- "vue": "1.0.26-csp"
+ "jshint": "^2.9.4"
+ },
+ "dependencies": {
+ "textarea-caret": "^3.0.2"
}
}
diff --git a/tests/units/Auth/ApiAccessTokenAuthTest.php b/tests/units/Auth/ApiAccessTokenAuthTest.php
new file mode 100644
index 00000000..22852805
--- /dev/null
+++ b/tests/units/Auth/ApiAccessTokenAuthTest.php
@@ -0,0 +1,71 @@
+<?php
+
+use Kanboard\Auth\ApiAccessTokenAuth;
+use Kanboard\Model\UserModel;
+
+require_once __DIR__.'/../Base.php';
+
+class ApiAccessTokenAuthTest extends Base
+{
+ public function testGetName()
+ {
+ $provider = new ApiAccessTokenAuth($this->container);
+ $this->assertEquals('API Access Token', $provider->getName());
+ }
+
+ public function testAuthenticateWithoutToken()
+ {
+ $provider = new ApiAccessTokenAuth($this->container);
+
+ $provider->setUsername('admin');
+ $provider->setPassword('admin');
+ $this->assertFalse($provider->authenticate());
+ $this->assertNull($provider->getUser());
+ }
+
+ public function testAuthenticateWithEmptyPassword()
+ {
+ $provider = new ApiAccessTokenAuth($this->container);
+
+ $provider->setUsername('admin');
+ $provider->setPassword('');
+ $this->assertFalse($provider->authenticate());
+ }
+
+ public function testAuthenticateWithTokenAndNoScope()
+ {
+ $provider = new ApiAccessTokenAuth($this->container);
+ $userModel = new UserModel($this->container);
+
+ $userModel->update(array(
+ 'id' => 1,
+ 'api_access_token' => 'test',
+ ));
+
+ $provider->setUsername('admin');
+ $provider->setPassword('test');
+ $this->assertFalse($provider->authenticate());
+ }
+
+ public function testAuthenticateWithToken()
+ {
+ $this->container['sessionStorage']->scope = 'API';
+
+ $provider = new ApiAccessTokenAuth($this->container);
+ $userModel = new UserModel($this->container);
+
+ $userModel->update(array(
+ 'id' => 1,
+ 'api_access_token' => 'test',
+ ));
+
+ $provider->setUsername('admin');
+ $provider->setPassword('test');
+ $this->assertTrue($provider->authenticate());
+ $this->assertInstanceOf('Kanboard\User\DatabaseUserProvider', $provider->getUser());
+
+ $provider->setUsername('admin');
+ $provider->setPassword('something else');
+ $this->assertFalse($provider->authenticate());
+ }
+}
diff --git a/tests/units/Base.php b/tests/units/Base.php
index 722a1335..1b986fcb 100644
--- a/tests/units/Base.php
+++ b/tests/units/Base.php
@@ -49,6 +49,7 @@ abstract class Base extends PHPUnit_Framework_TestCase
$this->container->register(new Kanboard\ServiceProvider\FilterProvider());
$this->container->register(new Kanboard\ServiceProvider\JobProvider());
$this->container->register(new Kanboard\ServiceProvider\QueueProvider());
+ $this->container->register(new Kanboard\ServiceProvider\ExternalTaskProvider());
$this->container['dispatcher'] = new TraceableEventDispatcher(
new EventDispatcher,
diff --git a/tests/units/EventBuilder/CommentEventBuilderTest.php b/tests/units/EventBuilder/CommentEventBuilderTest.php
index 2f6a90b5..ff1c630e 100644
--- a/tests/units/EventBuilder/CommentEventBuilderTest.php
+++ b/tests/units/EventBuilder/CommentEventBuilderTest.php
@@ -33,5 +33,7 @@ class CommentEventBuilderTest extends Base
$this->assertInstanceOf('Kanboard\Event\CommentEvent', $event);
$this->assertNotEmpty($event['comment']);
$this->assertNotEmpty($event['task']);
+ $this->assertEquals(1, $event->getTaskId());
+ $this->assertEquals(1, $event->getProjectId());
}
}
diff --git a/tests/units/EventBuilder/ProjectFileEventBuilderTest.php b/tests/units/EventBuilder/ProjectFileEventBuilderTest.php
index 8f5eb87e..c3595029 100644
--- a/tests/units/EventBuilder/ProjectFileEventBuilderTest.php
+++ b/tests/units/EventBuilder/ProjectFileEventBuilderTest.php
@@ -29,5 +29,7 @@ class ProjectFileEventBuilderTest extends Base
$this->assertInstanceOf('Kanboard\Event\ProjectFileEvent', $event);
$this->assertNotEmpty($event['file']);
$this->assertNotEmpty($event['project']);
+ $this->assertNull($event->getTaskId());
+ $this->assertEquals(1, $event->getProjectId());
}
}
diff --git a/tests/units/EventBuilder/SubtaskEventBuilderTest.php b/tests/units/EventBuilder/SubtaskEventBuilderTest.php
index fe425cb8..215b1ed2 100644
--- a/tests/units/EventBuilder/SubtaskEventBuilderTest.php
+++ b/tests/units/EventBuilder/SubtaskEventBuilderTest.php
@@ -58,5 +58,7 @@ class SubtaskEventBuilderTest extends Base
$this->assertCount(2, $event['changes']);
$this->assertEquals('new title', $event['changes']['title']);
$this->assertEquals(1, $event['changes']['user_id']);
+ $this->assertEquals(1, $event->getTaskId());
+ $this->assertEquals(1, $event->getProjectId());
}
}
diff --git a/tests/units/EventBuilder/TaskEventBuilderTest.php b/tests/units/EventBuilder/TaskEventBuilderTest.php
index c89dcd85..446b862b 100644
--- a/tests/units/EventBuilder/TaskEventBuilderTest.php
+++ b/tests/units/EventBuilder/TaskEventBuilderTest.php
@@ -33,6 +33,8 @@ class TaskEventBuilderTest extends Base
$this->assertInstanceOf('Kanboard\Event\TaskEvent', $event);
$this->assertNotEmpty($event['task']);
$this->assertEquals(1, $event['task_id']);
+ $this->assertEquals(1, $event->getTaskId());
+ $this->assertEquals(1, $event->getProjectId());
$this->assertEquals(array('title' => 'after'), $event['changes']);
}
diff --git a/tests/units/EventBuilder/TaskFileEventBuilderTest.php b/tests/units/EventBuilder/TaskFileEventBuilderTest.php
index c90e18d3..1e88b6fb 100644
--- a/tests/units/EventBuilder/TaskFileEventBuilderTest.php
+++ b/tests/units/EventBuilder/TaskFileEventBuilderTest.php
@@ -32,5 +32,7 @@ class TaskFileEventBuilderTest extends Base
$this->assertInstanceOf('Kanboard\Event\TaskFileEvent', $event);
$this->assertNotEmpty($event['file']);
$this->assertNotEmpty($event['task']);
+ $this->assertEquals(1, $event->getTaskId());
+ $this->assertEquals(1, $event->getProjectId());
}
}
diff --git a/tests/units/EventBuilder/TaskLinkEventBuilderTest.php b/tests/units/EventBuilder/TaskLinkEventBuilderTest.php
index 18508146..4e38eeb6 100644
--- a/tests/units/EventBuilder/TaskLinkEventBuilderTest.php
+++ b/tests/units/EventBuilder/TaskLinkEventBuilderTest.php
@@ -33,6 +33,8 @@ class TaskLinkEventBuilderTest extends Base
$this->assertInstanceOf('Kanboard\Event\TaskLinkEvent', $event);
$this->assertNotEmpty($event['task_link']);
$this->assertNotEmpty($event['task']);
+ $this->assertEquals(1, $event->getTaskId());
+ $this->assertEquals(1, $event->getProjectId());
}
public function testBuildTitle()
diff --git a/tests/units/Filter/TaskStartsWithIdFilterTest.php b/tests/units/Filter/TaskStartsWithIdFilterTest.php
new file mode 100644
index 00000000..e911a6a1
--- /dev/null
+++ b/tests/units/Filter/TaskStartsWithIdFilterTest.php
@@ -0,0 +1,103 @@
+<?php
+
+use Kanboard\Filter\TaskStartsWithIdFilter;
+use Kanboard\Model\ProjectModel;
+use Kanboard\Model\TaskCreationModel;
+use Kanboard\Model\TaskFinderModel;
+
+require_once __DIR__.'/../Base.php';
+
+class TaskStartsWithIdFilterTest extends Base
+{
+ public function testManyResults()
+ {
+ $taskFinderModel = new TaskFinderModel($this->container);
+ $projectModel = new ProjectModel($this->container);
+ $taskCreationModel = new TaskCreationModel($this->container);
+ $query = $taskFinderModel->getExtendedQuery();
+
+ $this->assertEquals(1, $projectModel->create(array('name' => 'Test')));
+
+ for ($i = 1; $i <= 20; $i++) {
+ $this->assertNotFalse($taskCreationModel->create(array('project_id' => 1, 'title' => 'Task #'.$i)));
+ }
+
+ $filter = new TaskStartsWithIdFilter();
+ $filter->withQuery($query);
+ $filter->withValue(1);
+ $filter->apply();
+
+ $tasks = $query->findAll();
+ $this->assertCount(11, $tasks);
+ $this->assertEquals('Task #1', $tasks[0]['title']);
+ $this->assertEquals('Task #19', $tasks[10]['title']);
+ }
+
+ public function testOneResult()
+ {
+ $taskFinderModel = new TaskFinderModel($this->container);
+ $projectModel = new ProjectModel($this->container);
+ $taskCreationModel = new TaskCreationModel($this->container);
+ $query = $taskFinderModel->getExtendedQuery();
+
+ $this->assertEquals(1, $projectModel->create(array('name' => 'Test')));
+
+ for ($i = 1; $i <= 20; $i++) {
+ $this->assertNotFalse($taskCreationModel->create(array('project_id' => 1, 'title' => 'Task #'.$i)));
+ }
+
+ $filter = new TaskStartsWithIdFilter();
+ $filter->withQuery($query);
+ $filter->withValue(3);
+ $filter->apply();
+
+ $tasks = $query->findAll();
+ $this->assertCount(1, $tasks);
+ $this->assertEquals('Task #3', $tasks[0]['title']);
+ }
+
+ public function testEmptyResult()
+ {
+ $taskFinderModel = new TaskFinderModel($this->container);
+ $projectModel = new ProjectModel($this->container);
+ $taskCreationModel = new TaskCreationModel($this->container);
+ $query = $taskFinderModel->getExtendedQuery();
+
+ $this->assertEquals(1, $projectModel->create(array('name' => 'Test')));
+
+ for ($i = 1; $i <= 20; $i++) {
+ $this->assertNotFalse($taskCreationModel->create(array('project_id' => 1, 'title' => 'Task #'.$i)));
+ }
+
+ $filter = new TaskStartsWithIdFilter();
+ $filter->withQuery($query);
+ $filter->withValue(30);
+ $filter->apply();
+
+ $tasks = $query->findAll();
+ $this->assertCount(0, $tasks);
+ }
+
+ public function testWithTwoDigits()
+ {
+ $taskFinderModel = new TaskFinderModel($this->container);
+ $projectModel = new ProjectModel($this->container);
+ $taskCreationModel = new TaskCreationModel($this->container);
+ $query = $taskFinderModel->getExtendedQuery();
+
+ $this->assertEquals(1, $projectModel->create(array('name' => 'Test')));
+
+ for ($i = 1; $i <= 20; $i++) {
+ $this->assertNotFalse($taskCreationModel->create(array('project_id' => 1, 'title' => 'Task #'.$i)));
+ }
+
+ $filter = new TaskStartsWithIdFilter();
+ $filter->withQuery($query);
+ $filter->withValue(11);
+ $filter->apply();
+
+ $tasks = $query->findAll();
+ $this->assertCount(1, $tasks);
+ $this->assertEquals('Task #11', $tasks[0]['title']);
+ }
+}
diff --git a/tests/units/Formatter/TaskSuggestMenuFormatterTest.php b/tests/units/Formatter/TaskSuggestMenuFormatterTest.php
new file mode 100644
index 00000000..d247d670
--- /dev/null
+++ b/tests/units/Formatter/TaskSuggestMenuFormatterTest.php
@@ -0,0 +1,39 @@
+<?php
+
+use Kanboard\Formatter\TaskSuggestMenuFormatter;
+use Kanboard\Model\ProjectModel;
+use Kanboard\Model\TaskCreationModel;
+
+require_once __DIR__.'/../Base.php';
+
+class TaskSuggestMenuFormatterTest extends Base
+{
+ public function testFormat()
+ {
+ $projectModel = new ProjectModel($this->container);
+ $taskCreationModel = new TaskCreationModel($this->container);
+ $taskSuggestMenuFormatter = new TaskSuggestMenuFormatter($this->container);
+
+ $this->assertEquals(1, $projectModel->create(array('name' => 'My Project')));
+ $this->assertEquals(1, $taskCreationModel->create(array('title' => 'Task 1', 'project_id' => 1)));
+ $this->assertEquals(2, $taskCreationModel->create(array('title' => 'Task 2', 'project_id' => 1)));
+
+ $result = $taskSuggestMenuFormatter
+ ->withQuery($this->container['taskFinderModel']->getExtendedQuery())
+ ->format()
+ ;
+
+ $expected = array(
+ array(
+ 'value' => '1',
+ 'html' => '#1 Task 1 <small>My Project</small>',
+ ),
+ array(
+ 'value' => '2',
+ 'html' => '#2 Task 2 <small>My Project</small>',
+ ),
+ );
+
+ $this->assertSame($expected, $result);
+ }
+}
diff --git a/tests/units/Formatter/UserMentionFormatterTest.php b/tests/units/Formatter/UserMentionFormatterTest.php
new file mode 100644
index 00000000..6338e80f
--- /dev/null
+++ b/tests/units/Formatter/UserMentionFormatterTest.php
@@ -0,0 +1,42 @@
+<?php
+
+use Kanboard\Formatter\UserMentionFormatter;
+
+require_once __DIR__.'/../Base.php';
+
+class UserMentionFormatterTest extends Base
+{
+ public function testFormat()
+ {
+ $userMentionFormatter = new UserMentionFormatter($this->container);
+ $users = array(
+ array(
+ 'id' => 1,
+ 'username' => 'someone',
+ 'name' => 'Someone',
+ 'email' => 'test@localhost',
+ 'avatar_path' => 'avatar_image',
+ ),
+ array(
+ 'id' => 2,
+ 'username' => 'somebody',
+ 'name' => '',
+ 'email' => '',
+ 'avatar_path' => '',
+ )
+ );
+
+ $expected = array(
+ array(
+ 'value' => 'someone',
+ 'html' => '<div class="avatar avatar-20 avatar-inline"><img src="?controller=AvatarFileController&amp;action=image&amp;user_id=1&amp;size=20" alt="Someone" title="Someone"></div> someone <small>Someone</small>',
+ ),
+ array(
+ 'value' => 'somebody',
+ 'html' => '<div class="avatar avatar-20 avatar-inline"><div class="avatar-letter" style="background-color: rgb(191, 210, 121)" title="somebody">S</div></div> somebody',
+ ),
+ );
+
+ $this->assertSame($expected, $userMentionFormatter->withUsers($users)->format());
+ }
+}
diff --git a/tests/units/FunctionTest.php b/tests/units/FunctionTest.php
index 1c5f971d..0709f1fb 100644
--- a/tests/units/FunctionTest.php
+++ b/tests/units/FunctionTest.php
@@ -59,6 +59,38 @@ class FunctionTest extends Base
$this->assertSame($expected, array_column_index($input, 'k1'));
}
+ public function testArrayColumnIndexUnique()
+ {
+ $input = array(
+ array(
+ 'k1' => 11,
+ 'k2' => 22,
+ ),
+ array(
+ 'k1' => 11,
+ 'k2' => 55,
+ ),
+ array(
+ 'k1' => 33,
+ 'k2' => 44,
+ ),
+ array()
+ );
+
+ $expected = array(
+ 11 => array(
+ 'k1' => 11,
+ 'k2' => 22,
+ ),
+ 33 => array(
+ 'k1' => 33,
+ 'k2' => 44,
+ )
+ );
+
+ $this->assertSame($expected, array_column_index_unique($input, 'k1'));
+ }
+
public function testArrayMergeRelation()
{
$relations = array(
diff --git a/tests/units/Helper/TextHelperTest.php b/tests/units/Helper/TextHelperTest.php
index c9447abb..a54c5780 100644
--- a/tests/units/Helper/TextHelperTest.php
+++ b/tests/units/Helper/TextHelperTest.php
@@ -32,7 +32,7 @@ class TextHelperTest extends Base
);
$this->assertEquals(
- '<p>Task <a href="?controller=TaskViewController&amp;action=readonly&amp;token='.$project['token'].'&amp;task_id=1">#1</a></p>',
+ '<p>Task <a href="http://localhost/?controller=TaskViewController&amp;action=readonly&amp;token='.$project['token'].'&amp;task_id=1">#1</a></p>',
$helper->markdown('Task #1', true)
);
@@ -48,6 +48,11 @@ class TextHelperTest extends Base
{
$h = new TextHelper($this->container);
$this->assertEquals('<p>Text <a href="?controller=UserViewController&amp;action=profile&amp;user_id=1" class="user-mention-link">@admin</a> @notfound</p>', $h->markdown('Text @admin @notfound'));
+ $this->assertEquals('<p>Text <a href="?controller=UserViewController&amp;action=profile&amp;user_id=1" class="user-mention-link">@admin</a>,</p>', $h->markdown('Text @admin,'));
+ $this->assertEquals('<p>Text <a href="?controller=UserViewController&amp;action=profile&amp;user_id=1" class="user-mention-link">@admin</a>!</p>', $h->markdown('Text @admin!'));
+ $this->assertEquals('<p>Text <a href="?controller=UserViewController&amp;action=profile&amp;user_id=1" class="user-mention-link">@admin</a>? </p>', $h->markdown('Text @admin? '));
+ $this->assertEquals('<p>Text <a href="?controller=UserViewController&amp;action=profile&amp;user_id=1" class="user-mention-link">@admin</a>.</p>', $h->markdown('Text @admin.'));
+ $this->assertEquals('<p>Text <a href="?controller=UserViewController&amp;action=profile&amp;user_id=1" class="user-mention-link">@admin</a>: test</p>', $h->markdown('Text @admin: test'));
$this->assertEquals('<p>Text @admin @notfound</p>', $h->markdown('Text @admin @notfound', true));
}
diff --git a/tests/units/Job/CommentEventJobTest.php b/tests/units/Job/CommentEventJobTest.php
index 8571af8e..b830b2b8 100644
--- a/tests/units/Job/CommentEventJobTest.php
+++ b/tests/units/Job/CommentEventJobTest.php
@@ -49,4 +49,46 @@ class CommentEventJobTest extends Base
$this->assertArrayHasKey(CommentModel::EVENT_UPDATE.'.closure', $called);
$this->assertArrayHasKey(CommentModel::EVENT_DELETE.'.closure', $called);
}
+
+ public function testThatUserMentionJobIsCalled()
+ {
+ $comment = 'some comment';
+
+ $this->container['queueManager'] = $this
+ ->getMockBuilder('\Kanboard\Core\Queue\QueueManager')
+ ->setConstructorArgs(array($this->container))
+ ->setMethods(array(
+ 'push',
+ ))
+ ->getMock();
+
+ $this->container['userMentionJob'] = $this
+ ->getMockBuilder('\Kanboard\Job\UserMentionJob')
+ ->setConstructorArgs(array($this->container))
+ ->setMethods(array(
+ 'withParams',
+ ))
+ ->getMock();
+
+ $this->container['queueManager']
+ ->expects($this->any())
+ ->method('push');
+
+ $this->container['userMentionJob']
+ ->expects($this->once())
+ ->method('withParams')
+ ->with($comment, CommentModel::EVENT_USER_MENTION, $this->anything())
+ ->will($this->returnValue($this->container['userMentionJob']));
+
+ $commentModel = new CommentModel($this->container);
+ $taskCreationModel = new TaskCreationModel($this->container);
+ $projectModel = new ProjectModel($this->container);
+ $commentEventJob = new CommentEventJob($this->container);
+
+ $this->assertEquals(1, $projectModel->create(array('name' => 'test1')));
+ $this->assertEquals(1, $taskCreationModel->create(array('title' => 'test', 'project_id' => 1)));
+ $this->assertEquals(1, $commentModel->create(array('task_id' => 1, 'comment' => $comment, 'user_id' => 1)));
+
+ $commentEventJob->execute(1, CommentModel::EVENT_CREATE);
+ }
}
diff --git a/tests/units/Job/TaskEventJobTest.php b/tests/units/Job/TaskEventJobTest.php
index c399faad..bfd7bc55 100644
--- a/tests/units/Job/TaskEventJobTest.php
+++ b/tests/units/Job/TaskEventJobTest.php
@@ -186,4 +186,44 @@ class TaskEventJobTest extends Base
$called = $this->container['dispatcher']->getCalledListeners();
$this->assertArrayHasKey(TaskModel::EVENT_MOVE_PROJECT.'.closure', $called);
}
+
+ public function testThatUserMentionJobIsCalled()
+ {
+ $description = 'something';
+
+ $this->container['queueManager'] = $this
+ ->getMockBuilder('\Kanboard\Core\Queue\QueueManager')
+ ->setConstructorArgs(array($this->container))
+ ->setMethods(array(
+ 'push',
+ ))
+ ->getMock();
+
+ $this->container['userMentionJob'] = $this
+ ->getMockBuilder('\Kanboard\Job\UserMentionJob')
+ ->setConstructorArgs(array($this->container))
+ ->setMethods(array(
+ 'withParams',
+ ))
+ ->getMock();
+
+ $this->container['queueManager']
+ ->expects($this->any())
+ ->method('push');
+
+ $this->container['userMentionJob']
+ ->expects($this->once())
+ ->method('withParams')
+ ->with($description, TaskModel::EVENT_USER_MENTION, $this->anything())
+ ->will($this->returnValue($this->container['userMentionJob']));
+
+ $taskCreationModel = new TaskCreationModel($this->container);
+ $projectModel = new ProjectModel($this->container);
+ $taskEventJob = new TaskEventJob($this->container);
+
+ $this->assertEquals(1, $projectModel->create(array('name' => 'test1')));
+ $this->assertEquals(1, $taskCreationModel->create(array('title' => 'test', 'description' => $description, 'project_id' => 1)));
+
+ $taskEventJob->execute(1, array(TaskModel::EVENT_CREATE));
+ }
}
diff --git a/tests/units/Model/UserMentionTest.php b/tests/units/Job/UserMentionJobTest.php
index b41c92cd..4cd4ac9b 100644
--- a/tests/units/Model/UserMentionTest.php
+++ b/tests/units/Job/UserMentionJobTest.php
@@ -1,45 +1,44 @@
<?php
-require_once __DIR__.'/../Base.php';
-
use Kanboard\Core\Security\Role;
-use Kanboard\Event\GenericEvent;
-use Kanboard\Model\UserModel;
-use Kanboard\Model\TaskModel;
-use Kanboard\Model\TaskCreationModel;
+use Kanboard\Event\TaskEvent;
+use Kanboard\Job\UserMentionJob;
use Kanboard\Model\ProjectModel;
use Kanboard\Model\ProjectUserRoleModel;
-use Kanboard\Model\UserMentionModel;
+use Kanboard\Model\TaskModel;
+use Kanboard\Model\UserModel;
+
+require_once __DIR__.'/../Base.php';
-class UserMentionTest extends Base
+class UserMentionJobTest extends Base
{
public function testGetMentionedUsersWithNoMentions()
{
$userModel = new UserModel($this->container);
- $userMentionModel = new UserMentionModel($this->container);
+ $userMentionJob = new UserMentionJob($this->container);
$this->assertNotFalse($userModel->create(array('username' => 'user1')));
- $this->assertEmpty($userMentionModel->getMentionedUsers('test'));
+ $this->assertEmpty($userMentionJob->getMentionedUsers('test'));
}
public function testGetMentionedUsersWithNotficationDisabled()
{
$userModel = new UserModel($this->container);
- $userMentionModel = new UserMentionModel($this->container);
+ $userMentionJob = new UserMentionJob($this->container);
$this->assertNotFalse($userModel->create(array('username' => 'user1')));
- $this->assertEmpty($userMentionModel->getMentionedUsers('test @user1'));
+ $this->assertEmpty($userMentionJob->getMentionedUsers('test @user1'));
}
public function testGetMentionedUsersWithNotficationEnabled()
{
$userModel = new UserModel($this->container);
- $userMentionModel = new UserMentionModel($this->container);
+ $userMentionJob = new UserMentionJob($this->container);
$this->assertNotFalse($userModel->create(array('username' => 'user1')));
$this->assertNotFalse($userModel->create(array('username' => 'user2', 'name' => 'Foobar', 'notifications_enabled' => 1)));
- $users = $userMentionModel->getMentionedUsers('test @user2');
+ $users = $userMentionJob->getMentionedUsers('test @user2');
$this->assertCount(1, $users);
$this->assertEquals('user2', $users[0]['username']);
$this->assertEquals('Foobar', $users[0]['name']);
@@ -47,48 +46,41 @@ class UserMentionTest extends Base
$this->assertEquals('', $users[0]['language']);
}
- public function testGetMentionedUsersWithNotficationEnabledAndUserLoggedIn()
+ public function testGetMentionedUsersWithNotficationEnabledAndPunctuationMarks()
{
- $this->container['sessionStorage']->user = array('id' => 3);
$userModel = new UserModel($this->container);
- $userMentionModel = new UserMentionModel($this->container);
+ $userMentionJob = new UserMentionJob($this->container);
$this->assertNotFalse($userModel->create(array('username' => 'user1')));
$this->assertNotFalse($userModel->create(array('username' => 'user2', 'name' => 'Foobar', 'notifications_enabled' => 1)));
- $this->assertEmpty($userMentionModel->getMentionedUsers('test @user2'));
+ $users = $userMentionJob->getMentionedUsers('test @user2, test');
+ $this->assertCount(1, $users);
+ $this->assertEquals('user2', $users[0]['username']);
+ $this->assertEquals('Foobar', $users[0]['name']);
+ $this->assertEquals('', $users[0]['email']);
+ $this->assertEquals('', $users[0]['language']);
}
- public function testFireEventsWithMultipleMentions()
+ public function testGetMentionedUsersWithNotficationEnabledAndUserLoggedIn()
{
- $projectUserRoleModel = new ProjectUserRoleModel($this->container);
- $projectModel = new ProjectModel($this->container);
+ $this->container['sessionStorage']->user = array('id' => 3);
$userModel = new UserModel($this->container);
- $userMentionModel = new UserMentionModel($this->container);
- $event = new GenericEvent(array('project_id' => 1));
-
- $this->assertEquals(2, $userModel->create(array('username' => 'user1', 'name' => 'User 1', 'notifications_enabled' => 1)));
- $this->assertEquals(3, $userModel->create(array('username' => 'user2', 'name' => 'User 2', 'notifications_enabled' => 1)));
-
- $this->assertEquals(1, $projectModel->create(array('name' => 'P1')));
- $this->assertTrue($projectUserRoleModel->addUser(1, 3, Role::PROJECT_MEMBER));
-
- $this->container['dispatcher']->addListener(TaskModel::EVENT_USER_MENTION, array($this, 'onUserMention'));
+ $userMentionJob = new UserMentionJob($this->container);
- $userMentionModel->fireEvents('test @user1 @user2', TaskModel::EVENT_USER_MENTION, $event);
+ $this->assertNotFalse($userModel->create(array('username' => 'user1')));
+ $this->assertNotFalse($userModel->create(array('username' => 'user2', 'name' => 'Foobar', 'notifications_enabled' => 1)));
- $called = $this->container['dispatcher']->getCalledListeners();
- $this->assertArrayHasKey(TaskModel::EVENT_USER_MENTION.'.UserMentionTest::onUserMention', $called);
+ $this->assertEmpty($userMentionJob->getMentionedUsers('test @user2'));
}
- public function testFireEventsWithNoProjectId()
+ public function testFireEventsWithMultipleMentions()
{
$projectUserRoleModel = new ProjectUserRoleModel($this->container);
$projectModel = new ProjectModel($this->container);
- $taskCreationModel = new TaskCreationModel($this->container);
$userModel = new UserModel($this->container);
- $userMentionModel = new UserMentionModel($this->container);
- $event = new GenericEvent(array('task_id' => 1));
+ $userMentionJob = new UserMentionJob($this->container);
+ $event = new TaskEvent(array('task' => array('project_id' => 1)));
$this->assertEquals(2, $userModel->create(array('username' => 'user1', 'name' => 'User 1', 'notifications_enabled' => 1)));
$this->assertEquals(3, $userModel->create(array('username' => 'user2', 'name' => 'User 2', 'notifications_enabled' => 1)));
@@ -96,14 +88,12 @@ class UserMentionTest extends Base
$this->assertEquals(1, $projectModel->create(array('name' => 'P1')));
$this->assertTrue($projectUserRoleModel->addUser(1, 3, Role::PROJECT_MEMBER));
- $this->assertEquals(1, $taskCreationModel->create(array('project_id' => 1, 'title' => 'Task 1')));
-
$this->container['dispatcher']->addListener(TaskModel::EVENT_USER_MENTION, array($this, 'onUserMention'));
- $userMentionModel->fireEvents('test @user1 @user2', TaskModel::EVENT_USER_MENTION, $event);
+ $userMentionJob->execute('test @user1 @user2', TaskModel::EVENT_USER_MENTION, $event->getAll());
$called = $this->container['dispatcher']->getCalledListeners();
- $this->assertArrayHasKey(TaskModel::EVENT_USER_MENTION.'.UserMentionTest::onUserMention', $called);
+ $this->assertArrayHasKey(TaskModel::EVENT_USER_MENTION.'.UserMentionJobTest::onUserMention', $called);
}
public function onUserMention($event)
diff --git a/tests/units/Model/ConfigModelTest.php b/tests/units/Model/ConfigModelTest.php
new file mode 100644
index 00000000..bbc792e3
--- /dev/null
+++ b/tests/units/Model/ConfigModelTest.php
@@ -0,0 +1,125 @@
+<?php
+
+require_once __DIR__.'/../Base.php';
+
+use Kanboard\Model\ConfigModel;
+
+class ConfigModelTest extends Base
+{
+ public function testRegenerateToken()
+ {
+ $configModel = new ConfigModel($this->container);
+ $token = $configModel->getOption('api_token');
+ $this->assertTrue($configModel->regenerateToken('api_token'));
+ $this->assertNotEquals($token, $configModel->getOption('api_token'));
+ }
+
+ public function testCRUDOperations()
+ {
+ $configModel = new ConfigModel($this->container);
+
+ $this->assertTrue($configModel->save(array('key1' => 'value1')));
+ $this->assertTrue($configModel->save(array('key1' => 'value2')));
+ $this->assertTrue($configModel->save(array('key2' => 'value2')));
+
+ $this->assertEquals('value2', $configModel->getOption('key1'));
+ $this->assertEquals('value2', $configModel->getOption('key2'));
+ $this->assertEquals('', $configModel->getOption('key3'));
+ $this->assertEquals('default', $configModel->getOption('key3', 'default'));
+
+ $this->assertTrue($configModel->exists('key1'));
+ $this->assertFalse($configModel->exists('key3'));
+
+ $this->assertTrue($configModel->save(array('key1' => 'value1')));
+
+ $this->assertArrayHasKey('key1', $configModel->getAll());
+ $this->assertArrayHasKey('key2', $configModel->getAll());
+
+ $this->assertContains('value1', $configModel->getAll());
+ $this->assertContains('value2', $configModel->getAll());
+ }
+
+ public function testSaveApplicationUrl()
+ {
+ $configModel = new ConfigModel($this->container);
+
+ $this->assertTrue($configModel->save(array('application_url' => 'http://localhost/')));
+ $this->assertEquals('http://localhost/', $configModel->getOption('application_url'));
+
+ $this->assertTrue($configModel->save(array('application_url' => 'http://localhost')));
+ $this->assertEquals('http://localhost/', $configModel->getOption('application_url'));
+
+ $this->assertTrue($configModel->save(array('application_url' => '')));
+ $this->assertEquals('', $configModel->getOption('application_url'));
+ }
+
+ public function testDefaultValues()
+ {
+ $configModel = new ConfigModel($this->container);
+
+ $this->assertEquals(172800, $configModel->getOption('board_highlight_period'));
+ $this->assertEquals(60, $configModel->getOption('board_public_refresh_interval'));
+ $this->assertEquals(10, $configModel->getOption('board_private_refresh_interval'));
+ $this->assertEmpty($configModel->getOption('board_columns'));
+
+ $this->assertEquals('yellow', $configModel->getOption('default_color'));
+ $this->assertEquals('en_US', $configModel->getOption('application_language'));
+ $this->assertEquals('UTC', $configModel->getOption('application_timezone'));
+ $this->assertEquals('m/d/Y', $configModel->getOption('application_date_format'));
+ $this->assertEmpty($configModel->getOption('application_url'));
+ $this->assertEmpty($configModel->getOption('application_stylesheet'));
+ $this->assertEquals('USD', $configModel->getOption('application_currency'));
+
+ $this->assertEquals(0, $configModel->getOption('calendar_user_subtasks_time_tracking'));
+ $this->assertEquals('date_started', $configModel->getOption('calendar_user_tasks'));
+ $this->assertEquals('date_started', $configModel->getOption('calendar_user_tasks'));
+
+ $this->assertEquals(0, $configModel->getOption('integration_gravatar'));
+ $this->assertEquals(1, $configModel->getOption('cfd_include_closed_tasks'));
+ $this->assertEquals(1, $configModel->getOption('password_reset'));
+
+ $this->assertEquals(1, $configModel->getOption('subtask_time_tracking'));
+ $this->assertEquals(0, $configModel->getOption('subtask_restriction'));
+ $this->assertEmpty($configModel->getOption('project_categories'));
+
+ $this->assertEmpty($configModel->getOption('webhook_url_task_modification'));
+ $this->assertEmpty($configModel->getOption('webhook_url_task_creation'));
+ $this->assertNotEmpty($configModel->getOption('webhook_token'));
+ $this->assertEmpty($configModel->getOption('webhook_url'));
+
+ $this->assertNotEmpty($configModel->getOption('api_token'));
+ }
+
+ public function testGetOption()
+ {
+ $configModel = new ConfigModel($this->container);
+
+ $this->assertEquals('', $configModel->getOption('board_columns'));
+ $this->assertEquals('test', $configModel->getOption('board_columns', 'test'));
+ $this->assertEquals(0, $configModel->getOption('board_columns', 0));
+ }
+
+ public function testGetWithCaching()
+ {
+ $configModel = new ConfigModel($this->container);
+
+ $this->assertEquals('UTC', $configModel->get('application_timezone'));
+ $this->assertTrue($configModel->save(array('application_timezone' => 'Europe/Paris')));
+
+ $this->assertEquals('UTC', $configModel->get('application_timezone')); // cached value
+ $this->assertEquals('Europe/Paris', $configModel->getOption('application_timezone'));
+
+ $this->assertEquals('', $configModel->get('board_columns'));
+ $this->assertEquals('test', $configModel->get('board_columns', 'test'));
+ $this->assertEquals('test', $configModel->get('empty_value', 'test'));
+ }
+
+ public function testValueLength()
+ {
+ $configModel = new ConfigModel($this->container);
+ $string = str_repeat('a', 65535);
+
+ $this->assertTrue($configModel->save(array('application_stylesheet' => $string)));
+ $this->assertSame($string, $configModel->getOption('application_stylesheet'));
+ }
+}
diff --git a/tests/units/Model/ConfigTest.php b/tests/units/Model/ConfigTest.php
deleted file mode 100644
index 3345ee3e..00000000
--- a/tests/units/Model/ConfigTest.php
+++ /dev/null
@@ -1,116 +0,0 @@
-<?php
-
-require_once __DIR__.'/../Base.php';
-
-use Kanboard\Model\ConfigModel;
-
-class ConfigTest extends Base
-{
- public function testRegenerateToken()
- {
- $configModel = new ConfigModel($this->container);
- $token = $configModel->getOption('api_token');
- $this->assertTrue($configModel->regenerateToken('api_token'));
- $this->assertNotEquals($token, $configModel->getOption('api_token'));
- }
-
- public function testCRUDOperations()
- {
- $c = new ConfigModel($this->container);
-
- $this->assertTrue($c->save(array('key1' => 'value1')));
- $this->assertTrue($c->save(array('key1' => 'value2')));
- $this->assertTrue($c->save(array('key2' => 'value2')));
-
- $this->assertEquals('value2', $c->getOption('key1'));
- $this->assertEquals('value2', $c->getOption('key2'));
- $this->assertEquals('', $c->getOption('key3'));
- $this->assertEquals('default', $c->getOption('key3', 'default'));
-
- $this->assertTrue($c->exists('key1'));
- $this->assertFalse($c->exists('key3'));
-
- $this->assertTrue($c->save(array('key1' => 'value1')));
-
- $this->assertArrayHasKey('key1', $c->getAll());
- $this->assertArrayHasKey('key2', $c->getAll());
-
- $this->assertContains('value1', $c->getAll());
- $this->assertContains('value2', $c->getAll());
- }
-
- public function testSaveApplicationUrl()
- {
- $c = new ConfigModel($this->container);
-
- $this->assertTrue($c->save(array('application_url' => 'http://localhost/')));
- $this->assertEquals('http://localhost/', $c->getOption('application_url'));
-
- $this->assertTrue($c->save(array('application_url' => 'http://localhost')));
- $this->assertEquals('http://localhost/', $c->getOption('application_url'));
-
- $this->assertTrue($c->save(array('application_url' => '')));
- $this->assertEquals('', $c->getOption('application_url'));
- }
-
- public function testDefaultValues()
- {
- $c = new ConfigModel($this->container);
-
- $this->assertEquals(172800, $c->getOption('board_highlight_period'));
- $this->assertEquals(60, $c->getOption('board_public_refresh_interval'));
- $this->assertEquals(10, $c->getOption('board_private_refresh_interval'));
- $this->assertEmpty($c->getOption('board_columns'));
-
- $this->assertEquals('yellow', $c->getOption('default_color'));
- $this->assertEquals('en_US', $c->getOption('application_language'));
- $this->assertEquals('UTC', $c->getOption('application_timezone'));
- $this->assertEquals('m/d/Y', $c->getOption('application_date_format'));
- $this->assertEmpty($c->getOption('application_url'));
- $this->assertEmpty($c->getOption('application_stylesheet'));
- $this->assertEquals('USD', $c->getOption('application_currency'));
-
- $this->assertEquals(0, $c->getOption('calendar_user_subtasks_time_tracking'));
- $this->assertEquals('date_started', $c->getOption('calendar_user_tasks'));
- $this->assertEquals('date_started', $c->getOption('calendar_user_tasks'));
-
- $this->assertEquals(0, $c->getOption('integration_gravatar'));
- $this->assertEquals(1, $c->getOption('cfd_include_closed_tasks'));
- $this->assertEquals(1, $c->getOption('password_reset'));
-
- $this->assertEquals(1, $c->getOption('subtask_time_tracking'));
- $this->assertEquals(0, $c->getOption('subtask_restriction'));
- $this->assertEmpty($c->getOption('project_categories'));
-
- $this->assertEmpty($c->getOption('webhook_url_task_modification'));
- $this->assertEmpty($c->getOption('webhook_url_task_creation'));
- $this->assertNotEmpty($c->getOption('webhook_token'));
- $this->assertEmpty($c->getOption('webhook_url'));
-
- $this->assertNotEmpty($c->getOption('api_token'));
- }
-
- public function testGetOption()
- {
- $c = new ConfigModel($this->container);
-
- $this->assertEquals('', $c->getOption('board_columns'));
- $this->assertEquals('test', $c->getOption('board_columns', 'test'));
- $this->assertEquals(0, $c->getOption('board_columns', 0));
- }
-
- public function testGetWithCaching()
- {
- $c = new ConfigModel($this->container);
-
- $this->assertEquals('UTC', $c->get('application_timezone'));
- $this->assertTrue($c->save(array('application_timezone' => 'Europe/Paris')));
-
- $this->assertEquals('UTC', $c->get('application_timezone')); // cached value
- $this->assertEquals('Europe/Paris', $c->getOption('application_timezone'));
-
- $this->assertEquals('', $c->get('board_columns'));
- $this->assertEquals('test', $c->get('board_columns', 'test'));
- $this->assertEquals('test', $c->get('empty_value', 'test'));
- }
-}
diff --git a/tests/units/Model/ProjectPermissionModelTest.php b/tests/units/Model/ProjectPermissionModelTest.php
index 3313cf2d..7f604374 100644
--- a/tests/units/Model/ProjectPermissionModelTest.php
+++ b/tests/units/Model/ProjectPermissionModelTest.php
@@ -26,7 +26,7 @@ class ProjectPermissionModelTest extends Base
$this->assertEquals(1, $projectModel->create(array('name' => 'Project 1')));
$this->assertEquals(2, $userModel->create(array('username' => 'user1')));
- $this->assertEquals(3, $userModel->create(array('username' => 'user2')));
+ $this->assertEquals(3, $userModel->create(array('username' => 'user2', 'name' => 'User 2', 'email' => 'test@here', 'avatar_path' => 'test')));
$this->assertEquals(4, $userModel->create(array('username' => 'user3')));
$this->assertEquals(1, $groupModel->create('Group A'));
@@ -35,7 +35,24 @@ class ProjectPermissionModelTest extends Base
$this->assertTrue($groupRoleModel->addGroup(1, 1, Role::PROJECT_MEMBER));
$this->assertTrue($userRoleModel->addUser(1, 3, Role::PROJECT_MANAGER));
- $this->assertEquals(array('user1', 'user2'), $projectPermissionModel->findUsernames(1, 'us'));
+ $expected = array(
+ 'user1' => array(
+ 'username' => 'user1',
+ 'name' => null,
+ 'email' => null,
+ 'avatar_path' => null,
+ 'id' => '2',
+ ),
+ 'user2' => array(
+ 'username' => 'user2',
+ 'name' => 'User 2',
+ 'email' => 'test@here',
+ 'avatar_path' => 'test',
+ 'id' => '3',
+ )
+ );
+
+ $this->assertEquals($expected, $projectPermissionModel->findUsernames(1, 'us'));
$this->assertEmpty($projectPermissionModel->findUsernames(1, 'a'));
$this->assertEmpty($projectPermissionModel->findUsernames(2, 'user'));
}